From 2fca87e691d6f6c48db2f8d9f7f18c54d15fdf8a Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:27:24 +0100 Subject: [PATCH 01/27] fixes on sw for interleaved memory --- Makefile | 15 +++++++-------- hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl | 7 ++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 1e060cc2..29cad677 100644 --- a/Makefile +++ b/Makefile @@ -13,22 +13,21 @@ PORT ?= /dev/ttyUSB2 # 1 external domain for the CGRA EXTERNAL_DOMAINS = 1 -# Use more memory banks -MEMORY_BANKS = 4 - -# Project options are based on the app to be build (default - hello_world) -PROJECT ?= hello_world +PROJECT ?= hello_world +MEMORY_BANKS ?= 2 # Multiple of 2 +MEMORY_BANKS_IL ?= 4 # Power of 2 + export HEEP_DIR = hw/vendor/esl_epfl_x_heep/ include $(HEEP_DIR)Makefile.venv - # Generates mcu files. First the mcu-gen from X-HEEP is called. # This is needed to be done after the X-HEEP mcu-gen because the test-bench to be used is the one from CGRA-X-HEEP, not the one from X-HEEP. + mcu-gen: - $(MAKE) -f $(XHEEP_MAKE) EXTERNAL_DOMAINS=${EXTERNAL_DOMAINS} MEMORY_BANKS=${MEMORY_BANKS} $(MAKECMDGOALS) + $(MAKE) -f $(XHEEP_MAKE) EXTERNAL_DOMAINS=${EXTERNAL_DOMAINS} MEMORY_BANKS=$(MEMORY_BANKS) MEMORY_BANKS_IL=$(MEMORY_BANKS_IL) BUS=NtoM $(MAKECMDGOALS) cd hw/vendor/esl_epfl_x_heep &&\ - python util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg pad_cfg.hjson --outdir ../../../tb/ --memorybanks $(MEMORY_BANKS) --tpl-sv ../../../tb/tb_util.svh.tpl + python util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg pad_cfg.hjson --outdir ../../../tb/ --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --bus NtoM --tpl-sv ../../../tb/tb_util.svh.tpl ## Builds (synthesis and implementation) the bitstream for the FPGA version using Vivado ## @param FPGA_BOARD=nexys-a7-100t,pynq-z2 diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl index f05c107b..98f491ce 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl @@ -335,11 +335,12 @@ SECTIONS PROVIDE(__freertos_irq_stack_top = .); } >ram1 -% if ram_numbanks_cont > 1 and ram_numbanks_il > 0: - .data_interleaved : +.data_interleaved : { + . = ALIGN(4); + *(.xheep_data_interleaved) + . = ALIGN(4); } >ram_il -% endif /* Stabs debugging sections. */ .stab 0 : { *(.stab) } From 59cebb87a32b0166bb04dcd2f13998d2fc7fbd2c Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:08:00 +0100 Subject: [PATCH 02/27] revendor x-heep --- hw/vendor/eslepfl_x_heep.vendor.hjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index 1b336093..2571c6da 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/esl-epfl/x-heep.git", - rev: "df569a88fc7eaa447645262f0d3a76dd22c519f7", + rev: "76d58efe7b9dec0723c1cb9aaf8ad76ad6c85373", }, patch_dir: "patches/esl_epfl_x_heep", From cf060ebb31173fabfb65219621042733367be9fb Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:08:39 +0100 Subject: [PATCH 03/27] Update esl_epfl_x_heep to esl-epfl/x-heep@76d58ef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update code from upstream repository https://github.com/esl- epfl/x-heep.git to revision 76d58efe7b9dec0723c1cb9aaf8ad76ad6c85373 * Update ci (esl-epfl/x-heep#454) (Luigi Giuffrida) * fix num of FPGAs in README (Davide Schiavone) * Porting Ultrascale ZCU104 board (esl-epfl/x-heep#435) (jmiranda) * Add absolute path to `CMakeLists.txt` match statements (esl- epfl/x-heep#469) (Michele Caon) * add SystemC example (esl-epfl/x-heep#443) (Davide Schiavone) * Structs multireg fix (esl-epfl/x-heep#466) (Stefano Albini) * add Coremark and update cv32e40p (esl-epfl/x-heep#465) (Davide Schiavone) * add tiled matmul (esl-epfl/x-heep#464) (Davide Schiavone) * fix software errors/warnings (esl-epfl/x-heep#462) (Davide Schiavone) * add xcelium support (esl-epfl/x-heep#452) (Davide Schiavone) * Add matmul example (esl-epfl/x-heep#461) (Davide Schiavone) * fix typo in debug_ss (esl-epfl/x-heep#460) (Luigi Giuffrida) * update riscv_dbg (esl-epfl/x-heep#230) (Davide Schiavone) * Fix esl-epfl/x-heep#430 (esl-epfl/x-heep#459) (David Mallasén Quintana) * fix esl-epfl/x-heep#447 (esl-epfl/x-heep#453) (Davide Schiavone) * fix typo (esl-epfl/x-heep#458) (Luigi Giuffrida) * add OpenOCD BSCAN configuration file (esl-epfl/x-heep#457) (Luis Waucquez) * Removed repeated code in dma hal (esl-epfl/x-heep#456) (Juan-n-only) * Fix linker script generation (esl-epfl/x-heep#451) (Luigi Giuffrida) * Add a target to the Makefile to directly program the FPGA (esl- epfl/x-heep#450) (Luigi Giuffrida) * [hw/sw] update flash load linker script, data_interleaved and data_flash_only sections (esl-epfl/x-heep#399) (Davide Schiavone) * add simple accelerator example (esl-epfl/x-heep#446) (Davide Schiavone) * change python format for Bootrom (esl-epfl/x-heep#442) (Davide Schiavone) * fix memset bug (esl-epfl/x-heep#439) (Mattia Consani) * update cv32e40px with dual-read support (esl-epfl/x-heep#441) (Davide Schiavone) * Added X-HEEP Reference. (esl-epfl/x-heep#440) (Simone Machetti) * add w25q128 flash BSP (esl-epfl/x-heep#433) (Mattia Consani) * removed FEMU (esl-epfl/x-heep#437) (Simone Machetti) * update cve2 (esl-epfl/x-heep#284) (Davide Schiavone) * porting X-HEEP to the nexys FPGA (esl-epfl/x-heep#432) (Davide Schiavone) * Add standard and quad write functionality to flash model (esl- epfl/x-heep#426) (Mattia Consani) * revert :bug: introduced in last revendor of iceprog (davide schiavone) * Add `example_spi_host_quadIO` (esl-epfl/x-heep#401) (Mattia Consani) * fix minimal cfg with stack and heap size (esl-epfl/x-heep#431) (Davide Schiavone) * Update verible url (esl-epfl/x-heep#428) (David Mallasén Quintana) * expose DMA slots externally + external FIFO example (esl- epfl/x-heep#417) (grinningmosfet) * Updated the documentation on how to add external interrupts (esl- epfl/x-heep#427) (Juan-n-only) * add citation in readme (Davide Schiavone) * Fix run-blinky-freertos command (esl-epfl/x-heep#424) (jmiranda) * Compilation fix (esl-epfl/x-heep#422) (jmiranda) * add stack and heap size as parameters to mcu-gen (esl- epfl/x-heep#419) (Luigi Giuffrida) Signed-off-by: mbelda <11842513+mbelda@users.noreply.github.com> --- hw/vendor/esl_epfl_x_heep/.gitignore | 6 +- hw/vendor/esl_epfl_x_heep/Makefile | 71 +- hw/vendor/esl_epfl_x_heep/README.md | 167 +- .../esl_epfl_x_heep/core-v-mini-mcu.core | 117 +- .../docs/source/How_to/CompileMakefile | 34 +- .../docs/source/How_to/Debug.md | 82 +- .../docs/source/How_to/ExternalDevices.md | 52 + .../docs/source/How_to/ProgramFlash.md | 18 +- .../docs/source/How_to/SystemC.md | 16 + .../ao_peripheral_subsystem.sv | 9 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv | 21 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl | 21 +- .../hw/core-v-mini-mcu/cpu_subsystem.sv | 82 +- .../hw/core-v-mini-mcu/debug_subsystem.sv | 7 +- ..._epfl_nexys-a7-100t_board_files.lock.hjson | 14 + ...pfl_nexys-a7-100t_board_files.vendor.hjson | 17 + .../board.xml | 1301 +++++++++++++++ .../mig.prj | 157 ++ .../part0_pins.xml | 153 ++ .../preset.xml | 398 +++++ .../esl_epfl_zcu104_board_files.lock.hjson | 14 + .../esl_epfl_zcu104_board_files.vendor.hjson | 16 + .../esl_epfl_zcu104_board_files/board.xml | 657 ++++++++ .../part0_pins.xml | 228 +++ .../esl_epfl_zcu104_board_files/preset.xml | 446 +++++ .../hw/fpga/constraints/nexys/constraints.xdc | 2 +- .../hw/fpga/constraints/nexys/pin_assign.xdc | 258 +-- .../fpga/constraints/pynq-z2/constraints.xdc | 2 +- .../fpga/constraints/pynq-z2/pin_assign.xdc | 135 +- .../hw/fpga/constraints/zcu104/pin_assign.xdc | 99 ++ .../hw/fpga/prim_xilinx_clk.sv | 9 + .../hw/fpga/scripts/nexys/set_board.tcl | 3 + .../nexys/xilinx_generate_clk_wizard.tcl | 43 + .../hw/fpga/scripts/pynq-z2/set_board.tcl | 3 + .../xilinx_generate_clk_wizard.tcl | 3 - .../hw/fpga/scripts/zcu104/set_board.tcl | 3 + .../zcu104/xilinx_generate_clk_wizard.tcl | 40 + .../hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv | 56 +- .../esl_epfl_x_heep/hw/ip/boot_rom/README.md | 28 - .../esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.S | 2 +- .../hw/ip/boot_rom/boot_rom.dump | 83 +- .../esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.h | 46 +- .../hw/ip/boot_rom/boot_rom.sv | 46 +- .../hw/ip/boot_rom/environment.yml | 6 - .../esl_epfl_x_heep/hw/ip/boot_rom/gen_rom.py | 5 +- .../esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_core.sv | 4 +- .../hw/ip/i2s/rtl/i2s_ws_gen.sv | 2 +- .../hw/ip_examples/iffifo/data/iffifo.hjson | 76 + .../hw/ip_examples/iffifo/iffifo.core | 26 + .../hw/ip_examples/iffifo/iffifo.vlt | 15 + .../hw/ip_examples/iffifo/iffifo_gen.sh | 8 + .../hw/ip_examples/iffifo/rtl/iffifo.sv | 115 ++ .../ip_examples/iffifo/rtl/iffifo_reg_pkg.sv | 106 ++ .../ip_examples/iffifo/rtl/iffifo_reg_top.sv | 451 +++++ .../simple_accelerator.core | 22 + .../simple_accelerator/simple_accelerator.sv | 421 +++++ .../simple_accelerator/simple_accelerator.vlt | 10 + .../slow_memory/rtl/slow_memory.sv | 35 +- .../hw/system/x_heep_system.sv.tpl | 7 +- .../hw/vendor/esl_epfl_cv32e40px.core | 1 + .../hw/vendor/esl_epfl_cv32e40px.lock.hjson | 2 +- .../hw/vendor/esl_epfl_cv32e40px.vendor.hjson | 4 +- .../bhv/cv32e40px_instr_trace.svh | 12 +- .../esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv | 275 ++-- .../bhv/cv32e40px_tb_wrapper.sv | 30 +- .../bhv/include/cv32e40px_tracer_pkg.sv | 12 +- .../esl_epfl_cv32e40px/bhv/insn_trace.sv | 201 +-- .../bhv/pipe_freeze_trace.sv | 47 +- .../rtl/cv32e40px_controller.sv | 10 +- .../esl_epfl_cv32e40px/rtl/cv32e40px_core.sv | 54 +- .../rtl/cv32e40px_cs_registers.sv | 8 +- .../rtl/cv32e40px_ex_stage.sv | 76 +- .../rtl/cv32e40px_fp_wrapper.sv | 2 +- .../rtl/cv32e40px_id_stage.sv | 179 +- .../rtl/cv32e40px_register_file_ff.sv | 66 +- .../rtl/cv32e40px_register_file_latch.sv | 53 +- .../rtl/cv32e40px_x_disp.sv | 115 +- .../rtl/include/cv32e40px_core_v_xif_pkg.sv | 7 +- .../hw/dv/dpi/uartdpi/uartdpi.sv | 2 + .../openhwgroup_cv32e20/.readthedocs.yaml | 23 + .../bhv/cve2_sim_clock_gate.sv | 2 +- .../cv32e20_manifest.flist | 63 + .../openhwgroup_cv32e20/cve2_configs.yaml | 94 ++ .../vendor/openhwgroup_cv32e20/cve2_core.core | 115 ++ .../openhwgroup_cv32e20/cve2_icache.core | 22 + .../openhwgroup_cv32e20/cve2_multdiv.core | 28 + .../{ibex_pkg.core => cve2_pkg.core} | 6 +- .../vendor/openhwgroup_cv32e20/cve2_top.core | 115 ++ .../{cve2.core => cve2_top_tracing.core} | 111 +- .../openhwgroup_cv32e20/cve2_tracer.core | 20 + .../lint/verilator_waiver.vlt | 30 +- .../rtl/{ibex_alu.sv => cve2_alu.sv} | 8 +- ...anch_predict.sv => cve2_branch_predict.sv} | 4 +- ..._decoder.sv => cve2_compressed_decoder.sv} | 4 +- ...{ibex_controller.sv => cve2_controller.sv} | 182 +-- .../openhwgroup_cv32e20/rtl/cve2_core.f | 17 + .../rtl/{ibex_core.sv => cve2_core.sv} | 475 +----- .../rtl/{ibex_counter.sv => cve2_counter.sv} | 2 +- ...x_cs_registers.sv => cve2_cs_registers.sv} | 295 +--- .../rtl/{ibex_csr.sv => cve2_csr.sv} | 2 +- .../rtl/{ibex_decoder.sv => cve2_decoder.sv} | 73 +- .../{ibex_ex_block.sv => cve2_ex_block.sv} | 50 +- ...{ibex_fetch_fifo.sv => cve2_fetch_fifo.sv} | 32 +- .../{ibex_id_stage.sv => cve2_id_stage.sv} | 475 +----- .../openhwgroup_cv32e20/rtl/cve2_if_stage.sv | 278 ++++ ..._store_unit.sv => cve2_load_store_unit.sv} | 14 +- ...x_multdiv_fast.sv => cve2_multdiv_fast.sv} | 27 +- ...x_multdiv_slow.sv => cve2_multdiv_slow.sv} | 15 +- .../rtl/{ibex_pkg.sv => cve2_pkg.sv} | 126 +- .../rtl/{ibex_pmp.sv => cve2_pmp.sv} | 14 +- ...default.svh => cve2_pmp_reset_default.svh} | 0 ...etch_buffer.sv => cve2_prefetch_buffer.sv} | 68 +- ...er_file_ff.sv => cve2_register_file_ff.sv} | 34 +- .../rtl/cve2_sleep_unit.sv | 118 -- .../openhwgroup_cv32e20/rtl/cve2_top.sv | 272 ++++ ...bex_top_tracing.sv => cve2_top_tracing.sv} | 75 +- .../rtl/{ibex_tracer.sv => cve2_tracer.sv} | 14 +- ...{ibex_tracer_pkg.sv => cve2_tracer_pkg.sv} | 4 +- .../vendor/openhwgroup_cv32e20/rtl/cve2_wb.sv | 69 + .../openhwgroup_cv32e20/rtl/ibex_core.f | 17 - .../rtl/ibex_dummy_instr.sv | 150 -- .../openhwgroup_cv32e20/rtl/ibex_icache.sv | 1165 ------------- .../openhwgroup_cv32e20/rtl/ibex_if_stage.sv | 750 --------- .../openhwgroup_cv32e20/rtl/ibex_lockstep.sv | 491 ------ .../rtl/ibex_register_file_fpga.sv | 83 - .../rtl/ibex_register_file_latch.sv | 164 -- .../openhwgroup_cv32e20/rtl/ibex_top.sv | 978 ----------- .../openhwgroup_cv32e20/rtl/ibex_wb_stage.sv | 214 --- .../lowrisc_ip/dv/sv/dv_utils/README.md | 0 .../dv/sv/dv_utils/dv_fcov_macros.core | 17 + .../dv/sv/dv_utils/dv_fcov_macros.svh | 112 ++ .../lowrisc_ip/dv/sv/dv_utils/dv_macros.core | 17 + .../lowrisc_ip/dv/sv/dv_utils/dv_macros.svh | 536 ++++++ .../dv/sv/dv_utils/dv_report_catcher.sv | 46 + .../dv/sv/dv_utils/dv_report_server.sv | 65 + .../dv/sv/dv_utils/dv_test_status.core | 17 + .../dv/sv/dv_utils/dv_test_status_pkg.sv | 31 + .../lowrisc_ip/dv/sv/dv_utils/dv_utils.core | 28 + .../lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv | 223 +++ .../lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv | 96 ++ .../hw/vendor/openhwgroup_cv32e40p.core | 1 + .../hw/vendor/openhwgroup_cv32e40p.lock.hjson | 2 +- .../vendor/openhwgroup_cv32e40p.vendor.hjson | 2 +- .../hw/vendor/openhwgroup_cv32e40p/.gitignore | 6 + .../bhv/cv32e40p_instr_trace.svh | 12 +- .../openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv | 333 ++-- .../bhv/cv32e40p_tb_wrapper.sv | 16 +- .../bhv/include/cv32e40p_tracer_pkg.sv | 12 +- .../openhwgroup_cv32e40p/bhv/insn_trace.sv | 205 +-- .../bhv/pipe_freeze_trace.sv | 47 +- .../rtl/cv32e40p_controller.sv | 12 +- .../openhwgroup_cv32e40p/rtl/cv32e40p_core.sv | 54 +- .../rtl/cv32e40p_cs_registers.sv | 10 +- .../rtl/cv32e40p_ex_stage.sv | 67 +- .../rtl/cv32e40p_fp_wrapper.sv | 2 +- .../rtl/cv32e40p_id_stage.sv | 14 +- .../hw/vendor/openhwgroup_cv32e40x.core | 1 + .../hw/vendor/openhwgroup_cve2.lock.hjson | 4 +- .../hw/vendor/openhwgroup_cve2.vendor.hjson | 29 +- .../0001-vendor-cv32e40px-Re-vendor.patch | 44 - .../patches/lowrisc_opentitan/uartdpi.patch | 8 +- .../openhwgroup_cv32e20/cv32e20_assert.patch | 12 + .../openhwgroup_cv32e20/cv32e20_core.patch | 12 + .../clk_mux_glitch_free.patch | 13 + .../0002-spiflash_valueargs.patch | 20 - .../patches/yosyshq_picorv32/spiflash.patch | 113 ++ ....-lowactive-reset.patch => spimemio.patch} | 0 .../src/clk_mux_glitch_free.sv | 2 +- .../hw/vendor/pulp_platform_fpnew.lock.hjson | 2 +- .../vendor/pulp_platform_fpnew.vendor.hjson | 2 +- .../hw/vendor/pulp_platform_gpio.core | 2 + .../vendor/pulp_platform_riscv_dbg.lock.hjson | 2 +- .../pulp_platform_riscv_dbg.vendor.hjson | 2 +- .../pulp_platform_riscv_dbg/CHANGELOG.md | 35 +- .../debug_rom/Makefile | 2 +- .../debug_rom/debug_rom.S | 9 +- .../debug_rom/debug_rom.h | 24 +- .../debug_rom/debug_rom.sv | 52 +- .../debug_rom/debug_rom_one_scratch.h | 24 +- .../debug_rom/debug_rom_one_scratch.sv | 44 +- .../debug_rom/gen_rom.py | 20 +- .../doc/debug-system.md | 10 +- .../pulp_platform_riscv_dbg/src/dm_csrs.sv | 110 +- .../pulp_platform_riscv_dbg/src/dm_mem.sv | 49 +- .../pulp_platform_riscv_dbg/src/dm_pkg.sv | 12 +- .../pulp_platform_riscv_dbg/src/dm_top.sv | 5 +- .../pulp_platform_riscv_dbg/src/dmi_jtag.sv | 33 +- .../src/dmi_jtag_tap.sv | 13 +- .../pulp_platform_tech_cells_generic.core | 1 + .../hw/vendor/waiver/lint/cv32e40p.vlt | 1 + .../hw/vendor/waiver/lint/cve2.vlt | 3 + .../hw/vendor/waiver/lint/riscv_dbg.vlt | 1 + .../yosyshq_picorv32/picosoc/spiflash.v | 53 +- .../esl_epfl_x_heep/linux_femu/README.md | 171 -- .../linux_femu/arm/openocd_cfg/README.md | 80 - .../arm/openocd_cfg/gpio_bitbang.cfg | 58 - .../linux_femu/arm/uart_enable/README.md | 57 - .../arm/uart_enable/uart_enable.dtbo | Bin 344 -> 0 bytes .../arm/uart_enable/uart_enable.dtsi | 18 - .../linux_femu/arm/uart_enable/uart_enable.sh | 5 - .../linux_femu/arm/virtual_flash/Makefile | 7 - .../arm/virtual_flash/OverlayControl.c | 103 -- .../arm/virtual_flash/OverlayControl.h | 27 - .../arm/virtual_flash/virtual_flash.cpp | 100 -- .../linux_femu/constraints/constraints.xdc | 1 - .../linux_femu/constraints/pin_assign.xdc | 73 - .../esl_epfl_x_heep/linux_femu/pad_cfg.hjson | 208 --- .../linux_femu/rtl/axi_address_hijacker.v | 331 ---- .../linux_femu/rtl/linux_femu.sv.tpl | 533 ------ .../xilinx_generate_processing_system.tcl | 118 -- hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson | 2 + .../esl_epfl_x_heep/mcu_cfg_minimal.hjson | 2 + hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt | 49 +- hw/vendor/esl_epfl_x_heep/sw/Makefile | 9 +- .../sw/applications/coremark/core_list_join.c | 612 +++++++ .../sw/applications/coremark/core_matrix.c | 376 +++++ .../sw/applications/coremark/core_portme.c | 104 ++ .../sw/applications/coremark/core_portme.h | 93 ++ .../sw/applications/coremark/core_state.c | 347 ++++ .../sw/applications/coremark/core_util.c | 266 +++ .../sw/applications/coremark/coremark.h | 211 +++ .../sw/applications/coremark/main.c | 459 ++++++ .../sw/applications/example_dma/main.c | 4 +- .../sw/applications/example_ext_memory/main.c | 128 ++ .../sw/applications/example_iffifo/main.c | 206 +++ .../example_matadd_interleaved/main.c | 84 + .../example_matadd_interleaved/matrixAdd32.h | 64 + .../example_matmul/gen_stimuly.py | 52 + .../sw/applications/example_matmul/main.c | 126 ++ .../applications/example_matmul/matrixMul8.h | 62 + .../example_simple_accelerator/main.c | 85 + .../example_spi_flash_write/main.c | 490 ------ .../sw/applications/example_spi_host/main.c | 265 --- .../applications/example_spi_host_dma/main.c | 312 ---- .../example_spi_host_dma_power_gate/main.c | 9 +- .../sw/applications/example_spi_read/buffer.h | 35 + .../sw/applications/example_spi_read/main.c | 300 ++++ .../sw/applications/example_spi_write/main.c | 351 ++++ .../applications/example_virtual_flash/main.c | 222 --- .../sw/applications/minver/arch.cfg | 67 + .../sw/applications/minver/beebsc.c | 177 ++ .../sw/applications/minver/beebsc.h | 65 + .../sw/applications/minver/board.c | 22 + .../sw/applications/minver/boardsupport.c | 21 + .../sw/applications/minver/boardsupport.h | 21 + .../sw/applications/minver/chip.c | 32 + .../sw/applications/minver/chipsupport.c | 73 + .../sw/applications/minver/chipsupport.h | 25 + .../sw/applications/minver/libminver.c | 292 ++++ .../sw/applications/minver/main.c | 50 + .../sw/applications/minver/support.h | 72 + .../esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c | 1449 +++++++++++++++++ .../sw/device/bsp/w25q/w25q128jw.h | 433 +++++ .../esl_epfl_x_heep/sw/device/lib/crt/crt0.S | 208 +-- .../sw/device/lib/drivers/dma/dma.c | 38 +- .../sw/device/lib/drivers/dma/dma.h | 4 +- .../sw/device/lib/drivers/gpio/gpio.c | 4 +- .../sw/device/lib/drivers/iffifo/iffifo.h | 56 + .../device/lib/drivers/iffifo/iffifo_regs.h | 47 + .../sw/device/lib/drivers/rv_plic/rv_plic.c | 2 +- .../sw/device/lib/drivers/spi_host/spi_host.h | 9 + .../sw/device/lib/runtime/core_v_mini_mcu.c | 37 + .../device/lib/runtime/core_v_mini_mcu.h.tpl | 4 + .../sw/device/lib/runtime/handler.c | 2 +- .../sw/device/lib/runtime/syscalls.c | 36 +- .../sw/device/target/nexys-a7-100t/x-heep.h | 30 + .../sw/device/target/systemc/x-heep.h | 30 + .../sw/device/target/zcu104/x-heep.h | 28 + .../esl_epfl_x_heep/sw/linker/link.ld.tpl | 55 +- .../sw/linker/link_flash_exec.ld.tpl | 6 +- .../sw/linker/link_flash_load.ld.tpl | 99 +- ...er-iceprog-custom-for-heep-with-gpio.patch | 136 +- .../vendor/yosyshq_icestorm/iceprog/iceprog.c | 64 +- .../tb/XHEEP_CmdLineOptions.cpp | 100 ++ .../tb/XHEEP_CmdLineOptions.hh | 24 + .../tb/core-v-mini-mcu-pynq-z2-bscan.cfg | 44 + .../esl_epfl_x_heep/tb/systemc_tb/Cache.h | 221 +++ .../tb/systemc_tb/MainMemory.h | 68 + .../tb/systemc_tb/MemoryRequest.h | 241 +++ hw/vendor/esl_epfl_x_heep/tb/tb_sc_top.cpp | 342 ++++ hw/vendor/esl_epfl_x_heep/tb/tb_top.cpp | 81 +- hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl | 2 +- hw/vendor/esl_epfl_x_heep/tb/testharness.sv | 98 +- .../esl_epfl_x_heep/tb/testharness_pkg.sv | 27 +- hw/vendor/esl_epfl_x_heep/util/mcu_gen.py | 27 + hw/vendor/esl_epfl_x_heep/util/structs_gen.py | 3 +- .../esl_epfl_x_heep/x-heep-tb-utils.core | 13 + hw/vendor/eslepfl_x_heep.lock.hjson | 2 +- 288 files changed, 18886 insertions(+), 10886 deletions(-) create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/SystemC.md create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.lock.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.vendor.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/board.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/mig.prj create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/part0_pins.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/preset.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.lock.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.vendor.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/board.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/part0_pins.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/preset.xml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl rename hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/{ => pynq-z2}/xilinx_generate_clk_wizard.tcl (86%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/environment.yml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/data/iffifo.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.vlt create mode 100755 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo_gen.sh create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.vlt create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/.readthedocs.yaml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cv32e20_manifest.flist create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_configs.yaml create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_core.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_icache.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_multdiv.core rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/{ibex_pkg.core => cve2_pkg.core} (73%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top.core rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/{cve2.core => cve2_top_tracing.core} (52%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_tracer.core rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_alu.sv => cve2_alu.sv} (99%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_branch_predict.sv => cve2_branch_predict.sv} (98%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_compressed_decoder.sv => cve2_compressed_decoder.sv} (99%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_controller.sv => cve2_controller.sv} (82%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.f rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_core.sv => cve2_core.sv} (73%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_counter.sv => cve2_counter.sv} (99%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_cs_registers.sv => cve2_cs_registers.sv} (86%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_csr.sv => cve2_csr.sv} (98%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_decoder.sv => cve2_decoder.sv} (94%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_ex_block.sv => cve2_ex_block.sv} (80%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_fetch_fifo.sv => cve2_fetch_fifo.sv} (92%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_id_stage.sv => cve2_id_stage.sv} (60%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_if_stage.sv rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_load_store_unit.sv => cve2_load_store_unit.sv} (96%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_multdiv_fast.sv => cve2_multdiv_fast.sv} (96%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_multdiv_slow.sv => cve2_multdiv_slow.sv} (96%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_pkg.sv => cve2_pkg.sv} (74%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_pmp.sv => cve2_pmp.sv} (95%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_pmp_reset_default.svh => cve2_pmp_reset_default.svh} (100%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_prefetch_buffer.sv => cve2_prefetch_buffer.sv} (81%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_register_file_ff.sv => cve2_register_file_ff.sv} (66%) delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_sleep_unit.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top.sv rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_top_tracing.sv => cve2_top_tracing.sv} (66%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_tracer.sv => cve2_tracer.sv} (98%) rename hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/{ibex_tracer_pkg.sv => cve2_tracer_pkg.sv} (99%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_wb.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.f delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_dummy_instr.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_icache.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_if_stage.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_lockstep.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_fpga.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_latch.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_wb_stage.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/README.md create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/esl_epfl_cv32e40px/0001-vendor-cv32e40px-Re-vendor.patch create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_assert.patch create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_core.patch create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_common_cells/clk_mux_glitch_free.patch delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spiflash.patch rename hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/{0001-async.-lowactive-reset.patch => spimemio.patch} (100%) delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/README.md delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/README.md delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/gpio_bitbang.cfg delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/README.md delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtbo delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtsi delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.sh delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/Makefile delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.c delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.h delete mode 100755 hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/virtual_flash.cpp delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/constraints/constraints.xdc delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/constraints/pin_assign.xdc delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/pad_cfg.hjson delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/rtl/axi_address_hijacker.v delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/rtl/linux_femu.sv.tpl delete mode 100644 hw/vendor/esl_epfl_x_heep/linux_femu/scripts/xilinx_generate_processing_system.tcl create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_list_join.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_matrix.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_state.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_util.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/coremark/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_ext_memory/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/matrixAdd32.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/gen_stimuly.py create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/matrixMul8.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_flash_write/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_read/buffer.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_read/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_write/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_virtual_flash/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/arch.cfg create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/board.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/chip.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/libminver.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/minver/support.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo_regs.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/target/systemc/x-heep.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h create mode 100644 hw/vendor/esl_epfl_x_heep/tb/XHEEP_CmdLineOptions.cpp create mode 100644 hw/vendor/esl_epfl_x_heep/tb/XHEEP_CmdLineOptions.hh create mode 100644 hw/vendor/esl_epfl_x_heep/tb/core-v-mini-mcu-pynq-z2-bscan.cfg create mode 100644 hw/vendor/esl_epfl_x_heep/tb/systemc_tb/Cache.h create mode 100644 hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MainMemory.h create mode 100644 hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MemoryRequest.h create mode 100644 hw/vendor/esl_epfl_x_heep/tb/tb_sc_top.cpp diff --git a/hw/vendor/esl_epfl_x_heep/.gitignore b/hw/vendor/esl_epfl_x_heep/.gitignore index a9a6e8c0..f2b85af8 100644 --- a/hw/vendor/esl_epfl_x_heep/.gitignore +++ b/hw/vendor/esl_epfl_x_heep/.gitignore @@ -7,16 +7,12 @@ build/ *.dis *.map *.do -.venv/* +.venv/ util/__pycache__/* # ignore apps output file run_verif_rtl_log.txt -#ignore femu generated hw -linux_femu/rtl/linux_femu.sv -.venv/ - # ignore the following hw automatically generated files environment.yml core-v-mini-mcu.upf diff --git a/hw/vendor/esl_epfl_x_heep/Makefile b/hw/vendor/esl_epfl_x_heep/Makefile index fa6e81ef..2d67386a 100644 --- a/hw/vendor/esl_epfl_x_heep/Makefile +++ b/hw/vendor/esl_epfl_x_heep/Makefile @@ -6,6 +6,7 @@ MAKE = make # Get the absolute path mkfile_path := $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") +$(info $$You are executing from: $(mkfile_path)) # Include the self-documenting tool FILE=$(mkfile_path)/Makefile @@ -33,7 +34,7 @@ PROJECT ?= hello_world # Linker options are 'on_chip' (default),'flash_load','flash_exec','freertos' LINKER ?= on_chip -# Target options are 'sim' (default) and 'pynq-z2' +# Target options are 'sim' (default) and 'pynq-z2' and 'nexys-a7-100t' TARGET ?= sim MCU_CFG ?= mcu_cfg.hjson PAD_CFG ?= pad_cfg.hjson @@ -49,7 +50,7 @@ COMPILER_PREFIX ?= riscv32-unknown- ARCH ?= rv32imc # Path relative from the location of sw/Makefile from which to fetch source files. The directory of that file is the default value. -SOURCE ?= "." +SOURCE ?= $(".") # Simulation engines options are verilator (default) and questasim SIMULATOR ?= verilator @@ -57,6 +58,31 @@ SIMULATOR ?= verilator # Timeout for simulation, default 120 TIMEOUT ?= 120 +# Flash read address for testing, in hexadecimal format 0x0000 +FLASHREAD_ADDR ?= 0x0 +FLASHREAD_FILE ?= $(mkfile_path)/flashcontent.hex +FLASHREAD_BYTES ?= 256 + +#max address in the hex file, used to program the flash +ifeq ($(wildcard sw/build/main.hex),) + MAX_HEX_ADDRESS = 0 + MAX_HEX_ADDRESS_DEC = 0 + BYTES_AFTER_MAX_HEX_ADDRESS = 0 + FLASHRWITE_BYTES = 0 +else + MAX_HEX_ADDRESS = $(shell cat sw/build/main.hex | grep "@" | tail -1 | cut -c2-) + MAX_HEX_ADDRESS_DEC = $(shell printf "%d" 0x$(MAX_HEX_ADDRESS)) + BYTES_AFTER_MAX_HEX_ADDRESS = $(shell tac sw/build/main.hex | awk 'BEGIN {count=0} /@/ {print count; exit} {count++}') + FLASHRWITE_BYTES = $(shell echo $(MAX_HEX_ADDRESS_DEC) + $(BYTES_AFTER_MAX_HEX_ADDRESS)*16 | bc) +endif + + +#binary to store in flash memory +FLASHWRITE_FILE = $(mkfile_path)/sw/build/main.hex + +# Export variables to sub-makefiles +export + ## @section Conda conda: environment.yml conda env create -f environment.yml @@ -64,13 +90,6 @@ conda: environment.yml environment.yml: python-requirements.txt util/python-requirements2conda.sh -## @section Linux-Emulation - -## Generates FEMU -linux-femu-gen: mcu-gen - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir linux_femu/rtl/ --tpl-sv linux_femu/rtl/linux_femu.sv.tpl - $(MAKE) verible - ## @section Installation ## Generates mcu files core-v-mini-mcu files and build the design with fusesoc @@ -115,7 +134,7 @@ verible: ## Generates the build folder in sw using CMake to build (compile and linking) ## @param PROJECT= -## @param TARGET=sim(default),pynq-z2 +## @param TARGET=sim(default),systemc,pynq-z2,nexys-a7-100t,zcu104 ## @param LINKER=on_chip(default),flash_load,flash_exec ## @param COMPILER=gcc(default), clang ## @param COMPILER_PREFIX=riscv32-unknown-(default) @@ -134,10 +153,14 @@ app-compile-all: ## @section Simulation -## Verilator simulation +## Verilator simulation with C++ verilator-sim: $(FUSESOC) --cores-root . run --no-export --target=sim --tool=verilator $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log +## Verilator simulation with SystemC +verilator-sim-sc: + $(FUSESOC) --cores-root . run --no-export --target=sim_sc --tool=verilator $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log + ## Questasim simulation questasim-sim: $(FUSESOC) --cores-root . run --no-export --target=sim --tool=modelsim $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log @@ -161,6 +184,10 @@ vcs-sim: vcs-ams-sim: $(FUSESOC) --cores-root . run --no-export --target=sim --flag "ams_sim" --tool=vcs $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log +## xcelium simulation +xcelium-sim: + $(FUSESOC) --cores-root . run --no-export --target=sim --tool=xcelium $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log + ## Generates the build output for helloworld application ## Uses verilator to simulate the HW model and run the FW ## UART Dumping in uart0.log to show recollected results @@ -175,7 +202,7 @@ run-helloworld: mcu-gen verilator-sim ## Uses verilator to simulate the HW model and run the FW ## UART Dumping in uart0.log to show recollected results run-blinkyfreertos: mcu-gen verilator-sim - $(MAKE) -C sw PROJECT=blinky_freertos TARGET=$(TARGET) LINKER=$(LINKER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH); + $(MAKE) -C sw PROJECT=example_freertos_blinky TARGET=$(TARGET) LINKER=$(LINKER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH); cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator; \ ./Vtestharness +firmware=../../../sw/build/main.hex; \ cat uart0.log; \ @@ -196,7 +223,7 @@ app-simulate-all: ## @section Vivado ## Builds (synthesis and implementation) the bitstream for the FPGA version using Vivado -## @param FPGA_BOARD=nexys-a7-100t,pynq-z2 +## @param FPGA_BOARD=nexys-a7-100t,pynq-z2,zcu104 ## @param FUSESOC_FLAGS=--flag= vivado-fpga: $(FUSESOC) --cores-root . run --no-export --target=$(FPGA_BOARD) $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildvivado.log @@ -204,6 +231,9 @@ vivado-fpga: vivado-fpga-nobuild: $(FUSESOC) --cores-root . run --no-export --target=$(FPGA_BOARD) $(FUSESOC_FLAGS) --setup openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildvivado.log +vivado-fpga-pgm: + $(MAKE) -C build/openhwgroup.org_systems_core-v-mini-mcu_0/$(FPGA_BOARD)-vivado pgm + ## @section ASIC ## Note that for this step you need to provide technology-dependent files (e.g., libs, constraints) asic: @@ -220,18 +250,27 @@ openroad-sky130: ## Read the id from the EPFL_Programmer flash flash-readid: - cd sw/vendor/yosyshq_icestorm/iceprog; \ + cd sw/vendor/yosyshq_icestorm/iceprog; make; \ ./iceprog -d i:0x0403:0x6011 -I B -t; ## Loads the obtained binary to the EPFL_Programmer flash flash-prog: - cd sw/vendor/yosyshq_icestorm/iceprog; \ - ./iceprog -d i:0x0403:0x6011 -I B $(mkfile_path)/sw/build/main.hex; + cd sw/vendor/yosyshq_icestorm/iceprog; make; \ + ./iceprog -a $(FLASHRWITE_BYTES) -d i:0x0403:0x6011 -I B $(FLASHWRITE_FILE); + +## Read the EPFL_Programmer flash +flash-read: + cd sw/vendor/yosyshq_icestorm/iceprog; make; \ + ./iceprog -d i:0x0403:0x6011 -I B -o $(shell printf "%d" $(FLASHREAD_ADDR)) -R $(FLASHREAD_BYTES) $(FLASHREAD_FILE); ## Run openOCD w/ EPFL_Programmer openOCD_epflp: xterm -e openocd -f ./tb/core-v-mini-mcu-pynq-z2-esl-programmer.cfg; +## Run openOCD w/ BSCAN of the Pynq-Z2 board +openOCD_bscan: + xterm -e openocd -f ./tb/core-v-mini-mcu-pynq-z2-bscan.cfg; + ## Start GDB gdb_connect: $(MAKE) -C sw gdb_connect diff --git a/hw/vendor/esl_epfl_x_heep/README.md b/hw/vendor/esl_epfl_x_heep/README.md index 0e0130b7..c9705474 100644 --- a/hw/vendor/esl_epfl_x_heep/README.md +++ b/hw/vendor/esl_epfl_x_heep/README.md @@ -39,6 +39,21 @@ The block diagram below shows the `X-HEEP` MCU

+# Reference + +If you use X-HEEP in your academic work you can cite us: [X-HEEP Paper](https://arxiv.org/abs/2401.05548) + +``` +@misc{machetti2024xheep, + title={X-HEEP: An Open-Source, Configurable and Extendible RISC-V Microcontroller for the Exploration of Ultra-Low-Power Edge Accelerators}, + author={Simone Machetti and Pasquale Davide Schiavone and Thomas Christoph Müller and Miguel Peón-Quirós and David Atienza}, + year={2024}, + eprint={2401.05548}, + archivePrefix={arXiv}, + primaryClass={cs.AR} +} +``` + # Self-documented Makefile Note that under `util` folder, the file `generate-makefile-help` is employed to generate a self-documented helping output. In case of including any other target or command under the main `Makefile`, follow the same general and parameter descriptions as already provided for every target. Check the `help` output by doing `make` or `make help`. Moreover, **note that some of the parameters required for some of the targets are initiated with _default values_** @@ -59,7 +74,6 @@ It has been tested only on `Ubuntu 20`, and we know it does NOT WORK on `Ubuntu ## 2. Python - We rely on either (a) `miniconda`, or (b) `virtual environment` enviroment. Choose between `2.a` or `2.b` to setup your enviroment. @@ -79,7 +93,6 @@ You need to do it only the first time, then just activate the environment everyt conda activate core-v-mini-mcu ``` - ### 2.b Virtual Environment Install the python virtual environment just as: @@ -153,13 +166,36 @@ sudo apt-get install -y gtkwave We use version v0.0-1824-ga3b5bedf -See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-6a-install-verible-optional) +See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-7a-install-verible-optional) To format your RTL code type: ``` make verible ``` + +## Docker alternative + +A docker image containing all the required software dependancies is available on [github-packages](https://github.com/orgs/esl-epfl/packages/container/package/x-heep-toolchain). + +It is only required to install [`docker`](https://docs.docker.com/get-docker/) and pull the image. + +```bash +docker pull ghcr.io/esl-epfl/x-heep-toolchain:latest +``` + +Assuming that X-HEEP has been cloned to `X-HEEP-DIR=\absolute\path\to\x-HEEP\folder`, it is possible to directly run the docker mounting `X-HEEP-DIR` to the path `\workspace\x-heep` in the docker. + +```bash +docker run -it -v ${X-HEEP-DIR}:/workspace/x-heep ghcr.io/esl-epfl/x-heep-toolchain +``` + +Take care to indicate the absolute path to the local clone of X-HEEP, otherwise `docker` will not be able to properly nount the local folder in the container. + +All the command listed in the README can be execute in the docker container, except for: +- Simulation with Questasim and VCS, synthesis with Design Compiler (licenses are required to use these tools, so they are not installed in the container) +- OpenRoad flow is not installed in the container, so it is not possible to run the related make commands + ## Compilation Flow and Package Manager We use [FuseSoC](https://github.com/olofk/fusesoc) for all the tools we use. @@ -168,7 +204,7 @@ The `fusesoc` commands are inside the Makefile. # Adding external IPs -This repository relies on [Vendor](https://opentitan.org/book/util/doc/vendor.html) to add new IPs. The `vendor.py` script in the [`./util`](./util/) folder implements what is describeb above, while [this](./ExternalDevices.md) file contains additional information on how to connect external devices to the system. +This repository relies on [Vendor](https://opentitan.org/book/util/doc/vendor.html) to add new IPs. The `vendor.py` script in the [`./util`](./util/) folder implements what is described above, while [this](./docs/source/How_to/ExternalDevices.md) file contains additional information on how to connect external devices to the system. # Compiling with Makefile @@ -206,7 +242,6 @@ make mcu-gen MCU_CFG=mcu_cfg_minimal.hjson The `minimal` configuration is a work-in-progress, thus not all the APPs have been tested. - ## Compiling Software Don't forget to set the `RISCV` env variable to the compiler folder (without the `/bin` included). @@ -219,11 +254,11 @@ make app To run any other application, please use the following command with appropiate parameters: ``` -app PROJECT= TARGET=sim(default),pynq-z2 LINKER=on_chip(default),flash_load,flash_exec COMPILER=gcc(default),clang COMPILER_PREFIX=riscv32-unknown-(default) ARCH=rv32imc(default), +app PROJECT= TARGET=sim(default),systemc,pynq-z2,nexys-a7-100t,zcu104 LINKER=on_chip(default),flash_load,flash_exec COMPILER=gcc(default),clang COMPILER_PREFIX=riscv32-unknown-(default) ARCH=rv32imc(default), Params: - PROJECT (ex: , hello_world(default)) -- TARGET (ex: sim(default),pynq-z2) +- TARGET (ex: sim(default),systemc,pynq-z2,nexys-a7-100t,zcu104) - LINKER (ex: on_chip(default),flash_load,flash_exec) - COMPILER (ex: gcc(default),clang) - COMPILER_PREFIX (ex: riscv32-unknown-(default)) @@ -238,9 +273,8 @@ make app TARGET=pynq-z2 Or, if you use the OpenHW Group [GCC](https://www.embecosm.com/resources/tool-chain-downloads/#corev) compiler with CORE_PULP extensions, make sure to point the `RISCV` env variable to the OpenHW Group compiler, then just run: - ``` -make app COMPILER_PREFIX=riscv32-corev- ARCH=rv32imc_zicsr_zifencei_xcvhwlp1p0_xcvmem1p0_xcvmac1p0_xcvbi1p0_xcvalu1p0_xcvsimd1p0_xcvbitmanip1p0 +make app COMPILER_PREFIX=riscv32-corev- ARCH=rv32imc_zicsr_zifencei_xcvhwlp_xcvmem_xcvmac_xcvbi_xcvalu_xcvsimd_xcvbitmanip ``` This will create the executable file to be loaded into your target system (ASIC, FPGA, Simulation). @@ -264,13 +298,13 @@ Moreover, FreeRTOS is being fetch from 'https://github.com/FreeRTOS/FreeRTOS-Ker ## Simulating -This project supports simulation with Verilator, Synopsys VCS, and Siemens Questasim. +This project supports simulation with Verilator, Synopsys VCS, Siemens Questasim and Cadence Xcelium. It relies on `fusesoc` to handle multiple EDA tools and parameters. For example, if you want to set the `FPU` and `COREV_PULP` parameters of the `cv32e40p` CPU, you need to add next to your compilation command `FUSESOC_PARAM="--COREV_PULP=1 --FPU=1"` Below the different EDA examples commands. -### Compiling for Verilator +### Compiling for Verilator (C++ testbench) To simulate your application with Verilator, first compile the HDL: @@ -296,6 +330,38 @@ or to execute all these three steps type: make run-helloworld ``` +### Compiling for Verilator (SystemC testbench) + +To simulate your application with Verilator using `SystemC`, + +make sure you have `SystemC 2.3.3` installed, if not, find it [here](https://www.accellera.org/downloads/standards/systemc). + +Make sure to have the following env variables set: + +``` +export SYSTEMC_INCLUDE=/your_path_to_systemc/systemc/include/ +export SYSTEMC_LIBDIR=/your_path_to_systemc/systemc/lib-linux64/ +``` + +Compile the HDL: + +``` +make verilator-sim-sc +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim_sc-verilator +``` + +and type to run your compiled software: + +``` +./Vtestharness +firmware=../../../sw/build/main.hex +``` + +If you want to know what is special about the SystemC testbench, have a look [here](./docs/source/How_to/SystemC.md) ### Compiling for VCS @@ -337,7 +403,7 @@ cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs and running the same executable as for the digital simulation. Note that with Verdi you can view both the digital and the analog waveforms. -Additional instructions on how to run an analog / mixed-signal simulation of X-HEEP can be found [here](AnalogMixedSignal.md). To try out the simulation, we provide an example SPICE netlist of an simple 1-bit ADC created by us and exported from [xschem](https://xschem.sourceforge.io/stefan/index.html) and which uses the PTM 65nm bulk CMOS model from [https://ptm.asu.edu](https://ptm.asu.edu/). +Additional instructions on how to run an analog / mixed-signal simulation of X-HEEP can be found [here](./docs/source/How_to/AnalogMixedSignal.md). To try out the simulation, we provide an example SPICE netlist of an simple 1-bit ADC created by us and exported from [xschem](https://xschem.sourceforge.io/stefan/index.html) and which uses the PTM 65nm bulk CMOS model from [https://ptm.asu.edu](https://ptm.asu.edu/). ### Compiling for Questasim @@ -390,6 +456,26 @@ make run RUN_OPT=1 RUN_UPF=1 PLUSARGS="c firmware=../../../sw/build/main.hex" Questasim version must be >= Questasim 2020.4 +### Compiling for Xcelium + +To simulate your application with Xcelium, first compile the HDL: + +``` +make xcelium-sim +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-xcelium/ +``` + +and type to run your compiled software: + +``` +make run PLUSARGS="c firmware=../../../sw/build/main.hex" +``` + ### UART DPI To simulate the UART, we use the LowRISC OpenTitan [UART DPI](https://github.com/lowRISC/opentitan/tree/master/hw/dv/dpi/uartdpi). @@ -427,7 +513,6 @@ The available parameters are: * LINKER: `on_chip`(default), `flash_load` or `flash_exec` (can provide more than one) * TIMEOUT: Integer number of seconds (default 120) - #### Usage ##### Comands @@ -440,7 +525,7 @@ make app-simulate-all ``` Note that both commands allow the previous parameters to specify compiling or simulation options. E.g.: ``` -make app-simulate-all LINKER=on_chip SIMULATOR=questasim COMPILER=clang TIMEOUT=150 +make app-simulate-all LINKER=on_chip SIMULATOR=questasim COMPILER=clang TIMEOUT=150 ``` ##### Manually @@ -467,25 +552,27 @@ The success of the script is not required for merging of a PR. ## Debug -Follow the [Debug](./Debug.md) guide to debug core-v-mini-mcu. +Follow the [Debug](./docs/source/How_to/Debug.md) guide to debug core-v-mini-mcu. Alternatively, in case you are used to developing using Integrated Development Environments (IDEs), please check [the IDE readme](./IDEs.md). ## Execute From Flash -Follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide to exxecute code directly from the FLASH with modelsim, FPGA, or ASIC. +Follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) guide to exxecute code directly from the FLASH with modelsim, FPGA, or ASIC. ## Emulation on Xilinx FPGAs -This project offers two different X-HEEP implementetions on the Xilinx FPGAs, called Standalone-FEMU and Linux-FEMU. +This project offers two different X-HEEP implementetions on Xilinx FPGAs, called Standalone and FEMU. -### Standalone-FEMU (Standalone Fpga EMUlation) +### Standalone In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board. +Three FPGA boards are supported: the Xilinx Pynq-z2, Nexys-A7-100t, Zynq Ultrascale+ ZCU104. + Make sure you have the FPGA board files installed in your Vivado. -For example, for the Xilinx Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: +For example, for the Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: To build and program the bitstream for your FPGA with vivado, type: @@ -493,6 +580,18 @@ To build and program the bitstream for your FPGA with vivado, type: make vivado-fpga FPGA_BOARD=pynq-z2 ``` +or + +``` +make vivado-fpga FPGA_BOARD=nexys-a7-100t +``` + +or + +``` +make vivado-fpga FPGA_BOARD=zcu104 +``` + or add the flag `use_bscane_xilinx` to use the native Xilinx scanchain: ``` @@ -507,11 +606,23 @@ To program the bitstream, open Vivado, open --> Hardware Manager --> Open Target --> Autoconnect --> Program Device ``` -and choose the file `openhwgroup.org_systems_core-v-mini-mcu_0.bit` +and choose the file `openhwgroup.org_systems_core-v-mini-mcu_0.bit`. -To run SW, follow the [Debug](./Debug.md) guide +Or simply type: + +``` +bash vivado-fpga-pgm FPGA_BOARD=pynq-z2 +``` + +or + +``` +make vivado-fpga-pgm FPGA_BOARD=nexys-a7-100t +``` + +To run SW, follow the [Debug](./docs/source/How_to/Debug.md) guide to load the binaries with the HS2 cable over JTAG, -or follow the [ExecuteFromFlash](./ExecuteFromFlash.md) +or follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) guide if you have a FLASH attached to the FPGA. Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. @@ -520,7 +631,7 @@ For example, if you want to run your application using flash_exec, do as follow: compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` -and then follow the [ExecuteFromFlash](./ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. +and then follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. To look at the output of your printf, run in another terminal: @@ -528,13 +639,11 @@ To look at the output of your printf, run in another terminal: Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). +### FPGA EMUlation Platform (FEMU) -### Linux-FEMU (Linux Fpga EMUlation) - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA and Linux is run on the ARM-based processing system (PS) side of the same chip. - -Read the [following](./linux_femu/README.md) documentation to have more information about this implementation. +In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Xilinx Zynq-7020 chip on the Pynq-Z2 board and Linux is run on the ARM-based processing system (PS) side of the same chip. +NOTE: This platform is not part of this repository, but you can access it with the following link: [FEMU](https://github.com/esl-epfl/x-heep-femu-sdk). # ASIC Implementation @@ -555,6 +664,6 @@ make asic ## OpenRoad support for SkyWater 130nm We are working on supporting OpenRoad and SkyWater 130nm PDK, please refer to the -[OpenRoadFlow](./OpenRoadFlow.md) page. This is not ready yet, it has not been tested. +[Implement on ASIC](./docs/source/How_to/ImplementASIC.md) page. This is not ready yet, it has not been tested. This relies on a fork of [edalize](https://github.com/davideschiavone/edalize) that contains templates for Design Compiler and OpenRoad. diff --git a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core index 7bebad44..dd439888 100644 --- a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core +++ b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core @@ -13,7 +13,7 @@ filesets: - x-heep::packages - openhwgroup.org:ip:cv32e40p - openhwgroup.org:ip:cv32e40x - - openhwgroup.org:ip:cve2 + - openhwgroup:cve2:cve2_top - esl_epfl:ip:cv32e40px - pulp-platform.org:ip:gpio - pulp-platform.org::common_cells @@ -102,7 +102,6 @@ filesets: ip-fpga: files: - - hw/fpga/scripts/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } - hw/fpga/scripts/generate_sram.tcl: { file_type: tclSource } - hw/fpga/prim_xilinx_clk.sv: { file_type: systemVerilogSource } - hw/fpga/cv32e40p_xilinx_clock_gate.sv: { file_type: systemVerilogSource } @@ -115,15 +114,20 @@ filesets: - hw/fpga/pad_cell_bypass_input_xilinx.sv: { file_type: systemVerilogSource } - hw/fpga/pad_cell_bypass_output_xilinx.sv: { file_type: systemVerilogSource } - fpga-arm-emulation: - depend: - - pulp-platform.org::axi_spi_slave + ip-fpga-pynq-z2: + files: + - hw/fpga/scripts/pynq-z2/set_board.tcl: { file_type: tclSource } + - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + ip-fpga-nexys: files: - - linux_femu/scripts/xilinx_generate_processing_system.tcl: {file_type: tclSource} - - linux_femu/rtl/axi_address_hijacker.v: {file_type: verilogSource} - - linux_femu/rtl/linux_femu.sv: {file_type: systemVerilogSource} - - linux_femu/constraints/pin_assign.xdc: {file_type: xdc} - - linux_femu/constraints/constraints.xdc: {file_type: xdc} + - hw/fpga/scripts/nexys/set_board.tcl: { file_type: tclSource } + - hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + ip-fpga-zcu104: + files: + - hw/fpga/scripts/zcu104/set_board.tcl: { file_type: tclSource } + - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } ip-asic: depend: @@ -155,6 +159,11 @@ filesets: - hw/fpga/constraints/pynq-z2/constraints.xdc file_type: xdc + xdc-fpga-zcu104: + files: + - hw/fpga/constraints/zcu104/pin_assign.xdc + file_type: xdc + netlist-fpga: files: - build/openhwgroup.org_systems_core-v-mini-mcu_0/nexys-a7-100t-vivado/core_v_mini_mcu_xiling_postsynth.v @@ -194,6 +203,8 @@ filesets: tb-verilator: files: + - tb/XHEEP_CmdLineOptions.hh: { is_include_file: true } + - tb/XHEEP_CmdLineOptions.cpp - tb/tb_top.cpp file_type: cppSource @@ -202,6 +213,14 @@ filesets: - tb/tb_top.sv file_type: systemVerilogSource + tb-sc-verilator: + files: + - tb/XHEEP_CmdLineOptions.hh: { is_include_file: true } + - tb/XHEEP_CmdLineOptions.cpp + - tb/tb_sc_top.cpp + file_type: cppSource + + openroad_base_files: files: - flow/OpenROAD-flow-scripts/flow/Makefile : {file_type: Makefile} @@ -262,7 +281,15 @@ parameters: datatype: bool paramtype: vlogdefine default: false - FPGA_NETLIST: + SIM_SYSTEMC: + datatype: bool + paramtype: vlogdefine + default: false + FPGA_NEXYS: + datatype: bool + paramtype: vlogdefine + default: false + FPGA_ZCU104: datatype: bool paramtype: vlogdefine default: false @@ -302,6 +329,8 @@ targets: - files_rtl_generic - target_sim ? (rtl-simulation) - target_sim ? (tool_verilator? (files_verilator_waiver)) + - target_sim_sc ? (rtl-simulation) + - target_sim_sc ? (tool_verilator? (files_verilator_waiver)) toplevel: [core_v_mini_mcu] sim: @@ -314,13 +343,17 @@ targets: - tool_modelsim? (pre_patch_modelsim_Makefile) - tool_vcs? (cfile_uartdpi) - tool_vcs? (pre_build_remote_bitbang) + - tool_xcelium? (pre_build_remote_bitbang) + - tool_xcelium? (pre_build_uartdpi) - tool_verilator? (tb-verilator) - tool_modelsim? (tb-sv) - tool_vcs? (tb-sv) + - tool_xcelium? (tb-sv) - "!integrated_heep? (x_heep_system)" toplevel: - tool_modelsim? (tb_top) - tool_vcs? (tb_top) + - tool_xcelium? (tb_top) - tool_verilator? (testharness) hooks: pre_build: @@ -328,6 +361,8 @@ targets: - tool_modelsim? (pre_build_remote_bitbang) - tool_modelsim? (pre_patch_modelsim_Makefile) # this is required by Questa 2020 on - ams_sim? (pre_patch_vcs_ams_Makefile) + - tool_xcelium? (pre_build_uartdpi) + - tool_xcelium? (pre_build_remote_bitbang) parameters: - COREV_PULP - FPU @@ -342,6 +377,7 @@ targets: - -override_timescale 1ns/1ps - -suppress vlog-2583 - -suppress vlog-2577 + - -suppress vlog-2720 - -pedanticerrors - -define MODELSIM vsim_options: @@ -364,6 +400,12 @@ targets: - -LDFLAGS "-pthread -lutil" - +lint=TFIPC-L - -V + xcelium: + xrun_options: + - -vtimescale 1ns/10ps + - -sv_lib ../../../hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi.so + - -sv_lib ../../../hw/vendor/pulp_platform_pulpissimo/rtl/tb/remote_bitbang/librbs.so + - -define XCELIUM verilator: mode: cc verilator_options: @@ -380,12 +422,48 @@ targets: - '-LDFLAGS "-pthread -lutil -lelf"' - "-Wall" + sim_sc: + <<: *default_target + default_tool: modelsim + filesets_append: + - tb-utils + - tool_verilator? (tb-sc-verilator) + - "!integrated_heep? (x_heep_system)" + toplevel: + - tool_verilator? (testharness) + parameters: + - COREV_PULP + - FPU + - JTAG_DPI + - X_EXT + - USE_EXTERNAL_DEVICE_EXAMPLE + - USE_UPF + - REMOVE_OBI_FIFO + - SIM_SYSTEMC=true + tools: + verilator: + mode: sc + verilator_options: + - '--sc' + - '--trace' + - '--trace-structs' + - '--trace-params' + - '--trace-max-array 1024' + - '--x-assign unique' + - '--x-initial unique' + - '--exe tb_sc_top.cpp' + - '-CFLAGS "-std=c++11 -Wall -g -fpermissive"' + - '-LDFLAGS "-pthread -lutil -lelf $(SYSTEMC_LIBDIR)/libsystemc.a"' + - "-Wall" + nexys-a7-100t: <<: *default_target default_tool: vivado description: Digilent Nexys-A7-100T Board filesets_append: + - x_heep_system - rtl-fpga + - ip-fpga-nexys - ip-fpga - xdc-fpga-nexys parameters: @@ -394,6 +472,7 @@ targets: - X_EXT - SYNTHESIS=true - REMOVE_OBI_FIFO + - FPGA_NEXYS=true tools: vivado: part: xc7a100tcsg324-1 @@ -406,6 +485,7 @@ targets: filesets_append: - x_heep_system - rtl-fpga + - ip-fpga-pynq-z2 - ip-fpga - xdc-fpga-pynq-z2 parameters: @@ -419,27 +499,28 @@ targets: part: xc7z020clg400-1 toplevel: [xilinx_core_v_mini_mcu_wrapper] - pynq-z2-arm-emulation: + zcu104: <<: *default_target default_tool: vivado - description: TUL Pynq-Z2 Board + description: ZCU104 Evaluation Board filesets_append: - x_heep_system - rtl-fpga + - ip-fpga-zcu104 - ip-fpga - - fpga-arm-emulation + - xdc-fpga-zcu104 parameters: - COREV_PULP - FPU - X_EXT - SYNTHESIS=true - REMOVE_OBI_FIFO + - FPGA_ZCU104=true tools: vivado: - part: xc7z020clg400-1 - jobs: 4 - toplevel: [linux_femu] - + part: xczu7ev-ffvc1156-2-e + toplevel: [xilinx_core_v_mini_mcu_wrapper] + asic_synthesis: <<: *default_target default_tool: design_compiler diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile index c0aab16c..2db8a17d 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile @@ -107,7 +107,6 @@ or to execute all these three steps type: make run-helloworld ``` - ### Compiling for VCS To simulate your application with VCS, first compile the HDL: @@ -238,7 +237,6 @@ The available parameters are: * LINKER: `on_chip`(default), `flash_load` or `flash_exec` (can provide more than one) * TIMEOUT: Integer number of seconds (default 120) - #### Usage ##### Comands @@ -286,15 +284,17 @@ Follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide to exxecute code dire ## Emulation on Xilinx FPGAs -This project offers two different X-HEEP implementetions on the Xilinx FPGAs, called Standalone-FEMU and Linux-FEMU. +This project offers two different X-HEEP implementetions on Xilinx FPGAs, called Standalone and FEMU. -### Standalone-FEMU (Standalone Fpga EMUlation) +### Standalone In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board. +Two FPGA boards are supported: the Xilinx Pynq-z2 and Nexys-A7-100t. + Make sure you have the FPGA board files installed in your Vivado. -For example, for the Xilinx Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: +For example, for the Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: To build and program the bitstream for your FPGA with vivado, type: @@ -302,6 +302,12 @@ To build and program the bitstream for your FPGA with vivado, type: make vivado-fpga FPGA_BOARD=pynq-z2 ``` +or + +``` +make vivado-fpga FPGA_BOARD=nexys-a7-100t +``` + or add the flag `use_bscane_xilinx` to use the native Xilinx scanchain: ``` @@ -323,12 +329,22 @@ to load the binaries with the HS2 cable over JTAG, or follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide if you have a FLASH attached to the FPGA. - Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. +For example, if you want to run your application using flash_exec, do as follow: + +compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` + +and then follow the [ExecuteFromFlash](./ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. + +To look at the output of your printf, run in another terminal: + +`picocom -b 9600 -r -l --imap lfcrlf /dev/ttyUSB2` + +Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). -### Linux-FEMU (Linux Fpga EMUlation) +### FPGA EMUlation Platform (FEMU) -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA and Linux is run on the ARM-based processing system (PS) side of the same chip. +In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Xilinx Zynq-7020 chip on the Pynq-Z2 board and Linux is run on the ARM-based processing system (PS) side of the same chip. -Read the [following](./linux_femu/README.md) documentation to have more information about this implementation. +NOTE: This platform is not part of this repository, but you can access it with the following link: [FEMU](https://github.com/esl-epfl/x-heep-femu-sdk). diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md index 4ec743f3..2a5882f6 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md @@ -40,7 +40,7 @@ Now we are going to Simulate debugging with core-v-mini-mcu. In this setup, OpenOCD communicates with the remote bitbang server by means of DPIs. The remote bitbang server is simplemented in the folder ./hw/vendor/pulp_platform_pulpissimo/rtl/tb/remote_bitbang and it will be compiled using fusesoc. -### Verilator +### Verilator (C++ only) To simulate your application with Questasim using the remote_bitbang server, you need to compile you system adding the `JTAG DPI` functions: @@ -130,24 +130,86 @@ Transfer rate: 67 bytes/sec, 798 bytes/write. `gdb` automatically set the `program counter` to start from `_start`, check with: +Anytime you want to check the `disassemble`, just do: + + +``` +(gdb) disassemble +``` + +and get an output that look like: + ``` -(gdb) i r pc +Dump of assembler code for function _start: +=> 0x00000180 <+0>: auipc gp,0xd + 0x00000184 <+4>: addi gp,gp,964 # 0xd544 + 0x00000188 <+8>: auipc sp,0xf + 0x0000018c <+12>: addi sp,sp,-1080 # 0xed50 + 0x00000190 <+16>: lui a0,0x20000 + ... ``` -It should give you `0x180`. + +``` +(gdb) info reg pc +``` +Gives you the program counter. Now you can play with `gdb` e.g: Ask for the content of register `a0` ``` -(gdb) i r a0 +(gdb) info reg a0 ``` -or just run the entire execution with the continue command and then check the `uart0.log` to see the printed hello world string: + +or set it to `15` as: + +``` +(gdb) set $a0=15 +``` + +or just run the entire execution with the and then check the `uart0.log` to see the printed hello world string: ``` (gdb) continue ``` +If you want to reset the non-debug modules (as the CPU): + +``` +(gdb) monitor reset halt +``` + +Set a breakpoint to a specific instruction address: + +``` +(gdb) b *0x0000019c +Breakpoint 1 at 0x19c: file /x-heep/sw/device/lib/crt/crt0.S, line 38. +``` + +and continue the execution untill the breakpoint as: + +``` +(gdb) continue +``` + +Then check the breakpoint status: + +``` +(gdb) info b +Num Type Disp Enb Address What +1 breakpoint keep y 0x0000019c /x-heep/sw/device/lib/crt/crt0.S:38 + breakpoint already hit 1 time +``` + +and finally delete it: + +``` +(gdb) delete 1 +(gdb) info b +No breakpoints or watchpoints. +``` + You can also run all the gdb steps by running: ``` make gdb_connect MAINFILE= @@ -202,6 +264,16 @@ or with the EPFL Programmer also using this other command (**strongly recommende make openOCD_epflp ``` +or with the BSCAN of the Pynq-Z2 board using this command: +``` +openocd -f ./tb/core-v-mini-mcu-pynq-z2-bscan.cfg +``` + +or with the BSCAN of the Pynq-Z2 board also using this other command (**strongly recommended**): + +``` +make openOCD_bscan +``` If you get this error: diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md index 530b9817..bbc89bd3 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md @@ -97,3 +97,55 @@ For example, launching the script [`memcopy_periph_gen.sh`](./../../../hw/ip_exa 1. `memcopy_periph_reg_top.sv`: the register file module. It can be directly instantiated inside your peripheral RTL code (e.g., [`memcopy_periph.sv`](./../../../hw/ip_examples/memcopy_periph/rtl/memcopy_periph.sv)) and connected to the peripheral device controller(s). 2. `memcopy_periph_reg_pkg.sv`: SystemVerilog package containing the definitions used in the SystemVerilog module above. 3. `memcopy_periph_regs.h`: C/C++ header file defining the address offset of the peripheral configuration registers. Take a look at the C code [here](./../../../sw/applications/example_external_peripheral/memcopy_periph.c) for a usage example. + +## External Interrupts + +X-HEEP includes several empty external interrupts slots that can be assigned both in HW and SW. + +Firstly, connect your external device's interrupt to one of the slots of the `external_interrupt_vector` of X-HEEP: + +```systemverilog + +logic [core_v_mini_mcu_pkg::NEXT_INT-1:0] ext_intr_vector; + +always_comb begin +for (int i = 0; i < core_v_mini_mcu_pkg::NEXT_INT; i++) begin + ext_intr_vector[i] = 1'b0; // All interrupt lines set to zero by default +end +ext_intr_vector[0] = my_device_int; // Re-assign the interrupt lines used here +end + +x_heep_system #( + . . . +) x_heep_system_i ( + .intr_vector_ext_i(ext_intr_vector), + . . . +) + +``` + +Then, when initializing the PLIC system in software, do not forget to assign the corresponding interrupt ID to your custom handler. + +```C +#define MY_DEVICE_INTR EXT_INTR_0 + +void handler_irq_my_device(uint32_t id) { + my_device_intr_flag = 1; + // Do whatever you need here +} + +void main() { + plic_Init(); // Init the PLIC, this will clear all external interrupts assigned previously. + plic_irq_set_priority(MY_DEVICE_INTR, 1); // Set the priority of the external device's interrupt. + plic_irq_set_enabled(MY_DEVICE_INTR, kPlicToggleEnabled); // Enable the external device's interrupt. + plic_assign_external_irq_handler( MY_DEVICE_INTR, (void *) &handler_irq_my_device); // Assign a handler taht will be called when this interrupt is triggered. + + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; + CSR_SET_BITS(CSR_REG_MIE, mask); + + . . . +} +``` \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md index 98c09221..7ed89d24 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md @@ -92,30 +92,28 @@ Generate the C program you want to execute as described in the [ExecuteFromFlash then program the FLASH as: ``` -./iceprog -d i:0x0403:0x6011 -I B ../../../build/main.hex +make flash-prog ``` -You can also program the FLASH by running: +You can read the content of the FLASH as: ``` -make flash-prog MAINFILE= +make flash-read FLASHREAD_ADDR=0x10000 FLASHREAD_BYTES=16; xxd flashcontent.hex ``` -You can read the content of the FLASH as: +In this example, we are reading `16` bytes from the flash address `0x10000`. -``` -./iceprog -d i:0x0403:0x6011 -I B -r flash_content.txt -xxd flash_content.txt > flash_content.dump.txt -``` Now program the FPGA with the x-heep bitstream: ``` -cd build/openhwgroup.org_systems_core-v-mini-mcu_0/pynq-z2-vivado +make vivado-fpga-pgm FPGA_BOARD=pynq-z2 ``` -Remember to set the `boot_sel_i` and `execute_from_flash_i` switches to 1. +Remember to set the `boot_sel_i` and `execute_from_flash_i` switches to `1` if you `execute from flash`, +or just `boot_sel_i` to `1` and `execute_from_flash_i` to `0` if you `load from flash`. + Reset the logic (so the x-heep reset and not the bitstream reset) and enjoy. Additional note: To use the flash directly from X-HEEP, you first need to execute from the PC any iceprog command targeting the Flash. On the exit of any iceprog program, the FTDI pins will be set to high impedance. If this is not performed, the pins from the FTDI won't be on high impedance and the SPI signals cannot be driven from X-HEEP (or any other device). diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/SystemC.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/SystemC.md new file mode 100644 index 00000000..1a1aad57 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/SystemC.md @@ -0,0 +1,16 @@ +# SystemC model + +Supporting SystemC model in `X-HEEP` is still a work-in-progress. +However, a simple example is provided in the SystemC testbench available in `tb/tb_sc_top.cpp`. + +When compiling the `X-HEEP` with Verilator using SystemC, the above testbench is used for simulation. +The testbench gets an `X-HEEP` external-memory `obi` master port to communicate with a SystemC memory model. + +Such model is very simple as meant to be an example and is provided in `tb/systemc_tb`. +For those who want to extend the functionality of `X-HEEP` with SystemC, such examples can be used as starting point. + +The SystemC modules leverages `TLM-2.0` as well as baseline SystemC functionalities. + +The `X-HEEP` `obi` port is connected to a `C++` direct-mapped cache who handles `hit` and `miss` with pre-defined latencies. +It uses `TLM-2.0` to communicate with the external SystemC memory on `miss` cache-transactions. +A module in SystemC then communicates with the RTL SystemC model compiled by Verilator to provides read/write data. \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv index 4a3073b8..504fed22 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv @@ -118,7 +118,10 @@ module ao_peripheral_subsystem // EXTERNAL PERIPH output reg_req_t ext_peripheral_slave_req_o, - input reg_rsp_t ext_peripheral_slave_resp_i + input reg_rsp_t ext_peripheral_slave_resp_i, + + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i ); import core_v_mini_mcu_pkg::*; @@ -364,13 +367,15 @@ module ao_peripheral_subsystem .intr_timer_expired_1_0_o(rv_timer_1_intr_o) ); - parameter DMA_TRIGGER_SLOT_NUM = 5; + parameter DMA_TRIGGER_SLOT_NUM = 7; logic [DMA_TRIGGER_SLOT_NUM-1:0] dma_trigger_slots; assign dma_trigger_slots[0] = spi_rx_valid; assign dma_trigger_slots[1] = spi_tx_ready; assign dma_trigger_slots[2] = spi_flash_rx_valid; assign dma_trigger_slots[3] = spi_flash_tx_ready; assign dma_trigger_slots[4] = i2s_rx_valid_i; + assign dma_trigger_slots[5] = ext_dma_slot_tx_i; + assign dma_trigger_slots[6] = ext_dma_slot_rx_i; dma #( .reg_req_t (reg_pkg::reg_req_t), diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv index 4a1ef2e9..45f21d2c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv @@ -315,7 +315,10 @@ module core_v_mini_mcu output logic [EXT_DOMAINS_RND-1:0] external_ram_banks_set_retentive_no, output logic [EXT_DOMAINS_RND-1:0] external_subsystem_clkgate_en_no, - output logic [31:0] exit_value_o + output logic [31:0] exit_value_o, + + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i ); import core_v_mini_mcu_pkg::*; @@ -365,6 +368,7 @@ module core_v_mini_mcu // signals to debug unit logic debug_core_req; + logic debug_reset_n; // core logic core_sleep; @@ -456,7 +460,7 @@ module core_v_mini_mcu ) cpu_subsystem_i ( // Clock and Reset .clk_i, - .rst_ni(cpu_subsystem_rst_n), + .rst_ni(cpu_subsystem_rst_n && debug_reset_n), .core_instr_req_o(core_instr_req), .core_instr_resp_i(core_instr_resp), .core_data_req_o(core_data_req), @@ -485,6 +489,7 @@ module core_v_mini_mcu .jtag_tdi_i, .jtag_tdo_o, .debug_core_req_o(debug_core_req), + .debug_ndmreset_no(debug_reset_n), .debug_slave_req_i(debug_slave_req), .debug_slave_resp_o(debug_slave_resp), .debug_master_req_o(debug_master_req), @@ -496,7 +501,7 @@ module core_v_mini_mcu .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER) ) system_bus_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .core_instr_req_i(core_instr_req), .core_instr_resp_o(core_instr_resp), .core_data_req_i(core_data_req), @@ -539,7 +544,7 @@ module core_v_mini_mcu .NUM_BANKS(core_v_mini_mcu_pkg::NUM_BANKS) ) memory_subsystem_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .clk_gate_en_ni(memory_subsystem_clkgate_en_n), .ram_req_i(ram_slave_req), .ram_resp_o(ram_slave_resp), @@ -548,7 +553,7 @@ module core_v_mini_mcu ao_peripheral_subsystem ao_peripheral_subsystem_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .slave_req_i(ao_peripheral_slave_req), .slave_resp_o(ao_peripheral_slave_resp), .boot_select_i, @@ -628,12 +633,14 @@ module core_v_mini_mcu .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), .i2s_rx_valid_i(i2s_rx_valid), .ext_peripheral_slave_req_o, - .ext_peripheral_slave_resp_i + .ext_peripheral_slave_resp_i, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); peripheral_subsystem peripheral_subsystem_i ( .clk_i, - .rst_ni(peripheral_subsystem_rst_n), + .rst_ni(peripheral_subsystem_rst_n && debug_reset_n), .clk_gate_en_ni(peripheral_subsystem_clkgate_en_n), .slave_req_i(peripheral_slave_req), .slave_resp_o(peripheral_slave_resp), diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl index b4935df4..84255ec1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl @@ -69,7 +69,10 @@ ${pad.core_v_mini_mcu_interface} output logic [EXT_DOMAINS_RND-1:0] external_ram_banks_set_retentive_no, output logic [EXT_DOMAINS_RND-1:0] external_subsystem_clkgate_en_no, - output logic [31:0] exit_value_o + output logic [31:0] exit_value_o, + + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i ); import core_v_mini_mcu_pkg::*; @@ -119,6 +122,7 @@ ${pad.core_v_mini_mcu_interface} // signals to debug unit logic debug_core_req; + logic debug_reset_n; // core logic core_sleep; @@ -210,7 +214,7 @@ ${pad.core_v_mini_mcu_interface} ) cpu_subsystem_i ( // Clock and Reset .clk_i, - .rst_ni(cpu_subsystem_rst_n), + .rst_ni(cpu_subsystem_rst_n && debug_reset_n), .core_instr_req_o(core_instr_req), .core_instr_resp_i(core_instr_resp), .core_data_req_o(core_data_req), @@ -239,6 +243,7 @@ ${pad.core_v_mini_mcu_interface} .jtag_tdi_i, .jtag_tdo_o, .debug_core_req_o(debug_core_req), + .debug_ndmreset_no(debug_reset_n), .debug_slave_req_i(debug_slave_req), .debug_slave_resp_o(debug_slave_resp), .debug_master_req_o(debug_master_req), @@ -250,7 +255,7 @@ ${pad.core_v_mini_mcu_interface} .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER) ) system_bus_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .core_instr_req_i(core_instr_req), .core_instr_resp_o(core_instr_resp), .core_data_req_i(core_data_req), @@ -293,7 +298,7 @@ ${pad.core_v_mini_mcu_interface} .NUM_BANKS(core_v_mini_mcu_pkg::NUM_BANKS) ) memory_subsystem_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .clk_gate_en_ni(memory_subsystem_clkgate_en_n), .ram_req_i(ram_slave_req), .ram_resp_o(ram_slave_resp), @@ -302,7 +307,7 @@ ${pad.core_v_mini_mcu_interface} ao_peripheral_subsystem ao_peripheral_subsystem_i ( .clk_i, - .rst_ni, + .rst_ni(rst_ni && debug_reset_n), .slave_req_i(ao_peripheral_slave_req), .slave_resp_o(ao_peripheral_slave_resp), .boot_select_i, @@ -380,12 +385,14 @@ ${pad.core_v_mini_mcu_interface} .uart_intr_rx_parity_err_o(uart_intr_rx_parity_err), .i2s_rx_valid_i(i2s_rx_valid), .ext_peripheral_slave_req_o, - .ext_peripheral_slave_resp_i + .ext_peripheral_slave_resp_i, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); peripheral_subsystem peripheral_subsystem_i ( .clk_i, - .rst_ni(peripheral_subsystem_rst_n), + .rst_ni(peripheral_subsystem_rst_n && debug_reset_n), .clk_gate_en_ni(peripheral_subsystem_clkgate_en_n), .slave_req_i(peripheral_slave_req), .slave_resp_o(peripheral_slave_resp), diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/cpu_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/cpu_subsystem.sv index bbb62d75..256723f6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/cpu_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/cpu_subsystem.sv @@ -59,21 +59,16 @@ module cpu_subsystem if (CPU_TYPE == cv32e20) begin : gen_cv32e20 - logic [4:0] rf_raddr_a, rf_raddr_b, rf_waddr_wb; - logic [31:0] rf_rdata_a, rf_rdata_b, rf_wdata_wb; - logic rf_we_wb; - - import ibex_pkg::*; - - ibex_core #( + cve2_top #( .DmHaltAddr(DM_HALTADDRESS), - .DmExceptionAddr(32'h0), - .DbgTriggerEn(1'b1), - .ResetAll(1'b1) + .DmExceptionAddr('0) ) cv32e20_i ( .clk_i (clk_i), .rst_ni(rst_ni), + .test_en_i(1'b0), + .ram_cfg_i('0), + .hart_id_i (32'h0), .boot_addr_i(BOOT_ADDR), @@ -94,79 +89,20 @@ module cpu_subsystem .data_rvalid_i(core_data_resp_i.rvalid), .data_err_i (1'b0), - .dummy_instr_id_o (), - .rf_raddr_a_o (rf_raddr_a), - .rf_raddr_b_o (rf_raddr_b), - .rf_waddr_wb_o (rf_waddr_wb), - .rf_we_wb_o (rf_we_wb), - .rf_wdata_wb_ecc_o(rf_wdata_wb), - .rf_rdata_a_ecc_i (rf_rdata_a), - .rf_rdata_b_ecc_i (rf_rdata_b), - - .ic_tag_req_o (), - .ic_tag_write_o (), - .ic_tag_addr_o (), - .ic_tag_wdata_o (), - .ic_tag_rdata_i (), - .ic_data_req_o (), - .ic_data_write_o (), - .ic_data_addr_o (), - .ic_data_wdata_o (), - .ic_data_rdata_i (), - .ic_scr_key_valid_i(), - .irq_software_i(irq_i[3]), .irq_timer_i (irq_i[7]), .irq_external_i(irq_i[11]), - .irq_fast_i (irq_i[30:16]), - .irq_nm_i (irq_i[31]), - .irq_pending_o (), + .irq_fast_i (irq_i[31:16]), + .irq_nm_i (1'b0), - .debug_req_i(debug_req_i), + .debug_req_i (debug_req_i), .crash_dump_o(), - .double_fault_seen_o(), .fetch_enable_i(fetch_enable), - .alert_minor_o (), - .alert_major_o (), - .icache_inval_o(), - .core_sleep_o - ); - - cv32e40p_register_file #( - .ADDR_WIDTH(6) - ) cv32e20_register_file_i ( - // Clock and Reset - .clk (clk_i), - .rst_n(rst_ni), - - .scan_cg_en_i(1'b0), - - //Read port R1 - .raddr_a_i({1'b0, rf_raddr_a}), - .rdata_a_o(rf_rdata_a), - - //Read port R2 - .raddr_b_i({1'b0, rf_raddr_b}), - .rdata_b_o(rf_rdata_b), - - //Read port R3 - .raddr_c_i('0), - .rdata_c_o(), - // Write port W1 - .waddr_a_i({1'b0, rf_waddr_wb}), - .wdata_a_i(rf_wdata_wb), - .we_a_i(rf_we_wb), - - // Write port W2 - .waddr_b_i('0), - .wdata_b_i('0), - .we_b_i('0) + .core_sleep_o ); - - assign irq_ack_o = '0; assign irq_id_o = '0; diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/debug_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/debug_subsystem.sv index 392c12ad..673c1b31 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/debug_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/debug_subsystem.sv @@ -16,6 +16,7 @@ module debug_subsystem input logic jtag_tdi_i, output logic jtag_tdo_o, + output logic debug_ndmreset_no, output logic debug_core_req_o, input obi_req_t debug_slave_req_i, @@ -42,7 +43,9 @@ module debug_subsystem dm::dmi_resp_t dmi_resp; logic dmi_resp_ready; logic dmi_resp_valid; + logic ndmreset; + assign debug_ndmreset_no = ~ndmreset; dmi_jtag #( .IdcodeValue(JTAG_IDCODE) @@ -69,10 +72,10 @@ module debug_subsystem .clk_i (clk_i), .rst_ni (rst_ni), .testmode_i (1'b0), - .ndmreset_o (), + .ndmreset_o (ndmreset), .dmactive_o (), .debug_req_o (debug_core_req_o), - .unavailable_i(~(1'b01)), + .unavailable_i(~(1'b1)), .hartinfo_i (hartinfo), .slave_req_i (debug_slave_req_i.req), diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.lock.hjson new file mode 100644 index 00000000..3a3e601c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.lock.hjson @@ -0,0 +1,14 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated by the util/vendor script. Please do not modify it +// manually. + +{ + upstream: + { + url: https://github.com/esl-epfl/nexys-a7-100t_board_files.git + rev: 19e19ad6bd3b5a405d3e0ef98fee94e7e19e3bab + } +} diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.vendor.hjson new file mode 100644 index 00000000..af1e9c40 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys-a7-100t_board_files.vendor.hjson @@ -0,0 +1,17 @@ +// Copyright 2022 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +{ + name: "esl_epfl_nexys_a7_100t_board_files", + target_dir: "esl_epfl_nexys_a7_100t_board_files", + + upstream: { + url: "https://github.com/esl-epfl/nexys-a7-100t_board_files.git", + rev: "19e19ad6bd3b5a405d3e0ef98fee94e7e19e3bab", + }, + + exclude_from_upstream: [ + "README.md" + ] +} diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/board.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/board.xml new file mode 100644 index 00000000..1ce62873 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/board.xml @@ -0,0 +1,1301 @@ + + + + + D.0 + +1.3 +Nexys A7-100T + + + + + Accelerometer control through SPI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DDR2 board interface, it can use MIG IP for connection. + + + + + + 16 DIP Switches + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dual 7 Seg LED Segments + + + + + + + + + + + + + + + + + + + + 16 LEDs + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 Push Buttons + + + + + + + + + + + + + + + + + Quad SPI Flash + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 RGB LEDs + + + + + + + + + + + + + + + + + + 7 Segment Display Anodes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Temperature Sensor connected to I2C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + USB-to-UART Bridge, which allows a connection to a host computer with a USB port + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Accelerometer controlled through SPI + + + 256 MB Onboard DDR Memory + + + + + + + 16 Switches + + + 7 Segment Display Segment Control + + + 16 LEDs + + + Push Buttons 5 to 0 {Down Right Left Up Center} + + + QSPI Flash + + + Onboard Reset Button + + + 2 RGB LEDs + + + 7 Segment Display Anodes + + + 100 MHz Single-Ended System Clock + + + SPI Controlled Temperature Sensor + + + USB-to-UART Bridge, which allows a connection to a host computer with a USB port + + + Pmod Connector JA + + + Pmod Connector JB + + + Pmod Connector JC + + + Pmod Connector JD + + + Pmod Connector JXADC + + + + + + + + + + + + + + + + + + + + + Onboard MicroSD Card Slot + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/mig.prj b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/mig.prj new file mode 100644 index 00000000..301f5834 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/mig.prj @@ -0,0 +1,157 @@ + + + + + + + + design_1_mig_7series_0_0 + + 1 + + 1 + + OFF + + 1024 + + ON + + Enabled + + xc7a100t-csg324/-1 + + 4.2 + + Single-Ended + + No Buffer + + ACTIVE LOW + + FALSE + + 1 + + 50 Ohms + + 0 + + + 7a/xc7a50t-csg324 + + + + DDR2_SDRAM/Components/MT47H64M16HR-25E + 3077 + 1.8V + 4:1 + 99.997 + 1 + 1200 + 6.000 + 1 + 1 + 1 + 1 + 16 + 1 + 1 + Disabled + Strict + 4 + FALSE + + 13 + 10 + 3 + 134217728 + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + Sequential + 5 + Normal + No + Fast exit + 5 + Enable-Normal + Fullstrength + Enable + 1 + 50ohms + 0 + OCD Exit + Enable + Disable + Enable + AXI + + RD_PRI_REG + 27 + 128 + 4 + 0 + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/part0_pins.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/part0_pins.xml new file mode 100644 index 00000000..43f20b5e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/part0_pins.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/preset.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/preset.xml new file mode 100644 index 00000000..7128ccee --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files/preset.xml @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.lock.hjson new file mode 100644 index 00000000..a05740cc --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.lock.hjson @@ -0,0 +1,14 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated by the util/vendor script. Please do not modify it +// manually. + +{ + upstream: + { + url: https://github.com/esl-epfl/zcu104_board_files.git + rev: 53e4affbaeec73809304940be8f5351ae147227a + } +} diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.vendor.hjson new file mode 100644 index 00000000..69028826 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files.vendor.hjson @@ -0,0 +1,16 @@ +// Copyright 2023 David Mallasén Quintana +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +{ + name: "esl_epfl_zcu104_board_files", + target_dir: "esl_epfl_zcu104_board_files", + + upstream: { + url: "https://github.com/esl-epfl/zcu104_board_files.git", + rev: "53e4affbaeec73809304940be8f5351ae147227a", + }, + + exclude_from_upstream: [ + "README.md" + ] +} diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/board.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/board.xml new file mode 100644 index 00000000..2206a918 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/board.xml @@ -0,0 +1,657 @@ + + + + + + ZCU104 Board File Image + + + + + RevA + RevB + RevC + + + 1.0 + + Zynq UltraScale+ ZCU104 Evaluation Board + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FPGA part on the board + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DDR4 board interface, it can use DDR4 controller IP for connection. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4-Position User DIP Switch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SI570 based User programmable differential 300 MHz Clock. Can be used for DDR4 input system clock + + + + + + + PL UART + + + + + + + + PL I2C + + + + + 2GB DDR4 SDRAM memory SODIMM + + + + + + + + CPU Reset Push Button, Active High + + + + DIP Switches 3 to 0 + + + + LEDs, 3 to 0, Active High + + + + Push Buttons, 3 to 0, Active High + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/part0_pins.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/part0_pins.xml new file mode 100644 index 00000000..e5d6301c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/part0_pins.xml @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/preset.xml b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/preset.xml new file mode 100644 index 00000000..b8d89084 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files/preset.xml @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/constraints.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/constraints.xdc index 5a3c1c4b..ed3a6e89 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/constraints.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/constraints.xdc @@ -1 +1 @@ -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets x_heep_system_i/pad_ring_i/pad_clk_i/xilinx_iobuf_i/O] +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_i}]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc index 53e0eb8f..be620356 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc @@ -1,213 +1,83 @@ -## This file is a general .xdc for the Nexys A7-100T -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 ## Clock signal -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk_i }]; #IO_L12P_T1_MRCC_35 Sch=clk100mhz -#create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {CLK100MHZ}]; +set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {clk_i}]; #IO_L12P_T1_MRCC_35 Sch=clk100mhz -##Switches -set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jtag_trst_ni }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { execute_from_flash_i }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { boot_select_i }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { SW[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { SW[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { SW[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { SW[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { SW[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { SW[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { SW[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { SW[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { SW[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { SW[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { SW[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { SW[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { SW[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] +set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS33} [get_ports {rst_i}]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn ## LEDs -set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { rst_led }]; #IO_L18P_T2_A24_15 Sch=led[0] -set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { clk_led }]; #IO_L24P_T3_RS1_15 Sch=led[1] -set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { exit_value_o }]; #IO_L17N_T2_A25_15 Sch=led[2] -set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { exit_valid_o }]; #IO_L8P_T1_D11_14 Sch=led[3] -set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[29] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[30] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[31] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { LED[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { LED[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { LED[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { LED[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { LED[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { LED[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { LED[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { LED[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { LED[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -## RGB LEDs -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { LED16_B }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { LED16_G }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { LED16_R }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { LED17_B }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { LED17_G }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LED17_R }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - -##7 segment display -set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[8] }]; #IO_L24N_T3_A00_D16_14 Sch=ca -set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[9] }]; #IO_25_14 Sch=cb -set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[10] }]; #IO_25_15 Sch=cc -set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[11] }]; #IO_L17P_T2_A26_15 Sch=cd -set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[12] }]; #IO_L13P_T2_MRCC_14 Sch=ce -set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[13] }]; #IO_L19P_T3_A10_D26_14 Sch=cf -set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[14] }]; #IO_L4P_T0_D04_14 Sch=cg -set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[15] }]; #IO_L19N_T3_A21_VREF_15 Sch=dp -set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[16] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[17] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[18] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[19] }]; #IO_L19P_T3_A22_15 Sch=an[3] -set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[20] }]; #IO_L8N_T1_D12_14 Sch=an[4] -set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[21] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[22] }]; #IO_L23P_T3_35 Sch=an[6] -set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[23] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] +set_property -dict {PACKAGE_PIN V11 IOSTANDARD LVCMOS33} [get_ports {rst_led_o}]; +set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS33} [get_ports {clk_led_o}]; +set_property -dict {PACKAGE_PIN N14 IOSTANDARD LVCMOS33} [get_ports {exit_valid_o}]; +set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {exit_value_o}]; +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_led_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_out_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_led_OBUF] -##CPU Reset Button -set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { rst_i }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -##Buttons -set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[24] }]; #IO_L9P_T1_DQS_14 Sch=btnc -set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[25] }]; #IO_L4N_T0_D05_14 Sch=btnu -set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[26] }]; #IO_L12P_T1_MRCC_14 Sch=btnl -set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[27] }]; #IO_L10N_T1_D15_14 Sch=btnr -set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[28] }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd +##Switches +set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports {execute_from_flash_i}]; #Sch=sw[1] +set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {boot_select_i}]; #Sch=sw[2] +##Switches +set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {jtag_trst_ni}]; #IO_L24N_T3_RS0_15 Sch=sw[0] ##Pmod Headers ##Pmod Header JA -set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - -##Pmod Header JB -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { JB[1] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { JB[2] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { JB[3] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { clk_out }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jtag_tms_i }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jtag_tdi_i }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jtag_tdo_o }]; #IO_0_15 Sch=jb[9] -set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jtag_tck_i }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS33} [get_ports {spi_flash_csb_o}]; #IO_L20N_T3_A19_15 Sch=ja[1] +set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sck_o}]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}]; #IO_L21P_T3_DQS_15 Sch=ja[3] +set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}]; #IO_L18N_T2_A23_15 Sch=ja[4] +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}]; #IO_L16N_T2_A27_15 Sch=ja[7] +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}]; #IO_L16P_T2_A28_15 Sch=ja[8] +#set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}]; #IO_L22N_T3_A16_15 Sch=ja[9] +#set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}]; #IO_L22P_T3_A17_15 Sch=ja[10] ##Pmod Header JC -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { JC[1] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { JC[2] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { i2c_scl_io }]; #IO_L22N_T3_35 Sch=jc[3] -set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { i2c_sda_io }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { JC[7] }]; #IO_L6P_T0_35 Sch=jc[7] -set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { spi_csb_o }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { JC[9] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { JC[10] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - -##Pmod Header JD -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { JD[1] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { JD[2] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { JD[3] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { JD[4] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { JD[7] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { JD[8] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { JD[9] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { JD[10] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] +set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {spi_csb_o}]; #IO_L23N_T3_35 Sch=jc[1] +set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {spi_sck_o}]; #IO_L19N_T3_VREF_35 Sch=jc[2] +set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[0]}]; #IO_L22N_T3_35 Sch=jc[3] +set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[1]}]; #IO_L19P_T3_35 Sch=jc[4] +set_property -dict {PACKAGE_PIN E7 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[2]}]; #IO_L6P_T0_35 Sch=jc[7] +set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[3]}]; #IO_L22P_T3_35 Sch=jc[8] +#set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {clk_out}]; #IO_L21P_T3_DQS_35 Sch=jc[9] +#set_property -dict {PACKAGE_PIN E6 IOSTANDARD LVCMOS33} [get_ports {JC[10]}]; #IO_L5P_T0_AD13P_35 Sch=jc[10] -##Pmod Header JXADC -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { XA_N[1] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { XA_P[1] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { spi_sd_io[2] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { spi_sd_io[0] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { XA_N[3] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { spi_sd_io[1] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { spi_sd_io[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { spi_sck_o }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - -##VGA Connector -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { VGA_R[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { VGA_R[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { VGA_R[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { VGA_R[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { VGA_G[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { VGA_G[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { VGA_G[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { VGA_G[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { VGA_B[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { VGA_B[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { VGA_B[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { VGA_B[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { VGA_HS }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { VGA_VS }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { SD_RESET }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { SD_CD }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { SD_SCK }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { SD_CMD }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { SD_DAT[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - -##Accelerometer -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { ACL_MISO }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { ACL_MOSI }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { ACL_SCLK }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { ACL_CSN }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { ACL_INT[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { ACL_INT[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - -##Temperature Sensor -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { TMP_SCL }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { TMP_SDA }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { TMP_INT }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { TMP_CT }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { M_CLK }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { M_DATA }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { M_LRSEL }]; #IO_0_35 Sch=m_lrsel +##USB-RS232 Interface +set_property -dict {PACKAGE_PIN C4 IOSTANDARD LVCMOS33} [get_ports {uart_rx_i}]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in +set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports {uart_tx_o}]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -##PWM Audio Amplifier -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { AUD_PWM }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { AUD_SD }]; #IO_L6P_T0_15 Sch=aud_sd +##Pmod Header JB +#set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {JB[1]}]; #IO_L1P_T0_AD0P_15 Sch=jb[1] +#set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {JB[2]}]; #IO_L14N_T2_SRCC_15 Sch=jb[2] +#set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS33} [get_ports {uart_tx_o}]; #IO_L13N_T2_MRCC_15 Sch=jb[3] +#set_property -dict {PACKAGE_PIN H14 IOSTANDARD LVCMOS33} [get_ports {uart_rx_i}]; #IO_L15P_T2_DQS_15 Sch=jb[4] +set_property -dict {PACKAGE_PIN E16 IOSTANDARD LVCMOS33} [get_ports {jtag_tms_i}]; #IO_L11N_T1_SRCC_15 Sch=jb[7] +set_property -dict {PACKAGE_PIN F13 IOSTANDARD LVCMOS33} [get_ports {jtag_tdi_i}]; #IO_L5P_T0_AD9P_15 Sch=jb[8] +set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {jtag_tdo_o}]; #IO_0_15 Sch=jb[9] +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports {jtag_tck_i}]; #IO_L13P_T2_MRCC_15 Sch=jb[10] -##USB-RS232 Interface -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_rx_i }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_tx_o }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { UART_CTS }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { UART_RTS }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts +## LEDs +set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[1]}]; +set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[2]}]; +set_property -dict {PACKAGE_PIN U16 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[3]}]; +set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {i2c_scl_io}]; +set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {i2c_sda_io}]; +set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[5]}]; +set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}]; +set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}]; +set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[8]}]; +set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports {gpio_io[9]}]; +set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[10]}]; -##USB HID (PS/2) -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { PS2_CLK }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { PS2_DATA }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data +##Buttons +set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[0]}]; #IO_L9P_T1_DQS_14 Sch=btnc +set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[1]}]; #IO_L4N_T0_D05_14 Sch=btnu +set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]}]; #IO_L12P_T1_MRCC_14 Sch=btnl +set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}]; #IO_L10N_T1_D15_14 Sch=btnr +set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}]; #IO_L9N_T1_DQS_D13_14 Sch=btnd -##SMSC Ethernet PHY -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { ETH_MDC }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { ETH_MDIO }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { ETH_RSTN }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { ETH_CRSDV }]; #IO_L6N_T0_VREF_16 Sch=eth_crsdv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { ETH_RXERR }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { ETH_RXD[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { ETH_RXD[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { ETH_TXEN }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { ETH_TXD[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { ETH_TXD[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ETH_REFCLK }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { ETH_INTN }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] -##Quad SPI Flash -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { QSPI_DQ[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { QSPI_CSN }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc index 5a3c1c4b..ed3a6e89 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc @@ -1 +1 @@ -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets x_heep_system_i/pad_ring_i/pad_clk_i/xilinx_iobuf_i/O] +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_i}]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/pin_assign.xdc index 116323f2..9f8f7ded 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/pin_assign.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/pin_assign.xdc @@ -2,84 +2,97 @@ # Solderpad Hardware License, Version 2.1, see LICENSE.md for details. # SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# Clock signal set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports clk_i] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] + set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports rst_i] -set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports rst_led] -set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports clk_led] -set_property -dict {PACKAGE_PIN W9 IOSTANDARD LVCMOS33} [get_ports clk_out] + +# LEDs +set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports rst_led_o] +set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports clk_led_o] set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports exit_value_o] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_led_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_out_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_led_OBUF] + +# Switches set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports boot_select_i] -## Pmoda -## RPi GPIO 7-0 are shared with pmoda_rpi_gpio_tri_io[7:0] - +# FLASH # QSPI # Q0 / MOSI # Q1 / MISO # Q2 / nWP # Q3 / nHLD +set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] ; # Pmoda[4] +set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] ; # Pmoda[0] +set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] ; # Pmoda[5] +set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] ; # Pmoda[1] +set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] ; # Pmoda[6] +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] ; # Pmoda[2] -set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] -set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] -set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] -set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] -set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] -set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] -#set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {crst}] -set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] +# UART +set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] ; # Pmodb[0] +set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] ; # Pmodb[4] -set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports spi_csb_o] -set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports spi_sck_o] -set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[0]}] -set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[1]}] -set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[2]}] -set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[3]}] +# JTAG +set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] ; # Pmob[1] +set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] ; # Pmodb[6] +set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] ; # Pmodb[2] +set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] ; # Pmodb[5] +set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] ; # Pmoda[7] -## Pmodb -set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] -set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] -set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] -set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] -set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] -set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] +# I2C +set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {i2c_scl_io}] ; # Pmodb[7] +set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {i2c_sda_io}] ; # Pmodb[3] -set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[0]}] -set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[1]}] -set_property -dict {PACKAGE_PIN W8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]}] -set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}] -set_property -dict {PACKAGE_PIN Y6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}] -set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {gpio_io[5]}] -set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}] -set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}] -set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[8]}] -set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[9]}] -set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[10]}] -set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[11]}] -set_property -dict {PACKAGE_PIN V6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[12]}] -set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[13]}] -set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[14]}] -set_property -dict {PACKAGE_PIN Y9 IOSTANDARD LVCMOS33} [get_ports {pdm2pcm_clk_io}] -set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {pdm2pcm_pdm_io}] -set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {i2s_sck_io}] -set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {i2s_ws_io}] -set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {i2s_sd_io}] +# SPI SD +set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports spi_csb_o] ; # arduino_direct_spi_ss_io +set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports spi_sck_o] ; # arduino_direct_spi_sck_io +set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[0]}] ; # arduino_direct_spi_io0_io +set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[1]}] ; # arduino_direct_spi_io1_io +set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[2]}] ; # arduino_gpio_tri_io[12] +set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[3]}] ; # arduino_gpio_tri_io[13] -## Tri-color LD5 for TARGET_PYNQ_Z2 -set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[15]}] -set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[16]}] -set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[17]}] +# GPIOs +set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[0]}] ; # arduino_gpio_tri_io[0] +set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[1]}] ; # rpi_gpio_tri_io[11] +set_property -dict {PACKAGE_PIN W8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]}] ; # rpi_gpio_tri_io[5] +set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}] ; # rpi_gpio_tri_io[16] +set_property -dict {PACKAGE_PIN Y6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}] ; # rpi_gpio_tri_io[7] +set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {gpio_io[5]}] ; # arduino_gpio_tri_io[1] +set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}] ; # rpi_gpio_tri_io[3] +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}] ; # rpi_gpio_tri_io[1] +set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[8]}] ; # rpi_gpio_tri_io[2] +set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[9]}] ; # rpi_gpio_tri_io[14] +set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[10]}] ; # rpi_gpio_tri_io[19] +set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[11]}] ; # rpi_gpio_tri_io[9] +set_property -dict {PACKAGE_PIN V6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[12]}] ; # rpi_gpio_tri_io[6] +set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[13]}] ; # arduino_gpio_tri_io[2] +set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[14]}] ; # arduino_gpio_tri_io[3] -set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_o[0]}] -set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_o[1]}] -set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {spi2_sck_o}] -set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_0_io}] -set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_1_io}] -set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_2_io}] -set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_3_io}] -set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {i2c_scl_io}] -set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {i2c_sda_io}] +# PDM2PCM +set_property -dict {PACKAGE_PIN Y9 IOSTANDARD LVCMOS33} [get_ports {pdm2pcm_clk_io}] ; # rpi_gpio_tri_io[13] +set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {pdm2pcm_pdm_io}] ; # rpi_gpio_tri_io[12] -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] +# I2S +set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {i2s_sck_io}] ; # rpi_gpio_tri_io[8] +set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {i2s_ws_io}] ; # rpi_gpio_tri_io[4] +set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {i2s_sd_io}] ; # arduino_direct_iic_scl_io + +# SPI2 +set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_o[0]}] ; # rpi_gpio_tri_io[15] +set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_o[1]}] ; # arduino_gpio_tri_io[5] +set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {spi2_sck_o}] ; # rpi_gpio_tri_io[10] +set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[0]}] ; # arduino__gpio_tri_io[8] +set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[1]}] ; # arduino_gpio_tri_io[9] +set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[2]}] ; # arduino_gpio_tri_io[10] +set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_io[3]}] ; # arduino_gpio_tri_io[11] +# Tri-color LEDs for TARGET_PYNQ_Z2 +set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[15]}] ; # rgbleds_6bits_tri_o[5] +set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[16]}] ; # rgbled_6bits_tri_o[3] +set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[17]}] ; # rgbleds_6bits_tri_o[4] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc new file mode 100644 index 00000000..4b523cdf --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc @@ -0,0 +1,99 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +# CLOCK +set_property -dict {PACKAGE_PIN AH18 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p] +set_property -dict {PACKAGE_PIN AH17 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i] + +# RESET +set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS33} [get_ports rst_i] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_i] + +# LEDS +set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led_o] +set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led_o] +set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] +set_property -dict {PACKAGE_PIN B5 IOSTANDARD LVCMOS33} [get_ports exit_value_o] + +# SWITCHES +set_property -dict {PACKAGE_PIN E4 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] +set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports boot_select_i] + +# FLASH +# QSPI +# Q0 / MOSI +# Q1 / MISO +# Q2 / nWP +# Q3 / nHLD +set_property -dict {PACKAGE_PIN L10 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] +set_property -dict {PACKAGE_PIN J9 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] +set_property -dict {PACKAGE_PIN M10 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] +set_property -dict {PACKAGE_PIN K9 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] +set_property -dict {PACKAGE_PIN M8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] +set_property -dict {PACKAGE_PIN K8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] + +# UART +set_property -dict {PACKAGE_PIN G8 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] +set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] + +# JTAG +set_property -dict {PACKAGE_PIN H8 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] +set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] +set_property -dict {PACKAGE_PIN G7 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] +set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] +set_property -dict {PACKAGE_PIN M9 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] + +# I2C +set_property -dict {PACKAGE_PIN J7 IOSTANDARD LVCMOS33} [get_ports i2c_scl_io] +set_property -dict {PACKAGE_PIN H7 IOSTANDARD LVCMOS33} [get_ports i2c_sda_io] + +## The following pins are sent to the FMC connector, using the LA pins as single-ended. +## The bank only supports up to 1.8 V. + +# SPI SD +set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS18} [get_ports spi_csb_o] +set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS18} [get_ports spi_sck_o] +set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[0]}] +set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[1]}] +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[2]}] +set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[3]}] + +# GPIOs +set_property -dict {PACKAGE_PIN D11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[0]}] +set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[1]}] +set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[2]}] +set_property -dict {PACKAGE_PIN A7 IOSTANDARD LVCMOS18} [get_ports {gpio_io[3]}] +set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[4]}] +set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[5]}] +set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[6]}] +set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[7]}] +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[8]}] +set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[9]}] +set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[10]}] +set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[11]}] +set_property -dict {PACKAGE_PIN F11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[12]}] +set_property -dict {PACKAGE_PIN E10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[13]}] +set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[14]}] +set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[15]}] +set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS18} [get_ports {gpio_io[16]}] +set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[17]}] + +# PDM2PCM +set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] + +# I2S +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] +set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] + +# SPI2 +set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[0]}] +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[1]}] +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports spi2_sck_o] +set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[0]}] +set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[1]}] +set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[2]}] +set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[3]}] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv index 349920c1..35165b88 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv @@ -158,3 +158,12 @@ module tc_clk_xor2 ( assign clk_o = clk0_i ^ clk1_i; endmodule + +module tc_clk_inverter ( + input logic clk_i, + output logic clk_o +); + + xilinx_clk_inverter clk_inv_i (.*); + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl new file mode 100644 index 00000000..544cd11b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl @@ -0,0 +1,3 @@ +# Select board +set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] +set_property -name "board_part" -value "digilentinc.com:nexys-a7-100t:part0:1.3" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl new file mode 100644 index 00000000..69dff9c3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl @@ -0,0 +1,43 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# Define design macros + +set design_name xilinx_clk_wizard +set in_clk_freq_MHz 100 +set out_clk_freq_MHz 15 + + +# Create block design +create_bd_design $design_name + +# Create ports +set clk_100MHz [ create_bd_port -dir I -type clk -freq_hz [ expr $in_clk_freq_MHz * 1000000 ] clk_100MHz ] +set clk_out1_0 [ create_bd_port -dir O -type clk clk_out1_0 ] +set_property -dict [ list CONFIG.FREQ_HZ [ expr $out_clk_freq_MHz * 1000000 ] ] $clk_out1_0 + +# Create instance and set properties +set clk_wiz_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0 ] +set_property -dict [ list \ + CONFIG.CLKOUT1_JITTER {333.843} \ + CONFIG.CLKOUT1_PHASE_ERROR {293.793} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {15} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {49.875} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {66.500} \ + CONFIG.PRIM_IN_FREQ $in_clk_freq_MHz \ + CONFIG.USE_LOCKED {false} \ + CONFIG.USE_RESET {false} \ +] $clk_wiz_0 + +# Create port connections +connect_bd_net -net clk_in1_0_1 [ get_bd_ports clk_100MHz ] [ get_bd_pins clk_wiz_0/clk_in1 ] +connect_bd_net -net clk_wiz_0_clk_out1 [ get_bd_ports clk_out1_0 ] [ get_bd_pins clk_wiz_0/clk_out1 ] + +# Save and close block design +save_bd_design +close_bd_design $design_name + +# create wrapper +set wrapper_path [ make_wrapper -fileset sources_1 -files [ get_files -norecurse xilinx_clk_wizard.bd ] -top ] +add_files -norecurse -fileset sources_1 $wrapper_path diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl new file mode 100644 index 00000000..f16f754f --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl @@ -0,0 +1,3 @@ +# Select board +set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] +set_property -name "board_part" -value "tul.com.tw:pynq-z2:part0:1.0" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl similarity index 86% rename from hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl rename to hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl index 1c2a41a0..e61c5832 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/xilinx_generate_clk_wizard.tcl +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl @@ -7,9 +7,6 @@ set design_name xilinx_clk_wizard set in_clk_freq_MHz 125 set out_clk_freq_MHz 15 -# Select board -set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] -set_property -name "board_part" -value "tul.com.tw:pynq-z2:part0:1.0" -objects [current_project] # Create block design create_bd_design $design_name diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl new file mode 100644 index 00000000..0108a4c8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl @@ -0,0 +1,3 @@ +# Select board +set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] +set_property -name "board_part" -value "xilinx.com:zcu104:part0:1.0" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl new file mode 100644 index 00000000..d67e4054 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl @@ -0,0 +1,40 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# Define design macros + +set design_name xilinx_clk_wizard + +# Create block design +create_bd_design $design_name + +# Create instance and set properties +create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0 +set_property -dict [list \ + CONFIG.CLKIN1_JITTER_PS {33.330000000000005} \ + CONFIG.CLKOUT1_JITTER {282.792} \ + CONFIG.CLKOUT1_PHASE_ERROR {207.545} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {15} \ + CONFIG.CLK_IN1_BOARD_INTERFACE {clk_300mhz} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {32.875} \ + CONFIG.MMCM_CLKIN1_PERIOD {3.333} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {65.750} \ + CONFIG.MMCM_DIVCLK_DIVIDE {10} \ + CONFIG.OPTIMIZE_CLOCKING_STRUCTURE_EN {true} \ + CONFIG.PRIM_SOURCE {Differential_clock_capable_pin} \ + CONFIG.USE_LOCKED {false} \ + CONFIG.USE_RESET {true} \ +] [get_bd_cells clk_wiz_0] + +# Create ports +make_bd_pins_external [get_bd_cells clk_wiz_0] +make_bd_intf_pins_external [get_bd_cells clk_wiz_0] + +# Save and close block design +save_bd_design +close_bd_design $design_name + +# Create wrapper +set wrapper_path [ make_wrapper -fileset sources_1 -files [ get_files -norecurse xilinx_clk_wizard.bd ] -top ] +add_files -norecurse -fileset sources_1 $wrapper_path diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv index 1324bfb1..fc9c53fb 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv @@ -13,13 +13,16 @@ module xilinx_core_v_mini_mcu_wrapper parameter CLK_LED_COUNT_LENGTH = 27 ) ( +`ifdef FPGA_ZCU104 + inout logic clk_300mhz_n, + inout logic clk_300mhz_p, +`else inout logic clk_i, +`endif inout logic rst_i, - //visibility signals - output logic rst_led, - output logic clk_led, - output logic clk_out, + output logic rst_led_o, + output logic clk_led_o, inout logic boot_select_i, inout logic execute_from_flash_i, @@ -33,7 +36,7 @@ module xilinx_core_v_mini_mcu_wrapper inout logic uart_rx_i, inout logic uart_tx_o, - inout logic [19:0] gpio_io, + inout logic [17:0] gpio_io, output logic exit_value_o, inout logic exit_valid_o, @@ -46,10 +49,7 @@ module xilinx_core_v_mini_mcu_wrapper inout logic spi_csb_o, inout logic spi_sck_o, - inout logic spi2_sd_0_io, - inout logic spi2_sd_1_io, - inout logic spi2_sd_2_io, - inout logic spi2_sd_3_io, + inout logic [3:0] spi2_sd_io, inout logic [1:0] spi2_csb_o, inout logic spi2_sck_o, @@ -71,13 +71,17 @@ module xilinx_core_v_mini_mcu_wrapper logic [CLK_LED_COUNT_LENGTH - 1:0] clk_count; // low active reset - assign rst_n = !rst_i; +`ifdef FPGA_NEXYS + assign rst_n = rst_i; +`else + assign rst_n = !rst_i; +`endif // reset LED for debugging - assign rst_led = rst_n; + assign rst_led_o = rst_n; // counter to blink an LED - assign clk_led = clk_count[CLK_LED_COUNT_LENGTH-1]; + assign clk_led_o = clk_count[CLK_LED_COUNT_LENGTH-1]; always_ff @(posedge clk_gen or negedge rst_n) begin : clk_count_process if (!rst_n) begin @@ -90,13 +94,23 @@ module xilinx_core_v_mini_mcu_wrapper // eXtension Interface if_xif #() ext_if (); - // clock output for debugging - assign clk_out = clk_gen; - +`ifdef FPGA_ZCU104 + xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( + .CLK_IN1_D_0_clk_n(clk_300mhz_n), + .CLK_IN1_D_0_clk_p(clk_300mhz_p), + .clk_out1_0(clk_gen) + ); +`elsif FPGA_NEXYS + xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( + .clk_100MHz(clk_i), + .clk_out1_0(clk_gen) + ); +`else // FPGA PYNQ-Z2 xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( .clk_125MHz(clk_i), .clk_out1_0(clk_gen) ); +`endif x_heep_system #( .X_EXT(X_EXT), @@ -180,10 +194,10 @@ module xilinx_core_v_mini_mcu_wrapper .spi_sck_io(spi_sck_o), .i2c_scl_io, .i2c_sda_io, - .spi2_sd_0_io(spi2_sd_0_io), - .spi2_sd_1_io(spi2_sd_1_io), - .spi2_sd_2_io(spi2_sd_2_io), - .spi2_sd_3_io(spi2_sd_3_io), + .spi2_sd_0_io(spi2_sd_io[0]), + .spi2_sd_1_io(spi2_sd_io[1]), + .spi2_sd_2_io(spi2_sd_io[2]), + .spi2_sd_3_io(spi2_sd_io[3]), .spi2_cs_0_io(spi2_csb_o[0]), .spi2_cs_1_io(spi2_csb_o[1]), .spi2_sck_io(spi2_sck_o), @@ -191,7 +205,9 @@ module xilinx_core_v_mini_mcu_wrapper .pdm2pcm_pdm_io, .i2s_sck_io(i2s_sck_io), .i2s_ws_io(i2s_ws_io), - .i2s_sd_io(i2s_sd_io) + .i2s_sd_io(i2s_sd_io), + .ext_dma_slot_tx_i('0), + .ext_dma_slot_rx_i('0) ); assign exit_value_o = exit_value[0]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/README.md b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/README.md index dc07aef1..65b4b051 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/README.md +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/README.md @@ -1,33 +1,5 @@ ## boot_rom -1. If you haven't done it yet, install [Conda](https://phoenixnap.com/kb/how-to-install-anaconda-ubuntu-18-04-or-20-04) as described in the link, -and create the Conda enviroment with python 2.7: - -```bash -conda update conda -conda env create -f environment.yml -``` - -Activate the environment with - -```bash -conda activate boot_rom -``` - -If you are already in the core-v-mini-mcu conda env, deactivate it first: - -```bash -conda deactivate -``` - -2. Install the required Python tools: - -``` -pip install --user -r python-requirements.txt -``` - -3. Generate the boot_rom: - If you modified the `boot_rom.S` file, generate it as: ``` diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.S b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.S index f154eec4..7b0fab66 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.S +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.S @@ -99,7 +99,7 @@ _wait_spi_ready_tx_init: _wait_spi_ready_read_prog: lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) bgez a5, _wait_spi_ready_read_prog - li a3, 1024 # 1KB copy size + li a3, 2048 # 2KB copy size li s1, 0 # dst ptr (ram) // For loop until the 1KB copy from flash to ram is done diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.dump b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.dump index c4a74476..025800d8 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.dump +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.dump @@ -6,14 +6,14 @@ Disassembly of section .text: 00000000 : 0: 200405b7 lui a1,0x20040 - 4: 0005c503 lbu a0,0(a1) # 20040000 <_end+0x2003ff16> + 4: 0005c503 lbu a0,0(a1) # 20040000 <_end+0x2003ff14> 8: c119 beqz a0,e a: 41c8 lw a0,4(a1) c: 9502 jalr a0 0000000e : e: 200005b7 lui a1,0x20000 - 12: 0085c503 lbu a0,8(a1) # 20000008 <_end+0x1fffff1e> + 12: 0085c503 lbu a0,8(a1) # 20000008 <_end+0x1fffff1c> 16: e511 bnez a0,22 <_jump_to_flash> 00000018 <_jump_to_debug_rom>: @@ -31,7 +31,7 @@ Disassembly of section .text: 2c: 4505 li a0,1 2e: c188 sw a0,0(a1) 30: 400005b7 lui a1,0x40000 - 34: 18058593 addi a1,a1,384 # 40000180 <_end+0x40000096> + 34: 18058593 addi a1,a1,384 # 40000180 <_end+0x40000094> 38: 9582 jalr a1 0000003a <_copy_from_flash>: @@ -73,41 +73,42 @@ Disassembly of section .text: 0000008a <_wait_spi_ready_read_prog>: 8a: 49dc lw a5,20(a1) 8c: fe07dfe3 bgez a5,8a <_wait_spi_ready_read_prog> - 90: 40000693 li a3,1024 - 94: 4481 li s1,0 - 96: 10000b13 li s6,256 - 9a: 09000437 lui s0,0x9000 - 9e: 0ff40a93 addi s5,s0,255 # 90000ff <_end+0x9000015> - -000000a2 <_32B_chunk_loop>: - a2: 00db4663 blt s6,a3,ae <_read_32B_chunk> - a6: 08000437 lui s0,0x8000 - aa: 0ff40a93 addi s5,s0,255 # 80000ff <_end+0x8000015> - -000000ae <_read_32B_chunk>: - ae: 0355a223 sw s5,36(a1) # 20020024 <_end+0x2001ff3a> - b2: 0001 nop - -000000b4 <_wait_spi_ready_read_32B_chunk>: - b4: 49dc lw a5,20(a1) - b6: fe07dfe3 bgez a5,b4 <_wait_spi_ready_read_32B_chunk> - ba: 10048b93 addi s7,s1,256 - -000000be <_wait_spi_rxwm_8_words>: - be: 49dc lw a5,20(a1) - c0: 83d1 srli a5,a5,0x14 - c2: 8b85 andi a5,a5,1 - c4: dfed beqz a5,be <_wait_spi_rxwm_8_words> - c6: 02048613 addi a2,s1,32 - -000000ca <_spi_fifo_read_8_words>: - ca: 0285a883 lw a7,40(a1) - ce: 0114a023 sw a7,0(s1) - d2: 0491 addi s1,s1,4 - d4: fec49be3 bne s1,a2,ca <_spi_fifo_read_8_words> - d8: ff7493e3 bne s1,s7,be <_wait_spi_rxwm_8_words> - dc: f0068693 addi a3,a3,-256 - e0: f2e9 bnez a3,a2 <_32B_chunk_loop> - e2: 200005b7 lui a1,0x20000 - e6: 4990 lw a2,16(a1) - e8: 9602 jalr a2 + 90: 6685 lui a3,0x1 + 92: 80068693 addi a3,a3,-2048 # 800 <_end+0x714> + 96: 4481 li s1,0 + 98: 10000b13 li s6,256 + 9c: 09000437 lui s0,0x9000 + a0: 0ff40a93 addi s5,s0,255 # 90000ff <_end+0x9000013> + +000000a4 <_32B_chunk_loop>: + a4: 00db4663 blt s6,a3,b0 <_read_32B_chunk> + a8: 08000437 lui s0,0x8000 + ac: 0ff40a93 addi s5,s0,255 # 80000ff <_end+0x8000013> + +000000b0 <_read_32B_chunk>: + b0: 0355a223 sw s5,36(a1) # 20020024 <_end+0x2001ff38> + b4: 0001 nop + +000000b6 <_wait_spi_ready_read_32B_chunk>: + b6: 49dc lw a5,20(a1) + b8: fe07dfe3 bgez a5,b6 <_wait_spi_ready_read_32B_chunk> + bc: 10048b93 addi s7,s1,256 + +000000c0 <_wait_spi_rxwm_8_words>: + c0: 49dc lw a5,20(a1) + c2: 83d1 srli a5,a5,0x14 + c4: 8b85 andi a5,a5,1 + c6: dfed beqz a5,c0 <_wait_spi_rxwm_8_words> + c8: 02048613 addi a2,s1,32 + +000000cc <_spi_fifo_read_8_words>: + cc: 0285a883 lw a7,40(a1) + d0: 0114a023 sw a7,0(s1) + d4: 0491 addi s1,s1,4 + d6: fec49be3 bne s1,a2,cc <_spi_fifo_read_8_words> + da: ff7493e3 bne s1,s7,c0 <_wait_spi_rxwm_8_words> + de: f0068693 addi a3,a3,-256 + e2: f2e9 bnez a3,a4 <_32B_chunk_loop> + e4: 200005b7 lui a1,0x20000 + e8: 4990 lw a2,16(a1) + ea: 9602 jalr a2 diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.h b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.h index 8f0e3d2b..bbb8198a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.h +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.h @@ -39,27 +39,27 @@ uint32_t reset_vec[reset_vec_size] = { 0xd1d8070d, 0x49dc0001, 0xfe07dfe3, - 0x40000693, - 0x0b134481, - 0x04371000, - 0x0a930900, - 0x46630ff4, - 0x043700db, - 0x0a930800, - 0xa2230ff4, - 0x00010355, - 0xdfe349dc, - 0x8b93fe07, - 0x49dc1004, - 0x8b8583d1, - 0x8613dfed, - 0xa8830204, - 0xa0230285, - 0x04910114, - 0xfec49be3, - 0xff7493e3, - 0xf0068693, - 0x05b7f2e9, - 0x49902000, - 0x00009602 + 0x86936685, + 0x44818006, + 0x10000b13, + 0x09000437, + 0x0ff40a93, + 0x00db4663, + 0x08000437, + 0x0ff40a93, + 0x0355a223, + 0x49dc0001, + 0xfe07dfe3, + 0x10048b93, + 0x83d149dc, + 0xdfed8b85, + 0x02048613, + 0x0285a883, + 0x0114a023, + 0x9be30491, + 0x93e3fec4, + 0x8693ff74, + 0xf2e9f006, + 0x200005b7, + 0x96024990 }; diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.sv index 07c74e3a..93983a15 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/boot_rom.sv @@ -26,29 +26,29 @@ module boot_rom logic [RomSize-1:0][31:0] mem; assign mem = { - 32'h00009602, - 32'h49902000, - 32'h05b7f2e9, - 32'hf0068693, - 32'hff7493e3, - 32'hfec49be3, - 32'h04910114, - 32'ha0230285, - 32'ha8830204, - 32'h8613dfed, - 32'h8b8583d1, - 32'h49dc1004, - 32'h8b93fe07, - 32'hdfe349dc, - 32'h00010355, - 32'ha2230ff4, - 32'h0a930800, - 32'h043700db, - 32'h46630ff4, - 32'h0a930900, - 32'h04371000, - 32'h0b134481, - 32'h40000693, + 32'h96024990, + 32'h200005b7, + 32'hf2e9f006, + 32'h8693ff74, + 32'h93e3fec4, + 32'h9be30491, + 32'h0114a023, + 32'h0285a883, + 32'h02048613, + 32'hdfed8b85, + 32'h83d149dc, + 32'h10048b93, + 32'hfe07dfe3, + 32'h49dc0001, + 32'h0355a223, + 32'h0ff40a93, + 32'h08000437, + 32'h00db4663, + 32'h0ff40a93, + 32'h09000437, + 32'h10000b13, + 32'h44818006, + 32'h86936685, 32'hfe07dfe3, 32'h49dc0001, 32'hd1d8070d, diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/environment.yml b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/environment.yml deleted file mode 100644 index 260ecf9a..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/environment.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: boot_rom -channels: - - defaults -dependencies: - - python=2.7.18 - diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/gen_rom.py b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/gen_rom.py index b52e22bd..b1a79b57 100755 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/gen_rom.py +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/boot_rom/gen_rom.py @@ -89,9 +89,8 @@ def read_bin(): with open(filename + ".img", 'rb') as f: - rom = binascii.hexlify(f.read()) - rom = map(''.join, zip(rom[::2], rom[1::2])) - + rom = bytes.hex(f.read()) + rom = list(map(''.join, zip(rom[::2], rom[1::2]))) # align to 32 bit align = (int((len(rom) + 3) / 4 )) * 4; diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_core.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_core.sv index fb155575..2195a075 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_core.sv @@ -7,8 +7,8 @@ // Description: I2s core logic module i2s_core #( - parameter MaxWordWidth, - parameter ClkDividerWidth + parameter MaxWordWidth = 32, + parameter ClkDividerWidth = 8 ) ( input logic clk_i, input logic rst_ni, diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_ws_gen.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_ws_gen.sv index ed85b649..a6ebeca2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_ws_gen.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_ws_gen.sv @@ -10,7 +10,7 @@ // by Antonio Pullini (pullinia@iis.ee.ethz.ch) module i2s_ws_gen #( - parameter MaxWordWidth, + parameter MaxWordWidth = 32, localparam int unsigned CounterWidth = $clog2(MaxWordWidth) ) ( input logic sck_i, diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/data/iffifo.hjson b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/data/iffifo.hjson new file mode 100644 index 00000000..919cceaf --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/data/iffifo.hjson @@ -0,0 +1,76 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +{ name: "iffifo" + clock_primary: "clk_i" + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + regwidth: 32 + registers: [ + + { name: "FIFO_OUT" + desc: "Data coming from the FIFO (Fifo Output/Software RX)" + swaccess: "ro" + hwaccess: "hrw" # required for RE signal + hwext: "true" # required for RE signal + hwre: "true" # Used to emulate a window behaviour + fields: [ + { bits: "31:0" } + ] + } + + { name: "FIFO_IN" + desc: "Data sent to the FIFO (Fifo Input/Software TX)" + hwaccess: "hro" + swaccess: "rw" # required for QE signal + hwqe: "true" # Used to emulate a window behaviour + fields: [ + { bits: "31:0" } + ] + } + + { name: "STATUS" + desc: "General purpose status register" + swaccess: "ro" + hwaccess: "hwo" + fields: [ + { bits: "0", name: "EMPTY", desc: "Asserted when FIFO empty." } + { bits: "1", name: "AVAILABLE", desc: "Asserted when data is available in FIFO." } + { bits: "2", name: "REACHED", desc: "Asserted when occupied data slots count greater than threshold." } + { bits: "3", name: "FULL", desc: "Asserted when all FIFO slots are occupied." } + ] + } + + { name: "OCCUPANCY" + desc: "Current number of occupied FIFO slots" + swaccess: "ro" + hwaccess: "hwo" + fields: [ + { bits: "31:0" } + ] + } + + { name: "WATERMARK" + desc: "FIFO occupancy at which the STATUS:REACHED bit is asserted" + swaccess: "rw" + hwaccess: "hro" + fields: [ + { bits: "31:0" } + ] + } + + { name: "INTERRUPTS" + desc: "Write any value to assert an interrupt. Write 0 or 1 to disable or enable an interrupt." + swaccess: "rw" + hwaccess: "hro" + hwqe: "true" # Used to catch software writes + fields: [ + { bits: "0", name: "REACHED", desc: "Watermark reached interrupt" } + ] + } + + ] +} + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.core b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.core new file mode 100644 index 00000000..f0e23463 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.core @@ -0,0 +1,26 @@ +CAPI=2: + +name: "example:ip:iffifo" +description: "core-v-mini-mcu iffifo peripheral" + +# Copyright 2023 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# +# Author: Pierre Guillod , EPFL, STI-SEL +# Date: 18.10.2023 + +filesets: + files_rtl: + depend: + - pulp-platform.org::common_cells + files: + - rtl/iffifo_reg_pkg.sv + - rtl/iffifo_reg_top.sv + - rtl/iffifo.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.vlt new file mode 100644 index 00000000..9820d038 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo.vlt @@ -0,0 +1,15 @@ +// Copyright 2023 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Author: Pierre Guillod , EPFL, STI-SEL +// Date: 18.10.2023 + +`verilator_config + +lint_off -rule DECLFILENAME -file "*/iffifo/rtl/iffifo_reg_top.sv" -match "Filename 'iffifo_reg_top' does not match MODULE name: 'iffifo_reg_top_intf'*" +lint_off -rule WIDTH -file "*/iffifo/rtl/iffifo_reg_top.sv" -match "Operator ASSIGNW expects 3 bits on the Assign RHS, but Assign RHS's SEL generates 32*" +lint_off -rule UNUSED -file "*/iffifo/rtl/iffifo.sv" -match "Bits of signal are not used: 'reg2hw'[0]*" + +lint_off -rule UNUSED -file "*/iffifo/rtl/iffifo_window.sv" -match "Bits of signal are not used: 'rx_win_i'[67:64,31:0]" +lint_off -rule WIDTH -file "*/iffifo/rtl/iffifo_*.sv" -match "Operator ASSIGNW expects*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo_gen.sh b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo_gen.sh new file mode 100755 index 00000000..45cc8f1c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/iffifo_gen.sh @@ -0,0 +1,8 @@ +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +echo "Generating RTL" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py -r -t rtl data/iffifo.hjson +echo "Generating SW" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py --cdefines -o ../../../sw/device/lib/drivers/iffifo/iffifo_regs.h data/iffifo.hjson diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo.sv new file mode 100644 index 00000000..35a6b008 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo.sv @@ -0,0 +1,115 @@ +// Copyright 2023 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Author: Pierre Guillod , EPFL, STI-SEL +// Date: 18.10.2023 + +module iffifo #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + localparam int WIDTH = 32, + localparam int DEPTH = 4, + localparam int DEPTHw = $clog2(DEPTH + 1) +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + // DMA slots + output logic iffifo_in_ready_o, + output logic iffifo_out_valid_o, + + // Interrupt lines + output logic iffifo_int_o +); + + import iffifo_reg_pkg::*; + + iffifo_reg2hw_t reg2hw; + iffifo_hw2reg_t hw2reg; + + logic [WIDTH-1:0] fifout; + logic [DEPTHw-1:0] occupancy; + logic empty, full, reached, available; + + assign hw2reg.fifo_out.d = fifout + 1; + + // Status (full/empty/watermark) reporting circuitry + assign empty = (occupancy == 0); + assign available = !empty; + assign hw2reg.status.empty.de = 1; + assign hw2reg.status.empty.d = empty; + assign hw2reg.status.available.de = 1; + assign hw2reg.status.available.d = available; + assign hw2reg.status.full.de = 1; + assign hw2reg.status.full.d = full; + assign hw2reg.status.reached.de = 1; + assign hw2reg.status.reached.d = reached; + assign hw2reg.occupancy.de = 1; + assign hw2reg.occupancy.d = {{32 - DEPTHw{1'b0}}, occupancy}; + assign reached = ({{32 - DEPTHw{1'b0}}, occupancy} >= reg2hw.watermark.q); + + // Interrupts circuitry + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + + iffifo_int_o <= 0; + + end else begin + + // Interrupts firing + if (reached & reg2hw.interrupts.q) begin + iffifo_int_o <= 1; + end + + // Interrupts assertion + if (reg2hw.interrupts.qe) begin + iffifo_int_o <= 0; + end + + end + end + + iffifo_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) iffifo_reg_top_i ( + .clk_i, + .rst_ni, + .reg2hw, + .hw2reg, + .reg_req_i, + .reg_rsp_o, + .devmode_i(1'b0) + ); + + prim_fifo_sync #( + .Width(WIDTH), + .Depth(DEPTH), + .Pass(1'b0), + .OutputZeroIfEmpty(1'b0) + ) iffifo_fifo_i ( + + .clk_i, + .rst_ni, + .clr_i(1'b0), + + // From DMA (output) to FIFO (input, TX) + .wvalid_i(reg2hw.fifo_in.qe), + .wready_o(iffifo_in_ready_o), + .wdata_i (reg2hw.fifo_in.q), + + // From FIFO (output) to DMA (input, RX) + .rvalid_o(iffifo_out_valid_o), + .rready_i(reg2hw.fifo_out.re), + .rdata_o (fifout), + + .full_o (full), + .depth_o(occupancy) + + ); + +endmodule : iffifo + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv new file mode 100644 index 00000000..e362798d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_pkg.sv @@ -0,0 +1,106 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package iffifo_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 5; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + logic [31:0] q; + logic re; + } iffifo_reg2hw_fifo_out_reg_t; + + typedef struct packed { + logic [31:0] q; + logic qe; + } iffifo_reg2hw_fifo_in_reg_t; + + typedef struct packed {logic [31:0] q;} iffifo_reg2hw_watermark_reg_t; + + typedef struct packed { + logic q; + logic qe; + } iffifo_reg2hw_interrupts_reg_t; + + typedef struct packed {logic [31:0] d;} iffifo_hw2reg_fifo_out_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } empty; + struct packed { + logic d; + logic de; + } available; + struct packed { + logic d; + logic de; + } reached; + struct packed { + logic d; + logic de; + } full; + } iffifo_hw2reg_status_reg_t; + + typedef struct packed { + logic [31:0] d; + logic de; + } iffifo_hw2reg_occupancy_reg_t; + + // Register -> HW type + typedef struct packed { + iffifo_reg2hw_fifo_out_reg_t fifo_out; // [99:67] + iffifo_reg2hw_fifo_in_reg_t fifo_in; // [66:34] + iffifo_reg2hw_watermark_reg_t watermark; // [33:2] + iffifo_reg2hw_interrupts_reg_t interrupts; // [1:0] + } iffifo_reg2hw_t; + + // HW -> register type + typedef struct packed { + iffifo_hw2reg_fifo_out_reg_t fifo_out; // [72:41] + iffifo_hw2reg_status_reg_t status; // [40:33] + iffifo_hw2reg_occupancy_reg_t occupancy; // [32:0] + } iffifo_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] IFFIFO_FIFO_OUT_OFFSET = 5'h0; + parameter logic [BlockAw-1:0] IFFIFO_FIFO_IN_OFFSET = 5'h4; + parameter logic [BlockAw-1:0] IFFIFO_STATUS_OFFSET = 5'h8; + parameter logic [BlockAw-1:0] IFFIFO_OCCUPANCY_OFFSET = 5'hc; + parameter logic [BlockAw-1:0] IFFIFO_WATERMARK_OFFSET = 5'h10; + parameter logic [BlockAw-1:0] IFFIFO_INTERRUPTS_OFFSET = 5'h14; + + // Reset values for hwext registers and their fields + parameter logic [31:0] IFFIFO_FIFO_OUT_RESVAL = 32'h0; + + // Register index + typedef enum int { + IFFIFO_FIFO_OUT, + IFFIFO_FIFO_IN, + IFFIFO_STATUS, + IFFIFO_OCCUPANCY, + IFFIFO_WATERMARK, + IFFIFO_INTERRUPTS + } iffifo_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] IFFIFO_PERMIT[6] = '{ + 4'b1111, // index[0] IFFIFO_FIFO_OUT + 4'b1111, // index[1] IFFIFO_FIFO_IN + 4'b0001, // index[2] IFFIFO_STATUS + 4'b1111, // index[3] IFFIFO_OCCUPANCY + 4'b1111, // index[4] IFFIFO_WATERMARK + 4'b0001 // index[5] IFFIFO_INTERRUPTS + }; + +endpackage + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv new file mode 100644 index 00000000..cd8d2f56 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/iffifo/rtl/iffifo_reg_top.sv @@ -0,0 +1,451 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module iffifo_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 5 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output iffifo_reg_pkg::iffifo_reg2hw_t reg2hw, // Write + input iffifo_reg_pkg::iffifo_hw2reg_t hw2reg, // Read + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import iffifo_reg_pkg::*; + + localparam int DW = 32; + localparam int DBW = DW / 8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [ AW-1:0] reg_addr; + logic [ DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [ DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic [31:0] fifo_out_qs; + logic fifo_out_re; + logic [31:0] fifo_in_qs; + logic [31:0] fifo_in_wd; + logic fifo_in_we; + logic status_empty_qs; + logic status_available_qs; + logic status_reached_qs; + logic status_full_qs; + logic [31:0] occupancy_qs; + logic [31:0] watermark_qs; + logic [31:0] watermark_wd; + logic watermark_we; + logic interrupts_qs; + logic interrupts_wd; + logic interrupts_we; + + // Register instances + // R[fifo_out]: V(True) + + prim_subreg_ext #( + .DW(32) + ) u_fifo_out ( + .re (fifo_out_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.fifo_out.d), + .qre(reg2hw.fifo_out.re), + .qe (), + .q (reg2hw.fifo_out.q), + .qs (fifo_out_qs) + ); + + + // R[fifo_in]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_fifo_in ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(fifo_in_we), + .wd(fifo_in_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.fifo_in.qe), + .q (reg2hw.fifo_in.q), + + // to register interface (read) + .qs(fifo_in_qs) + ); + + + // R[status]: V(False) + + // F[empty]: 0:0 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_empty ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.empty.de), + .d (hw2reg.status.empty.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_empty_qs) + ); + + + // F[available]: 1:1 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_available ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.available.de), + .d (hw2reg.status.available.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_available_qs) + ); + + + // F[reached]: 2:2 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_reached ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.reached.de), + .d (hw2reg.status.reached.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_reached_qs) + ); + + + // F[full]: 3:3 + prim_subreg #( + .DW (1), + .SWACCESS("RO"), + .RESVAL (1'h0) + ) u_status_full ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.status.full.de), + .d (hw2reg.status.full.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(status_full_qs) + ); + + + // R[occupancy]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RO"), + .RESVAL (32'h0) + ) u_occupancy ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .we(1'b0), + .wd('0), + + // from internal hardware + .de(hw2reg.occupancy.de), + .d (hw2reg.occupancy.d), + + // to internal hardware + .qe(), + .q (), + + // to register interface (read) + .qs(occupancy_qs) + ); + + + // R[watermark]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_watermark ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(watermark_we), + .wd(watermark_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.watermark.q), + + // to register interface (read) + .qs(watermark_qs) + ); + + + // R[interrupts]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_interrupts ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(interrupts_we), + .wd(interrupts_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.interrupts.qe), + .q (reg2hw.interrupts.q), + + // to register interface (read) + .qs(interrupts_qs) + ); + + + + + logic [5:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == IFFIFO_FIFO_OUT_OFFSET); + addr_hit[1] = (reg_addr == IFFIFO_FIFO_IN_OFFSET); + addr_hit[2] = (reg_addr == IFFIFO_STATUS_OFFSET); + addr_hit[3] = (reg_addr == IFFIFO_OCCUPANCY_OFFSET); + addr_hit[4] = (reg_addr == IFFIFO_WATERMARK_OFFSET); + addr_hit[5] = (reg_addr == IFFIFO_INTERRUPTS_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[0] & (|(IFFIFO_PERMIT[0] & ~reg_be))) | + (addr_hit[1] & (|(IFFIFO_PERMIT[1] & ~reg_be))) | + (addr_hit[2] & (|(IFFIFO_PERMIT[2] & ~reg_be))) | + (addr_hit[3] & (|(IFFIFO_PERMIT[3] & ~reg_be))) | + (addr_hit[4] & (|(IFFIFO_PERMIT[4] & ~reg_be))) | + (addr_hit[5] & (|(IFFIFO_PERMIT[5] & ~reg_be))))); + end + + assign fifo_out_re = addr_hit[0] & reg_re & !reg_error; + + assign fifo_in_we = addr_hit[1] & reg_we & !reg_error; + assign fifo_in_wd = reg_wdata[31:0]; + + assign watermark_we = addr_hit[4] & reg_we & !reg_error; + assign watermark_wd = reg_wdata[31:0]; + + assign interrupts_we = addr_hit[5] & reg_we & !reg_error; + assign interrupts_wd = reg_wdata[0]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[31:0] = fifo_out_qs; + end + + addr_hit[1]: begin + reg_rdata_next[31:0] = fifo_in_qs; + end + + addr_hit[2]: begin + reg_rdata_next[0] = status_empty_qs; + reg_rdata_next[1] = status_available_qs; + reg_rdata_next[2] = status_reached_qs; + reg_rdata_next[3] = status_full_qs; + end + + addr_hit[3]: begin + reg_rdata_next[31:0] = occupancy_qs; + end + + addr_hit[4]: begin + reg_rdata_next[31:0] = watermark_qs; + end + + addr_hit[5]: begin + reg_rdata_next[0] = interrupts_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module iffifo_reg_top_intf #( + parameter int AW = 5, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output iffifo_reg_pkg::iffifo_reg2hw_t reg2hw, // Write + input iffifo_reg_pkg::iffifo_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW / 8; + + `include "register_interface/typedef.svh" + `include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + iffifo_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.core b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.core new file mode 100644 index 00000000..2ef913ea --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.core @@ -0,0 +1,22 @@ +CAPI=2: + +name: "example:ip:simple_accelerator" +description: "core-v-mini-mcu iffifo peripheral" + +# Copyright 2024 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# +# Author: Davide Schiavone , EPFL, STI-SEL +# Date: 12.02.2024 + +filesets: + files_rtl: + files: + - simple_accelerator.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.sv new file mode 100644 index 00000000..846775af --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.sv @@ -0,0 +1,421 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +module simple_accelerator #( + parameter int unsigned FIFO_DEPTH = 4, + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter type obi_req_t = logic, + parameter type obi_resp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + output obi_req_t acc_read_ch0_req_o, + input obi_resp_t acc_read_ch0_resp_i, + + output obi_req_t acc_write_ch0_req_o, + input obi_resp_t acc_write_ch0_resp_i + +); + + + + logic status_ready_d, status_ready_q, status_start_q; + logic [31:0] address_read_q, address_write_q; + logic [31:0] threshold_q; + logic [ 9:0] size_q; + + localparam int unsigned LastFifoUsage = FIFO_DEPTH - 1; + localparam int unsigned Addr_Fifo_Depth = (FIFO_DEPTH > 1) ? $clog2(FIFO_DEPTH) : 1; + + + logic [ 31:0] read_ptr_reg; + logic [ 31:0] read_ptr_valid_reg; + logic [ 31:0] write_ptr_reg; + logic [ 31:0] write_address; + logic [ 9:0] dma_cnt; + logic dma_start; + logic dma_done; + + + logic [Addr_Fifo_Depth-1:0] fifo_usage; + logic fifo_alm_full; + + logic data_in_req; + logic data_in_we; + logic [ 3:0] data_in_be; + logic [ 31:0] data_in_addr; + logic data_in_gnt; + logic data_in_rvalid; + logic [ 31:0] data_in_rdata; + + logic data_out_req; + logic data_out_we; + logic [ 3:0] data_out_be; + logic [ 31:0] data_out_addr; + logic [ 31:0] data_out_wdata; + logic data_out_gnt; + + logic fifo_flush; + logic fifo_full; + logic fifo_empty; + + + logic [ 31:0] fifo_input; + logic [ 31:0] fifo_output; + + logic [ 3:0] byte_enable_out; + + logic dma_start_pending; + + enum { + DMA_READY, + DMA_STARTING, + DMA_RUNNING + } + dma_state_q, dma_state_d; + + logic [Addr_Fifo_Depth-1:0] outstanding_req; + + enum logic { + DMA_READ_FSM_IDLE, + DMA_READ_FSM_ON + } + dma_read_fsm_state, dma_read_fsm_n_state; + + enum logic { + DMA_WRITE_FSM_IDLE, + DMA_WRITE_FSM_ON + } + dma_write_fsm_state, dma_write_fsm_n_state; + + assign acc_read_ch0_req_o.req = data_in_req; + assign acc_read_ch0_req_o.we = data_in_we; + assign acc_read_ch0_req_o.be = data_in_be; + assign acc_read_ch0_req_o.addr = data_in_addr; + assign acc_read_ch0_req_o.wdata = 32'h0; + + assign data_in_gnt = acc_read_ch0_resp_i.gnt; + assign data_in_rvalid = acc_read_ch0_resp_i.rvalid; + assign data_in_rdata = acc_read_ch0_resp_i.rdata; + + assign acc_write_ch0_req_o.req = data_out_req; + assign acc_write_ch0_req_o.we = data_out_we; + assign acc_write_ch0_req_o.be = data_out_be; + assign acc_write_ch0_req_o.addr = data_out_addr; + + //complete the function + assign acc_write_ch0_req_o.wdata = data_out_wdata > threshold_q ? data_out_wdata : threshold_q; + //assign acc_write_ch0_req_o.wdata = data_out_wdata; + + assign data_out_gnt = acc_write_ch0_resp_i.gnt; + + assign status_ready_d = (dma_state_q == DMA_READY); + + assign write_address = write_ptr_reg; + + assign fifo_alm_full = (fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + + assign dma_start = (dma_state_q == DMA_STARTING); + + //decoder + + //0 READ ADDRESS + //4 WRITE ADDRESS + //8 THRESHOLD + //C READY + //10 SIZE + //14 START + always_comb begin + reg_rsp_o.rdata = '0; + reg_rsp_o.error = 1'b0; + reg_rsp_o.ready = 1'b1; + + if (reg_req_i.valid) begin + if (reg_req_i.addr[7:0] == 8'h14) begin + reg_rsp_o.rdata = {31'h0, status_start_q}; + end + if (reg_req_i.addr[7:0] == 8'h10) begin + reg_rsp_o.rdata = {22'h0, size_q}; + end + if (reg_req_i.addr[7:0] == 8'hC) begin + reg_rsp_o.rdata = {31'h0, status_ready_q}; + end + if (reg_req_i.addr[7:0] == 8'h8) begin + reg_rsp_o.rdata = threshold_q; + end + if (reg_req_i.addr[7:0] == 8'h4) begin + reg_rsp_o.rdata = address_write_q; + end + if (reg_req_i.addr[7:0] == 8'h0) begin + reg_rsp_o.rdata = address_read_q; + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + status_start_q <= '0; + size_q <= '0; + status_ready_q <= '0; + threshold_q <= '0; + address_write_q <= '0; + address_read_q <= '0; + end else begin + if (reg_req_i.valid && reg_req_i.write) begin + if (reg_req_i.addr[7:0] == 8'h14) begin + status_start_q <= reg_req_i.wdata[0]; + end + if (reg_req_i.addr[7:0] == 8'h10) begin + size_q <= reg_req_i.wdata[9:0]; + end + if (reg_req_i.addr[7:0] == 8'hC) begin + status_ready_q <= reg_req_i.wdata[0]; + end + if (reg_req_i.addr[7:0] == 8'h8) begin + threshold_q <= reg_req_i.wdata; + end + if (reg_req_i.addr[7:0] == 8'h4) begin + address_write_q <= reg_req_i.wdata; + end + if (reg_req_i.addr[7:0] == 8'h0) begin + address_read_q <= reg_req_i.wdata; + end + end else begin + if (dma_done) status_ready_q <= 1'b1; + status_start_q <= '0; + end + end + end + + + // + // Main DMA state machine + // + // READY : idle, waiting for a write pulse to size registered in `dma_start_pending` + // STARTING: load transaction data + // RUNNING : waiting for transaction finish + // when `dma_done` rises either enter ready or restart in circular mode + // + always_comb begin + dma_state_d = dma_state_q; + case (dma_state_q) + DMA_READY: begin + if (dma_start_pending) begin + dma_state_d = DMA_STARTING; + end + end + DMA_STARTING: begin + dma_state_d = DMA_RUNNING; + end + DMA_RUNNING: begin + if (dma_done) begin + dma_state_d = DMA_READY; + end + end + endcase + end + + // update state + always_ff @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + dma_state_q <= DMA_READY; + end else begin + dma_state_q <= dma_state_d; + end + end + + + // DMA pulse start when dma_start register is written + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_start + if (~rst_ni) begin + dma_start_pending <= 1'b0; + end else begin + if (dma_start == 1'b1) begin + dma_start_pending <= 1'b0; + end else if (status_start_q && size_q != '0) begin + dma_start_pending <= 1'b1; + end + end + end + + // Store input data pointer and increment everytime read request is granted + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_in_reg + if (~rst_ni) begin + read_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + read_ptr_reg <= address_read_q; + end else if (data_in_gnt == 1'b1) begin + read_ptr_reg <= read_ptr_reg + 32'h4; + end + end + end + + // Only update read_ptr_valid_reg when the data is stored in the fifo + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_valid_in_reg + if (~rst_ni) begin + read_ptr_valid_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + read_ptr_valid_reg <= address_read_q; + end else if (data_in_rvalid == 1'b1) begin + read_ptr_valid_reg <= read_ptr_valid_reg + 32'h4; + end + end + end + + // Store output data pointer and increment everytime write request is granted + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_out_reg + if (~rst_ni) begin + write_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + write_ptr_reg <= address_write_q; + end else if (data_out_gnt == 1'b1) begin + write_ptr_reg <= write_ptr_reg + 32'h4; + end + end + end + + // Store dma transfer size and decrement it everytime input data rvalid is asserted + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_cnt_reg + if (~rst_ni) begin + dma_cnt <= '0; + end else begin + if (dma_start == 1'b1) begin + dma_cnt <= size_q; + end else if (data_in_gnt == 1'b1) begin + dma_cnt <= dma_cnt - 10'h1; + end + end + end + + assign byte_enable_out = 4'b1111; + + assign data_out_wdata = fifo_output; + + assign fifo_input = data_in_rdata; + + // FSM state update + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_fsm_state + if (~rst_ni) begin + dma_read_fsm_state <= DMA_READ_FSM_IDLE; + dma_write_fsm_state <= DMA_WRITE_FSM_IDLE; + outstanding_req <= '0; + end else begin + dma_read_fsm_state <= dma_read_fsm_n_state; + dma_write_fsm_state <= dma_write_fsm_n_state; + outstanding_req <= outstanding_req + (data_in_req && data_in_gnt) - data_in_rvalid; + end + end + + // Read master FSM + always_comb begin : proc_dma_read_fsm_logic + + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + + data_in_req = '0; + data_in_we = '0; + data_in_be = '0; + data_in_addr = '0; + + fifo_flush = 1'b0; + + unique case (dma_read_fsm_state) + + DMA_READ_FSM_IDLE: begin + // Wait for start signal + if (dma_start == 1'b1) begin + dma_read_fsm_n_state = DMA_READ_FSM_ON; + fifo_flush = 1'b1; + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end + end + // Read one word + DMA_READ_FSM_ON: begin + // If all input data read exit + if (|dma_cnt == 1'b0) begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data) + if (fifo_full == 1'b0 && fifo_alm_full == 1'b0) begin + data_in_req = 1'b1; + data_in_we = 1'b0; + data_in_be = 4'b1111; // always read all bytes + data_in_addr = read_ptr_reg; + end + end + end + endcase + end + + // Write master FSM + always_comb begin : proc_dma_write_fsm_logic + + dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; + dma_done = 1'b0; + + data_out_req = '0; + data_out_we = '0; + data_out_be = '0; + data_out_addr = '0; + + unique case (dma_write_fsm_state) + + DMA_WRITE_FSM_IDLE: begin + // Wait for start signal + if (dma_start == 1'b1) begin + dma_write_fsm_n_state = DMA_WRITE_FSM_ON; + end else begin + dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; + end + end + // Read one word + DMA_WRITE_FSM_ON: begin + // If all input data read exit + if (fifo_empty == 1'b1 && dma_read_fsm_state == DMA_READ_FSM_IDLE) begin + dma_done = outstanding_req == '0; + dma_write_fsm_n_state = dma_done ? DMA_WRITE_FSM_IDLE : DMA_WRITE_FSM_ON; + end else begin + dma_write_fsm_n_state = DMA_WRITE_FSM_ON; + // Wait if fifo is empty + if (fifo_empty == 1'b0) begin + data_out_req = 1'b1; + data_out_we = 1'b1; + data_out_be = byte_enable_out; + data_out_addr = write_address; + end + end + end + endcase + end + + fifo_v3 #( + .DEPTH(FIFO_DEPTH) + ) dma_fifo_i ( + .clk_i, + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(fifo_full), + .empty_o(fifo_empty), + .usage_o(fifo_usage), + // as long as the queue is not full we can push new data + .data_i(fifo_input), + .push_i(data_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(fifo_output), + .pop_i(data_out_gnt) + ); + + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.vlt new file mode 100644 index 00000000..ac1ea03e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/simple_accelerator/simple_accelerator.vlt @@ -0,0 +1,10 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Author: Davide Schiavone , EPFL, STI-SEL +// Date: 12.02.2024 + +`verilator_config + +lint_off -rule UNUSED -file "*/simple_accelerator/simple_accelerator.sv" -match "*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/slow_memory/rtl/slow_memory.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/slow_memory/rtl/slow_memory.sv index 785ddd46..6cedd80a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/slow_memory/rtl/slow_memory.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/slow_memory/rtl/slow_memory.sv @@ -79,12 +79,21 @@ module slow_memory #( always_comb begin - gnt_o = 1'b0; - rvalid_o = rvalid_q; - state_n = state_q; - counter_n = counter_q - 1; - rvalid_n = rvalid_q; - + gnt_o = 1'b0; + rvalid_o = rvalid_q; + state_n = state_q; + counter_n = counter_q - 1; + rvalid_n = rvalid_q; + mem_req = '0; + mem_we = '0; + mem_addr = '0; + mem_wdata = '0; + mem_be = '0; + mem_req_n = mem_req_q; + mem_we_n = mem_we_q; + mem_addr_n = mem_addr_q; + mem_wdata_n = mem_wdata_q; + mem_be_n = mem_be_q; unique case (state_q) READY: begin @@ -92,13 +101,13 @@ module slow_memory #( if (req_i) begin gnt_o = random1[0]; if (gnt_o) begin - state_n = WAIT_RVALID; - counter_n = random2[4:0] + 1; - mem_req_n <= req_i; - mem_we_n <= we_i; - mem_addr_n <= addr_i; - mem_wdata_n <= wdata_i; - mem_be_n <= be_i; + state_n = WAIT_RVALID; + counter_n = random2[4:0] + 1; + mem_req_n = req_i; + mem_we_n = we_i; + mem_addr_n = addr_i; + mem_wdata_n = wdata_i; + mem_be_n = be_i; end end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl index 7d58ed79..c88bdaca 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl @@ -48,6 +48,9 @@ module x_heep_system output logic [31:0] exit_value_o, + input logic ext_dma_slot_tx_i, + input logic ext_dma_slot_rx_i, + // eXtension interface if_xif.cpu_compressed xif_compressed_if, if_xif.cpu_issue xif_issue_if, @@ -137,7 +140,9 @@ ${pad.core_v_mini_mcu_bonding} .external_subsystem_rst_no, .external_ram_banks_set_retentive_no, .external_subsystem_clkgate_en_no, - .exit_value_o + .exit_value_o, + .ext_dma_slot_tx_i, + .ext_dma_slot_rx_i ); pad_ring pad_ring_i ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.core index 56a485a4..a31337d1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.core @@ -60,3 +60,4 @@ targets: - files_rtl - ff_regfile - target_sim? (files_clk_gate) + - target_sim_sc? (files_clk_gate) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson index 39f77e7a..7248758f 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/cv32e40px.git - rev: acf3442b414725191fb7a2027facd0b5b4123c1c + rev: 49770e7dd5d569f440810866f4f33ce6a4f7ef1f } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson index b261db04..547959fe 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson @@ -7,11 +7,9 @@ upstream: { url: "https://github.com/esl-epfl/cv32e40px.git", - rev: "acf3442b414725191fb7a2027facd0b5b4123c1c", + rev: "49770e7dd5d569f440810866f4f33ce6a4f7ef1f", }, - patch_dir: "patches/esl_epfl_cv32e40px", - exclude_from_upstream: [ "ci", ".github", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh index 8c4ae99f..a89ed4e4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh @@ -679,22 +679,22 @@ class instr_trace_t; // decode and print instruction case (instr[11:8]) // cv.starti, cv.endi - 4'b0000, 4'b0010: str = $sformatf("%-16s %d, 0x%0x", mnemonic, rd[0], imm_iz_type); + 4'b0000, 4'b0010: str = $sformatf("%-16s %d, 0x%0x", mnemonic, instr[7], imm_iz_type); // cv.counti - 4'b0100: str = $sformatf("%-16s %d, %d", mnemonic, rd[0], imm_iz_type); + 4'b0100: str = $sformatf("%-16s %d, %d", mnemonic, instr[7], imm_iz_type); // cv.start, cv.end, cv.count 4'b0001, 4'b0011, 4'b0101: begin regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %d, %s", mnemonic, rd[0], regAddrToStr(rs1)); + str = $sformatf("%-16s %d, %s", mnemonic, instr[7], regAddrToStr(rs1)); end // cv.setupi 4'b0110: begin - str = $sformatf("%-16s %d, %d, 0x%0x", mnemonic, rd[0], imm_iz_type, rs1); + str = $sformatf("%-16s %d, %d, 0x%0x", mnemonic, instr[7], imm_iz_type, rs1); end // cv.setup 4'b0111: begin regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %d, %s, 0x%0x", mnemonic, rd[0], regAddrToStr(rs1), imm_iz_type); + str = $sformatf("%-16s %d, %s, 0x%0x", mnemonic, instr[7], regAddrToStr(rs1), imm_iz_type); end endcase end @@ -861,7 +861,7 @@ class instr_trace_t; endcase str_sci = ""; end - + // shuffle/pack 6'b110000: begin if (instr[14:12] == 3'b111) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv index 868de33c..4effb2b8 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv @@ -73,6 +73,10 @@ module cv32e40px_rvfi input logic is_compressed_id_i, input logic ebrk_insn_dec_i, + input logic ecall_insn_dec_i, + + input logic mret_insn_dec_i, + input logic mret_dec_i, input logic [5:0] csr_cause_i, @@ -126,6 +130,9 @@ module cv32e40px_rvfi input logic [31:0] data_wdata_ex_i, input logic lsu_split_q_ex_i, + input logic mult_ready_i, + input logic alu_ready_i, + //// WB probes //// input logic [31:0] pc_wb_i, input logic wb_ready_i, @@ -202,6 +209,7 @@ module cv32e40px_rvfi input logic csr_we_i, input logic [31:0] csr_wdata_int_i, + input logic csr_fregs_we_i, input logic csr_jvt_we_i, input Status_t csr_mstatus_n_i, input Status_t csr_mstatus_q_i, @@ -617,6 +625,8 @@ module cv32e40px_rvfi logic pc_mux_interrupt; logic pc_mux_nmi; + localparam logic [31:0] MSTATUS_WRITE_MASK = 32'h0000_6088; + `include "pipe_freeze_trace.sv" `include "insn_trace.sv" @@ -633,6 +643,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; logic [2:0] saved_debug_cause; integer next_send; + event e_empty_queue; function void empty_fifo(); integer i, trace_q_size; trace_q_size = wb_bypass_trace_q.size(); @@ -648,6 +659,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; new_rvfi_trace.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; rvfi_trace_q.push_back(new_rvfi_trace); next_send = next_send + 1; + ->e_empty_queue; end else begin wb_bypass_trace_q.push_back(new_rvfi_trace); end @@ -658,6 +670,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; /* * Function used to alocate a new insn and send it to the rvfi driver */ + event e_add_to_bypass; function void send_rvfi(insn_trace_t m_wb_insn); insn_trace_t new_rvfi_trace; new_rvfi_trace = new(); @@ -667,6 +680,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; next_send = next_send + 1; end else begin wb_bypass_trace_q.push_back(new_rvfi_trace); + ->e_add_to_bypass; end empty_fifo(); endfunction @@ -837,7 +851,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; //CSR rvfi_csr_mstatus_rmask = new_rvfi_trace.m_csr.mstatus_rmask | new_rvfi_trace.m_csr.mstatus_fs_rmask; - rvfi_csr_mstatus_wmask = new_rvfi_trace.m_csr.mstatus_wmask; + rvfi_csr_mstatus_wmask = new_rvfi_trace.m_csr.mstatus_wmask & MSTATUS_WRITE_MASK; rvfi_csr_mstatus_wmask[31] = new_rvfi_trace.m_csr.mstatus_fs_wmask[31]; rvfi_csr_mstatus_wmask[14:13] = new_rvfi_trace.m_csr.mstatus_fs_wmask[14:13]; @@ -870,7 +884,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end rvfi_csr_mstatus_wdata[30:18] = '0; // MPRV is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[17] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.mprv; + rvfi_csr_mstatus_wdata[17] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.mprv; rvfi_csr_mstatus_wdata[16:15] = '0; if (FPU == 1 && ZFINX == 0) begin rvfi_csr_mstatus_wdata[14:13] = new_rvfi_trace.m_csr.mstatus_fs_wdata; @@ -882,11 +896,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; rvfi_csr_mstatus_wdata[7] = new_rvfi_trace.m_csr.mstatus_wdata.mpie; rvfi_csr_mstatus_wdata[6:5] = '0; // UPIE is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[4] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.upie; + rvfi_csr_mstatus_wdata[4] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.upie; rvfi_csr_mstatus_wdata[3] = new_rvfi_trace.m_csr.mstatus_wdata.mie; rvfi_csr_mstatus_wdata[2:1] = '0; // UIE is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[0] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.uie; + rvfi_csr_mstatus_wdata[0] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.uie; `SET_RVFI_CSR_FROM_INSN(misa) `SET_RVFI_CSR_FROM_INSN(mie) @@ -1111,6 +1125,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; * The third updates the rvfi interface */ `define CSR_FROM_PIPE(TRACE_NAME, CSR_NAME) \ + if(!trace_``TRACE_NAME``.m_csr.``CSR_NAME``_we) begin \ + trace_``TRACE_NAME``.m_csr.``CSR_NAME``_wdata = r_pipe_freeze_trace.csr.``CSR_NAME``_n; \ + end\ if (r_pipe_freeze_trace.csr.``CSR_NAME``_we) begin \ trace_``TRACE_NAME``.m_csr.``CSR_NAME``_we = r_pipe_freeze_trace.csr.``CSR_NAME``_we; \ trace_``TRACE_NAME``.m_csr.``CSR_NAME``_wdata = r_pipe_freeze_trace.csr.``CSR_NAME``_n; \ @@ -1120,9 +1137,14 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_``TRACE_NAME``.m_csr.``CSR_NAME``_rmask = '1; event e_mstatus_to_id; + event e_fregs_dirty_1, e_fregs_dirty_2, e_fregs_dirty_3; function void mstatus_to_id(); `CSR_FROM_PIPE(id, mstatus) `CSR_FROM_PIPE(id, mstatus_fs) + if(r_pipe_freeze_trace.csr.fregs_we && !r_pipe_freeze_trace.csr.mstatus_fs_we && !(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we)) begin //writes happening in ex that needs to be reported to id + trace_id.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + ->e_fregs_dirty_2; + end ->e_mstatus_to_id; endfunction //those event are for debug purpose @@ -1133,10 +1155,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; e_dev_commit_rf_to_ex_3, e_dev_commit_rf_to_ex_4, e_dev_commit_rf_to_ex_5; - event e_if_2_id_1, e_if_2_id_2; + event e_if_2_id_1, e_if_2_id_2, e_if_2_id_3; event e_ex_to_wb_1, e_ex_to_wb_2; event e_id_to_ex_1, e_id_to_ex_2; event e_commit_dpc; + event e_csr_in_ex, e_csr_irq; event e_send_rvfi_trace_apu_resp; event @@ -1160,12 +1183,17 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(apu_resp, fcsr) `CSR_FROM_PIPE(apu_resp, fflags) - // `CSR_FROM_PIPE(apu_resp, mstatus) `CSR_FROM_PIPE(apu_resp, mstatus_fs) - if (r_pipe_freeze_trace.csr.mstatus_we) begin + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_id.m_order > trace_apu_resp.m_order)) begin + trace_id.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + end + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_ex.m_order > trace_apu_resp.m_order)) begin trace_ex.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; end + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_wb.m_order > trace_apu_resp.m_order)) begin + trace_wb.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + end endfunction function void csr_to_apu_req(); @@ -1243,6 +1271,15 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_is_irq_start; bit s_id_done; function void if_to_id(); + if (trace_id.m_valid) begin + minstret_to_id(); + `CSR_FROM_PIPE(id, misa) + `CSR_FROM_PIPE(id, tdata1) + `CSR_FROM_PIPE(id, tdata2) + tinfo_to_id(); + `CSR_FROM_PIPE(id, mip) + send_rvfi(trace_id); + end trace_id.init(trace_if); trace_id.m_trap = ~r_pipe_freeze_trace.minstret; trace_id.m_is_illegal = r_pipe_freeze_trace.is_illegal; @@ -1280,34 +1317,40 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_core_is_decoding; // For readability, ctrl_fsm is DECODE or DECODE_HWLOOP - trace_if = new(); - trace_id = new(); - trace_ex = new(); - trace_wb = new(); - s_new_valid_insn = 1'b0; - s_ex_valid_adjusted = 1'b0; + bit s_ex_reg_we_adjusted; //ex_reg_we + bit s_rf_we_wb_adjusted; // + + trace_if = new(); + trace_id = new(); + trace_ex = new(); + trace_wb = new(); + s_new_valid_insn = 1'b0; + s_ex_valid_adjusted = 1'b0; - s_id_done = 1'b0; - s_apu_wb_ok = 1'b0; - s_apu_0_cycle_reps = 1'b0; + s_id_done = 1'b0; + s_apu_wb_ok = 1'b0; + s_apu_0_cycle_reps = 1'b0; - next_send = 1; - cnt_data_req = 0; - cnt_data_resp = 0; - cnt_apu_req = 0; - cnt_apu_resp = 0; - csr_is_irq = '0; - is_dbg_taken = '0; - s_was_flush = 1'b0; + next_send = 1; + cnt_data_req = 0; + cnt_data_resp = 0; + cnt_apu_req = 0; + cnt_apu_resp = 0; + csr_is_irq = '0; + is_dbg_taken = '0; + s_was_flush = 1'b0; - s_is_pc_set = 1'b0; - s_is_irq_start = 1'b0; + s_is_pc_set = 1'b0; + s_is_irq_start = 1'b0; - s_is_pc_set = 1'b0; - s_is_irq_start = 1'b0; - s_skip_wb = 1'b0; + s_is_pc_set = 1'b0; + s_is_irq_start = 1'b0; + s_skip_wb = 1'b0; - s_core_is_decoding = 1'b0; + s_core_is_decoding = 1'b0; + + s_ex_reg_we_adjusted = 1'b0; + s_rf_we_wb_adjusted = 1'b0; forever begin wait(e_pipe_monitor_ok.triggered); // event triggered @@ -1387,7 +1430,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; s_new_valid_insn = r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.is_decoding;// && !r_pipe_freeze_trace.apu_rvalid; - s_wb_valid_adjusted = r_pipe_freeze_trace.wb_valid && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX));// && !r_pipe_freeze_trace.apu_rvalid;; + s_wb_valid_adjusted = r_pipe_freeze_trace.wb_valid && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_WB) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF));// && !r_pipe_freeze_trace.apu_rvalid;; + s_ex_reg_we_adjusted = r_pipe_freeze_trace.ex_reg_we && r_pipe_freeze_trace.mult_ready && r_pipe_freeze_trace.alu_ready && r_pipe_freeze_trace.lsu_ready_ex && !s_apu_to_alu_port; + s_rf_we_wb_adjusted = r_pipe_freeze_trace.rf_we_wb && (~r_pipe_freeze_trace.data_misaligned_ex && r_pipe_freeze_trace.wb_ready) && (!s_apu_to_lsu_port || r_pipe_freeze_trace.wb_contention_lsu); s_fflags_we_non_apu = 1'b0; if (r_pipe_freeze_trace.csr.fflags_we) begin @@ -1418,40 +1463,34 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; s_skip_wb = 1'b1; end end - if (trace_wb.m_valid && !s_skip_wb) begin - if (r_pipe_freeze_trace.rf_we_wb) begin - if((trace_wb.m_rd_addr[0] == r_pipe_freeze_trace.rf_addr_wb) && (cnt_data_resp == trace_wb.m_mem_req_id[0]) && trace_wb.m_mem_req_id_valid[0]) begin - trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_wb.m_mem_req_id_valid[0] = 1'b0; - end else if (trace_wb.m_2_rd_insn && (trace_wb.m_rd_addr[1] == r_pipe_freeze_trace.rf_addr_wb) && (cnt_data_resp == trace_wb.m_mem_req_id[1]) && trace_wb.m_mem_req_id_valid[1]) begin - trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_wb.m_mem_req_id_valid[1] = 1'b0; - end - end - if (!trace_wb.m_data_missaligned) begin - send_rvfi(trace_wb); - ->e_dev_send_wb_1; ->e_send_rvfi_trace_wb_2; - trace_wb.m_valid = 1'b0; + if (trace_wb.m_valid && !s_skip_wb && s_rf_we_wb_adjusted) begin + if (trace_wb.m_2_rd_insn) begin + trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + end else if (trace_wb.m_ex_fw) begin + trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + trace_wb.m_2_rd_insn = 1'b1; end else begin - if (s_wb_valid_adjusted) begin - if (r_pipe_freeze_trace.rf_we_wb) begin - if (!trace_wb.m_ex_fw) begin - trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - end - if (trace_wb.m_data_missaligned && !trace_wb.m_got_first_data) begin - trace_wb.m_got_first_data = 1'b1; - end else begin - send_rvfi(trace_wb); - ->e_dev_send_wb_2; ->e_send_rvfi_trace_wb_3; - trace_wb.m_valid = 1'b0; - end - end // rf_we_wb + trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; + end + + if (r_pipe_freeze_trace.csr.fregs_we) begin + `CSR_FROM_PIPE(wb, mstatus_fs) + trace_wb.m_csr.mstatus_fs_we = 1'b1; + trace_wb.m_csr.mstatus_fs_wmask = '1; + if(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we) begin //In this specific case, two writes to mstatus_fs happen at the same time. We need to recreate the writes caused by fregs_we + trace_wb.m_csr.mstatus_fs_wdata = FS_DIRTY; end + ->e_fregs_dirty_1; end + + send_rvfi(trace_wb); + ->e_dev_send_wb_1; ->e_send_rvfi_trace_wb_2; + trace_wb.m_valid = 1'b0; + end if (trace_ex.m_valid) begin @@ -1464,14 +1503,14 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(ex, tdata2) tinfo_to_ex(); - if (r_pipe_freeze_trace.regfile_we_lsu) begin + if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_4; - if ((cnt_data_resp == trace_ex.m_mem_req_id[0]) && !(trace_ex.m_got_ex_reg) && trace_ex.m_mem_req_id_valid[0]) begin + if (!(trace_ex.m_got_ex_reg) && trace_ex.m_mem_req_id_valid[0]) begin trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; trace_ex.m_mem_req_id_valid[0] = 1'b0; - end else if ((cnt_data_resp == trace_ex.m_mem_req_id[1]) && trace_ex.m_mem_req_id_valid[1]) begin + end else if (trace_ex.m_mem_req_id_valid[1]) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; @@ -1485,7 +1524,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_valid = 1'b0; ->e_send_rvfi_trace_ex_2; end else begin - if (r_pipe_freeze_trace.rf_we_wb && !s_apu_to_lsu_port) begin + if (!s_ex_valid_adjusted & !trace_ex.m_csr.got_minstret) begin + minstret_to_ex(); + end + + if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_1; if (trace_ex.m_got_ex_reg) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; @@ -1497,24 +1540,35 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; end - end - if (!s_ex_valid_adjusted & !trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end - if (trace_ex.m_is_load) begin // only move relevant instr in wb stage - ->e_ex_to_wb_1; - trace_wb.move_down_pipe(trace_ex); - end else begin - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); + if (r_pipe_freeze_trace.csr.fregs_we) begin + `CSR_FROM_PIPE(ex, mstatus_fs) + trace_ex.m_csr.mstatus_fs_we = 1'b1; + trace_ex.m_csr.mstatus_fs_wmask = '1; + if(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we) begin //In this specific case, two writes to mstatus_fs happen at the same time. We need to recreate the writes caused by fregs_we + trace_ex.m_csr.mstatus_fs_wdata = FS_DIRTY; + end + ->e_fregs_dirty_3; end + send_rvfi(trace_ex); - ->e_send_rvfi_trace_ex_6; + trace_ex.m_valid = 1'b0; + + end else begin + if (trace_ex.m_is_load) begin // only move relevant instr in wb stage + ->e_ex_to_wb_1; + trace_wb.move_down_pipe(trace_ex); + end else begin + if (!trace_ex.m_csr.got_minstret) begin + minstret_to_ex(); + end + send_rvfi(trace_ex); + ->e_send_rvfi_trace_ex_6; + end + trace_ex.m_valid = 1'b0; end - trace_ex.m_valid = 1'b0; end - end else if (r_pipe_freeze_trace.rf_we_wb && !s_apu_to_lsu_port && !s_was_flush) begin + end else if (s_rf_we_wb_adjusted && !s_was_flush) begin ->e_dev_commit_rf_to_ex_2; if (trace_ex.m_got_ex_reg) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; @@ -1529,22 +1583,29 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end - s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF)) && (!r_pipe_freeze_trace.apu_rvalid || r_pipe_freeze_trace.data_req_ex); + // If mret, we need to keep the instruction in Id during flush_ex because mstatus update happens at that time + s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || ((r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) && !r_pipe_freeze_trace.mret_insn_dec)) && (!r_pipe_freeze_trace.apu_rvalid || r_pipe_freeze_trace.data_req_ex); //EX_STAGE if (trace_id.m_valid) begin + + if(trace_id.m_sample_csr_write_in_ex && !csr_is_irq && !s_is_irq_start) begin //First cycle after id_ready, csr write is asserted in this cycle + `CSR_FROM_PIPE(id, mstatus) + `CSR_FROM_PIPE(id, mstatus_fs) + `CSR_FROM_PIPE(id, mepc) + `CSR_FROM_PIPE(id, mcause) + `CSR_FROM_PIPE(id, dscratch0) + `CSR_FROM_PIPE(id, dscratch1) + ->e_csr_in_ex; + end + + if(r_pipe_freeze_trace.is_decoding) begin + trace_id.m_sample_csr_write_in_ex = 1'b0; + end mtvec_to_id(); `CSR_FROM_PIPE(id, mip) `CSR_FROM_PIPE(id, misa) - if (!csr_is_irq && !s_is_irq_start) begin - mstatus_to_id(); - `CSR_FROM_PIPE(id, mepc) - if (trace_id.m_csr.mcause_we == '0) begin //for debug purpose - `CSR_FROM_PIPE(id, mcause) - end - end - `CSR_FROM_PIPE(id, mcountinhibit) `CSR_FROM_PIPE(id, mscratch) `CSR_FROM_PIPE(id, mie) @@ -1603,10 +1664,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_rd_addr[0] = r_pipe_freeze_trace.ex_reg_addr; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.ex_reg_wdata; trace_id.m_got_ex_reg = 1'b1; - end else if (!trace_ex.m_valid & r_pipe_freeze_trace.rf_we_wb & !trace_id.m_ex_fw) begin + end else if (!trace_ex.m_valid & s_rf_we_wb_adjusted & !trace_id.m_ex_fw) begin trace_id.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - end else if (r_pipe_freeze_trace.rf_we_wb) begin + end else if (s_rf_we_wb_adjusted) begin trace_id.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; trace_id.m_2_rd_insn = 1'b1; @@ -1621,19 +1682,16 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem.addr = r_pipe_freeze_trace.data_addr_pmp; if (r_pipe_freeze_trace.data_misaligned) begin cnt_data_req = cnt_data_req + 1; + trace_id.m_mem_req_id[0] = cnt_data_req; end + if (!r_pipe_freeze_trace.data_we_ex) begin trace_id.m_is_load = 1'b1; trace_id.m_mem.wmask = be_to_mask(r_pipe_freeze_trace.lsu_data_be); //'1; - if (r_pipe_freeze_trace.data_misaligned) begin - trace_id.m_data_missaligned = 1'b1; - trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; - trace_id.m_mem_req_id[0] = cnt_data_req; - trace_id.m_mem_req_id_valid[1] = 1'b1; - end end else begin trace_id.m_mem.rmask = be_to_mask(r_pipe_freeze_trace.lsu_data_be); //'1; end + if (trace_id.m_got_ex_reg) begin // Shift index 0 to 1 trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; trace_id.m_mem_req_id[0] = 0; @@ -1692,15 +1750,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem.addr = r_pipe_freeze_trace.data_addr_pmp; if (r_pipe_freeze_trace.data_misaligned) begin cnt_data_req = cnt_data_req + 1; + trace_id.m_mem_req_id[0] = cnt_data_req; end if (!r_pipe_freeze_trace.data_we_ex) begin trace_id.m_is_load = 1'b1; - if (r_pipe_freeze_trace.data_misaligned) begin - trace_id.m_data_missaligned = 1'b1; - trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; - trace_id.m_mem_req_id[0] = cnt_data_req; - trace_id.m_mem_req_id_valid[1] = 1'b1; - end end if (trace_id.m_got_ex_reg) begin // Shift index 0 to 1 trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; @@ -1708,7 +1761,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem_req_id_valid[0] = 1'b0; trace_id.m_mem_req_id_valid[1] = 1'b1; end - end else if (r_pipe_freeze_trace.rf_we_wb && !r_pipe_freeze_trace.ex_reg_we) begin + end else if (s_rf_we_wb_adjusted && !r_pipe_freeze_trace.ex_reg_we) begin trace_id.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; end @@ -1734,12 +1787,21 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; //IF_STAGE if (r_pipe_freeze_trace.if_valid && r_pipe_freeze_trace.if_ready) begin - if(trace_if.m_valid && r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.id_ready && !trace_id.m_valid && r_pipe_freeze_trace.ebrk_insn_dec) begin - if_to_id(); - trace_id.m_is_ebreak = '1; //trace_if.m_is_ebreak; - ->e_if_2_id_2; + if (trace_if.m_valid) begin + if (r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.id_ready && !trace_id.m_valid && r_pipe_freeze_trace.ebrk_insn_dec) begin + if_to_id(); + trace_id.m_is_ebreak = '1; //trace_if.m_is_ebreak; + ->e_if_2_id_2; + end else if (r_pipe_freeze_trace.is_illegal) begin + if_to_id(); + trace_id.m_is_illegal = 1'b1; + ->e_if_2_id_3; + end else if (r_pipe_freeze_trace.ecall_insn_dec) begin + if_to_id(); + end end + trace_if.m_insn = r_pipe_freeze_trace.instr_if; //Instr comes from if, buffer for one cycle trace_if.m_pc_rdata = r_pipe_freeze_trace.pc_if; trace_if.m_dbg_taken = is_dbg_taken; @@ -1754,6 +1816,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; mstatus_to_id(); `CSR_FROM_PIPE(id, mepc) `CSR_FROM_PIPE(id, mcause) + ->e_csr_irq; end if (!s_id_done && r_pipe_freeze_trace.is_decoding) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv index 1b40b80e..d4aa94dc 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv @@ -272,13 +272,19 @@ module cv32e40px_tb_wrapper .rs1_addr_id_i (cv32e40px_top_i.core_i.id_stage_i.regfile_addr_ra_id), .rs2_addr_id_i (cv32e40px_top_i.core_i.id_stage_i.regfile_addr_rb_id), + .rs3_addr_id_i (cv32e40px_top_i.core_i.id_stage_i.regfile_addr_rc_id), .operand_a_fw_id_i (cv32e40px_top_i.core_i.id_stage_i.operand_a_fw_id), .operand_b_fw_id_i (cv32e40px_top_i.core_i.id_stage_i.operand_b_fw_id), + .operand_c_fw_id_i (cv32e40px_top_i.core_i.id_stage_i.operand_c_fw_id), // .instr (cv32e40px_top_i.core_i.id_stage_i.instr ), .is_compressed_id_i(cv32e40px_top_i.core_i.id_stage_i.is_compressed_i), .ebrk_insn_dec_i (cv32e40px_top_i.core_i.id_stage_i.ebrk_insn_dec), - .csr_cause_i (cv32e40px_top_i.core_i.csr_cause), - .debug_csr_save_i (cv32e40px_top_i.core_i.debug_csr_save), + .ecall_insn_dec_i (cv32e40px_top_i.core_i.id_stage_i.ecall_insn_dec), + .mret_insn_dec_i (cv32e40px_top_i.core_i.id_stage_i.mret_insn_dec), + .mret_dec_i (cv32e40px_top_i.core_i.id_stage_i.mret_dec), + + .csr_cause_i (cv32e40px_top_i.core_i.csr_cause), + .debug_csr_save_i(cv32e40px_top_i.core_i.debug_csr_save), // HWLOOP regs .hwlp_start_q_i (hwlp_start_q), @@ -298,14 +304,16 @@ module cv32e40px_tb_wrapper .apu_multicycle_i (cv32e40px_top_i.core_i.ex_stage_i.apu_multicycle), .wb_contention_lsu_i(cv32e40px_top_i.core_i.ex_stage_i.wb_contention_lsu), .wb_contention_i (cv32e40px_top_i.core_i.ex_stage_i.wb_contention), - + .regfile_we_lsu_i (cv32e40px_top_i.core_i.ex_stage_i.regfile_we_lsu), // .rf_we_alu_i (cv32e40px_top_i.core_i.id_stage_i.regfile_alu_we_fw_i), // .rf_addr_alu_i (cv32e40px_top_i.core_i.id_stage_i.regfile_alu_waddr_fw_i), // .rf_wdata_alu_i (cv32e40px_top_i.core_i.id_stage_i.regfile_alu_wdata_fw_i), + .mult_ready_i (cv32e40px_top_i.core_i.ex_stage_i.mult_ready), + .alu_ready_i (cv32e40px_top_i.core_i.ex_stage_i.alu_ready), //// WB probes //// - .wb_valid_i(cv32e40px_top_i.core_i.wb_valid), - + .wb_valid_i (cv32e40px_top_i.core_i.wb_valid), + .wb_ready_i (cv32e40px_top_i.core_i.lsu_ready_wb), //// LSU probes //// .data_we_ex_i (cv32e40px_top_i.core_i.data_we_ex), .data_atop_ex_i (cv32e40px_top_i.core_i.data_atop_ex), @@ -325,6 +333,8 @@ module cv32e40px_tb_wrapper .lsu_ready_ex_i (cv32e40px_top_i.core_i.lsu_ready_ex), .lsu_ready_wb_i (cv32e40px_top_i.core_i.lsu_ready_wb), + .lsu_data_be_i(cv32e40px_top_i.core_i.load_store_unit_i.data_be), + .data_req_pmp_i(cv32e40px_top_i.core_i.data_req_pmp), .data_gnt_pmp_i(cv32e40px_top_i.core_i.data_gnt_pmp), .data_rvalid_i(cv32e40px_top_i.core_i.data_rvalid_i), @@ -339,11 +349,12 @@ module cv32e40px_tb_wrapper .rf_we_wb_i(cv32e40px_top_i.core_i.id_stage_i.regfile_we_wb_i), .rf_addr_wb_i(cv32e40px_top_i.core_i.id_stage_i.regfile_waddr_wb_i), .rf_wdata_wb_i(cv32e40px_top_i.core_i.id_stage_i.regfile_wdata_wb_i), + .regfile_alu_we_ex_i(cv32e40px_top_i.core_i.id_stage_i.regfile_alu_we_ex_o), // APU .apu_req_i (cv32e40px_top_i.core_i.apu_req_o), .apu_gnt_i (cv32e40px_top_i.core_i.apu_gnt_i), - .apu_rvalid_i(cv32e40px_top_i.core_i.apu_rvalid_i), + .apu_rvalid_i(cv32e40px_top_i.core_i.ex_stage_i.apu_valid), // Controller FSM probes .ctrl_fsm_cs_i(cv32e40px_top_i.core_i.id_stage_i.controller_i.ctrl_fsm_cs), @@ -355,6 +366,8 @@ module cv32e40px_tb_wrapper .csr_we_i (cv32e40px_top_i.core_i.cs_registers_i.csr_we_int), .csr_wdata_int_i(cv32e40px_top_i.core_i.cs_registers_i.csr_wdata_int), + .csr_fregs_we_i(cv32e40px_top_i.core_i.cs_registers_i.fregs_we_i), + .csr_mstatus_n_i (cv32e40px_top_i.core_i.cs_registers_i.mstatus_n), .csr_mstatus_q_i (cv32e40px_top_i.core_i.cs_registers_i.mstatus_q), .csr_mstatus_fs_n_i(cv32e40px_top_i.core_i.cs_registers_i.mstatus_fs_n), @@ -367,6 +380,10 @@ module cv32e40px_tb_wrapper .csr_tdata1_q_i (cv32e40px_top_i.core_i.cs_registers_i.tmatch_control_rdata),//gen_trigger_regs.tmatch_control_exec_q ), .csr_tdata1_we_i(cv32e40px_top_i.core_i.cs_registers_i.gen_trigger_regs.tmatch_control_we), + .csr_tdata2_n_i (cv32e40px_top_i.core_i.cs_registers_i.tmatch_value_rdata),//csr_wdata_int ), + .csr_tdata2_q_i (cv32e40px_top_i.core_i.cs_registers_i.tmatch_value_rdata),//gen_trigger_regs.tmatch_control_exec_q ), + .csr_tdata2_we_i(cv32e40px_top_i.core_i.cs_registers_i.gen_trigger_regs.tmatch_value_we), + .csr_tinfo_n_i({16'h0, cv32e40px_top_i.core_i.cs_registers_i.tinfo_types}), .csr_tinfo_q_i({16'h0, cv32e40px_top_i.core_i.cs_registers_i.tinfo_types}), @@ -424,6 +441,7 @@ module cv32e40px_tb_wrapper ); `endif + `ifdef CV32E40P_RVFI_TRACE_EXECUTION bind cv32e40px_rvfi: rvfi_i cv32e40px_rvfi_trace #( .FPU (FPU), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv index 40edce03..90ee5be9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv @@ -196,8 +196,8 @@ package cv32e40px_tracer_pkg; parameter INSTR_CVEND0 = {12'b000000000000, 5'b?, 3'b100, 4'b0011, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNTI0 = {12'b?, 5'b00000, 3'b100, 4'b0100, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNT0 = {12'b000000000000, 5'b?, 3'b100, 4'b0101, 1'b0, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUPI0 = {12'b?, 5'b00000, 3'b100, 4'b0110, 1'b0, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUP0 = {12'b?, 5'b00000, 3'b100, 4'b0111, 1'b0, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUPI0 = {17'b?, 3'b100, 4'b0110, 1'b0, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUP0 = {12'b?, 5'b?, 3'b100, 4'b0111, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVSTARTI1 = {12'b?, 5'b00000, 3'b100, 4'b0000, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVSTART1 = {12'b000000000000, 5'b?, 3'b100, 4'b0001, 1'b1, OPCODE_CUSTOM_1}; @@ -205,8 +205,8 @@ package cv32e40px_tracer_pkg; parameter INSTR_CVEND1 = {12'b000000000000, 5'b?, 3'b100, 4'b0011, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNTI1 = {12'b?, 5'b00000, 3'b100, 4'b0100, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNT1 = {12'b000000000000, 5'b?, 3'b100, 4'b0101, 1'b1, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUPI1 = {12'b?, 5'b00000, 3'b100, 4'b0110, 1'b1, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUP1 = {12'b?, 5'b00000, 3'b100, 4'b0111, 1'b1, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUPI1 = {17'b?, 3'b100, 4'b0110, 1'b1, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUP1 = {12'b?, 5'b?, 3'b100, 4'b0111, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_FF1 = {7'b0100001, 5'b0, 5'b?, 3'b011, 5'b?, OPCODE_CUSTOM_1}; @@ -449,8 +449,8 @@ package cv32e40px_tracer_pkg; parameter INSTR_CVSHUFFLE2H = {5'b11100, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVSHUFFLE2B = {5'b11100, 1'b0, 1'b0, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; - parameter INSTR_CVPACK = {5'b11101, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; - parameter INSTR_CVPACKH = {5'b11101, 1'b0, 1'b1, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; + parameter INSTR_CVPACK = {5'b11110, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; + parameter INSTR_CVPACKH = {5'b11110, 1'b0, 1'b1, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVPACKHIB = {5'b11111, 1'b0, 1'b1, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVPACKLOB = {5'b11111, 1'b0, 1'b0, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv index 3db2a7ee..3fe7c184 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv @@ -66,6 +66,8 @@ int m_instret_cnt; + bit m_sample_csr_write_in_ex; + struct { logic [31:0] addr ; logic [ 3:0] rmask; @@ -145,32 +147,33 @@ function new(); - this.m_order = 0; - this.m_skip_order = 1'b0; - this.m_valid = 1'b0; - this.m_move_down_pipe = 1'b0; - this.m_data_missaligned = 1'b0; - this.m_got_first_data = 1'b0; - this.m_got_ex_reg = 1'b0; - this.m_intr = '0; - this.m_dbg_taken = 1'b0; - this.m_dbg_cause = '0; - this.m_is_ebreak = '0; - this.m_is_illegal = '0; - this.m_is_irq = '0; - this.m_is_memory = 1'b0; - this.m_is_load = 1'b0; - this.m_is_apu = 1'b0; - this.m_is_apu_ok = 1'b0; - this.m_apu_req_id = 0; - this.m_mem_req_id[0] = 0; - this.m_mem_req_id[1] = 0; - this.m_mem_req_id_valid = '0; - this.m_trap = 1'b0; - this.m_fflags_we_non_apu = 1'b0; - this.m_frm_we_non_apu = 1'b0; - this.m_fcsr_we_non_apu = 1'b0; - this.m_instret_cnt = 0; + this.m_order = 0; + this.m_skip_order = 1'b0; + this.m_valid = 1'b0; + this.m_move_down_pipe = 1'b0; + this.m_data_missaligned = 1'b0; + this.m_got_first_data = 1'b0; + this.m_got_ex_reg = 1'b0; + this.m_intr = '0; + this.m_dbg_taken = 1'b0; + this.m_dbg_cause = '0; + this.m_is_ebreak = '0; + this.m_is_illegal = '0; + this.m_is_irq = '0; + this.m_is_memory = 1'b0; + this.m_is_load = 1'b0; + this.m_is_apu = 1'b0; + this.m_is_apu_ok = 1'b0; + this.m_apu_req_id = 0; + this.m_mem_req_id[0] = 0; + this.m_mem_req_id[1] = 0; + this.m_mem_req_id_valid = '0; + this.m_trap = 1'b0; + this.m_fflags_we_non_apu = 1'b0; + this.m_frm_we_non_apu = 1'b0; + this.m_fcsr_we_non_apu = 1'b0; + this.m_instret_cnt = 0; + this.m_sample_csr_write_in_ex = 1'b1; endfunction function void get_mnemonic(); @@ -875,37 +878,38 @@ if(this.m_skip_order) begin this.m_order = this.m_order + 64'h1; end - this.m_skip_order = 1'b0; - this.m_pc_rdata = r_pipe_freeze_trace.pc_id; - this.m_is_illegal = 1'b0; - this.m_is_irq = 1'b0; - this.m_is_memory = 1'b0; - this.m_is_load = 1'b0; - this.m_is_apu = 1'b0; - this.m_is_apu_ok = 1'b0; - this.m_apu_req_id = 0; - this.m_mem_req_id[0] = 0; - this.m_mem_req_id[1] = 0; - this.m_mem_req_id_valid = '0; - this.m_data_missaligned = 1'b0; - this.m_got_first_data = 1'b0; - this.m_got_ex_reg = 1'b0; - this.m_got_regs_write = 1'b0; - this.m_move_down_pipe = 1'b0; - this.m_instret_cnt = 0; - this.m_rd_addr[0] = '0; - this.m_rd_addr[1] = '0; - this.m_2_rd_insn = 1'b0; - this.m_rs1_addr = '0; - this.m_rs2_addr = '0; - this.m_rs3_addr = '0; - this.m_ex_fw = '0; - this.m_csr.got_minstret = '0; - this.m_dbg_taken = '0; - this.m_trap = 1'b0; - this.m_fflags_we_non_apu = 1'b0; - this.m_frm_we_non_apu = 1'b0; - this.m_fcsr_we_non_apu = 1'b0; + this.m_skip_order = 1'b0; + this.m_pc_rdata = r_pipe_freeze_trace.pc_id; + this.m_is_illegal = 1'b0; + this.m_is_irq = 1'b0; + this.m_is_memory = 1'b0; + this.m_is_load = 1'b0; + this.m_is_apu = 1'b0; + this.m_is_apu_ok = 1'b0; + this.m_apu_req_id = 0; + this.m_mem_req_id[0] = 0; + this.m_mem_req_id[1] = 0; + this.m_mem_req_id_valid = '0; + this.m_data_missaligned = 1'b0; + this.m_got_first_data = 1'b0; + this.m_got_ex_reg = 1'b0; + this.m_got_regs_write = 1'b0; + this.m_move_down_pipe = 1'b0; + this.m_instret_cnt = 0; + this.m_sample_csr_write_in_ex = 1'b1; + this.m_rd_addr[0] = '0; + this.m_rd_addr[1] = '0; + this.m_2_rd_insn = 1'b0; + this.m_rs1_addr = '0; + this.m_rs2_addr = '0; + this.m_rs3_addr = '0; + this.m_ex_fw = '0; + this.m_csr.got_minstret = '0; + this.m_dbg_taken = '0; + this.m_trap = 1'b0; + this.m_fflags_we_non_apu = 1'b0; + this.m_frm_we_non_apu = 1'b0; + this.m_fcsr_we_non_apu = 1'b0; this.m_csr.mcause_we = '0; if (is_compressed_id_i) begin this.m_insn[31:16] = '0; @@ -944,47 +948,48 @@ endfunction function void copy_full(insn_trace_t m_source); - this.m_valid = m_source.m_valid; - this.m_stage = m_source.m_stage; - this.m_order = m_source.m_order; - this.m_pc_rdata = m_source.m_pc_rdata; - this.m_insn = m_source.m_insn; - this.m_mnemonic = m_source.m_mnemonic; - this.m_is_memory = m_source.m_is_memory; - this.m_is_load = m_source.m_is_load; - this.m_is_apu = m_source.m_is_apu; - this.m_is_apu_ok = m_source.m_is_apu_ok; - this.m_apu_req_id = m_source.m_apu_req_id; - this.m_mem_req_id = m_source.m_mem_req_id; - this.m_mem_req_id_valid = m_source.m_mem_req_id_valid; - this.m_data_missaligned = m_source.m_data_missaligned; - this.m_got_first_data = m_source.m_got_first_data; - this.m_got_ex_reg = m_source.m_got_ex_reg; - this.m_dbg_taken = m_source.m_dbg_taken; - this.m_dbg_cause = m_source.m_dbg_cause; - this.m_is_ebreak = m_source.m_is_ebreak; - this.m_is_illegal = m_source.m_is_illegal; - this.m_is_irq = m_source.m_is_irq; - this.m_instret_cnt = m_source.m_instret_cnt; - this.m_rs1_addr = m_source.m_rs1_addr; - this.m_rs2_addr = m_source.m_rs2_addr; - this.m_rs3_addr = m_source.m_rs3_addr; - this.m_rs1_rdata = m_source.m_rs1_rdata; - this.m_rs2_rdata = m_source.m_rs2_rdata; - this.m_rs3_rdata = m_source.m_rs3_rdata; - - this.m_ex_fw = m_source.m_ex_fw; - this.m_rd_addr = m_source.m_rd_addr; - this.m_2_rd_insn = m_source.m_2_rd_insn; - this.m_rd_wdata = m_source.m_rd_wdata; - - this.m_intr = m_source.m_intr; - this.m_trap = m_source.m_trap; - this.m_fflags_we_non_apu = m_source.m_fflags_we_non_apu; - this.m_frm_we_non_apu = m_source.m_frm_we_non_apu ; - this.m_fcsr_we_non_apu = m_source.m_fcsr_we_non_apu; - - this.m_mem = m_source.m_mem; + this.m_valid = m_source.m_valid; + this.m_stage = m_source.m_stage; + this.m_order = m_source.m_order; + this.m_pc_rdata = m_source.m_pc_rdata; + this.m_insn = m_source.m_insn; + this.m_mnemonic = m_source.m_mnemonic; + this.m_is_memory = m_source.m_is_memory; + this.m_is_load = m_source.m_is_load; + this.m_is_apu = m_source.m_is_apu; + this.m_is_apu_ok = m_source.m_is_apu_ok; + this.m_apu_req_id = m_source.m_apu_req_id; + this.m_mem_req_id = m_source.m_mem_req_id; + this.m_mem_req_id_valid = m_source.m_mem_req_id_valid; + this.m_data_missaligned = m_source.m_data_missaligned; + this.m_got_first_data = m_source.m_got_first_data; + this.m_got_ex_reg = m_source.m_got_ex_reg; + this.m_dbg_taken = m_source.m_dbg_taken; + this.m_dbg_cause = m_source.m_dbg_cause; + this.m_is_ebreak = m_source.m_is_ebreak; + this.m_is_illegal = m_source.m_is_illegal; + this.m_is_irq = m_source.m_is_irq; + this.m_instret_cnt = m_source.m_instret_cnt; + this.m_sample_csr_write_in_ex = m_source.m_sample_csr_write_in_ex; + this.m_rs1_addr = m_source.m_rs1_addr; + this.m_rs2_addr = m_source.m_rs2_addr; + this.m_rs3_addr = m_source.m_rs3_addr; + this.m_rs1_rdata = m_source.m_rs1_rdata; + this.m_rs2_rdata = m_source.m_rs2_rdata; + this.m_rs3_rdata = m_source.m_rs3_rdata; + + this.m_ex_fw = m_source.m_ex_fw; + this.m_rd_addr = m_source.m_rd_addr; + this.m_2_rd_insn = m_source.m_2_rd_insn; + this.m_rd_wdata = m_source.m_rd_wdata; + + this.m_intr = m_source.m_intr; + this.m_trap = m_source.m_trap; + this.m_fflags_we_non_apu = m_source.m_fflags_we_non_apu; + this.m_frm_we_non_apu = m_source.m_frm_we_non_apu ; + this.m_fcsr_we_non_apu = m_source.m_fcsr_we_non_apu; + + this.m_mem = m_source.m_mem; //CRS `ASSIGN_CSR(mstatus) `ASSIGN_CSR(mstatus_fs) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv index 58051ab8..88d65d0b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv @@ -64,6 +64,9 @@ typedef struct { logic is_compressed_id; logic ebrk_insn_dec; + logic ecall_insn_dec; + logic mret_insn_dec; + logic mret_dec; logic [5:0] csr_cause; @@ -112,6 +115,9 @@ typedef struct { logic [31:0] data_wdata_ex; logic lsu_split_q_ex; + logic mult_ready; + logic alu_ready; + //// WB probes //// logic [31:0] pc_wb; logic wb_ready; @@ -198,6 +204,8 @@ typedef struct { logic mcause_we; logic dcsr_we; + logic fregs_we; + logic jvt_we; Status_t mstatus_n; Status_t mstatus_q; @@ -348,16 +356,24 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.mstatus_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; end - CSR_MISA: r_pipe_freeze_trace.csr.misa_we = 1'b1; - CSR_MTVEC: r_pipe_freeze_trace.csr.mtvec_we = 1'b1; - CSR_MSCRATCH: r_pipe_freeze_trace.csr.mscratch_we = 1'b1; - CSR_MEPC: r_pipe_freeze_trace.csr.mepc_we = 1'b1; - CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = 1'b1; - CSR_DCSR: r_pipe_freeze_trace.csr.dcsr_we = 1'b1; - CSR_FFLAGS: r_pipe_freeze_trace.csr.fflags_we = 1'b1; - CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; - CSR_FCSR: r_pipe_freeze_trace.csr.fcsr_we = 1'b1; - CSR_DPC: r_pipe_freeze_trace.csr.dpc_we = 1'b1; + CSR_MISA: r_pipe_freeze_trace.csr.misa_we = 1'b1; + CSR_MTVEC: r_pipe_freeze_trace.csr.mtvec_we = 1'b1; + CSR_MSCRATCH: r_pipe_freeze_trace.csr.mscratch_we = 1'b1; + CSR_MEPC: r_pipe_freeze_trace.csr.mepc_we = 1'b1; + CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = 1'b1; + CSR_DCSR: r_pipe_freeze_trace.csr.dcsr_we = 1'b1; + CSR_FFLAGS: begin + r_pipe_freeze_trace.csr.fflags_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end + CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; + CSR_FCSR: begin + r_pipe_freeze_trace.csr.fcsr_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end + CSR_DPC: r_pipe_freeze_trace.csr.dpc_we = 1'b1; + CSR_DSCRATCH0: r_pipe_freeze_trace.csr.dscratch0_we = 1'b1; + CSR_DSCRATCH1: r_pipe_freeze_trace.csr.dscratch1_we = 1'b1; endcase end // CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = r_pipe_freeze_trace.csr.mcause_n != r_pipe_freeze_trace.csr.mcause_q; //for debug purpose @@ -416,6 +432,9 @@ task monitor_pipeline(); r_pipe_freeze_trace.jump_target_id = jump_target_id_i; r_pipe_freeze_trace.is_compressed_id = is_compressed_id_i; r_pipe_freeze_trace.ebrk_insn_dec = ebrk_insn_dec_i; + r_pipe_freeze_trace.ecall_insn_dec = ecall_insn_dec_i; + r_pipe_freeze_trace.mret_insn_dec = mret_insn_dec_i; + r_pipe_freeze_trace.mret_dec = mret_dec_i; r_pipe_freeze_trace.csr_cause = csr_cause_i; r_pipe_freeze_trace.debug_csr_save = debug_csr_save_i; r_pipe_freeze_trace.minstret = minstret_i; @@ -462,6 +481,8 @@ task monitor_pipeline(); r_pipe_freeze_trace.data_wdata_ex = data_wdata_ex_i; r_pipe_freeze_trace.lsu_split_q_ex = lsu_split_q_ex_i; + r_pipe_freeze_trace.mult_ready = mult_ready_i; + r_pipe_freeze_trace.alu_ready = alu_ready_i; //// WB probes //// r_pipe_freeze_trace.pc_wb = pc_wb_i; r_pipe_freeze_trace.wb_ready = wb_ready_i; @@ -526,6 +547,8 @@ task monitor_pipeline(); r_pipe_freeze_trace.csr.we = csr_we_i; r_pipe_freeze_trace.csr.wdata_int = csr_wdata_int_i; + r_pipe_freeze_trace.csr.fregs_we = csr_fregs_we_i; + r_pipe_freeze_trace.csr.jvt_we = csr_jvt_we_i; r_pipe_freeze_trace.csr.mstatus_n = csr_mstatus_n_i; r_pipe_freeze_trace.csr.mstatus_q = csr_mstatus_q_i; @@ -650,10 +673,6 @@ task monitor_pipeline(); if (r_pipe_freeze_trace.csr.fcsr_we) begin r_pipe_freeze_trace.csr.fflags_we = 1'b1; r_pipe_freeze_trace.csr.frm_we = 1'b1; - end else begin - if (r_pipe_freeze_trace.csr.fflags_we || r_pipe_freeze_trace.csr.frm_we) begin - r_pipe_freeze_trace.csr.fcsr_we = 1'b1; - end end if (csr_fcsr_fflags_we_i) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv index 6516f932..a3e3bac9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv @@ -491,6 +491,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; if ( (debug_req_pending || trigger_match_i) & ~debug_mode_q ) begin //Serving the debug + is_decoding_o = COREV_PULP ? 1'b0 : 1'b1; halt_if_o = 1'b1; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; @@ -712,6 +713,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; if ( (debug_req_pending || trigger_match_i) & ~debug_mode_q ) begin //Serving the debug + is_decoding_o = COREV_PULP ? 1'b0 : 1'b1; halt_if_o = 1'b1; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; @@ -764,7 +766,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; ebrk_insn_i: begin halt_if_o = 1'b1; - halt_id_o = 1'b1; + halt_id_o = 1'b0; if (debug_mode_q) // we got back to the park loop in the debug rom @@ -776,15 +778,15 @@ module cv32e40px_controller import cv32e40px_pkg::*; else begin // otherwise just a normal ebreak exception - ctrl_fsm_ns = FLUSH_EX; + ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; end end ecall_insn_i: begin halt_if_o = 1'b1; - halt_id_o = 1'b1; - ctrl_fsm_ns = FLUSH_EX; + halt_id_o = 1'b0; + ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; end csr_status_i: begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv index fc301b91..25aa6cc9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv @@ -194,6 +194,7 @@ module cv32e40px_core logic [31:0] jump_target_id, jump_target_ex; logic branch_in_ex; logic branch_decision; + logic [ 1:0] ctrl_transfer_insn_in_dec; logic ctrl_busy; logic if_busy; @@ -237,6 +238,7 @@ module cv32e40px_core logic [ C_RM-1:0] frm_csr; logic [ C_FFLAG-1:0] fflags_csr; logic fflags_we; + logic fregs_we; // APU logic apu_en_ex; @@ -272,6 +274,7 @@ module cv32e40px_core logic regfile_we_ex; logic [ 5:0] regfile_waddr_fw_wb_o; // From WB to ID logic regfile_we_wb; + logic regfile_we_wb_power; logic [ 31:0] regfile_wdata; logic [ 5:0] regfile_alu_waddr_ex; @@ -279,6 +282,7 @@ module cv32e40px_core logic [ 5:0] regfile_alu_waddr_fw; logic regfile_alu_we_fw; + logic regfile_alu_we_fw_power; logic [ 31:0] regfile_alu_wdata_fw; // CSR control @@ -596,9 +600,10 @@ module cv32e40px_core .instr_req_o (instr_req_int), // Jumps and branches - .branch_in_ex_o (branch_in_ex), - .branch_decision_i(branch_decision), - .jump_target_o (jump_target_id), + .branch_in_ex_o (branch_in_ex), + .branch_decision_i (branch_decision), + .jump_target_o (jump_target_id), + .ctrl_transfer_insn_in_dec_o(ctrl_transfer_insn_in_dec), // IF and ID control signals .clear_instr_valid_o(clear_instr_valid), @@ -790,13 +795,15 @@ module cv32e40px_core .wake_from_sleep_o(wake_from_sleep), // Forward Signals - .regfile_waddr_wb_i(regfile_waddr_fw_wb_o), // Write address ex-wb pipeline - .regfile_we_wb_i (regfile_we_wb), // write enable for the register file - .regfile_wdata_wb_i(regfile_wdata), // write data to commit in the register file + .regfile_waddr_wb_i (regfile_waddr_fw_wb_o), // Write address ex-wb pipeline + .regfile_we_wb_i (regfile_we_wb), // write enable for the register file + .regfile_we_wb_power_i(regfile_we_wb_power), + .regfile_wdata_wb_i (regfile_wdata), // write data to commit in the register file - .regfile_alu_waddr_fw_i(regfile_alu_waddr_fw), - .regfile_alu_we_fw_i (regfile_alu_we_fw), - .regfile_alu_wdata_fw_i(regfile_alu_wdata_fw), + .regfile_alu_waddr_fw_i (regfile_alu_waddr_fw), + .regfile_alu_we_fw_i (regfile_alu_we_fw), + .regfile_alu_we_fw_power_i(regfile_alu_we_fw_power), + .regfile_alu_wdata_fw_i (regfile_alu_wdata_fw), // from ALU .mult_multicycle_i(mult_multicycle), @@ -828,6 +835,7 @@ module cv32e40px_core // // ///////////////////////////////////////////////////// cv32e40px_ex_stage #( + .COREV_PULP (COREV_PULP), .FPU (FPU), .APU_NARGS_CPU (APU_NARGS_CPU), .APU_WOP_CPU (APU_WOP_CPU), @@ -876,6 +884,8 @@ module cv32e40px_core .data_misaligned_ex_i(data_misaligned_ex), // from ID/EX pipeline .data_misaligned_i (data_misaligned), + .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec), + // FPU .fpu_fflags_we_o(fflags_we), .fpu_fflags_o (fflags_csr), @@ -941,18 +951,20 @@ module cv32e40px_core .regfile_we_i (regfile_we_ex), // Output of ex stage pipeline - .regfile_waddr_wb_o(regfile_waddr_fw_wb_o), - .regfile_we_wb_o (regfile_we_wb), - .regfile_wdata_wb_o(regfile_wdata), + .regfile_waddr_wb_o (regfile_waddr_fw_wb_o), + .regfile_we_wb_o (regfile_we_wb), + .regfile_we_wb_power_o(regfile_we_wb_power), + .regfile_wdata_wb_o (regfile_wdata), // To IF: Jump and branch target and decision .jump_target_o (jump_target_ex), .branch_decision_o(branch_decision), // To ID stage: Forwarding signals - .regfile_alu_waddr_fw_o(regfile_alu_waddr_fw), - .regfile_alu_we_fw_o (regfile_alu_we_fw), - .regfile_alu_wdata_fw_o(regfile_alu_wdata_fw), + .regfile_alu_waddr_fw_o (regfile_alu_waddr_fw), + .regfile_alu_we_fw_o (regfile_alu_we_fw), + .regfile_alu_we_fw_power_o(regfile_alu_we_fw_power), + .regfile_alu_wdata_fw_o (regfile_alu_wdata_fw), // stall control .is_decoding_i (is_decoding), @@ -1072,6 +1084,7 @@ module cv32e40px_core .frm_o (frm_csr), .fflags_i (fflags_csr), .fflags_we_i(fflags_we), + .fregs_we_i (fregs_we), // Interrupt related control signals .mie_bypass_o (mie_bypass), @@ -1140,13 +1153,16 @@ module cv32e40px_core ); // CSR access - assign csr_addr = csr_addr_int; - assign csr_wdata = alu_operand_a_ex; - assign csr_op = csr_op_ex; + assign csr_addr = csr_addr_int; + assign csr_wdata = alu_operand_a_ex; + assign csr_op = csr_op_ex; assign csr_addr_int = csr_num_e'(csr_access_ex ? alu_operand_b_ex[11:0] : '0); - + // Floating-Point registers write + assign fregs_we = (FPU & !ZFINX) ? ((regfile_alu_we_fw && regfile_alu_waddr_fw[5]) || + (regfile_we_wb && regfile_waddr_fw_wb_o[5])) + : 1'b0; /////////////////////////// // ____ __ __ ____ // diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv index 2d873452..f24b3bf9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv @@ -68,6 +68,7 @@ module cv32e40px_cs_registers output logic [ 2:0] frm_o, input logic [C_FFLAG-1:0] fflags_i, input logic fflags_we_i, + input logic fregs_we_i, // Interrupts output logic [31:0] mie_bypass_o, @@ -212,6 +213,7 @@ module cv32e40px_cs_registers logic [31:0] exception_pc; Status_t mstatus_q, mstatus_n; + logic mstatus_we_int; FS_t mstatus_fs_q, mstatus_fs_n; logic [5:0] mcause_q, mcause_n; logic [5:0] ucause_q, ucause_n; @@ -897,6 +899,7 @@ module cv32e40px_cs_registers dscratch0_n = dscratch0_q; dscratch1_n = dscratch1_q; + mstatus_we_int = 1'b0; mstatus_n = mstatus_q; mcause_n = mcause_q; ucause_n = '0; // Not used if PULP_SECURE == 0 @@ -957,7 +960,8 @@ module cv32e40px_cs_registers mprv: csr_wdata_int[MSTATUS_MPRV_BIT] }; if (FPU == 1 && ZFINX == 0) begin - mstatus_fs_n = FS_t'(csr_wdata_int[MSTATUS_FS_BIT_HIGH:MSTATUS_FS_BIT_LOW]); + mstatus_we_int = 1'b1; + mstatus_fs_n = FS_t'(csr_wdata_int[MSTATUS_FS_BIT_HIGH:MSTATUS_FS_BIT_LOW]); end end // mie: machine interrupt enable @@ -1027,7 +1031,7 @@ module cv32e40px_cs_registers if (ZFINX == 0) begin // FPU Register File/Flags implicit update or modified by CSR instructions - if (fflags_we_i || fcsr_update) begin + if ((fregs_we_i && !(mstatus_we_int && mstatus_fs_n != FS_DIRTY)) || fflags_we_i || fcsr_update) begin mstatus_fs_n = FS_DIRTY; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv index 6ab1b01b..3beaf022 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv @@ -34,6 +34,7 @@ module cv32e40px_ex_stage import cv32e40px_apu_core_pkg::*; import cv32e40px_core_v_xif_pkg::*; #( + parameter COREV_PULP = 0, parameter FPU = 0, parameter APU_NARGS_CPU = 3, parameter APU_WOP_CPU = 6, @@ -82,6 +83,8 @@ module cv32e40px_ex_stage input logic data_misaligned_ex_i, input logic data_misaligned_i, + input logic [1:0] ctrl_transfer_insn_in_dec_i, + // FPU signals output logic fpu_fflags_we_o, output logic [APU_NUSFLAGS_CPU-1:0] fpu_fflags_o, @@ -152,11 +155,13 @@ module cv32e40px_ex_stage // Output of EX stage pipeline output logic [ 5:0] regfile_waddr_wb_o, output logic regfile_we_wb_o, + output logic regfile_we_wb_power_o, output logic [31:0] regfile_wdata_wb_o, // Forwarding ports : to ID stage output logic [ 5:0] regfile_alu_waddr_fw_o, output logic regfile_alu_we_fw_o, + output logic regfile_alu_we_fw_power_o, output logic [31:0] regfile_alu_wdata_fw_o, // forward to RF and ID/EX pipe, ALU & MUL // To IF: Jump and branch target and decision @@ -204,30 +209,36 @@ module cv32e40px_ex_stage // ALU write port mux always_comb begin - regfile_alu_wdata_fw_o = '0; - regfile_alu_waddr_fw_o = '0; - regfile_alu_we_fw_o = '0; - wb_contention = 1'b0; - result_fw_to_x_o = '0; + regfile_alu_wdata_fw_o = '0; + regfile_alu_waddr_fw_o = '0; + regfile_alu_we_fw_o = '0; + wb_contention = 1'b0; + result_fw_to_x_o = '0; + regfile_alu_we_fw_power_o = 1'b0; if (x_result_valid_assigned_i & x_result_we_i & (x_result_rd_i != 5'b00000)) begin - regfile_alu_we_fw_o = 1'b1; - regfile_alu_waddr_fw_o = {1'b0, x_result_rd_i}; - regfile_alu_wdata_fw_o = x_result_data_i; + regfile_alu_we_fw_o = 1'b1; + regfile_alu_we_fw_power_o = 1'b1; + regfile_alu_waddr_fw_o = {1'b0, x_result_rd_i}; + regfile_alu_wdata_fw_o = x_result_data_i; if (regfile_alu_we_i) begin wb_contention = 1'b1; end end else begin // APU single cycle operations, and multicycle operations (>2cycles) are written back on ALU port if (apu_valid & (apu_singlecycle | apu_multicycle)) begin - regfile_alu_we_fw_o = 1'b1; - regfile_alu_waddr_fw_o = apu_waddr; - regfile_alu_wdata_fw_o = apu_result; - result_fw_to_x_o = apu_result; + regfile_alu_we_fw_o = 1'b1; + regfile_alu_we_fw_power_o = 1'b1; + regfile_alu_waddr_fw_o = apu_waddr; + regfile_alu_wdata_fw_o = apu_result; + result_fw_to_x_o = apu_result; if (regfile_alu_we_i & ~apu_en_i) begin wb_contention = 1'b1; end end else begin - regfile_alu_we_fw_o = regfile_alu_we_i & ~apu_en_i; // private fpu incomplete? + regfile_alu_we_fw_o = regfile_alu_we_i & ~apu_en_i; // private fpu incomplete? + regfile_alu_we_fw_power_o = !COREV_PULP ? regfile_alu_we_i & ~apu_en_i : + regfile_alu_we_i & ~apu_en_i & + mult_ready & alu_ready & lsu_ready_ex_i; regfile_alu_waddr_fw_o = regfile_alu_waddr_i; if (alu_en_i) begin regfile_alu_wdata_fw_o = alu_result; @@ -247,21 +258,24 @@ module cv32e40px_ex_stage // LSU write port mux always_comb begin - regfile_we_wb_o = 1'b0; - regfile_waddr_wb_o = regfile_waddr_lsu; - regfile_wdata_wb_o = lsu_rdata_i; - wb_contention_lsu = 1'b0; + regfile_we_wb_o = 1'b0; + regfile_we_wb_power_o = 1'b0; + regfile_waddr_wb_o = regfile_waddr_lsu; + regfile_wdata_wb_o = lsu_rdata_i; + wb_contention_lsu = 1'b0; if (regfile_we_lsu) begin - regfile_we_wb_o = 1'b1; + regfile_we_wb_o = 1'b1; + regfile_we_wb_power_o = !COREV_PULP ? 1'b1 : ~data_misaligned_ex_i & wb_ready_i; if (apu_valid & (!apu_singlecycle & !apu_multicycle)) begin wb_contention_lsu = 1'b1; end // APU two-cycle operations are written back on LSU port end else if (apu_valid & (!apu_singlecycle & !apu_multicycle)) begin - regfile_we_wb_o = 1'b1; - regfile_waddr_wb_o = apu_waddr; - regfile_wdata_wb_o = apu_result; + regfile_we_wb_o = 1'b1; + regfile_we_wb_power_o = 1'b1; + regfile_waddr_wb_o = apu_waddr; + regfile_wdata_wb_o = apu_result; end end @@ -406,11 +420,20 @@ module cv32e40px_ex_stage apu_result_q <= 'b0; apu_flags_q <= 'b0; end else begin - if (apu_rvalid_i && apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || (data_req_i && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) begin + if (apu_rvalid_i && apu_multicycle && + (data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) begin apu_rvalid_q <= 1'b1; apu_result_q <= apu_result_i; apu_flags_q <= apu_flags_i; - end else if (apu_rvalid_q && !(data_misaligned_i || data_misaligned_ex_i || ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) begin + end else if (apu_rvalid_q && !(data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) begin apu_rvalid_q <= 1'b0; end end @@ -418,7 +441,12 @@ module cv32e40px_ex_stage assign apu_req_o = apu_req; assign apu_gnt = apu_gnt_i; - assign apu_valid = (apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) ? 1'b0 : (apu_rvalid_i || apu_rvalid_q); + assign apu_valid = (apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) + ? 1'b0 : (apu_rvalid_i || apu_rvalid_q); assign apu_operands_o = apu_operands_i; assign apu_op_o = apu_op_i; assign apu_result = apu_rvalid_q ? apu_result_q : apu_result_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv index 8502e341..54add99d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv @@ -111,7 +111,7 @@ module cv32e40px_fp_wrapper .int_fmt_i (fpnew_pkg::int_format_e'(fpu_int_fmt)), .vectorial_op_i(fpu_vec_op), .tag_i (1'b0), - .simd_mask_i ('b0), + .simd_mask_i (1'b0), .in_valid_i (apu_req_i), .in_ready_o (apu_gnt_o), .flush_i (1'b0), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv index 4c513d27..6e996c32 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv @@ -72,6 +72,7 @@ module cv32e40px_id_stage output logic branch_in_ex_o, input logic branch_decision_i, output logic [31:0] jump_target_o, + output logic [ 1:0] ctrl_transfer_insn_in_dec_o, // IF and ID stage signals output logic clear_instr_valid_o, @@ -263,10 +264,12 @@ module cv32e40px_id_stage // Forward Signals input logic [5:0] regfile_waddr_wb_i, input logic regfile_we_wb_i, + input logic regfile_we_wb_power_i, input logic [31:0] regfile_wdata_wb_i, // From wb_stage: selects data from data memory, ex_stage result and sp rdata input logic [ 5:0] regfile_alu_waddr_fw_i, input logic regfile_alu_we_fw_i, + input logic regfile_alu_we_fw_power_i, input logic [31:0] regfile_alu_wdata_fw_i, // from ALU @@ -302,6 +305,9 @@ module cv32e40px_id_stage localparam REG_D_MSB = 11; localparam REG_D_LSB = 7; + + localparam REGFILE_NUM_READ_PORTS = ((COREV_X_IF == 1) & (X_DUALREAD == 1)) ? 2 : 1; + logic [31:0] instr; @@ -381,9 +387,9 @@ module cv32e40px_id_stage logic [ 5:0] regfile_alu_waddr_id; logic regfile_alu_we_id, regfile_alu_we_dec_id; - logic [31:0] regfile_data_ra_id; - logic [31:0] regfile_data_rb_id; - logic [31:0] regfile_data_rc_id; + logic [REGFILE_NUM_READ_PORTS-1:0][31:0] regfile_data_ra_id; + logic [REGFILE_NUM_READ_PORTS-1:0][31:0] regfile_data_rb_id; + logic [REGFILE_NUM_READ_PORTS-1:0][31:0] regfile_data_rc_id; // ALU Control logic alu_en; @@ -438,8 +444,8 @@ module cv32e40px_id_stage logic [2:0][4:0] x_rs_addr; logic x_mem_data_req; logic x_mem_valid; - logic [2:0] x_ex_fwd; - logic [2:0] x_wb_fwd; + logic [RF_READ_PORTS-1:0] x_ex_fwd; + logic [RF_READ_PORTS-1:0] x_wb_fwd; // Register Write Control logic regfile_we_id; @@ -622,17 +628,18 @@ module cv32e40px_id_stage // \___/ \__,_|_| |_| |_| .__/ |_|\__,_|_| \__, |\___|\__| // // |_| |___/ // ////////////////////////////////////////////////////////////////// - - always_comb begin : jump_target_mux - unique case (ctrl_transfer_target_mux_sel) - JT_JAL: jump_target = pc_id_i + imm_uj_type; - JT_COND: jump_target = pc_id_i + imm_sb_type; - - // JALR: Cannot forward RS1, since the path is too long - JT_JALR: jump_target = regfile_data_ra_id + imm_i_type; - default: jump_target = regfile_data_ra_id + imm_i_type; - endcase - end + generate + always_comb begin : jump_target_mux + unique case (ctrl_transfer_target_mux_sel) + JT_JAL: jump_target = pc_id_i + imm_uj_type; + JT_COND: jump_target = pc_id_i + imm_sb_type; + + // JALR: Cannot forward RS1, since the path is too long + JT_JALR: jump_target = regfile_data_ra_id[0] + imm_i_type; + default: jump_target = regfile_data_ra_id[0] + imm_i_type; + endcase + end + endgenerate assign jump_target_o = jump_target; @@ -666,16 +673,18 @@ module cv32e40px_id_stage endcase end - // Operand a forwarding mux - always_comb begin : operand_a_fw_mux - case (operand_a_fw_mux_sel) - SEL_FW_EX: operand_a_fw_id = regfile_alu_wdata_fw_i; - SEL_FW_WB: operand_a_fw_id = regfile_wdata_wb_i; - SEL_REGFILE: operand_a_fw_id = regfile_data_ra_id; - default: operand_a_fw_id = regfile_data_ra_id; - endcase - ; // case (operand_a_fw_mux_sel) - end + generate + // Operand a forwarding mux + always_comb begin : operand_a_fw_mux + case (operand_a_fw_mux_sel) + SEL_FW_EX: operand_a_fw_id = regfile_alu_wdata_fw_i; + SEL_FW_WB: operand_a_fw_id = regfile_wdata_wb_i; + SEL_REGFILE: operand_a_fw_id = regfile_data_ra_id[0]; + default: operand_a_fw_id = regfile_data_ra_id[0]; + endcase + ; // case (operand_a_fw_mux_sel) + end + endgenerate ////////////////////////////////////////////////////// // ___ _ ____ // @@ -732,16 +741,31 @@ module cv32e40px_id_stage assign alu_operand_b = (scalar_replication == 1'b1) ? operand_b_vec : operand_b; - // Operand b forwarding mux - always_comb begin : operand_b_fw_mux - case (operand_b_fw_mux_sel) - SEL_FW_EX: operand_b_fw_id = regfile_alu_wdata_fw_i; - SEL_FW_WB: operand_b_fw_id = regfile_wdata_wb_i; - SEL_REGFILE: operand_b_fw_id = regfile_data_rb_id; - default: operand_b_fw_id = regfile_data_rb_id; - endcase - ; // case (operand_b_fw_mux_sel) - end + generate + if (X_DUALREAD == 0) begin : no_dualread_fw_b + // Operand b forwarding mux + always_comb begin : operand_b_fw_mux + case (operand_b_fw_mux_sel) + SEL_FW_EX: operand_b_fw_id = regfile_alu_wdata_fw_i; + SEL_FW_WB: operand_b_fw_id = regfile_wdata_wb_i; + SEL_REGFILE: operand_b_fw_id = regfile_data_rb_id; + default: operand_b_fw_id = regfile_data_rb_id; + endcase + ; // case (operand_b_fw_mux_sel) + end + end else begin : dualread_fw_b + // Operand b forwarding mux + always_comb begin : operand_b_fw_mux + case (operand_b_fw_mux_sel) + SEL_FW_EX: operand_b_fw_id = regfile_alu_wdata_fw_i; + SEL_FW_WB: operand_b_fw_id = regfile_wdata_wb_i; + SEL_REGFILE: operand_b_fw_id = regfile_data_rb_id[0]; + default: operand_b_fw_id = regfile_data_rb_id[0]; + endcase + ; // case (operand_b_fw_mux_sel) + end + end + endgenerate ////////////////////////////////////////////////////// @@ -777,17 +801,31 @@ module cv32e40px_id_stage assign alu_operand_c = (scalar_replication_c == 1'b1) ? operand_c_vec : operand_c; - // Operand c forwarding mux - always_comb begin : operand_c_fw_mux - case (operand_c_fw_mux_sel) - SEL_FW_EX: operand_c_fw_id = regfile_alu_wdata_fw_i; - SEL_FW_WB: operand_c_fw_id = regfile_wdata_wb_i; - SEL_REGFILE: operand_c_fw_id = regfile_data_rc_id; - default: operand_c_fw_id = regfile_data_rc_id; - endcase - ; // case (operand_c_fw_mux_sel) - end - + generate + if (X_DUALREAD == 0) begin : no_dualread_fw_c + // Operand c forwarding mux + always_comb begin : operand_c_fw_mux + case (operand_c_fw_mux_sel) + SEL_FW_EX: operand_c_fw_id = regfile_alu_wdata_fw_i; + SEL_FW_WB: operand_c_fw_id = regfile_wdata_wb_i; + SEL_REGFILE: operand_c_fw_id = regfile_data_rc_id; + default: operand_c_fw_id = regfile_data_rc_id; + endcase + ; // case (operand_c_fw_mux_sel) + end + end else begin : dualread_fw_c + // Operand c forwarding mux + always_comb begin : operand_c_fw_mux + case (operand_c_fw_mux_sel) + SEL_FW_EX: operand_c_fw_id = regfile_alu_wdata_fw_i; + SEL_FW_WB: operand_c_fw_id = regfile_wdata_wb_i; + SEL_REGFILE: operand_c_fw_id = regfile_data_rc_id[0]; + default: operand_c_fw_id = regfile_data_rc_id[0]; + endcase + ; // case (operand_c_fw_mux_sel) + end + end + endgenerate /////////////////////////////////////////////////////////////////////////// // ___ _ _ _ ___ ____ // @@ -865,6 +903,9 @@ module cv32e40px_id_stage if (ctrl_transfer_target_mux_sel == JT_JALR) begin apu_read_regs[0] = regfile_addr_ra_id; apu_read_regs_valid[0] = 1'b1; + end else begin + apu_read_regs[0] = regfile_addr_ra_id; + apu_read_regs_valid[0] = 1'b0; end end // OP_A_CURRPC: OP_A_REGA_OR_FWD: begin @@ -982,13 +1023,17 @@ module cv32e40px_id_stage .ADDR_WIDTH(6), .DATA_WIDTH(32), .FPU (FPU), - .ZFINX (ZFINX) + .ZFINX (ZFINX), + .COREV_X_IF(COREV_X_IF), + .X_DUALREAD(X_DUALREAD) ) register_file_i ( .clk (clk), .rst_n(rst_n), .scan_cg_en_i(scan_cg_en_i), + .dualread_i(x_issue_resp_i.dualread), + // Read port a .raddr_a_i(regfile_addr_ra_id), .rdata_a_o(regfile_data_ra_id), @@ -1004,12 +1049,12 @@ module cv32e40px_id_stage // Write port a .waddr_a_i(regfile_waddr_wb_i), .wdata_a_i(regfile_wdata_wb_i), - .we_a_i (regfile_we_wb_i), + .we_a_i (regfile_we_wb_power_i), // Write port b .waddr_b_i(regfile_alu_waddr_fw_i), .wdata_b_i(regfile_alu_wdata_fw_i), - .we_b_i (regfile_alu_we_fw_i) + .we_b_i (regfile_alu_we_fw_power_i) ); logic [1:0] x_mem_data_type_id; @@ -1037,6 +1082,7 @@ module cv32e40px_id_stage .x_issue_valid_o (x_issue_valid_o), .x_issue_ready_i (x_issue_ready_i), .x_issue_resp_writeback_i(x_issue_resp_i.writeback), + .x_issue_resp_dualread_i (x_issue_resp_i.dualread), .x_issue_resp_accept_i (x_issue_resp_i.accept), .x_issue_resp_loadstore_i(x_issue_resp_i.loadstore), .x_issue_req_rs_valid_o (x_issue_req_o.rs_valid), @@ -1118,22 +1164,25 @@ module cv32e40px_id_stage assign x_mem_valid = x_mem_valid_i; // xif integer souce operand selection - for (genvar i = 0; i < 3; i++) begin : xif_operand_assignment - always_comb begin - if (i == 0) begin - x_issue_req_o.rs[i] = regfile_data_ra_id; - end else if (i == 1) begin - x_issue_req_o.rs[i] = regfile_data_rb_id; - end else begin - x_issue_req_o.rs[i] = regfile_data_rc_id; - end - if (x_ex_fwd[i]) begin - x_issue_req_o.rs[i] = result_fw_to_x_i; - end else if (x_wb_fwd[i]) begin - x_issue_req_o.rs[i] = regfile_wdata_wb_i; + for (genvar j = 0; j < REGFILE_NUM_READ_PORTS; j++) begin : xif_operand_assignment_dualread + for (genvar i = 0; i < 3; i++) begin : xif_operand_assignment + always_comb begin + if (i == 0) begin + x_issue_req_o.rs[i+3*j] = regfile_data_ra_id[j]; + end else if (i == 1) begin + x_issue_req_o.rs[i+3*j] = regfile_data_rb_id[j]; + end else begin + x_issue_req_o.rs[i+3*j] = regfile_data_rc_id[j]; + end + if (x_ex_fwd[i+3*j]) begin + x_issue_req_o.rs[i+3*j] = result_fw_to_x_i; + end else if (x_wb_fwd[i+3*j]) begin + x_issue_req_o.rs[i+3*j] = regfile_wdata_wb_i; + end end end end + // LSU signal assignment/MUX always_comb begin x_mem_data_type_id = 2'b00; @@ -1300,7 +1349,7 @@ module cv32e40px_id_stage .debug_wfi_no_sleep_i(debug_wfi_no_sleep), // jump/branches - .ctrl_transfer_insn_in_dec_o (ctrl_transfer_insn_in_dec), + .ctrl_transfer_insn_in_dec_o (ctrl_transfer_insn_in_dec_o), .ctrl_transfer_insn_in_id_o (ctrl_transfer_insn_in_id), .ctrl_transfer_target_mux_sel_o(ctrl_transfer_target_mux_sel), @@ -1400,7 +1449,7 @@ module cv32e40px_id_stage // jump/branch control .branch_taken_ex_i (branch_taken_ex), .ctrl_transfer_insn_in_id_i (ctrl_transfer_insn_in_id), - .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec), + .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec_o), // Interrupt signals .irq_wu_ctrl_i (irq_wu_ctrl), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_ff.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_ff.sv index 1543f6e9..d0aad583 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_ff.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_ff.sv @@ -31,7 +31,9 @@ module cv32e40px_register_file #( parameter ADDR_WIDTH = 5, parameter DATA_WIDTH = 32, parameter FPU = 0, - parameter ZFINX = 0 + parameter ZFINX = 0, + parameter COREV_X_IF = 0, + parameter X_DUALREAD = 0 ) ( // Clock and Reset input logic clk, @@ -39,17 +41,19 @@ module cv32e40px_register_file #( input logic scan_cg_en_i, + input logic [2:0] dualread_i, + //Read port R1 - input logic [ADDR_WIDTH-1:0] raddr_a_i, - output logic [DATA_WIDTH-1:0] rdata_a_o, + input logic [ADDR_WIDTH-1:0] raddr_a_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_a_o, //Read port R2 - input logic [ADDR_WIDTH-1:0] raddr_b_i, - output logic [DATA_WIDTH-1:0] rdata_b_o, + input logic [ADDR_WIDTH-1:0] raddr_b_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_b_o, //Read port R3 - input logic [ADDR_WIDTH-1:0] raddr_c_i, - output logic [DATA_WIDTH-1:0] rdata_c_o, + input logic [ADDR_WIDTH-1:0] raddr_c_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_c_o, // Write port W1 input logic [ADDR_WIDTH-1:0] waddr_a_i, @@ -86,17 +90,53 @@ module cv32e40px_register_file #( //----------------------------------------------------------------------------- //-- READ : Read address decoder RAD //----------------------------------------------------------------------------- - assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; - assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; - assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; - + generate + if (COREV_X_IF != 0) begin + if (X_DUALREAD) begin + always_comb begin + rdata_a_o[0] = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + rdata_b_o[0] = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + rdata_c_o[0] = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + if (dualread_i[0] == 1) + rdata_a_o[1] = raddr_a_i[5] ? (mem_fp[{ + raddr_a_i[4:1], raddr_a_i[0]|1'b1 + }]) : (mem[{ + raddr_a_i[4:1], raddr_a_i[0]|1'b1 + }]); + else rdata_a_o[1] = '0; + if (dualread_i[1] == 1) + rdata_b_o[1] = raddr_b_i[5] ? (mem_fp[{ + raddr_b_i[4:1], raddr_b_i[0]|1'b1 + }]) : (mem[{ + raddr_b_i[4:1], raddr_b_i[0]|1'b1 + }]); + else rdata_b_o[1] = '0; + if (dualread_i[2] == 1) + rdata_c_o[1] = raddr_c_i[5] ? (mem_fp[{ + raddr_c_i[4:1], raddr_c_i[0]|1'b1 + }]) : (mem[{ + raddr_c_i[4:1], raddr_c_i[0]|1'b1 + }]); + else rdata_c_o[1] = '0; + end + end else begin + assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + end + end else begin + assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + end + endgenerate //----------------------------------------------------------------------------- //-- WRITE : Write Address Decoder (WAD), combinatorial process //----------------------------------------------------------------------------- // Mask top bit of write address to disable fp regfile - assign waddr_a = waddr_a_i; - assign waddr_b = waddr_b_i; + assign waddr_a = waddr_a_i; + assign waddr_b = waddr_b_i; genvar gidx; generate diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv index 037db7c4..217150c0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv @@ -33,7 +33,9 @@ module cv32e40px_register_file #( parameter ADDR_WIDTH = 5, parameter DATA_WIDTH = 32, parameter FPU = 0, - parameter ZFINX = 0 + parameter ZFINX = 0, + parameter COREV_X_IF = 0, + parameter X_DUALREAD = 0 ) ( // Clock and Reset input logic clk, @@ -41,17 +43,19 @@ module cv32e40px_register_file #( input logic scan_cg_en_i, + input logic dualread_i, + //Read port R1 - input logic [ADDR_WIDTH-1:0] raddr_a_i, - output logic [DATA_WIDTH-1:0] rdata_a_o, + input logic [ADDR_WIDTH-1:0] raddr_a_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_a_o, //Read port R2 - input logic [ADDR_WIDTH-1:0] raddr_b_i, - output logic [DATA_WIDTH-1:0] rdata_b_o, + input logic [ADDR_WIDTH-1:0] raddr_b_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_b_o, //Read port R3 - input logic [ADDR_WIDTH-1:0] raddr_c_i, - output logic [DATA_WIDTH-1:0] rdata_c_o, + input logic [ADDR_WIDTH-1:0] raddr_c_i, + output logic [X_DUALREAD:0][DATA_WIDTH-1:0] rdata_c_o, // Write port W1 input logic [ADDR_WIDTH-1:0] waddr_a_i, @@ -98,10 +102,37 @@ module cv32e40px_register_file #( //----------------------------------------------------------------------------- //-- READ : Read address decoder RAD //----------------------------------------------------------------------------- - assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; - assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; - assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; - + generate + if (COREV_X_IF != 0) begin + if (X_DUALREAD) begin + always_comb begin + if (dualread_i) begin + rdata_a_o[0] = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + rdata_b_o[0] = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + rdata_c_o[0] = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + rdata_a_o[1] = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0] | 5'b00001] : mem[raddr_a_i[4:0] | 5'b00001]; + rdata_b_o[1] = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0] | 5'b00001] : mem[raddr_b_i[4:0] | 5'b00001]; + rdata_c_o[1] = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0] | 5'b00001] : mem[raddr_c_i[4:0] | 5'b00001]; + end else begin + rdata_a_o[0] = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + rdata_b_o[0] = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + rdata_c_o[0] = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + rdata_b_o[1] = '0; + rdata_a_o[1] = '0; + rdata_c_o[1] = '0; + end + end + end else begin + assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + end + end else begin + assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]]; + assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]]; + assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]]; + end + endgenerate //----------------------------------------------------------------------------- // WRITE : SAMPLE INPUT DATA //--------------------------------------------------------------------------- diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv index 71bbf665..fe147124 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv @@ -33,11 +33,13 @@ module cv32e40px_x_disp input logic x_issue_ready_i, input logic x_issue_resp_accept_i, input logic x_issue_resp_writeback_i, - input logic x_issue_resp_loadstore_i, // unused - output logic [2:0] x_issue_req_rs_valid_o, - output logic [3:0] x_issue_req_id_o, - output logic [1:0] x_issue_req_mode_o, - output logic x_issue_req_ecs_valid, + + input logic [ 2:0] x_issue_resp_dualread_i, + input logic x_issue_resp_loadstore_i, // unused + output logic [RF_READ_PORTS-1:0] x_issue_req_rs_valid_o, + output logic [ 3:0] x_issue_req_id_o, + output logic [ 1:0] x_issue_req_mode_o, + output logic x_issue_req_ecs_valid, // commit interface output logic x_commit_valid_o, @@ -65,19 +67,19 @@ module cv32e40px_x_disp input logic x_result_we_i, // scoreboard, dependency check, stall, forwarding - input logic [4:0] waddr_id_i, - input logic [4:0] waddr_ex_i, - input logic [4:0] waddr_wb_i, - input logic we_ex_i, - input logic we_wb_i, - input logic [4:0] mem_instr_waddr_ex_i, - input logic mem_instr_we_ex_i, - input logic [2:0] regs_used_i, - input logic branch_or_jump_i, - input logic instr_valid_i, - input logic [2:0][4:0] x_rs_addr_i, - output logic [2:0] x_ex_fwd_o, - output logic [2:0] x_wb_fwd_o, + input logic [ 4:0] waddr_id_i, + input logic [ 4:0] waddr_ex_i, + input logic [ 4:0] waddr_wb_i, + input logic we_ex_i, + input logic we_wb_i, + input logic [ 4:0] mem_instr_waddr_ex_i, + input logic mem_instr_we_ex_i, + input logic [ 2:0] regs_used_i, + input logic branch_or_jump_i, + input logic instr_valid_i, + input logic [ 2:0][4:0] x_rs_addr_i, + output logic [RF_READ_PORTS-1:0] x_ex_fwd_o, + output logic [RF_READ_PORTS-1:0] x_wb_fwd_o, // memory request core-internal status signals output logic x_mem_data_req_o, @@ -109,14 +111,31 @@ module cv32e40px_x_disp // issue interface assign x_issue_valid_o = x_illegal_insn_dec_i & ~branch_or_jump_i & ~instr_offloaded_q & instr_valid_i & ~illegal_forwarding_prevention; assign x_issue_req_id_o = id_q; - assign x_issue_req_rs_valid_o[0] = (~scoreboard_q[x_rs_addr_i[0]] | x_ex_fwd_o[0] | x_wb_fwd_o[0]) - & ~(x_rs_addr_i[0] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[0] == waddr_wb_i & ~ex_valid_i); - assign x_issue_req_rs_valid_o[1] = (~scoreboard_q[x_rs_addr_i[1]] | x_ex_fwd_o[1] | x_wb_fwd_o[1]) - & ~(x_rs_addr_i[1] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[1] == waddr_wb_i & ~ex_valid_i); - assign x_issue_req_rs_valid_o[2] = (~scoreboard_q[x_rs_addr_i[2]] | x_ex_fwd_o[2] | x_wb_fwd_o[2]) - & ~(x_rs_addr_i[2] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[2] == waddr_wb_i & ~ex_valid_i); - assign x_issue_req_ecs_valid = 1'b1; // extension context status is not implemented in cv32e40px - + generate + if (X_DUALREAD != 0) begin + assign x_issue_req_rs_valid_o[0] = (~scoreboard_q[x_rs_addr_i[0]] | x_ex_fwd_o[0] | x_wb_fwd_o[0]) + & ~(x_rs_addr_i[0] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[0] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[1] = (~scoreboard_q[x_rs_addr_i[1]] | x_ex_fwd_o[1] | x_wb_fwd_o[1]) + & ~(x_rs_addr_i[1] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[1] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[2] = (~scoreboard_q[x_rs_addr_i[2]] | x_ex_fwd_o[2] | x_wb_fwd_o[2]) + & ~(x_rs_addr_i[2] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[2] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[3] = (~scoreboard_q[x_rs_addr_i[0] | 5'b00001] | x_ex_fwd_o[3] | x_wb_fwd_o[3]) + & ~((x_rs_addr_i[0] | 5'b00001) == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~((x_rs_addr_i[0] | 5'b00001) == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[4] = (~scoreboard_q[x_rs_addr_i[1] | 5'b00001] | x_ex_fwd_o[4] | x_wb_fwd_o[4]) + & ~((x_rs_addr_i[1] | 5'b00001) == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~((x_rs_addr_i[1] | 5'b00001) == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[5] = (~scoreboard_q[x_rs_addr_i[2] | 5'b00001] | x_ex_fwd_o[5] | x_wb_fwd_o[5]) + & ~((x_rs_addr_i[2] | 5'b00001) == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~((x_rs_addr_i[2] | 5'b00001) == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_ecs_valid = 1'b1; // extension context status is not implemented in cv32e40px + end else begin + assign x_issue_req_rs_valid_o[0] = (~scoreboard_q[x_rs_addr_i[0]] | x_ex_fwd_o[0] | x_wb_fwd_o[0]) + & ~(x_rs_addr_i[0] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[0] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[1] = (~scoreboard_q[x_rs_addr_i[1]] | x_ex_fwd_o[1] | x_wb_fwd_o[1]) + & ~(x_rs_addr_i[1] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[1] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_rs_valid_o[2] = (~scoreboard_q[x_rs_addr_i[2]] | x_ex_fwd_o[2] | x_wb_fwd_o[2]) + & ~(x_rs_addr_i[2] == mem_instr_waddr_ex_i & mem_instr_we_ex_i) & ~(x_rs_addr_i[2] == waddr_wb_i & ~ex_valid_i); + assign x_issue_req_ecs_valid = 1'b1; // extension context status is not implemented in cv32e40px + end + endgenerate // commit interface assign x_commit_valid_o = x_issue_valid_o; assign x_commit_id_o = id_q; @@ -140,22 +159,46 @@ module cv32e40px_x_disp // core stall signal assign x_stall_o = dep | outstanding_mem | x_if_not_ready | x_if_memory_instr | illegal_forwarding_prevention; - assign dep = ~x_illegal_insn_o & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) - | (regs_used_i[1] & scoreboard_q[x_rs_addr_i[1]] & (x_result_rd_i != x_rs_addr_i[1])) - | (regs_used_i[2] & scoreboard_q[x_rs_addr_i[2]] & (x_result_rd_i != x_rs_addr_i[2]))); + assign outstanding_mem = data_req_dec_i & (mem_counter_q != '0); assign x_if_memory_instr = x_mem_data_req_o & ~(x_issue_valid_o & x_issue_ready_i); assign x_if_not_ready = x_issue_valid_o & ~x_issue_ready_i; - assign illegal_forwarding_prevention = x_result_valid_i & (x_ex_fwd_o[0] | x_ex_fwd_o[1] | x_ex_fwd_o[2]); + assign illegal_forwarding_prevention = x_result_valid_i & (|x_ex_fwd_o); // forwarding - assign x_ex_fwd_o[0] = x_rs_addr_i[0] == waddr_ex_i & we_ex_i & ex_valid_i; - assign x_ex_fwd_o[1] = x_rs_addr_i[1] == waddr_ex_i & we_ex_i & ex_valid_i; - assign x_ex_fwd_o[2] = x_rs_addr_i[2] == waddr_ex_i & we_ex_i & ex_valid_i; - assign x_wb_fwd_o[0] = x_rs_addr_i[0] == waddr_wb_i & we_wb_i & ex_valid_i; - assign x_wb_fwd_o[1] = x_rs_addr_i[1] == waddr_wb_i & we_wb_i & ex_valid_i; - assign x_wb_fwd_o[2] = x_rs_addr_i[2] == waddr_wb_i & we_wb_i & ex_valid_i; + generate + if (X_DUALREAD != 0) begin + assign x_ex_fwd_o[0] = x_rs_addr_i[0] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_ex_fwd_o[1] = x_rs_addr_i[1] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_ex_fwd_o[2] = x_rs_addr_i[2] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_ex_fwd_o[3] = (x_rs_addr_i[0] | 5'b00001) == waddr_ex_i & we_ex_i & ex_valid_i & x_issue_resp_dualread_i[0]; + assign x_ex_fwd_o[4] = (x_rs_addr_i[1] | 5'b00001) == waddr_ex_i & we_ex_i & ex_valid_i & x_issue_resp_dualread_i[1]; + assign x_ex_fwd_o[5] = (x_rs_addr_i[2] | 5'b00001) == waddr_ex_i & we_ex_i & ex_valid_i & x_issue_resp_dualread_i[2]; + assign x_wb_fwd_o[0] = x_rs_addr_i[0] == waddr_wb_i & we_wb_i & ex_valid_i; + assign x_wb_fwd_o[1] = x_rs_addr_i[1] == waddr_wb_i & we_wb_i & ex_valid_i; + assign x_wb_fwd_o[2] = x_rs_addr_i[2] == waddr_wb_i & we_wb_i & ex_valid_i; + assign x_wb_fwd_o[3] = (x_rs_addr_i[0] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[0]; + assign x_wb_fwd_o[4] = (x_rs_addr_i[1] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[1]; + assign x_wb_fwd_o[5] = (x_rs_addr_i[2] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[2]; + assign dep = ~x_illegal_insn_o & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) + | (regs_used_i[1] & scoreboard_q[x_rs_addr_i[1]] & (x_result_rd_i != x_rs_addr_i[1])) + | (regs_used_i[2] & scoreboard_q[x_rs_addr_i[2]] & (x_result_rd_i != x_rs_addr_i[2])) + | (((regs_used_i[0] & x_issue_resp_dualread_i[0]) & scoreboard_q[x_rs_addr_i[0] | 5'b00001] & (x_result_rd_i != (x_rs_addr_i[0] | 5'b00001))) & x_issue_resp_dualread_i[0]) + | (((regs_used_i[1] & x_issue_resp_dualread_i[1]) & scoreboard_q[x_rs_addr_i[1] | 5'b00001] & (x_result_rd_i != (x_rs_addr_i[1] | 5'b00001))) & x_issue_resp_dualread_i[1]) + | (((regs_used_i[2] & x_issue_resp_dualread_i[2]) & scoreboard_q[x_rs_addr_i[2] | 5'b00001] & (x_result_rd_i != (x_rs_addr_i[2] | 5'b00001))) & x_issue_resp_dualread_i[2])); + end else begin + assign x_ex_fwd_o[0] = x_rs_addr_i[0] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_ex_fwd_o[1] = x_rs_addr_i[1] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_ex_fwd_o[2] = x_rs_addr_i[2] == waddr_ex_i & we_ex_i & ex_valid_i; + assign x_wb_fwd_o[0] = x_rs_addr_i[0] == waddr_wb_i & we_wb_i & ex_valid_i; + assign x_wb_fwd_o[1] = x_rs_addr_i[1] == waddr_wb_i & we_wb_i & ex_valid_i; + assign x_wb_fwd_o[2] = x_rs_addr_i[2] == waddr_wb_i & we_wb_i & ex_valid_i; + assign dep = ~x_illegal_insn_o & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) + | (regs_used_i[1] & scoreboard_q[x_rs_addr_i[1]] & (x_result_rd_i != x_rs_addr_i[1])) + | (regs_used_i[2] & scoreboard_q[x_rs_addr_i[2]] & (x_result_rd_i != x_rs_addr_i[2]))); + end + endgenerate // id generation assign x_compressed_id_o = id_d; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/include/cv32e40px_core_v_xif_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/include/cv32e40px_core_v_xif_pkg.sv index 499fec31..678635d0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/include/cv32e40px_core_v_xif_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/include/cv32e40px_core_v_xif_pkg.sv @@ -15,6 +15,7 @@ package cv32e40px_core_v_xif_pkg; // cv-x-if parameters parameter int X_NUM_RS = 3; + parameter int X_DUALREAD = 0; // 0: single read, 1: dual read parameter int X_ID_WIDTH = 4; parameter int X_MEM_WIDTH = 32; parameter int X_RFR_WIDTH = 32; @@ -23,6 +24,8 @@ package cv32e40px_core_v_xif_pkg; parameter logic [1:0] X_ECS_XS = '0; localparam int XLEN = 32; + localparam int RF_READ_PORTS = (X_DUALREAD == 1) ? 2 * X_NUM_RS : X_NUM_RS; + typedef struct packed { logic [15:0] instr; // Offloaded compressed instruction @@ -39,8 +42,8 @@ package cv32e40px_core_v_xif_pkg; logic [31:0] instr; // Offloaded instruction logic [1:0] mode; // Privilege level logic [X_ID_WIDTH-1:0] id; // Identification of the offloaded instruction - logic [X_NUM_RS -1:0][X_RFR_WIDTH-1:0] rs; // Register file source operands for the offloaded instruction - logic [X_NUM_RS -1:0] rs_valid; // Validity of the register file source operand(s) + logic [RF_READ_PORTS-1:0][X_RFR_WIDTH-1:0] rs; // Register file source operands for the offloaded instruction + logic [RF_READ_PORTS-1:0] rs_valid; // Validity of the register file source operand(s) logic [5:0] ecs; // Extension Context Status ({mstatus.xs, mstatus.fs, mstatus.vs}) logic ecs_valid; // Validity of the Extension Context Status } x_issue_req_t; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi.sv index 07c75cf8..2be4df54 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/lowrisc_opentitan/hw/dv/dpi/uartdpi/uartdpi.sv @@ -84,11 +84,13 @@ module uartdpi #( `ifndef VCS `ifndef MODELSIM +`ifndef XCELIUM initial begin // Prevent falling edges of rx_i before reset causing spurious characters seen_reset = 0; end `endif +`endif `endif // RX diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/.readthedocs.yaml b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/.readthedocs.yaml new file mode 100644 index 00000000..00178f19 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/.readthedocs.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 OpenHW Group +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "3.9" + +# Build from the docs directory with Sphinx +sphinx: + configuration: doc/conf.py + +# Explicitly set the Python requirements +python: + install: + - requirements: doc/requirements.txt \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/bhv/cve2_sim_clock_gate.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/bhv/cve2_sim_clock_gate.sv index 8cc81dd3..7974cf92 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/bhv/cve2_sim_clock_gate.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/bhv/cve2_sim_clock_gate.sv @@ -27,4 +27,4 @@ module cve2_clock_gate ( assign clk_o = clk_i & clk_en; -endmodule // cv32e40p_clock_gate +endmodule // cve2_clock_gate diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cv32e20_manifest.flist b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cv32e20_manifest.flist new file mode 100644 index 00000000..4a0142d8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cv32e20_manifest.flist @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 OpenHW Group +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +/////////////////////////////////////////////////////////////////////////////// +// +// Manifest for the CV32E20 RTL model. +// - Format based on manifest used by other CORE-V cores. +// - Intended to be used by both synthesis and simulation. +// - Relevent synthesis and simulation scripts/Makefiles must set the shell +// ENV variable DESIGN_RTL_DIR as required. +// +// TODO: Replace once-and-for-all with unified manifest (FuseSoc?) +// +/////////////////////////////////////////////////////////////////////////////// + ++incdir+${DESIGN_RTL_DIR}/../shared/rtl/ ++incdir+${DESIGN_RTL_DIR}/../rtl ++incdir+${DESIGN_RTL_DIR}/../shared/rtl/sim ++incdir+${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/ip/prim/rtl ++incdir+${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/dv/sv/dv_utils + +${DESIGN_RTL_DIR}/cve2_pkg.sv +${DESIGN_RTL_DIR}/cve2_tracer_pkg.sv +${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv +${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv +${DESIGN_RTL_DIR}/cve2_alu.sv +${DESIGN_RTL_DIR}/cve2_compressed_decoder.sv +${DESIGN_RTL_DIR}/cve2_controller.sv +${DESIGN_RTL_DIR}/cve2_cs_registers.sv +${DESIGN_RTL_DIR}/cve2_csr.sv +${DESIGN_RTL_DIR}/cve2_counter.sv +${DESIGN_RTL_DIR}/cve2_decoder.sv +${DESIGN_RTL_DIR}/cve2_ex_block.sv +${DESIGN_RTL_DIR}/cve2_fetch_fifo.sv +${DESIGN_RTL_DIR}/cve2_id_stage.sv +${DESIGN_RTL_DIR}/cve2_if_stage.sv +${DESIGN_RTL_DIR}/cve2_load_store_unit.sv +${DESIGN_RTL_DIR}/cve2_multdiv_fast.sv +${DESIGN_RTL_DIR}/cve2_multdiv_slow.sv +${DESIGN_RTL_DIR}/cve2_prefetch_buffer.sv +${DESIGN_RTL_DIR}/cve2_pmp.sv +${DESIGN_RTL_DIR}/cve2_register_file_ff.sv +${DESIGN_RTL_DIR}/cve2_wb.sv +${DESIGN_RTL_DIR}/cve2_core.sv +${DESIGN_RTL_DIR}/cve2_top.sv +${DESIGN_RTL_DIR}/cve2_top_tracing.sv +${DESIGN_RTL_DIR}/cve2_tracer.sv + +${DESIGN_RTL_DIR}/../bhv/cve2_sim_clock_gate.sv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_configs.yaml b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_configs.yaml new file mode 100644 index 00000000..1dba358d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_configs.yaml @@ -0,0 +1,94 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Ibex configurations files, holds the parameter sets that are tested under CI. +# Each configuration must specify the same set of parameters + +# Two-stage pipeline without additional branch target ALU and 3 cycle multiplier +# (4 cycles for mulh), resulting in 2 stall cycles for mul (3 for mulh) +small: + RV32E : 0 + RV32M : "cve2_pkg::RV32MFast" + RV32B : "cve2_pkg::RV32BNone" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 0 + PMPEnable : 0 + PMPGranularity : 0 + PMPNumRegions : 4 + +# Configuration to match that used in the OpenTitan project +opentitan: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BOTEarlGrey" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 1 + PMPGranularity : 0 + PMPNumRegions : 16 + +# =============================== +# * EXPERIMENTAL CONFIGURATIONS * +# =============================== + +# Three-stage pipeline with additional branch traget ALU and 1 cycle multiplier +# (2 cycles for mulh) so mul does not stall (mulh stall 1 cycles). This is the +# maximum performance configuration. +experimental-maxperf: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BNone" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 0 + PMPGranularity : 0 + PMPNumRegions : 4 + +# experimental-maxperf config above plus PMP enabled with 16 regions. +experimental-maxperf-pmp: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BNone" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 1 + PMPGranularity : 0 + PMPNumRegions : 16 + +# experimental-maxperf-pmp config above with balanced bitmanip extension +experimental-maxperf-pmp-bmbalanced: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BBalanced" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 1 + PMPGranularity : 0 + PMPNumRegions : 16 + +# experimental-maxperf-pmp config above with full bitmanip extension +experimental-maxperf-pmp-bmfull: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BFull" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 1 + PMPGranularity : 0 + PMPNumRegions : 16 + +# experimental-maxperf with branch predictor switched on. This exists to allow +# easy use of Ibex with the branch predictor in particular for CI runs. The +# branch predictor will be enabled in all the 'maxperf' configs after further +# development. +experimental-branch-predictor: + RV32E : 0 + RV32M : "cve2_pkg::RV32MSingleCycle" + RV32B : "cve2_pkg::RV32BNone" + RegFile : "cve2_pkg::RegFileFF" + WritebackStage : 1 + PMPEnable : 0 + PMPGranularity : 0 + PMPNumRegions : 4 + diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_core.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_core.core new file mode 100644 index 00000000..6d621a43 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_core.core @@ -0,0 +1,115 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "openhwgroup:cve2:cve2_core:0.1" +description: "Ibex CPU Core Components" + +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + - openhwgroup:cve2:cve2_pkg + - lowrisc:dv:dv_fcov_macros + files: + - rtl/cve2_alu.sv + - rtl/cve2_branch_predict.sv + - rtl/cve2_compressed_decoder.sv + - rtl/cve2_controller.sv + - rtl/cve2_cs_registers.sv + - rtl/cve2_csr.sv + - rtl/cve2_counter.sv + - rtl/cve2_decoder.sv + - rtl/cve2_ex_block.sv + - rtl/cve2_fetch_fifo.sv + - rtl/cve2_id_stage.sv + - rtl/cve2_if_stage.sv + - rtl/cve2_load_store_unit.sv + - rtl/cve2_multdiv_fast.sv + - rtl/cve2_multdiv_slow.sv + - rtl/cve2_prefetch_buffer.sv + - rtl/cve2_pmp.sv + - rtl/cve2_wb.sv + - rtl/cve2_core.sv + - rtl/cve2_pmp_reset_default.svh: {is_include_file: true} + file_type: systemVerilogSource + + files_lint_verilator: + files: + - lint/verilator_waiver.vlt: {file_type: vlt} + + files_lint_verible: + files: + - lint/verible_waiver.vbw: {file_type: veribleLintWaiver} + + files_check_tool_requirements: + depend: + - lowrisc:tool:check_tool_requirements + +parameters: + RVFI: + datatype: bool + paramtype: vlogdefine + + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + + FPGA_XILINX: + datatype: bool + description: Identifies Xilinx FPGA targets to set DSP pragmas for performance counters. + default: false + paramtype: vlogdefine + + RV32E: + datatype: int + default: 0 + paramtype: vlogparam + + RV32M: + datatype: str + default: cve2_pkg::RV32MFast + paramtype: vlogdefine + description: "RV32M implementation parameter enum. See the cve2_pkg::rv32m_e enum in cve2_pkg.sv for permitted values." + + RV32B: + datatype: str + default: cve2_pkg::RV32BNone + paramtype: vlogdefine + description: "Bitmanip implementation parameter enum. See the cve2_pkg::rv32b_e enum in cve2_pkg.sv for permitted values." + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_lint_verilator) + - tool_veriblelint ? (files_lint_verible) + - files_rtl + toplevel: cve2_core + parameters: + - tool_vivado ? (FPGA_XILINX=true) + lint: + <<: *default_target + parameters: + - SYNTHESIS=true + - RVFI=true + default_tool: verilator + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall" + # RAM primitives wider than 64bit (required for ECC) fail to build in + # Verilator without increasing the unroll count (see Verilator#1266) + - "--unroll-count 72" + format: + filesets: + - files_rtl + parameters: + - SYNTHESIS=true + - RVFI=true + default_tool: veribleformat + toplevel: cve2_core + tools: + veribleformat: + verible_format_args: + - "--inplace" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_icache.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_icache.core new file mode 100644 index 00000000..ad2c2617 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_icache.core @@ -0,0 +1,22 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:cve2:cve2_icache:0.1" +description: "Ibex instruction cache" +filesets: + files_rtl: + depend: + - lowrisc:prim:secded + - lowrisc:prim:assert + - lowrisc:cve2:cve2_pkg + files: + - rtl/cve2_icache.sv + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - files_rtl + toplevel: cve2_icache + default_tool: vcs diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_multdiv.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_multdiv.core new file mode 100644 index 00000000..700e6c9e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_multdiv.core @@ -0,0 +1,28 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:cve2:cve2_multdiv:0.1" +description: "Multiplier and divider" + +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + - lowrisc:cve2:cve2_pkg + files: + - rtl/cve2_multdiv_fast.sv + - rtl/cve2_multdiv_slow.sv + file_type: systemVerilogSource + +parameters: + RV32M: + datatype: int + default: 2 + paramtype: vlogparam + description: "Selection of multiplication implementation. Switch to enable single cycle multiplications." + +targets: + default: &default_target + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/ibex_pkg.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_pkg.core similarity index 73% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/ibex_pkg.core rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_pkg.core index 17f47e08..a89c9e12 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/ibex_pkg.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_pkg.core @@ -2,13 +2,13 @@ CAPI=2: # Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:ibex:ibex_pkg:0.1" -description: "Header package for Ibex" +name: "openhwgroup:cve2:cve2_pkg:0.1" +description: "Header package for CVE2" filesets: files_rtl: files: - - rtl/ibex_pkg.sv + - rtl/cve2_pkg.sv file_type: systemVerilogSource targets: diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top.core new file mode 100644 index 00000000..0d9d2c5c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top.core @@ -0,0 +1,115 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "openhwgroup:cve2:cve2_top:0.1" +description: "Ibex, a small RV32 CPU core" + +filesets: + files_rtl: + depend: + - openhwgroup:cve2:cve2_pkg + - openhwgroup:cve2:cve2_core + - lowrisc:prim:buf + - lowrisc:prim:clock_mux2 + - lowrisc:prim:flop + - lowrisc:prim:ram_1p_scr + files: + - rtl/cve2_register_file_ff.sv # generic FF-based + - rtl/cve2_top.sv + file_type: systemVerilogSource + + files_lint_verilator: + files: + - lint/verilator_waiver.vlt: {file_type: vlt} + + files_lint_verible: + files: + - lint/verible_waiver.vbw: {file_type: veribleLintWaiver} + + files_check_tool_requirements: + depend: + - lowrisc:tool:check_tool_requirements + + files_clk_gate: + files: + - bhv/cve2_sim_clock_gate.sv + file_type: systemVerilogSource + +parameters: + RVFI: + datatype: bool + paramtype: vlogdefine + + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + + FPGA_XILINX: + datatype: bool + description: Identifies Xilinx FPGA targets to set DSP pragmas for performance counters. + default: false + paramtype: vlogdefine + + RV32E: + datatype: int + default: 0 + paramtype: vlogparam + + RV32M: + datatype: str + default: cve2_pkg::RV32MFast + paramtype: vlogdefine + description: "RV32M implementation parameter enum. See the cve2_pkg::rv32m_e enum in cve2_pkg.sv for permitted values." + + RV32B: + datatype: str + default: cve2_pkg::RV32BNone + paramtype: vlogdefine + description: "Bitmanip implementation parameter enum. See the cve2_pkg::rv32b_e enum in cve2_pkg.sv for permitted values." + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_lint_verilator) + - tool_veriblelint ? (files_lint_verible) + - files_rtl + - target_sim ? (files_clk_gate) + - target_sim_sc ? (files_clk_gate) + toplevel: cve2_top + parameters: + - tool_vivado ? (FPGA_XILINX=true) + + lint: + <<: *default_target + parameters: + - SYNTHESIS=true + - RVFI=true + filesets_append: + - files_clk_gate + default_tool: verilator + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall" + # RAM primitives wider than 64bit (required for ECC) fail to build in + # Verilator without increasing the unroll count (see Verilator#1266) + - "--unroll-count 72" + + format: + filesets: + - files_rtl + parameters: + - SYNTHESIS=true + - RVFI=true + default_tool: veribleformat + toplevel: cve2_top + tools: + veribleformat: + verible_format_args: + - "--inplace" + - "--formal_parameters_indentation=indent" + - "--named_parameter_indentation=indent" + - "--named_port_indentation=indent" + - "--port_declarations_indentation=indent" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top_tracing.core similarity index 52% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2.core rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top_tracing.core index ec43f9cb..65d2b5b7 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_top_tracing.core @@ -2,68 +2,28 @@ CAPI=2: # Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 - -name: "openhwgroup.org:ip:cve2" -description: "OpenHW Group RISC-V Core CVE2" - +name: "lowrisc:cve2:cve2_top_tracing:0.1" +description: "Ibex, a small RV32 CPU core with tracing enabled" filesets: files_rtl: depend: - - lowrisc:prim:assert - - lowrisc:ibex:ibex_pkg - files: - - rtl/ibex_alu.sv - - rtl/ibex_branch_predict.sv - - rtl/ibex_compressed_decoder.sv - - rtl/ibex_controller.sv - - rtl/ibex_cs_registers.sv - - rtl/ibex_csr.sv - - rtl/ibex_counter.sv - - rtl/ibex_decoder.sv - - rtl/ibex_ex_block.sv - - rtl/ibex_fetch_fifo.sv - - rtl/ibex_id_stage.sv - - rtl/ibex_if_stage.sv - - rtl/ibex_load_store_unit.sv - - rtl/ibex_multdiv_fast.sv - - rtl/ibex_multdiv_slow.sv - - rtl/ibex_prefetch_buffer.sv - - rtl/ibex_pmp.sv - - rtl/ibex_wb_stage.sv - - rtl/ibex_dummy_instr.sv - - rtl/ibex_core.sv - - rtl/cve2_sleep_unit.sv - - rtl/ibex_pmp_reset_default.svh: {is_include_file: true} - file_type: systemVerilogSource - - files_lint_verilator: - files: - - lint/verilator_waiver.vlt: {file_type: vlt} - - files_lint_verible: - files: - - lint/verible_waiver.vbw: {file_type: veribleLintWaiver} - - files_clk_gate: + - lowrisc:cve2:cve2_top + - lowrisc:cve2:cve2_tracer files: - - bhv/cve2_sim_clock_gate.sv + - rtl/cve2_top_tracing.sv file_type: systemVerilogSource parameters: + # The tracer uses the RISC-V Formal Interface (RVFI) to collect trace signals. RVFI: datatype: bool paramtype: vlogdefine + default: true SYNTHESIS: datatype: bool paramtype: vlogdefine - FPGA_XILINX: - datatype: bool - description: Identifies Xilinx FPGA targets to set DSP pragmas for performance counters. - default: false - paramtype: vlogdefine - RV32E: datatype: int default: 0 @@ -71,21 +31,21 @@ parameters: RV32M: datatype: str - default: ibex_pkg::RV32MFast + default: cve2_pkg::RV32MFast paramtype: vlogdefine - description: "RV32M implementation parameter enum. See the ibex_pkg::rv32m_e enum in ibex_pkg.sv for permitted values." + description: "RV32M implementation parameter enum. See the cve2_pkg::rv32m_e enum in cve2_pkg.sv for permitted values." RV32B: datatype: str - default: ibex_pkg::RV32BNone + default: cve2_pkg::RV32BNone paramtype: vlogdefine - description: "Bitmanip implementation parameter enum. See the ibex_pkg::rv32b_e enum in ibex_pkg.sv for permitted values." + description: "Bitmanip implementation parameter enum. See the cve2_pkg::rv32b_e enum in cve2_pkg.sv for permitted values." RegFile: datatype: str - default: ibex_pkg::RegFileFF + default: cve2_pkg::RegFileFF paramtype: vlogdefine - description: "Register file implementation parameter enum. See the ibex_pkg::regfile_e enum in ibex_pkg.sv for permitted values." + description: "Register file implementation parameter enum. See the cve2_pkg::regfile_e enum in cve2_pkg.sv for permitted values." ICache: datatype: int @@ -99,29 +59,23 @@ parameters: paramtype: vlogparam description: "Enable ECC protection in instruction cache" - BranchTargetALU: - datatype: int - default: 0 - paramtype: vlogparam - description: "Enables separate branch target ALU (increasing branch performance EXPERIMENTAL) [0/1]" - WritebackStage: datatype: int default: 0 paramtype: vlogparam description: "Enables third pipeline stage (EXPERIMENTAL) [0/1]" - BranchPredictor: + SecureCVE2: datatype: int - paramtype: vlogparam default: 0 - description: "Enables static branch prediction (EXPERIMENTAL)" + paramtype: vlogparam + description: "Enables security hardening features (EXPERIMENTAL) [0/1]" - SecureIbex: + ICacheScramble: datatype: int default: 0 paramtype: vlogparam - description: "Enables security hardening features (EXPERIMENTAL) [0/1]" + description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]" PMPEnable: datatype: int @@ -144,19 +98,28 @@ parameters: targets: default: &default_target filesets: - - tool_verilator ? (files_lint_verilator) - - tool_veriblelint ? (files_lint_verible) - files_rtl - - target_sim? (files_clk_gate) - - target_sim-opt? (files_clk_gate) - toplevel: ibex_core parameters: - - tool_vivado ? (FPGA_XILINX=true) + - RVFI=true + toplevel: cve2_top_tracing + lint: <<: *default_target parameters: - - SYNTHESIS=true - RVFI=true + - SYNTHESIS=true + - RV32E + - RV32M + - RV32B + - RegFile + - ICache + - ICacheECC + - WritebackStage + - SecureCVE2 + - ICacheScramble + - PMPEnable + - PMPGranularity + - PMPNumRegions default_tool: verilator tools: verilator: @@ -173,8 +136,12 @@ targets: - SYNTHESIS=true - RVFI=true default_tool: veribleformat - toplevel: ibex_core + toplevel: cve2_top_tracing tools: veribleformat: verible_format_args: - "--inplace" + - "--formal_parameters_indentation=indent" + - "--named_parameter_indentation=indent" + - "--named_port_indentation=indent" + - "--port_declarations_indentation=indent" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_tracer.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_tracer.core new file mode 100644 index 00000000..0e43a806 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/cve2_tracer.core @@ -0,0 +1,20 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:cve2:cve2_tracer:0.1" +description: "Tracer for use with Ibex using the RVFI interface" +filesets: + files_rtl: + depend: + - lowrisc:prim:assert + - lowrisc:cve2:cve2_pkg + files: + - rtl/cve2_tracer_pkg.sv + - rtl/cve2_tracer.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/lint/verilator_waiver.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/lint/verilator_waiver.vlt index b7c952ca..bac40c20 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/lint/verilator_waiver.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/lint/verilator_waiver.vlt @@ -12,7 +12,7 @@ `verilator_config lint_off -rule PINCONNECTEMPTY -// We have some boolean top-level parameters in e.g. ibex_core_tracing.sv. +// We have some boolean top-level parameters in e.g. cve2_core_tracing.sv. // When building with fusesoc, these get set with defines like // -GRV32M=1 (rather than -GRV32M=1'b1), leading to warnings like: // @@ -23,13 +23,13 @@ lint_off -rule PINCONNECTEMPTY // matches when you set a 1-bit value to a literal 1, so it won't hide // silly mistakes like setting it to 2. // -lint_off -rule WIDTH -file "*/rtl/ibex_top_tracing.sv" +lint_off -rule WIDTH -file "*/rtl/cve2_top_tracing.sv" -match "*expects 1 bits*Initial value's CONST '32'h1'*" // Operator expects 1 bit on initial value but initial value's CONST generates // 32 bits, need a specific RV32B waiver as it uses enums so the above catch-all // waiver doesn't work. -lint_off -rule WIDTH -file "*/rtl/ibex_top_tracing.sv" -match "*'RV32B'*" +lint_off -rule WIDTH -file "*/rtl/cve2_top_tracing.sv" -match "*'RV32B'*" // Bits of signal are not used: be_i[3:1] // Bits of signal are not used: addr_i[31:10,1:0] @@ -52,21 +52,25 @@ lint_off -rule UNUSED -file "*/rtl/timer.sv" -match "*'timer_addr_i'[31:10]*" // Signal is not used: clk_i // leaving clk and reset connected in-case we want to add assertions -lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*clk_i*" -lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*clk_i*" -lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*clk_i*" -lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/cve2_pmp.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/cve2_compressed_decoder.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/cve2_decoder.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/cve2_branch_predict.sv" -match "*clk_i*" // Signal is not used: rst_ni // leaving clk and reset connected in-case we want to add assertions -lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*rst_ni*" -lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*rst_ni*" -lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*rst_ni*" -lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/cve2_pmp.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/cve2_compressed_decoder.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/cve2_decoder.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/cve2_branch_predict.sv" -match "*rst_ni*" // Temporary waivers until OpenTitan primitives are lint-clean // https://github.com/lowRISC/opentitan/issues/2313 lint_off -file "*/lowrisc_prim_*/rtl/*.sv" -lint_off -rule UNUSED -file "*/rtl/ibex_top_tracing.sv" -match "*RndCnstLfsrSeed*" -lint_off -rule UNUSED -file "*/rtl/ibex_top_tracing.sv" -match "*RndCnstLfsrPerm*" +lint_off -rule UNUSED -file "*/rtl/cve2_top_tracing.sv" -match "*RndCnstLfsrSeed*" +lint_off -rule UNUSED -file "*/rtl/cve2_top_tracing.sv" -match "*RndCnstLfsrPerm*" +lint_off -rule DECLFILENAME -file "*/bhv/cve2_sim_clock_gate.sv" -match "Filename 'cve2_sim_clock_gate' does not match MODULE name: 'cve2_clock_gate'" +lint_off -rule UNOPTFLAT -file "*/rtl/cve2_core.sv" -match "Signal unoptimizable: Feedback to clock or circular logic: 'cve2_top.u_cve2_core.irqs'" +lint_off -rule UNUSED -file "*/rtl/cve2_wb.sv" -match "Signal is not used: 'clk_i'*" +lint_off -rule UNUSED -file "*/rtl/cve2_wb.sv" -match "Signal is not used: 'rst_ni'*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_alu.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_alu.sv similarity index 99% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_alu.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_alu.sv index eb6afcae..2471c621 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_alu.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_alu.sv @@ -6,10 +6,10 @@ /** * Arithmetic logic unit */ -module ibex_alu #( - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone +module cve2_alu #( + parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( - input ibex_pkg::alu_op_e operator_i, + input cve2_pkg::alu_op_e operator_i, input logic [31:0] operand_a_i, input logic [31:0] operand_b_i, @@ -31,7 +31,7 @@ module ibex_alu #( output logic comparison_result_o, output logic is_equal_result_o ); - import ibex_pkg::*; + import cve2_pkg::*; logic [31:0] operand_a_rev; logic [32:0] operand_b_neg; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_branch_predict.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_branch_predict.sv similarity index 98% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_branch_predict.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_branch_predict.sv index 87f83836..e49c7007 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_branch_predict.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_branch_predict.sv @@ -17,7 +17,7 @@ `include "prim_assert.sv" -module ibex_branch_predict ( +module cve2_branch_predict ( input logic clk_i, input logic rst_ni, @@ -30,7 +30,7 @@ module ibex_branch_predict ( output logic predict_branch_taken_o, output logic [31:0] predict_branch_pc_o ); - import ibex_pkg::*; + import cve2_pkg::*; logic [31:0] imm_j_type; logic [31:0] imm_b_type; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_compressed_decoder.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_compressed_decoder.sv similarity index 99% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_compressed_decoder.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_compressed_decoder.sv index e3c6aa52..1b5b17ff 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_compressed_decoder.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_compressed_decoder.sv @@ -13,7 +13,7 @@ `include "prim_assert.sv" -module ibex_compressed_decoder ( +module cve2_compressed_decoder ( input logic clk_i, input logic rst_ni, input logic valid_i, @@ -22,7 +22,7 @@ module ibex_compressed_decoder ( output logic is_compressed_o, output logic illegal_instr_o ); - import ibex_pkg::*; + import cve2_pkg::*; // valid_i indicates if instr_i is valid and is used for assertions only. // The following signal is used to avoid possible lint errors. diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_controller.sv similarity index 82% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_controller.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_controller.sv index 0f2ae7bc..fba4352f 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_controller.sv @@ -8,15 +8,14 @@ */ `include "prim_assert.sv" -//`include "dv_fcov_macros.svh" +`include "dv_fcov_macros.svh" -module ibex_controller #( - parameter bit WritebackStage = 0, - parameter bit BranchPredictor = 0 +module cve2_controller #( ) ( input logic clk_i, input logic rst_ni, + input logic fetch_enable_i, // core can fetch instructions leave RESET state output logic ctrl_busy_o, // core is busy processing instrs // decoder related signals @@ -33,7 +32,6 @@ module ibex_controller #( input logic [31:0] instr_i, // uncompressed instr data for mtval input logic [15:0] instr_compressed_i, // instr compressed data for mtval input logic instr_is_compressed_i, // instr is compressed - input logic instr_bp_taken_i, // instr was predicted taken branch input logic instr_fetch_err_i, // instr has error input logic instr_fetch_err_plus2_i, // instr error is x32 input logic [31:0] pc_id_i, // instr address @@ -47,37 +45,32 @@ module ibex_controller #( // to prefetcher output logic instr_req_o, // start fetching instructions output logic pc_set_o, // jump to address set by pc_mux - output ibex_pkg::pc_sel_e pc_mux_o, // IF stage fetch address selector + output cve2_pkg::pc_sel_e pc_mux_o, // IF stage fetch address selector // (boot, normal, exception...) - output logic nt_branch_mispredict_o, // Not-taken branch in ID/EX was - // mispredicted (predicted taken) - output ibex_pkg::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC - output ibex_pkg::exc_cause_e exc_cause_o, // for IF stage, CSRs + output cve2_pkg::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC + output cve2_pkg::exc_cause_e exc_cause_o, // for IF stage, CSRs // LSU input logic [31:0] lsu_addr_last_i, // for mtval input logic load_err_i, input logic store_err_i, - output logic wb_exception_o, // Instruction in WB taking an exception - output logic id_exception_o, // Instruction in ID taking an exception // jump/branch signals input logic branch_set_i, // branch set signal (branch definitely // taken) - input logic branch_not_set_i, // branch is definitely not taken input logic jump_set_i, // jump taken set signal // interrupt signals input logic csr_mstatus_mie_i, // M-mode interrupt enable bit input logic irq_pending_i, // interrupt request pending - input ibex_pkg::irqs_t irqs_i, // interrupt requests qualified with + input cve2_pkg::irqs_t irqs_i, // interrupt requests qualified with // mie CSR input logic irq_nm_i, // non-maskeable interrupt output logic nmi_mode_o, // core executing NMI handler // debug signals input logic debug_req_i, - output ibex_pkg::dbg_cause_e debug_cause_o, + output cve2_pkg::dbg_cause_e debug_cause_o, output logic debug_csr_save_o, output logic debug_mode_o, input logic debug_single_step_i, @@ -85,24 +78,18 @@ module ibex_controller #( input logic debug_ebreaku_i, input logic trigger_match_i, - // Wakeup Signal - output logic wake_from_sleep_o, - output logic csr_save_if_o, output logic csr_save_id_o, - output logic csr_save_wb_o, output logic csr_restore_mret_id_o, output logic csr_restore_dret_id_o, output logic csr_save_cause_o, output logic [31:0] csr_mtval_o, - input ibex_pkg::priv_lvl_e priv_mode_i, + input cve2_pkg::priv_lvl_e priv_mode_i, input logic csr_mstatus_tw_i, // stall & flush signals input logic stall_id_i, - input logic stall_wb_i, output logic flush_id_o, - input logic ready_wb_i, // performance monitors output logic perf_jump_o, // we are executing a jump @@ -110,7 +97,7 @@ module ibex_controller #( output logic perf_tbranch_o // we are executing a taken branch // instruction ); - import ibex_pkg::*; + import cve2_pkg::*; // FSM state encoding typedef enum logic [3:0] { @@ -153,8 +140,6 @@ module ibex_controller #( logic enter_debug_mode; logic ebreak_into_debug; logic handle_irq; - logic id_wb_pending; - logic [3:0] mfip_id; logic unused_irq_timer; @@ -173,8 +158,8 @@ module ibex_controller #( always_ff @(negedge clk_i) begin // print warning in case of decoding errors if ((ctrl_fsm_cs == DECODE) && instr_valid_i && !instr_fetch_err_i && illegal_insn_d) begin - $display("%t: Illegal instruction (hart %0x) at PC 0x%h: 0x%h", $time, ibex_core.hart_id_i, - ibex_id_stage.pc_id_i, ibex_id_stage.instr_rdata_i); + $display("%m @ %t: Illegal instruction (hart %0x) at PC 0x%h: 0x%h", $time, cve2_core.hart_id_i, + cve2_id_stage.pc_id_i, cve2_id_stage.instr_rdata_i); end end // synopsys translate_on @@ -206,7 +191,7 @@ module ibex_controller #( (mret_insn | (csr_mstatus_tw_i & wfi_insn)); // This is recorded in the illegal_insn_q flop to help timing. Specifically - // it is needed to break the path from ibex_cs_registers/illegal_csr_insn_o + // it is needed to break the path from cve2_cs_registers/illegal_csr_insn_o // to pc_set_o. Clear when controller is in FLUSH so it won't remain set // once illegal instruction is handled. // All terms in this expression are qualified by instr_valid_i @@ -223,8 +208,6 @@ module ibex_controller #( // LSU exception requests assign exc_req_lsu = store_err_i | load_err_i; - assign id_exception_o = exc_req_d; - // special requests: special instructions, pipeline flushes, exceptions... // All terms in these expressions are qualified by instr_valid_i except exc_req_lsu which can come // from the Writeback stage with no instr_valid_i from the ID stage @@ -239,40 +222,7 @@ module ibex_controller #( // generic special request signal, applies to all instructions assign special_req = special_req_pc_change | special_req_flush_only; - // Is there an instruction in ID or WB that has yet to complete? - assign id_wb_pending = instr_valid_i | ~ready_wb_i; - // Exception/fault prioritisation is taken from Table 3.7 of Priviledged Spec v1.11 - if (WritebackStage) begin : g_wb_exceptions - always_comb begin - instr_fetch_err_prio = 0; - illegal_insn_prio = 0; - ecall_insn_prio = 0; - ebrk_insn_prio = 0; - store_err_prio = 0; - load_err_prio = 0; - - // Note that with the writeback stage store/load errors occur on the instruction in writeback, - // all other exception/faults occur on the instruction in ID/EX. The faults from writeback - // must take priority as that instruction is architecurally ordered before the one in ID/EX. - if (store_err_q) begin - store_err_prio = 1'b1; - end else if (load_err_q) begin - load_err_prio = 1'b1; - end else if (instr_fetch_err) begin - instr_fetch_err_prio = 1'b1; - end else if (illegal_insn_q) begin - illegal_insn_prio = 1'b1; - end else if (ecall_insn) begin - ecall_insn_prio = 1'b1; - end else if (ebrk_insn) begin - ebrk_insn_prio = 1'b1; - end - end - - // Instruction in writeback is generating an exception so instruction in ID must not execute - assign wb_exception_o = load_err_q | store_err_q | load_err_i | store_err_i; - end else begin : g_no_wb_exceptions always_comb begin instr_fetch_err_prio = 0; illegal_insn_prio = 0; @@ -295,8 +245,6 @@ module ibex_controller #( load_err_prio = 1'b1; end end - assign wb_exception_o = 1'b0; - end `ASSERT_IF(IbexExceptionPrioOnehot, $onehot({instr_fetch_err_prio, @@ -346,6 +294,7 @@ module ibex_controller #( // - while in debug mode [Debug Spec v0.13.2, p.39], // - while in NMI mode (nested NMIs are not supported, NMI has highest priority and // cannot be interrupted by regular interrupts). + // - while single stepping. assign handle_irq = ~debug_mode_q & ~nmi_mode_q & (irq_nm_i | (irq_pending_i & csr_mstatus_mie_i)); @@ -353,7 +302,7 @@ module ibex_controller #( always_comb begin : gen_mfip_id mfip_id = 4'd0; - for (int i = 14; i >= 0; i--) begin + for (int i = 15; i >= 0; i--) begin if (irqs_i.irq_fast[i]) begin mfip_id = i[3:0]; end @@ -372,7 +321,6 @@ module ibex_controller #( csr_save_if_o = 1'b0; csr_save_id_o = 1'b0; - csr_save_wb_o = 1'b0; csr_restore_mret_id_o = 1'b0; csr_restore_dret_id_o = 1'b0; csr_save_cause_o = 1'b0; @@ -384,7 +332,6 @@ module ibex_controller #( // helping timing. pc_mux_o = PC_BOOT; pc_set_o = 1'b0; - nt_branch_mispredict_o = 1'b0; exc_pc_mux_o = EXC_PC_IRQ; exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00 @@ -412,9 +359,11 @@ module ibex_controller #( instr_req_o = 1'b0; pc_mux_o = PC_BOOT; pc_set_o = 1'b1; - ctrl_fsm_ns = BOOT_SET; + if (fetch_enable_i == 1'b1) + begin + ctrl_fsm_ns = BOOT_SET; + end end - BOOT_SET: begin // copy boot address to instr fetch address instr_req_o = 1'b1; @@ -441,13 +390,12 @@ module ibex_controller #( // normal execution flow // in debug mode or single step mode we leave immediately (wfi=nop) - if (wake_from_sleep_o) begin - ctrl_fsm_ns = FIRST_FETCH; + if (irq_nm_i || irq_pending_i || debug_req_i || debug_mode_q || debug_single_step_i) begin + ctrl_fsm_ns = FIRST_FETCH; end else begin // Make sure clock remains disabled. ctrl_busy_o = 1'b0; end - end FIRST_FETCH: begin @@ -497,40 +445,25 @@ module ibex_controller #( // FLUSH state. retain_id = 1'b1; - // Wait for the writeback stage to either be ready for a new instruction or raise its own - // exception before going to FLUSH. If the instruction in writeback raises an exception it - // must take priority over any exception from an instruction in ID/EX. Only once the - // writeback stage is ready can we be certain that won't happen. Without a writeback - // stage ready_wb_i == 1 so the FSM will always go directly to FLUSH. + // The FSM will always go directly to FLUSH. - if (ready_wb_i | wb_exception_o) begin - ctrl_fsm_ns = FLUSH; - end + ctrl_fsm_ns = FLUSH; end if (branch_set_i || jump_set_i) begin - // Only set the PC if the branch predictor hasn't already done the branch for us - pc_set_o = BranchPredictor ? ~instr_bp_taken_i : 1'b1; + pc_set_o = 1'b1; perf_tbranch_o = branch_set_i; perf_jump_o = jump_set_i; end - if (BranchPredictor) begin - if (instr_bp_taken_i & branch_not_set_i) begin - // If the instruction is a branch that was predicted to be taken but was not taken - // signal a mispredict. - nt_branch_mispredict_o = 1'b1; - end - end - // If entering debug mode or handling an IRQ the core needs to wait until any instruction in - // ID or WB has finished executing. Stall IF during that time. - if ((enter_debug_mode || handle_irq) && (stall || id_wb_pending)) begin + // ID has finished executing. Stall IF during that time. + if ((enter_debug_mode || handle_irq) && (stall || instr_valid_i)) begin halt_if = 1'b1; end - if (!stall && !special_req && !id_wb_pending) begin + if (!stall && !special_req && !instr_valid_i) begin if (enter_debug_mode) begin // enter debug mode ctrl_fsm_ns = DBG_TAKEN_IF; @@ -565,12 +498,13 @@ module ibex_controller #( if (irq_nm_i && !nmi_mode_q) begin exc_cause_o = EXC_CAUSE_IRQ_NM; nmi_mode_d = 1'b1; // enter NMI mode - end else if (irqs_i.irq_fast != 15'b0) begin + end else if (irqs_i.irq_fast != 16'b0) begin // generate exception cause ID from fast interrupt ID: // - first bit distinguishes interrupts from exceptions, - // - second bit adds 16 to fast interrupt ID - // for example EXC_CAUSE_IRQ_FAST_0 = {1'b1, 5'd16} - exc_cause_o = exc_cause_e'({2'b11, mfip_id}); + // - third bit adds 16 to fast interrupt ID so that the interrup 0 becomes 16 and the interrupt 15 becomes 31 (hence 5bits) + // - second bit is always 0 as the FAST interrupts are represented in the first 5bits, the 6th is always 0 cause is used by the NMI (in that case is 1 as represented by the number 32) + // for example EXC_CAUSE_IRQ_FAST_0 = {1'b1, 6'd16} + exc_cause_o = exc_cause_e'({3'b101, mfip_id}); end else if (irqs_i.irq_external) begin exc_cause_o = EXC_CAUSE_IRQ_EXTERNAL_M; end else if (irqs_i.irq_software) begin @@ -597,11 +531,11 @@ module ibex_controller #( csr_save_cause_o = 1'b1; if (trigger_match_i) begin - debug_cause_o = DBG_CAUSE_TRIGGER; - end else if (debug_single_step_i) begin - debug_cause_o = DBG_CAUSE_STEP; + debug_cause_o = DBG_CAUSE_TRIGGER; // (priority 4) + end else if (debug_req_i) begin + debug_cause_o = DBG_CAUSE_HALTREQ; // (priority 1) end else begin - debug_cause_o = DBG_CAUSE_HALTREQ; + debug_cause_o = DBG_CAUSE_STEP; // (priority 0, lowest) end // enter debug mode @@ -657,13 +591,7 @@ module ibex_controller #( pc_mux_o = PC_EXC; exc_pc_mux_o = debug_mode_q ? EXC_PC_DBG_EXC : EXC_PC_EXC; - if (WritebackStage) begin : g_writeback_mepc_save - // With the writeback stage present whether an instruction accessing memory will cause - // an exception is only known when it is in writeback. So when taking such an exception - // epc must come from writeback. - csr_save_id_o = ~(store_err_q | load_err_q); - csr_save_wb_o = store_err_q | load_err_q; - end else begin : g_no_writeback_mepc_save + begin : g_no_writeback_mepc_save csr_save_id_o = 1'b0; end @@ -742,9 +670,6 @@ module ibex_controller #( csr_restore_dret_id_o = 1'b1; end else if (wfi_insn) begin ctrl_fsm_ns = WAIT_SLEEP; - end else if (csr_pipe_flush && handle_irq) begin - // start handling IRQs when doing CSR-related pipeline flushes - ctrl_fsm_ns = IRQ_TAKEN; end end // exc_req_q @@ -754,9 +679,14 @@ module ibex_controller #( // Leave all other signals as is to ensure CSRs and PC get set as if // core was entering exception handler, entry to debug mode will then // see the appropriate state and setup dpc correctly. + // If an EBREAK instruction is causing us to enter debug mode on the // same cycle as a debug_req or single step, honor the EBREAK and - // proceed to DBG_TAKEN_ID. + // proceed to DBG_TAKEN_ID, as it has the highest priority. + // [Debug Spec v1.0.0-STABLE, p.53] + // cause==EBREAK -> prio 3 (highest) + // cause==debug_req -> prio 2 + // cause==step -> prio 1 (lowest) if (enter_debug_mode_prio_q && !(ebrk_insn_prio && ebreak_into_debug)) begin ctrl_fsm_ns = DBG_TAKEN_IF; end @@ -782,9 +712,8 @@ module ibex_controller #( /////////////////// // If high current instruction cannot complete this cycle. Either because it needs more cycles to - // finish (stall_id_i) or because the writeback stage cannot accept it yet (stall_wb_i). If there - // is no writeback stage stall_wb_i is a constant 0. - assign stall = stall_id_i | stall_wb_i; + // finish (stall_id_i) + assign stall = stall_id_i; // signal to IF stage that ID stage is ready for next instr assign id_in_ready_o = ~stall & ~halt_if & ~retain_id; @@ -821,27 +750,22 @@ module ibex_controller #( end end - assign wake_from_sleep_o = irq_nm_i || irq_pending_i || debug_req_i || debug_mode_q || debug_single_step_i; - - ////////// // FCOV // ////////// - //`DV_FCOV_SIGNAL(logic, interrupt_taken, (ctrl_fsm_cs != IRQ_TAKEN) & (ctrl_fsm_ns == IRQ_TAKEN)) - //`DV_FCOV_SIGNAL(logic, debug_entry_if, - // (ctrl_fsm_cs != DBG_TAKEN_IF) & (ctrl_fsm_ns == DBG_TAKEN_IF)) - //`DV_FCOV_SIGNAL(logic, debug_entry_id, - // (ctrl_fsm_cs != DBG_TAKEN_ID) & (ctrl_fsm_ns == DBG_TAKEN_ID)) - //`DV_FCOV_SIGNAL(logic, pipe_flush, (ctrl_fsm_cs != FLUSH) & (ctrl_fsm_ns == FLUSH)) - //`DV_FCOV_SIGNAL(logic, debug_req, debug_req_i & ~debug_mode_q) + `DV_FCOV_SIGNAL(logic, interrupt_taken, (ctrl_fsm_cs != IRQ_TAKEN) & (ctrl_fsm_ns == IRQ_TAKEN)) + `DV_FCOV_SIGNAL(logic, debug_entry_if, + (ctrl_fsm_cs != DBG_TAKEN_IF) & (ctrl_fsm_ns == DBG_TAKEN_IF)) + `DV_FCOV_SIGNAL(logic, debug_entry_id, + (ctrl_fsm_cs != DBG_TAKEN_ID) & (ctrl_fsm_ns == DBG_TAKEN_ID)) + `DV_FCOV_SIGNAL(logic, pipe_flush, (ctrl_fsm_cs != FLUSH) & (ctrl_fsm_ns == FLUSH)) + `DV_FCOV_SIGNAL(logic, debug_req, debug_req_i & ~debug_mode_q) //////////////// // Assertions // //////////////// - `ASSERT(AlwaysInstrClearOnMispredict, nt_branch_mispredict_o |-> instr_valid_clear_o) - // Selectors must be known/valid. `ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside { RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH, @@ -923,7 +847,7 @@ module ibex_controller #( `ifdef RVFI // Workaround for internal verilator error when using hierarchical refers to calcuate this - // directly in ibex_core + // directly in cve2_core logic rvfi_flush_next; assign rvfi_flush_next = ctrl_fsm_ns == FLUSH; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.f b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.f new file mode 100644 index 00000000..3250f707 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.f @@ -0,0 +1,17 @@ +cve2_pkg.sv +cve2_alu.sv +cve2_compressed_decoder.sv +cve2_controller.sv +cve2_counter.sv +cve2_cs_registers.sv +cve2_decoder.sv +cve2_ex_block.sv +cve2_id_stage.sv +cve2_if_stage.sv +cve2_load_store_unit.sv +cve2_multdiv_slow.sv +cve2_multdiv_fast.sv +cve2_prefetch_buffer.sv +cve2_fetch_fifo.sv +cve2_register_file_ff.sv +cve2_core.sv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv similarity index 73% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv index f57c87d9..4f79b67f 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv @@ -12,7 +12,7 @@ /** * Top level module of the ibex RISC-V core */ -module ibex_core import ibex_pkg::*; #( +module cve2_core import cve2_pkg::*; #( parameter bit PMPEnable = 1'b0, parameter int unsigned PMPGranularity = 0, parameter int unsigned PMPNumRegions = 4, @@ -21,23 +21,8 @@ module ibex_core import ibex_pkg::*; #( parameter bit RV32E = 1'b0, parameter rv32m_e RV32M = RV32MFast, parameter rv32b_e RV32B = RV32BNone, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter int unsigned BusSizeECC = BUS_SIZE, - parameter int unsigned TagSizeECC = IC_TAG_SIZE, - parameter int unsigned LineSizeECC = IC_LINE_SIZE, - parameter bit BranchPredictor = 1'b0, parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DbgHwBreakNum = 1, - parameter bit ResetAll = 1'b0, - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, - parameter bit SecureIbex = 1'b0, - parameter bit DummyInstructions = 1'b0, - parameter bit RegFileECC = 1'b0, - parameter int unsigned RegFileDataWidth = 32, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -45,6 +30,8 @@ module ibex_core import ibex_pkg::*; #( input logic clk_i, input logic rst_ni, + input logic test_en_i, + input logic [31:0] hart_id_i, input logic [31:0] boot_addr_i, @@ -67,34 +54,11 @@ module ibex_core import ibex_pkg::*; #( input logic [31:0] data_rdata_i, input logic data_err_i, - // Register file interface - output logic dummy_instr_id_o, - output logic [4:0] rf_raddr_a_o, - output logic [4:0] rf_raddr_b_o, - output logic [4:0] rf_waddr_wb_o, - output logic rf_we_wb_o, - output logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_o, - input logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_i, - input logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_i, - - // RAMs interface - output logic [IC_NUM_WAYS-1:0] ic_tag_req_o, - output logic ic_tag_write_o, - output logic [IC_INDEX_W-1:0] ic_tag_addr_o, - output logic [TagSizeECC-1:0] ic_tag_wdata_o, - input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS], - output logic [IC_NUM_WAYS-1:0] ic_data_req_o, - output logic ic_data_write_o, - output logic [IC_INDEX_W-1:0] ic_data_addr_o, - output logic [LineSizeECC-1:0] ic_data_wdata_o, - input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS], - input logic ic_scr_key_valid_i, - // Interrupt inputs input logic irq_software_i, input logic irq_timer_i, input logic irq_external_i, - input logic [14:0] irq_fast_i, + input logic [15:0] irq_fast_i, input logic irq_nm_i, // non-maskeable interrupt output logic irq_pending_o, @@ -103,7 +67,6 @@ module ibex_core import ibex_pkg::*; #( output crash_dump_t crash_dump_o, // SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC // SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC - output logic double_fault_seen_o, // RISC-V Formal Interface // Does not comply with the coding standards of _i/_o suffixes, but follows @@ -139,22 +102,14 @@ module ibex_core import ibex_pkg::*; #( `endif // CPU Control Signals - // SEC_CM: FETCH.CTRL.LC_GATED input logic fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_o, - output logic icache_inval_o, - output logic core_sleep_o + output logic core_busy_o ); localparam int unsigned PMP_NUM_CHAN = 3; // SEC_CM: CORE.DATA_REG_SW.SCA - localparam bit DataIndTiming = SecureIbex; - localparam bit PCIncrCheck = SecureIbex; - localparam bit ShadowCSR = 1'b0; // IF/ID signals - logic dummy_instr_id; logic instr_valid_id; logic instr_new_id; logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage @@ -163,33 +118,18 @@ module ibex_core import ibex_pkg::*; #( logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage logic instr_is_compressed_id; logic instr_perf_count_id; - logic instr_bp_taken_id; logic instr_fetch_err; // Bus error on instr fetch logic instr_fetch_err_plus2; // Instruction error is misaligned logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage logic [31:0] pc_if; // Program counter in IF stage logic [31:0] pc_id; // Program counter in ID stage - logic [31:0] pc_wb; // Program counter in WB stage logic [33:0] imd_val_d_ex[2]; // Intermediate register for multicycle Ops logic [33:0] imd_val_q_ex[2]; // Intermediate register for multicycle Ops logic [1:0] imd_val_we_ex; - logic data_ind_timing; - logic dummy_instr_en; - logic [2:0] dummy_instr_mask; - logic dummy_instr_seed_en; - logic [31:0] dummy_instr_seed; - logic icache_enable; - logic icache_inval; - logic icache_ecc_error; - logic pc_mismatch_alert; - logic csr_shadow_err; - logic instr_first_cycle_id; logic instr_valid_clear; logic pc_set; - logic nt_branch_mispredict; - logic [31:0] nt_branch_addr; pc_sel_e pc_mux_id; // Mux selector for next PC exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC exc_cause_e exc_cause; // Exception cause @@ -221,26 +161,19 @@ module ibex_core import ibex_pkg::*; #( logic [31:0] rf_wdata_wb; // Writeback register write data that can be used on the forwarding path (doesn't factor in memory // read data as this is too late for the forwarding path) - logic [31:0] rf_wdata_fwd_wb; logic [31:0] rf_wdata_lsu; logic rf_we_wb; logic rf_we_lsu; - logic rf_ecc_err_comb; logic [4:0] rf_waddr_id; logic [31:0] rf_wdata_id; logic rf_we_id; - logic rf_rd_a_wb_match; - logic rf_rd_b_wb_match; // ALU Control alu_op_e alu_operator_ex; logic [31:0] alu_operand_a_ex; logic [31:0] alu_operand_b_ex; - logic [31:0] bt_a_operand; - logic [31:0] bt_b_operand; - logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU logic [31:0] result_ex; @@ -253,7 +186,6 @@ module ibex_core import ibex_pkg::*; #( logic [1:0] multdiv_signed_mode_ex; logic [31:0] multdiv_operand_a_ex; logic [31:0] multdiv_operand_b_ex; - logic multdiv_ready_id; // CSR control logic csr_access; @@ -272,7 +204,6 @@ module ibex_core import ibex_pkg::*; #( logic lsu_sign_ext; logic lsu_req; logic [31:0] lsu_wdata; - logic lsu_req_done; // stall control logic id_in_ready; @@ -285,13 +216,8 @@ module ibex_core import ibex_pkg::*; #( logic instr_req_int; // Id stage asserts a req to instruction core interface logic instr_req_gated; - // Writeback stage - logic en_wb; - wb_instr_type_e instr_type_wb; - logic ready_wb; - logic rf_write_wb; - logic outstanding_load_wb; - logic outstanding_store_wb; + // Writeback + logic en_wb; // Interrupts logic nmi_mode; @@ -308,7 +234,6 @@ module ibex_core import ibex_pkg::*; #( logic csr_save_if; logic csr_save_id; - logic csr_save_wb; logic csr_restore_mret_id; logic csr_restore_dret_id; logic csr_save_cause; @@ -331,15 +256,12 @@ module ibex_core import ibex_pkg::*; #( // signals relating to instruction movements between pipeline stages // used by performance counters and RVFI logic instr_id_done; - logic instr_done_wb; logic perf_instr_ret_wb; logic perf_instr_ret_compressed_wb; - logic perf_instr_ret_wb_spec; - logic perf_instr_ret_compressed_wb_spec; logic perf_iside_wait; logic perf_dside_wait; - logic perf_mul_wait; + logic perf_wfi_wait; logic perf_div_wait; logic perf_jump; logic perf_branch; @@ -350,63 +272,23 @@ module ibex_core import ibex_pkg::*; #( // for RVFI logic illegal_insn_id, unused_illegal_insn_id; // ID stage sees an illegal instruction - ////////////////////////////////////////////////////////////////////////////////////////////// - // ____ _ _ __ __ _ // - // / ___| | ___ ___| | __ | \/ | __ _ _ __ __ _ __ _ ___ _ __ ___ ___ _ __ | |_ // - // | | | |/ _ \ / __| |/ / | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '_ ` _ \ / _ \ '_ \| __| // - // | |___| | (_) | (__| < | | | | (_| | | | | (_| | (_| | __/ | | | | | __/ | | | |_ // - // \____|_|\___/ \___|_|\_\ |_| |_|\__,_|_| |_|\__,_|\__, |\___|_| |_| |_|\___|_| |_|\__| // - // |___/ // - ////////////////////////////////////////////////////////////////////////////////////////////// - - logic clk; - logic fetch_enable; - logic wake_from_sleep; - - cve2_sleep_unit sleep_unit_i ( - // Clock, reset interface - .clk_ungated_i(clk_i), // Ungated clock - .rst_n (rst_ni), - .clk_gated_o (clk), // Gated clock - .scan_cg_en_i (1'b0), - - // Core sleep - .core_sleep_o(core_sleep_o), - - // Fetch enable - .fetch_enable_i(fetch_enable_i), - .fetch_enable_o(fetch_enable), - - // Core status - .if_busy_i (if_busy), - .ctrl_busy_i(ctrl_busy), - .lsu_busy_i (lsu_busy), - - // WFI wake - .wake_from_sleep_i(wake_from_sleep) - ); + ////////////////////// + // Clock management // + ////////////////////// + // Before going to sleep, wait for I- and D-side + // interfaces to finish ongoing operations. + assign core_busy_o = ctrl_busy | if_busy | lsu_busy; ////////////// // IF stage // ////////////// - ibex_if_stage #( + cve2_if_stage #( .DmHaltAddr (DmHaltAddr), - .DmExceptionAddr (DmExceptionAddr), - .DummyInstructions(DummyInstructions), - .ICache (ICache), - .ICacheECC (ICacheECC), - .BusSizeECC (BusSizeECC), - .TagSizeECC (TagSizeECC), - .LineSizeECC (LineSizeECC), - .PCIncrCheck (PCIncrCheck), - .ResetAll ( ResetAll ), - .RndCnstLfsrSeed ( RndCnstLfsrSeed ), - .RndCnstLfsrPerm ( RndCnstLfsrPerm ), - .BranchPredictor (BranchPredictor) + .DmExceptionAddr (DmExceptionAddr) ) if_stage_i ( - .clk_i (clk), + .clk_i (clk_i), .rst_ni(rst_ni), .boot_addr_i(boot_addr_i), @@ -420,18 +302,6 @@ module ibex_core import ibex_pkg::*; #( .instr_rdata_i (instr_rdata_i), .instr_err_i (instr_err_i), - .ic_tag_req_o (ic_tag_req_o), - .ic_tag_write_o (ic_tag_write_o), - .ic_tag_addr_o (ic_tag_addr_o), - .ic_tag_wdata_o (ic_tag_wdata_o), - .ic_tag_rdata_i (ic_tag_rdata_i), - .ic_data_req_o (ic_data_req_o), - .ic_data_write_o (ic_data_write_o), - .ic_data_addr_o (ic_data_addr_o), - .ic_data_wdata_o (ic_data_wdata_o), - .ic_data_rdata_i (ic_data_rdata_i), - .ic_scr_key_valid_i(ic_scr_key_valid_i), - // outputs to ID stage .instr_valid_id_o (instr_valid_id), .instr_new_id_o (instr_new_id), @@ -439,11 +309,9 @@ module ibex_core import ibex_pkg::*; #( .instr_rdata_alu_id_o (instr_rdata_alu_id), .instr_rdata_c_id_o (instr_rdata_c_id), .instr_is_compressed_id_o(instr_is_compressed_id), - .instr_bp_taken_o (instr_bp_taken_id), .instr_fetch_err_o (instr_fetch_err), .instr_fetch_err_plus2_o (instr_fetch_err_plus2), .illegal_c_insn_id_o (illegal_c_insn_id), - .dummy_instr_id_o (dummy_instr_id), .pc_if_o (pc_if), .pc_id_o (pc_id), .pmp_err_if_i (pmp_req_err[PMP_I]), @@ -453,20 +321,11 @@ module ibex_core import ibex_pkg::*; #( .instr_valid_clear_i (instr_valid_clear), .pc_set_i (pc_set), .pc_mux_i (pc_mux_id), - .nt_branch_mispredict_i(nt_branch_mispredict), .exc_pc_mux_i (exc_pc_mux_id), .exc_cause (exc_cause), - .dummy_instr_en_i (dummy_instr_en), - .dummy_instr_mask_i (dummy_instr_mask), - .dummy_instr_seed_en_i (dummy_instr_seed_en), - .dummy_instr_seed_i (dummy_instr_seed), - .icache_enable_i (icache_enable), - .icache_inval_i (icache_inval), - .icache_ecc_error_o (icache_ecc_error), // branch targets .branch_target_ex_i(branch_target_ex), - .nt_branch_addr_i (nt_branch_addr), // CSRs .csr_mepc_i (csr_mepc), // exception return address @@ -477,7 +336,6 @@ module ibex_core import ibex_pkg::*; #( // pipeline stalls .id_in_ready_i(id_in_ready), - .pc_mismatch_alert_o(pc_mismatch_alert), .if_busy_o (if_busy) ); @@ -485,27 +343,23 @@ module ibex_core import ibex_pkg::*; #( // available assign perf_iside_wait = id_in_ready & ~instr_valid_id; - // fetch_enable_i can be used to stop the core fetching new instructions - assign instr_req_gated = instr_req_int & fetch_enable; + // For non secure Ibex only the bottom bit of fetch enable is considered + assign instr_req_gated = instr_req_int; ////////////// // ID stage // ////////////// - ibex_id_stage #( + cve2_id_stage #( .RV32E (RV32E), .RV32M (RV32M), - .RV32B (RV32B), - .BranchTargetALU(BranchTargetALU), - .DataIndTiming (DataIndTiming), - .WritebackStage (WritebackStage), - .BranchPredictor(BranchPredictor) + .RV32B (RV32B) ) id_stage_i ( - - .clk_i(clk), + .clk_i (clk_i), .rst_ni(rst_ni), // Processor Enable + .fetch_enable_i(fetch_enable_i), .ctrl_busy_o (ctrl_busy), .illegal_insn_o(illegal_insn_id), @@ -515,7 +369,6 @@ module ibex_core import ibex_pkg::*; #( .instr_rdata_alu_i (instr_rdata_alu_id), .instr_rdata_c_i (instr_rdata_c_id), .instr_is_compressed_i(instr_is_compressed_id), - .instr_bp_taken_i (instr_bp_taken_id), // Jumps and branches .branch_decision_i(branch_decision), @@ -527,11 +380,8 @@ module ibex_core import ibex_pkg::*; #( .instr_req_o (instr_req_int), .pc_set_o (pc_set), .pc_mux_o (pc_mux_id), - .nt_branch_mispredict_o(nt_branch_mispredict), - .nt_branch_addr_o (nt_branch_addr), .exc_pc_mux_o (exc_pc_mux_id), .exc_cause_o (exc_cause), - .icache_inval_o (icache_inval), .instr_fetch_err_i (instr_fetch_err), .instr_fetch_err_plus2_i(instr_fetch_err_plus2), @@ -551,9 +401,6 @@ module ibex_core import ibex_pkg::*; #( .imd_val_d_ex_i (imd_val_d_ex), .imd_val_we_ex_i(imd_val_we_ex), - .bt_a_operand_o(bt_a_operand), - .bt_b_operand_o(bt_b_operand), - .mult_en_ex_o (mult_en_ex), .div_en_ex_o (div_en_ex), .mult_sel_ex_o (mult_sel_ex), @@ -562,7 +409,6 @@ module ibex_core import ibex_pkg::*; #( .multdiv_signed_mode_ex_o(multdiv_signed_mode_ex), .multdiv_operand_a_ex_o (multdiv_operand_a_ex), .multdiv_operand_b_ex_o (multdiv_operand_b_ex), - .multdiv_ready_id_o (multdiv_ready_id), // CSR ID/EX .csr_access_o (csr_access), @@ -570,7 +416,6 @@ module ibex_core import ibex_pkg::*; #( .csr_op_en_o (csr_op_en), .csr_save_if_o (csr_save_if), // control signal to save PC .csr_save_id_o (csr_save_id), // control signal to save PC - .csr_save_wb_o (csr_save_wb), // control signal to save PC .csr_restore_mret_id_o(csr_restore_mret_id), // restore mstatus upon MRET .csr_restore_dret_id_o(csr_restore_dret_id), // restore mstatus upon MRET .csr_save_cause_o (csr_save_cause), @@ -578,7 +423,6 @@ module ibex_core import ibex_pkg::*; #( .priv_mode_i (priv_mode_id), .csr_mstatus_tw_i (csr_mstatus_tw), .illegal_csr_insn_i (illegal_csr_insn_id), - .data_ind_timing_i (data_ind_timing), // LSU .lsu_req_o (lsu_req), // to load store unit @@ -586,7 +430,6 @@ module ibex_core import ibex_pkg::*; #( .lsu_type_o (lsu_type), // to load store unit .lsu_sign_ext_o(lsu_sign_ext), // to load store unit .lsu_wdata_o (lsu_wdata), // to load store unit - .lsu_req_done_i(lsu_req_done), // from load store unit .lsu_addr_incr_req_i(lsu_addr_incr_req), .lsu_addr_last_i (lsu_addr_last), @@ -611,9 +454,6 @@ module ibex_core import ibex_pkg::*; #( .debug_ebreaku_i (debug_ebreaku), .trigger_match_i (trigger_match), - // Wakeup Signal - .wake_from_sleep_o(wake_from_sleep), - // write data to commit in the register file .result_ex_i(result_ex), .csr_rdata_i(csr_rdata), @@ -627,40 +467,28 @@ module ibex_core import ibex_pkg::*; #( .rf_waddr_id_o (rf_waddr_id), .rf_wdata_id_o (rf_wdata_id), .rf_we_id_o (rf_we_id), - .rf_rd_a_wb_match_o(rf_rd_a_wb_match), - .rf_rd_b_wb_match_o(rf_rd_b_wb_match), - - .rf_waddr_wb_i (rf_waddr_wb), - .rf_wdata_fwd_wb_i(rf_wdata_fwd_wb), - .rf_write_wb_i (rf_write_wb), - .en_wb_o (en_wb), - .instr_type_wb_o (instr_type_wb), + .en_wb_o (en_wb), .instr_perf_count_id_o (instr_perf_count_id), - .ready_wb_i (ready_wb), - .outstanding_load_wb_i (outstanding_load_wb), - .outstanding_store_wb_i(outstanding_store_wb), // Performance Counters .perf_jump_o (perf_jump), .perf_branch_o (perf_branch), .perf_tbranch_o (perf_tbranch), .perf_dside_wait_o(perf_dside_wait), - .perf_mul_wait_o (perf_mul_wait), + .perf_wfi_wait_o (perf_wfi_wait), .perf_div_wait_o (perf_div_wait), .instr_id_done_o (instr_id_done) ); - assign icache_inval_o = icache_inval; // for RVFI only assign unused_illegal_insn_id = illegal_insn_id; - ibex_ex_block #( + cve2_ex_block #( .RV32M (RV32M), - .RV32B (RV32B), - .BranchTargetALU(BranchTargetALU) + .RV32B (RV32B) ) ex_block_i ( - .clk_i (clk), + .clk_i (clk_i), .rst_ni(rst_ni), // ALU signal from ID stage @@ -669,10 +497,6 @@ module ibex_core import ibex_pkg::*; #( .alu_operand_b_i (alu_operand_b_ex), .alu_instr_first_cycle_i(instr_first_cycle_id), - // Branch target ALU signal from ID stage - .bt_a_operand_i(bt_a_operand), - .bt_b_operand_i(bt_b_operand), - // Multipler/Divider signal from ID stage .multdiv_operator_i (multdiv_operator_ex), .mult_en_i (mult_en_ex), @@ -682,8 +506,6 @@ module ibex_core import ibex_pkg::*; #( .multdiv_signed_mode_i(multdiv_signed_mode_ex), .multdiv_operand_a_i (multdiv_operand_a_ex), .multdiv_operand_b_i (multdiv_operand_b_ex), - .multdiv_ready_id_i (multdiv_ready_id), - .data_ind_timing_i (data_ind_timing), // Intermediate value register .imd_val_we_o(imd_val_we_ex), @@ -707,8 +529,8 @@ module ibex_core import ibex_pkg::*; #( assign data_req_o = data_req_out & ~pmp_req_err[PMP_D]; assign lsu_resp_err = lsu_load_err | lsu_store_err; - ibex_load_store_unit load_store_unit_i ( - .clk_i (clk), + cve2_load_store_unit load_store_unit_i ( + .clk_i (clk_i), .rst_ni(rst_ni), // data interface @@ -733,7 +555,6 @@ module ibex_core import ibex_pkg::*; #( .lsu_rdata_o (rf_wdata_lsu), .lsu_rdata_valid_o(rf_we_lsu), .lsu_req_i (lsu_req), - .lsu_req_done_o (lsu_req_done), .adder_result_ex_i(alu_adder_result_ex), @@ -753,27 +574,17 @@ module ibex_core import ibex_pkg::*; #( .perf_store_o(perf_store) ); - ibex_wb_stage #( - .ResetAll ( ResetAll ), - .WritebackStage(WritebackStage) - ) wb_stage_i ( - .clk_i (clk), - .rst_ni (rst_ni), - .en_wb_i (en_wb), - .instr_type_wb_i (instr_type_wb), - .pc_id_i (pc_id), + cve2_wb #( + ) wb_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .en_wb_i (en_wb), + .instr_is_compressed_id_i(instr_is_compressed_id), .instr_perf_count_id_i (instr_perf_count_id), - .ready_wb_o (ready_wb), - .rf_write_wb_o (rf_write_wb), - .outstanding_load_wb_o (outstanding_load_wb), - .outstanding_store_wb_o (outstanding_store_wb), - .pc_wb_o (pc_wb), .perf_instr_ret_wb_o (perf_instr_ret_wb), .perf_instr_ret_compressed_wb_o (perf_instr_ret_compressed_wb), - .perf_instr_ret_wb_spec_o (perf_instr_ret_wb_spec), - .perf_instr_ret_compressed_wb_spec_o(perf_instr_ret_compressed_wb_spec), .rf_waddr_id_i(rf_waddr_id), .rf_wdata_id_i(rf_wdata_id), @@ -782,79 +593,14 @@ module ibex_core import ibex_pkg::*; #( .rf_wdata_lsu_i(rf_wdata_lsu), .rf_we_lsu_i (rf_we_lsu), - .rf_wdata_fwd_wb_o(rf_wdata_fwd_wb), - .rf_waddr_wb_o(rf_waddr_wb), .rf_wdata_wb_o(rf_wdata_wb), .rf_we_wb_o (rf_we_wb), .lsu_resp_valid_i(lsu_resp_valid), - .lsu_resp_err_i (lsu_resp_err), - - .instr_done_wb_o(instr_done_wb) + .lsu_resp_err_i (lsu_resp_err) ); - ///////////////////////////// - // Register file interface // - ///////////////////////////// - - assign dummy_instr_id_o = dummy_instr_id; - assign rf_raddr_a_o = rf_raddr_a; - assign rf_waddr_wb_o = rf_waddr_wb; - assign rf_we_wb_o = rf_we_wb; - assign rf_raddr_b_o = rf_raddr_b; - - if (RegFileECC) begin : gen_regfile_ecc - - // SEC_CM: DATA_REG_SW.INTEGRITY - logic [1:0] rf_ecc_err_a, rf_ecc_err_b; - logic rf_ecc_err_a_id, rf_ecc_err_b_id; - - // ECC checkbit generation for regiter file wdata - prim_secded_inv_39_32_enc regfile_ecc_enc ( - .data_i(rf_wdata_wb), - .data_o(rf_wdata_wb_ecc_o) - ); - - // ECC checking on register file rdata - prim_secded_inv_39_32_dec regfile_ecc_dec_a ( - .data_i (rf_rdata_a_ecc_i), - .data_o (), - .syndrome_o(), - .err_o (rf_ecc_err_a) - ); - prim_secded_inv_39_32_dec regfile_ecc_dec_b ( - .data_i (rf_rdata_b_ecc_i), - .data_o (), - .syndrome_o(), - .err_o (rf_ecc_err_b) - ); - - // Assign read outputs - no error correction, just trigger an alert - assign rf_rdata_a = rf_rdata_a_ecc_i[31:0]; - assign rf_rdata_b = rf_rdata_b_ecc_i[31:0]; - - // Calculate errors - qualify with WB forwarding to avoid xprop into the alert signal - assign rf_ecc_err_a_id = |rf_ecc_err_a & rf_ren_a & ~rf_rd_a_wb_match; - assign rf_ecc_err_b_id = |rf_ecc_err_b & rf_ren_b & ~rf_rd_b_wb_match; - - // Combined error - assign rf_ecc_err_comb = instr_valid_id & (rf_ecc_err_a_id | rf_ecc_err_b_id); - - end else begin : gen_no_regfile_ecc - logic unused_rf_ren_a, unused_rf_ren_b; - logic unused_rf_rd_a_wb_match, unused_rf_rd_b_wb_match; - - assign unused_rf_ren_a = rf_ren_a; - assign unused_rf_ren_b = rf_ren_b; - assign unused_rf_rd_a_wb_match = rf_rd_a_wb_match; - assign unused_rf_rd_b_wb_match = rf_rd_b_wb_match; - assign rf_wdata_wb_ecc_o = rf_wdata_wb; - assign rf_rdata_a = rf_rdata_a_ecc_i; - assign rf_rdata_b = rf_rdata_b_ecc_i; - assign rf_ecc_err_comb = 1'b0; - end - /////////////////////// // Crash dump output // /////////////////////// @@ -864,15 +610,6 @@ module ibex_core import ibex_pkg::*; #( assign crash_dump_o.last_data_addr = lsu_addr_last; assign crash_dump_o.exception_addr = csr_mepc; - /////////////////// - // Alert outputs // - /////////////////// - - // Minor alert - core is in a recoverable state - assign alert_minor_o = icache_ecc_error; - - // Major alert - core is unrecoverable - assign alert_major_o = rf_ecc_err_comb | pc_mismatch_alert | csr_shadow_err; // Explict INC_ASSERT block to avoid unused signal lint warnings were asserts are not included `ifdef INC_ASSERT @@ -888,19 +625,7 @@ module ibex_core import ibex_pkg::*; #( assign outstanding_store_id = id_stage_i.instr_executing & id_stage_i.lsu_req_dec & id_stage_i.lsu_we; - if (WritebackStage) begin : gen_wb_stage - // When the writeback stage is present a load/store could be in ID or WB. A Load/store in ID can - // see a response before it moves to WB when it is unaligned otherwise we should only see - // a response when load/store is in WB. - assign outstanding_load_resp = outstanding_load_wb | - (outstanding_load_id & load_store_unit_i.split_misaligned_access); - - assign outstanding_store_resp = outstanding_store_wb | - (outstanding_store_id & load_store_unit_i.split_misaligned_access); - - // When writing back the result of a load, the load must have made it to writeback - `ASSERT(NoMemRFWriteWithoutPendingLoad, rf_we_lsu |-> outstanding_load_wb, clk_i, !rst_ni) - end else begin : gen_no_wb_stage + begin : gen_no_wb_stage // Without writeback stage only look into whether load or store is in ID to determine if // a response is expected. assign outstanding_load_resp = outstanding_load_id; @@ -916,8 +641,24 @@ module ibex_core import ibex_pkg::*; #( //////////////////////// // RF (Register File) // //////////////////////// -`ifdef RVFI -`endif + cve2_register_file_ff #( + .RV32E (RV32E), + .DataWidth (32), + .WordZeroVal (32'h0) + ) register_file_i ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .test_en_i(test_en_i), + + .raddr_a_i(rf_raddr_a), + .rdata_a_o(rf_rdata_a), + .raddr_b_i(rf_raddr_b), + .rdata_b_o(rf_rdata_b), + .waddr_a_i(rf_waddr_wb), + .wdata_a_i(rf_wdata_wb), + .we_a_i (rf_we_wb) + ); ///////////////////////////////////////// @@ -927,13 +668,9 @@ module ibex_core import ibex_pkg::*; #( assign csr_wdata = alu_operand_a_ex; assign csr_addr = csr_num_e'(csr_access ? alu_operand_b_ex[11:0] : 12'b0); - ibex_cs_registers #( + cve2_cs_registers #( .DbgTriggerEn (DbgTriggerEn), .DbgHwBreakNum (DbgHwBreakNum), - .DataIndTiming (DataIndTiming), - .DummyInstructions(DummyInstructions), - .ShadowCSR (ShadowCSR), - .ICache (ICache), .MHPMCounterNum (MHPMCounterNum), .MHPMCounterWidth (MHPMCounterWidth), .PMPEnable (PMPEnable), @@ -943,7 +680,7 @@ module ibex_core import ibex_pkg::*; #( .RV32M (RV32M), .RV32B (RV32B) ) cs_registers_i ( - .clk_i (clk), + .clk_i (clk_i), .rst_ni(rst_ni), // Hart ID from outside @@ -993,19 +730,9 @@ module ibex_core import ibex_pkg::*; #( .pc_if_i(pc_if), .pc_id_i(pc_id), - .pc_wb_i(pc_wb), - - .data_ind_timing_o (data_ind_timing), - .dummy_instr_en_o (dummy_instr_en), - .dummy_instr_mask_o (dummy_instr_mask), - .dummy_instr_seed_en_o(dummy_instr_seed_en), - .dummy_instr_seed_o (dummy_instr_seed), - .icache_enable_o (icache_enable), - .csr_shadow_err_o (csr_shadow_err), .csr_save_if_i (csr_save_if), .csr_save_id_i (csr_save_id), - .csr_save_wb_i (csr_save_wb), .csr_restore_mret_i(csr_restore_mret_id), .csr_restore_dret_i(csr_restore_dret_id), .csr_save_cause_i (csr_save_cause), @@ -1013,13 +740,9 @@ module ibex_core import ibex_pkg::*; #( .csr_mtval_i (csr_mtval), .illegal_csr_insn_o(illegal_csr_insn_id), - .double_fault_seen_o, - // performance counter related signals .instr_ret_i (perf_instr_ret_wb), .instr_ret_compressed_i (perf_instr_ret_compressed_wb), - .instr_ret_spec_i (perf_instr_ret_wb_spec), - .instr_ret_compressed_spec_i(perf_instr_ret_compressed_wb_spec), .iside_wait_i (perf_iside_wait), .jump_i (perf_jump), .branch_i (perf_branch), @@ -1027,7 +750,7 @@ module ibex_core import ibex_pkg::*; #( .mem_load_i (perf_load), .mem_store_i (perf_store), .dside_wait_i (perf_dside_wait), - .mul_wait_i (perf_mul_wait), + .wfi_wait_i (perf_wfi_wait), .div_wait_i (perf_div_wait) ); @@ -1055,7 +778,7 @@ module ibex_core import ibex_pkg::*; #( assign pmp_req_type[PMP_D] = data_we_o ? PMP_ACC_WRITE : PMP_ACC_READ; assign pmp_priv_lvl[PMP_D] = priv_mode_lsu; - ibex_pmp #( + cve2_pmp #( .PMPGranularity(PMPGranularity), .PMPNumChan (PMP_NUM_CHAN), .PMPNumRegions (PMPNumRegions) @@ -1096,7 +819,7 @@ module ibex_core import ibex_pkg::*; #( // second stage. RVFI outputs are all straight from flops. So 2 stage pipeline requires a single // set of flops (instr_info => RVFI_out), 3 stage pipeline requires two sets (instr_info => wb // => RVFI_out) - localparam int RVFI_STAGES = WritebackStage ? 2 : 1; + localparam int RVFI_STAGES = 1; logic rvfi_stage_valid [RVFI_STAGES]; logic [63:0] rvfi_stage_order [RVFI_STAGES]; @@ -1153,22 +876,20 @@ module ibex_core import ibex_pkg::*; #( logic [31:0] rvfi_mem_addr_d; logic [31:0] rvfi_mem_addr_q; logic rvfi_trap_id; - logic rvfi_trap_wb; logic [63:0] rvfi_stage_order_d; logic rvfi_id_done; - logic rvfi_wb_done; logic new_debug_req; logic new_nmi; logic new_irq; - ibex_pkg::irqs_t captured_mip; + cve2_pkg::irqs_t captured_mip; logic captured_nmi; logic captured_debug_req; logic captured_valid; // RVFI extension for co-simulation support // debug_req and MIP captured at IF -> ID transition so one extra stage - ibex_pkg::irqs_t rvfi_ext_stage_mip [RVFI_STAGES+1]; + cve2_pkg::irqs_t rvfi_ext_stage_mip [RVFI_STAGES+1]; logic rvfi_ext_stage_nmi [RVFI_STAGES+1]; logic rvfi_ext_stage_debug_req [RVFI_STAGES+1]; logic [63:0] rvfi_ext_stage_mcycle [RVFI_STAGES]; @@ -1226,56 +947,20 @@ module ibex_core import ibex_pkg::*; #( // Factor in exceptions taken in ID so RVFI tracking picks up flushed instructions that took // a trap - assign rvfi_id_done = instr_id_done | (id_stage_i.controller_i.rvfi_flush_next & - id_stage_i.controller_i.id_exception_o); - - if (WritebackStage) begin : gen_rvfi_wb_stage - logic unused_instr_new_id; + // MRET causes MSTATUS to get written one clock later. Fix rvfi_valid when executing MRET + assign rvfi_id_done = (instr_id_done & !id_stage_i.controller_i.mret_insn)| + id_stage_i.csr_restore_mret_id_o | + (id_stage_i.controller_i.rvfi_flush_next & id_stage_i.controller_i.exc_req_d); - assign unused_instr_new_id = instr_new_id; + // Without writeback stage first RVFI stage is output stage so simply valid the cycle after + // instruction leaves ID/EX (and so has retired) + assign rvfi_stage_valid_d[0] = rvfi_id_done; + // Without writeback stage signal new instr_new_wb when instruction enters ID/EX to correctly + // setup register write signals + assign rvfi_instr_new_wb = instr_new_id; + assign rvfi_trap_id = id_stage_i.controller_i.exc_req_d | id_stage_i.controller_i.exc_req_lsu; - // With writeback stage first RVFI stage buffers instruction information captured in ID/EX - // awaiting instruction retirement and RF Write data/Mem read data whilst instruction is in WB - // So first stage becomes valid when instruction leaves ID/EX stage and remains valid until - // instruction leaves WB - assign rvfi_stage_valid_d[0] = (rvfi_id_done & ~dummy_instr_id) | - (rvfi_stage_valid[0] & ~rvfi_wb_done); - // Second stage is output stage so simple valid cycle after instruction leaves WB (and so has - // retired) - assign rvfi_stage_valid_d[1] = rvfi_wb_done; - - // Signal new instruction in WB cycle after instruction leaves ID/EX (to enter WB) - logic rvfi_instr_new_wb_q; - - // Signal new instruction in WB either when one has just entered or when a trap is progressing - // through the tracking pipeline - assign rvfi_instr_new_wb = rvfi_instr_new_wb_q | (rvfi_stage_valid[0] & rvfi_stage_trap[0]); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rvfi_instr_new_wb_q <= 0; - end else begin - rvfi_instr_new_wb_q <= rvfi_id_done; - end - end - - assign rvfi_trap_id = id_stage_i.controller_i.id_exception_o; - assign rvfi_trap_wb = id_stage_i.controller_i.exc_req_lsu; - // WB is instantly done in the tracking pipeline when a trap is progress through the pipeline - assign rvfi_wb_done = instr_done_wb | (rvfi_stage_valid[0] & rvfi_stage_trap[0]); - end else begin : gen_rvfi_no_wb_stage - // Without writeback stage first RVFI stage is output stage so simply valid the cycle after - // instruction leaves ID/EX (and so has retired) - assign rvfi_stage_valid_d[0] = rvfi_id_done & ~dummy_instr_id; - // Without writeback stage signal new instr_new_wb when instruction enters ID/EX to correctly - // setup register write signals - assign rvfi_instr_new_wb = instr_new_id; - assign rvfi_trap_id = id_stage_i.controller_i.exc_req_d | id_stage_i.controller_i.exc_req_lsu; - assign rvfi_trap_wb = 1'b0; - assign rvfi_wb_done = instr_done_wb; - end - - assign rvfi_stage_order_d = dummy_instr_id ? rvfi_stage_order[0] : rvfi_stage_order[0] + 64'd1; + assign rvfi_stage_order_d = rvfi_stage_order[0] + 64'd1; // For interrupts and debug Ibex will take the relevant trap as soon as whatever instruction in ID // finishes or immediately if the ID stage is empty. The rvfi_ext interface provides the DV @@ -1410,9 +1095,8 @@ module ibex_core import ibex_pkg::*; #( rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o; end end else begin - if (rvfi_wb_done) begin rvfi_stage_halt[i] <= rvfi_stage_halt[i-1]; - rvfi_stage_trap[i] <= rvfi_stage_trap[i-1] | rvfi_trap_wb; + rvfi_stage_trap[i] <= rvfi_stage_trap[i-1]; rvfi_stage_intr[i] <= rvfi_stage_intr[i-1]; rvfi_stage_order[i] <= rvfi_stage_order[i-1]; rvfi_stage_insn[i] <= rvfi_stage_insn[i-1]; @@ -1443,7 +1127,6 @@ module ibex_core import ibex_pkg::*; #( rvfi_ext_stage_nmi[i+1] <= rvfi_ext_stage_nmi[i]; rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; rvfi_ext_stage_mcycle[i] <= rvfi_ext_stage_mcycle[i-1]; - end end end end @@ -1596,13 +1279,9 @@ module ibex_core import ibex_pkg::*; #( end `else - logic unused_instr_new_id, unused_instr_id_done, unused_instr_done_wb; + logic unused_instr_new_id, unused_instr_id_done; assign unused_instr_id_done = instr_id_done; assign unused_instr_new_id = instr_new_id; - assign unused_instr_done_wb = instr_done_wb; `endif - // Certain parameter combinations are not supported - `ASSERT_INIT(IllegalParamSecure, !(SecureIbex && (RV32M == RV32MNone))) - endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_counter.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_counter.sv similarity index 99% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_counter.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_counter.sv index a6187b78..417614b1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_counter.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_counter.sv @@ -1,4 +1,4 @@ -module ibex_counter #( +module cve2_counter #( parameter int CounterWidth = 32, // When set `counter_val_upd_o` provides an incremented version of the counter value, otherwise // the output is hard-wired to 0. This is required to allow Xilinx DSP inference to work diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_cs_registers.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv similarity index 86% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_cs_registers.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv index aa328205..dfce0985 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_cs_registers.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv @@ -12,21 +12,17 @@ `include "prim_assert.sv" -module ibex_cs_registers #( +module cve2_cs_registers #( parameter bit DbgTriggerEn = 0, parameter int unsigned DbgHwBreakNum = 1, - parameter bit DataIndTiming = 1'b0, - parameter bit DummyInstructions = 1'b0, - parameter bit ShadowCSR = 1'b0, - parameter bit ICache = 1'b0, parameter int unsigned MHPMCounterNum = 10, parameter int unsigned MHPMCounterWidth = 40, parameter bit PMPEnable = 0, parameter int unsigned PMPGranularity = 0, parameter int unsigned PMPNumRegions = 4, parameter bit RV32E = 0, - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone + parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast, + parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( // Clock and Reset input logic clk_i, @@ -36,8 +32,8 @@ module ibex_cs_registers #( input logic [31:0] hart_id_i, // Privilege mode - output ibex_pkg::priv_lvl_e priv_mode_id_o, - output ibex_pkg::priv_lvl_e priv_mode_lsu_o, + output cve2_pkg::priv_lvl_e priv_mode_id_o, + output cve2_pkg::priv_lvl_e priv_mode_lsu_o, output logic csr_mstatus_tw_o, // mtvec @@ -47,9 +43,9 @@ module ibex_cs_registers #( // Interface to registers (SRAM like) input logic csr_access_i, - input ibex_pkg::csr_num_e csr_addr_i, + input cve2_pkg::csr_num_e csr_addr_i, input logic [31:0] csr_wdata_i, - input ibex_pkg::csr_op_e csr_op_i, + input cve2_pkg::csr_op_e csr_op_i, input csr_op_en_i, output logic [31:0] csr_rdata_o, @@ -57,21 +53,21 @@ module ibex_cs_registers #( input logic irq_software_i, input logic irq_timer_i, input logic irq_external_i, - input logic [14:0] irq_fast_i, + input logic [15:0] irq_fast_i, input logic nmi_mode_i, output logic irq_pending_o, // interrupt request pending - output ibex_pkg::irqs_t irqs_o, // interrupt requests qualified with mie + output cve2_pkg::irqs_t irqs_o, // interrupt requests qualified with mie output logic csr_mstatus_mie_o, output logic [31:0] csr_mepc_o, // PMP - output ibex_pkg::pmp_cfg_t csr_pmp_cfg_o [PMPNumRegions], + output cve2_pkg::pmp_cfg_t csr_pmp_cfg_o [PMPNumRegions], output logic [33:0] csr_pmp_addr_o [PMPNumRegions], - output ibex_pkg::pmp_mseccfg_t csr_pmp_mseccfg_o, + output cve2_pkg::pmp_mseccfg_t csr_pmp_mseccfg_o, // debug input logic debug_mode_i, - input ibex_pkg::dbg_cause_e debug_cause_i, + input cve2_pkg::dbg_cause_e debug_cause_i, input logic debug_csr_save_i, output logic [31:0] csr_depc_o, output logic debug_single_step_o, @@ -81,35 +77,21 @@ module ibex_cs_registers #( input logic [31:0] pc_if_i, input logic [31:0] pc_id_i, - input logic [31:0] pc_wb_i, - - // CPU control bits - output logic data_ind_timing_o, - output logic dummy_instr_en_o, - output logic [2:0] dummy_instr_mask_o, - output logic dummy_instr_seed_en_o, - output logic [31:0] dummy_instr_seed_o, - output logic icache_enable_o, - output logic csr_shadow_err_o, // Exception save/restore input logic csr_save_if_i, input logic csr_save_id_i, - input logic csr_save_wb_i, input logic csr_restore_mret_i, input logic csr_restore_dret_i, input logic csr_save_cause_i, - input ibex_pkg::exc_cause_e csr_mcause_i, + input cve2_pkg::exc_cause_e csr_mcause_i, input logic [31:0] csr_mtval_i, output logic illegal_csr_insn_o, // access to non-existent CSR, // with wrong priviledge level, or // missing write permissions - output logic double_fault_seen_o, // Performance Counters input logic instr_ret_i, // instr retired in ID/EX stage input logic instr_ret_compressed_i, // compressed instr retired - input logic instr_ret_spec_i, // speculative instr_ret_i - input logic instr_ret_compressed_spec_i, // speculative instr_ret_compressed_i input logic iside_wait_i, // core waiting for the iside input logic jump_i, // jump instr seen (j, jr, jal, jalr) input logic branch_i, // branch instr seen (bf, bnf) @@ -117,11 +99,11 @@ module ibex_cs_registers #( input logic mem_load_i, // load from memory in this cycle input logic mem_store_i, // store to memory in this cycle input logic dside_wait_i, // core waiting for the dside - input logic mul_wait_i, // core waiting for multiply + input logic wfi_wait_i, // core waiting for interrupt input logic div_wait_i // core waiting for divide ); - import ibex_pkg::*; + import cve2_pkg::*; localparam int unsigned RV32BEnabled = (RV32B == RV32BNone) ? 0 : 1; localparam int unsigned RV32MEnabled = (RV32M == RV32MNone) ? 0 : 1; @@ -174,23 +156,12 @@ module ibex_cs_registers #( priv_lvl_e prv; } dcsr_t; - // CPU control register fields - typedef struct packed { - logic double_fault_seen; - logic sync_exc_seen; - logic [2:0] dummy_instr_mask; - logic dummy_instr_en; - logic data_ind_timing; - logic icache_enable; - } cpu_ctrl_t; - // Interrupt and exception control signals logic [31:0] exception_pc; // CSRs priv_lvl_e priv_lvl_q, priv_lvl_d; status_t mstatus_q, mstatus_d; - logic mstatus_err; logic mstatus_en; irqs_t mie_q, mie_d; logic mie_en; @@ -198,12 +169,11 @@ module ibex_cs_registers #( logic mscratch_en; logic [31:0] mepc_q, mepc_d; logic mepc_en; - logic [5:0] mcause_q, mcause_d; + logic [6:0] mcause_q, mcause_d; logic mcause_en; logic [31:0] mtval_q, mtval_d; logic mtval_en; logic [31:0] mtvec_q, mtvec_d; - logic mtvec_err; logic mtvec_en; irqs_t mip; dcsr_t dcsr_q, dcsr_d; @@ -219,12 +189,11 @@ module ibex_cs_registers #( status_stk_t mstack_q, mstack_d; logic mstack_en; logic [31:0] mstack_epc_q, mstack_epc_d; - logic [5:0] mstack_cause_q, mstack_cause_d; + logic [6:0] mstack_cause_q, mstack_cause_d; // PMP Signals logic [31:0] pmp_addr_rdata [PMP_MAX_REGIONS]; logic [PMP_CFG_W-1:0] pmp_cfg_rdata [PMP_MAX_REGIONS]; - logic pmp_csr_err; pmp_mseccfg_t pmp_mseccfg; // Hardware performance monitor signals @@ -246,18 +215,13 @@ module ibex_cs_registers #( logic unused_mhpmcounterh_we_1; logic unused_mhpmcounter_incr_1; - logic [63:0] minstret_next, minstret_raw; + logic [63:0] minstret_raw; // Debug / trigger registers logic [31:0] tselect_rdata; logic [31:0] tmatch_control_rdata; logic [31:0] tmatch_value_rdata; - // CPU control bits - cpu_ctrl_t cpuctrl_q, cpuctrl_d, cpuctrl_wdata_raw, cpuctrl_wdata; - logic cpuctrl_we; - logic cpuctrl_err; - // CSR update logic logic [31:0] csr_wdata_int; logic [31:0] csr_rdata_int; @@ -308,6 +272,8 @@ module ibex_cs_registers #( CSR_MIMPID: csr_rdata_int = CSR_MIMPID_VALUE; // mhartid: unique hardware thread id CSR_MHARTID: csr_rdata_int = hart_id_i; + // mconfigptr: pointer to configuration data structre + CSR_MCONFIGPTR: csr_rdata_int = CSR_MCONFIGPTR_VALUE; // mstatus: always M-mode, contains IE bit CSR_MSTATUS: begin @@ -319,6 +285,13 @@ module ibex_cs_registers #( csr_rdata_int[CSR_MSTATUS_TW_BIT] = mstatus_q.tw; end + // mstatush: All zeros for Ibex (fixed little endian and all other bits reserved) + CSR_MSTATUSH: csr_rdata_int = '0; + + // menvcfg: machine environment configuration, all zeros for Ibex (none of the relevant + // features are implemented) + CSR_MENVCFG, CSR_MENVCFGH: csr_rdata_int = '0; + // misa CSR_MISA: csr_rdata_int = MISA_VALUE; @@ -345,7 +318,7 @@ module ibex_cs_registers #( CSR_MEPC: csr_rdata_int = mepc_q; // mcause: exception cause - CSR_MCAUSE: csr_rdata_int = {mcause_q[5], 26'b0, mcause_q[4:0]}; + CSR_MCAUSE: csr_rdata_int = {mcause_q[6], 25'b0, mcause_q[5:0]}; // mtval: trap value CSR_MTVAL: csr_rdata_int = mtval_q; @@ -486,11 +459,6 @@ module ibex_cs_registers #( illegal_csr = ~DbgTriggerEn; end - // Custom CSR for controlling CPU features - CSR_CPUCTRL: begin - csr_rdata_int = {{32 - $bits(cpu_ctrl_t) {1'b0}}, cpuctrl_q}; - end - // Custom CSR for LFSR re-seeding (cannot be read) CSR_SECURESEED: begin csr_rdata_int = '0; @@ -500,6 +468,16 @@ module ibex_cs_registers #( illegal_csr = 1'b1; end endcase + + if (!PMPEnable) begin + if (csr_addr inside {CSR_PMPCFG0, CSR_PMPCFG1, CSR_PMPCFG2, CSR_PMPCFG3, + CSR_PMPADDR0, CSR_PMPADDR1, CSR_PMPADDR2, CSR_PMPADDR3, + CSR_PMPADDR4, CSR_PMPADDR5, CSR_PMPADDR6, CSR_PMPADDR7, + CSR_PMPADDR8, CSR_PMPADDR9, CSR_PMPADDR10, CSR_PMPADDR11, + CSR_PMPADDR12, CSR_PMPADDR13, CSR_PMPADDR14, CSR_PMPADDR15}) begin + illegal_csr = 1'b1; + end + end end // write logic @@ -514,7 +492,7 @@ module ibex_cs_registers #( mepc_en = 1'b0; mepc_d = {csr_wdata_int[31:1], 1'b0}; mcause_en = 1'b0; - mcause_d = {csr_wdata_int[31], csr_wdata_int[4:0]}; + mcause_d = {csr_wdata_int[31], csr_wdata_int[5:0]}; mtval_en = 1'b0; mtval_d = csr_wdata_int; mtvec_en = csr_mtvec_init_i; @@ -539,11 +517,6 @@ module ibex_cs_registers #( mhpmcounter_we = '0; mhpmcounterh_we = '0; - cpuctrl_we = 1'b0; - cpuctrl_d = cpuctrl_q; - - double_fault_seen_o = 1'b0; - if (csr_we_int) begin unique case (csr_addr_i) // mstatus: IE bit @@ -641,11 +614,6 @@ module ibex_cs_registers #( mhpmcounterh_we[mhpmcounter_idx] = 1'b1; end - CSR_CPUCTRL: begin - cpuctrl_d = cpuctrl_wdata; - cpuctrl_we = 1'b1; - end - default:; endcase end @@ -661,9 +629,6 @@ module ibex_cs_registers #( csr_save_id_i: begin exception_pc = pc_id_i; end - csr_save_wb_i: begin - exception_pc = pc_wb_i; - end default:; endcase @@ -695,17 +660,6 @@ module ibex_cs_registers #( // save previous status for recoverable NMI mstack_en = 1'b1; - if (!mcause_d[5]) begin - // SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC - // SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC - cpuctrl_we = 1'b1; - - cpuctrl_d.sync_exc_seen = 1'b1; - if (cpuctrl_q.sync_exc_seen) begin - double_fault_seen_o = 1'b1; - cpuctrl_d.double_fault_seen = 1'b1; - end - end end end // csr_save_cause_i @@ -718,10 +672,12 @@ module ibex_cs_registers #( mstatus_en = 1'b1; mstatus_d.mie = mstatus_q.mpie; // re-enable interrupts + if (mstatus_q.mpp != PRIV_LVL_M) begin + mstatus_d.mprv = 1'b0; + end + // SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC // SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC - cpuctrl_we = 1'b1; - cpuctrl_d.sync_exc_seen = 1'b0; if (nmi_mode_i) begin // when returning from an NMI restore state from mstack CSR @@ -797,13 +753,12 @@ module ibex_cs_registers #( // MSTATUS localparam status_t MSTATUS_RST_VAL = '{mie: 1'b0, - mpie: 1'b1, - mpp: PRIV_LVL_U, + mpie: 1'b0, + mpp: PRIV_LVL_M, mprv: 1'b0, tw: 1'b0}; - ibex_csr #( + cve2_csr #( .Width ($bits(status_t)), - .ShadowCopy(ShadowCSR), .ResetValue({MSTATUS_RST_VAL}) ) u_mstatus_csr ( .clk_i (clk_i), @@ -811,11 +766,11 @@ module ibex_cs_registers #( .wr_data_i ({mstatus_d}), .wr_en_i (mstatus_en), .rd_data_o (mstatus_q), - .rd_error_o(mstatus_err) + .rd_error_o() ); // MEPC - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -833,7 +788,7 @@ module ibex_cs_registers #( assign mie_d.irq_timer = csr_wdata_int[CSR_MTIX_BIT]; assign mie_d.irq_external = csr_wdata_int[CSR_MEIX_BIT]; assign mie_d.irq_fast = csr_wdata_int[CSR_MFIX_BIT_HIGH:CSR_MFIX_BIT_LOW]; - ibex_csr #( + cve2_csr #( .Width ($bits(irqs_t)), .ShadowCopy(1'b0), .ResetValue('0) @@ -847,7 +802,7 @@ module ibex_cs_registers #( ); // MSCRATCH - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -861,8 +816,8 @@ module ibex_cs_registers #( ); // MCAUSE - ibex_csr #( - .Width (6), + cve2_csr #( + .Width (7), .ShadowCopy(1'b0), .ResetValue('0) ) u_mcause_csr ( @@ -875,7 +830,7 @@ module ibex_cs_registers #( ); // MTVAL - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -889,9 +844,8 @@ module ibex_cs_registers #( ); // MTVEC - ibex_csr #( + cve2_csr #( .Width (32), - .ShadowCopy(ShadowCSR), .ResetValue(32'd1) ) u_mtvec_csr ( .clk_i (clk_i), @@ -899,7 +853,7 @@ module ibex_cs_registers #( .wr_data_i (mtvec_d), .wr_en_i (mtvec_en), .rd_data_o (mtvec_q), - .rd_error_o(mtvec_err) + .rd_error_o() ); // DCSR @@ -909,7 +863,7 @@ module ibex_cs_registers #( prv: PRIV_LVL_M, default: '0 }; - ibex_csr #( + cve2_csr #( .Width ($bits(dcsr_t)), .ShadowCopy(1'b0), .ResetValue({DCSR_RESET_VAL}) @@ -923,7 +877,7 @@ module ibex_cs_registers #( ); // DEPC - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -937,7 +891,7 @@ module ibex_cs_registers #( ); // DSCRATCH0 - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -951,7 +905,7 @@ module ibex_cs_registers #( ); // DSCRATCH1 - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -966,7 +920,7 @@ module ibex_cs_registers #( // MSTACK localparam status_stk_t MSTACK_RESET_VAL = '{mpie: 1'b1, mpp: PRIV_LVL_U}; - ibex_csr #( + cve2_csr #( .Width ($bits(status_stk_t)), .ShadowCopy(1'b0), .ResetValue({MSTACK_RESET_VAL}) @@ -980,7 +934,7 @@ module ibex_cs_registers #( ); // MSTACK_EPC - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -994,8 +948,8 @@ module ibex_cs_registers #( ); // MSTACK_CAUSE - ibex_csr #( - .Width (6), + cve2_csr #( + .Width (7), .ShadowCopy(1'b0), .ResetValue('0) ) u_mstack_cause_csr ( @@ -1013,10 +967,10 @@ module ibex_cs_registers #( if (PMPEnable) begin : g_pmp_registers // PMP reset values - `ifdef IBEX_CUSTOM_PMP_RESET_VALUES - `include "ibex_pmp_reset.svh" + `ifdef CVE2_CUSTOM_PMP_RESET_VALUES + `include "cve2_pmp_reset.svh" `else - `include "ibex_pmp_reset_default.svh" + `include "cve2_pmp_reset_default.svh" `endif pmp_mseccfg_t pmp_mseccfg_q, pmp_mseccfg_d; @@ -1102,9 +1056,8 @@ module ibex_cs_registers #( &csr_wdata_int[(i%4)*PMP_CFG_W+:2]; assign pmp_cfg_wdata[i].read = csr_wdata_int[(i%4)*PMP_CFG_W]; - ibex_csr #( + cve2_csr #( .Width ($bits(pmp_cfg_t)), - .ShadowCopy(ShadowCSR), .ResetValue(pmp_cfg_rst[i]) ) u_pmp_cfg_csr ( .clk_i (clk_i), @@ -1131,9 +1084,8 @@ module ibex_cs_registers #( (csr_addr == (CSR_OFF_PMP_ADDR + i[11:0])); end - ibex_csr #( + cve2_csr #( .Width (PMPAddrWidth), - .ShadowCopy(ShadowCSR), .ResetValue(pmp_addr_rst[i][33-:PMPAddrWidth]) ) u_pmp_addr_csr ( .clk_i (clk_i), @@ -1164,9 +1116,8 @@ module ibex_cs_registers #( // MSECCFG.RLB cannot be set again assign pmp_mseccfg_d.rlb = any_pmp_entry_locked ? 1'b0 : csr_wdata_int[CSR_MSECCFG_RLB_BIT]; - ibex_csr #( + cve2_csr #( .Width ($bits(pmp_mseccfg_t)), - .ShadowCopy(ShadowCSR), .ResetValue(pmp_mseccfg_rst) ) u_pmp_mseccfg ( .clk_i (clk_i), @@ -1177,7 +1128,6 @@ module ibex_cs_registers #( .rd_error_o(pmp_mseccfg_err) ); - assign pmp_csr_err = (|pmp_cfg_err) | (|pmp_addr_err) | pmp_mseccfg_err; assign pmp_mseccfg = pmp_mseccfg_q; end else begin : g_no_pmp_tieoffs @@ -1190,7 +1140,6 @@ module ibex_cs_registers #( assign csr_pmp_cfg_o[i] = pmp_cfg_t'(1'b0); assign csr_pmp_addr_o[i] = '0; end - assign pmp_csr_err = 1'b0; assign pmp_mseccfg = '0; end @@ -1219,7 +1168,7 @@ module ibex_cs_registers #( end // When adding or altering performance counter meanings and default - // mappings please update dv/verilator/pcount/cpp/ibex_pcounts.cc + // mappings please update dv/verilator/pcount/cpp/cve2_pcounts.cc // appropriately. // // active counters @@ -1234,7 +1183,7 @@ module ibex_cs_registers #( mhpmcounter_incr[8] = branch_i; // num of branches (conditional) mhpmcounter_incr[9] = branch_taken_i; // num of taken branches (conditional) mhpmcounter_incr[10] = instr_ret_compressed_i; // num of compressed instr - mhpmcounter_incr[11] = mul_wait_i; // cycles waiting for multiply + mhpmcounter_incr[11] = wfi_wait_i; // cycles waiting for multiply mhpmcounter_incr[12] = div_wait_i; // cycles waiting for divide end @@ -1255,7 +1204,7 @@ module ibex_cs_registers #( end // mcycle - ibex_counter #( + cve2_counter #( .CounterWidth(64) ) mcycle_counter_i ( .clk_i(clk_i), @@ -1270,7 +1219,7 @@ module ibex_cs_registers #( // minstret - ibex_counter #( + cve2_counter #( .CounterWidth(64), .ProvideValUpd(1) ) minstret_counter_i ( @@ -1281,7 +1230,7 @@ module ibex_cs_registers #( .counter_we_i(mhpmcounter_we[2]), .counter_val_i(csr_wdata_int), .counter_val_o(minstret_raw), - .counter_val_upd_o(minstret_next) + .counter_val_upd_o() ); // Where the writeback stage is present instruction in ID observing value of minstret must take @@ -1291,7 +1240,7 @@ module ibex_cs_registers #( // so the incorrect value doesn't matter. A similar behaviour is required for the compressed // instruction retired counter below. When the writeback stage isn't present the speculative // signals are always 0. - assign mhpmcounter[2] = instr_ret_spec_i & ~mcountinhibit[2] ? minstret_next : minstret_raw; + assign mhpmcounter[2] = minstret_raw; // reserved: assign mhpmcounter[1] = '0; @@ -1306,7 +1255,7 @@ module ibex_cs_registers #( if (i < MHPMCounterNum) begin : gen_imp logic [63:0] mhpmcounter_raw, mhpmcounter_next; - ibex_counter #( + cve2_counter #( .CounterWidth(MHPMCounterWidth), .ProvideValUpd(Cnt == 10) ) mcounters_variable_i ( @@ -1324,7 +1273,6 @@ module ibex_cs_registers #( // Special behaviour for reading compressed instruction retired counter, see comment on // `mhpmcounter[2]` above for further information. assign mhpmcounter[Cnt] = - instr_ret_compressed_spec_i & ~mcountinhibit[Cnt] ? mhpmcounter_next: mhpmcounter_raw; end else begin : gen_other_cnts logic [63:0] unused_mhpmcounter_next; @@ -1334,11 +1282,6 @@ module ibex_cs_registers #( end end else begin : gen_unimp assign mhpmcounter[Cnt] = '0; - - if (Cnt == 10) begin : gen_no_compressed_instr_cnt - logic unused_instr_ret_compressed_spec_i; - assign unused_instr_ret_compressed_spec_i = instr_ret_compressed_spec_i; - end end end @@ -1407,7 +1350,7 @@ module ibex_cs_registers #( assign tmatch_value_d = csr_wdata_int[31:0]; // Registers - ibex_csr #( + cve2_csr #( .Width (DbgHwNumLen), .ShadowCopy(1'b0), .ResetValue('0) @@ -1421,7 +1364,7 @@ module ibex_cs_registers #( ); for (genvar i = 0; i < DbgHwBreakNum; i++) begin : g_dbg_tmatch_reg - ibex_csr #( + cve2_csr #( .Width (1), .ShadowCopy(1'b0), .ResetValue('0) @@ -1434,7 +1377,7 @@ module ibex_cs_registers #( .rd_error_o() ); - ibex_csr #( + cve2_csr #( .Width (32), .ShadowCopy(1'b0), .ResetValue('0) @@ -1501,88 +1444,12 @@ module ibex_cs_registers #( // CPU control register // ////////////////////////// - // Cast register write data - assign cpuctrl_wdata_raw = cpu_ctrl_t'(csr_wdata_int[$bits(cpu_ctrl_t)-1:0]); - - // Generate fixed time execution bit - if (DataIndTiming) begin : gen_dit - // SEC_CM: CORE.DATA_REG_SW.SCA - assign cpuctrl_wdata.data_ind_timing = cpuctrl_wdata_raw.data_ind_timing; - - end else begin : gen_no_dit - // tieoff for the unused bit - logic unused_dit; - assign unused_dit = cpuctrl_wdata_raw.data_ind_timing; - - // field will always read as zero if not configured - assign cpuctrl_wdata.data_ind_timing = 1'b0; - end - - assign data_ind_timing_o = cpuctrl_q.data_ind_timing; - - // Generate dummy instruction signals - if (DummyInstructions) begin : gen_dummy - // SEC_CM: CTRL_FLOW.UNPREDICTABLE - assign cpuctrl_wdata.dummy_instr_en = cpuctrl_wdata_raw.dummy_instr_en; - assign cpuctrl_wdata.dummy_instr_mask = cpuctrl_wdata_raw.dummy_instr_mask; - - // Signal a write to the seed register - assign dummy_instr_seed_en_o = csr_we_int && (csr_addr == CSR_SECURESEED); - assign dummy_instr_seed_o = csr_wdata_int; - - end else begin : gen_no_dummy - // tieoff for the unused bit - logic unused_dummy_en; - logic [2:0] unused_dummy_mask; - assign unused_dummy_en = cpuctrl_wdata_raw.dummy_instr_en; - assign unused_dummy_mask = cpuctrl_wdata_raw.dummy_instr_mask; - - // field will always read as zero if not configured - assign cpuctrl_wdata.dummy_instr_en = 1'b0; - assign cpuctrl_wdata.dummy_instr_mask = 3'b000; - assign dummy_instr_seed_en_o = 1'b0; - assign dummy_instr_seed_o = '0; - end - - assign dummy_instr_en_o = cpuctrl_q.dummy_instr_en; - assign dummy_instr_mask_o = cpuctrl_q.dummy_instr_mask; - - // Generate icache enable bit - if (ICache) begin : gen_icache_enable - assign cpuctrl_wdata.icache_enable = cpuctrl_wdata_raw.icache_enable; - end else begin : gen_no_icache - // tieoff for the unused icen bit - logic unused_icen; - assign unused_icen = cpuctrl_wdata_raw.icache_enable; - - // icen field will always read as zero if ICache not configured - assign cpuctrl_wdata.icache_enable = 1'b0; - end - - assign cpuctrl_wdata.double_fault_seen = cpuctrl_wdata_raw.double_fault_seen; - assign cpuctrl_wdata.sync_exc_seen = cpuctrl_wdata_raw.sync_exc_seen; - - assign icache_enable_o = cpuctrl_q.icache_enable; - - ibex_csr #( - .Width ($bits(cpu_ctrl_t)), - .ShadowCopy(ShadowCSR), - .ResetValue('0) - ) u_cpuctrl_csr ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .wr_data_i ({cpuctrl_d}), - .wr_en_i (cpuctrl_we), - .rd_data_o (cpuctrl_q), - .rd_error_o(cpuctrl_err) - ); - - assign csr_shadow_err_o = mstatus_err | mtvec_err | pmp_csr_err | cpuctrl_err; + // Removed //////////////// // Assertions // //////////////// - `ASSERT(IbexCsrOpEnRequiresAccess, csr_op_en_i |-> csr_access_i) + `ASSERT(CVE2CsrOpEnRequiresAccess, csr_op_en_i |-> csr_access_i) endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_csr.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_csr.sv similarity index 98% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_csr.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_csr.sv index 309a325f..b464bcce 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_csr.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_csr.sv @@ -8,7 +8,7 @@ `include "prim_assert.sv" -module ibex_csr #( +module cve2_csr #( parameter int unsigned Width = 32, parameter bit ShadowCopy = 1'b0, parameter bit [Width-1:0] ResetValue = '0 diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_decoder.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_decoder.sv similarity index 94% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_decoder.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_decoder.sv index 4b019593..5b9cbca1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_decoder.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_decoder.sv @@ -13,11 +13,10 @@ `include "prim_assert.sv" -module ibex_decoder #( +module cve2_decoder #( parameter bit RV32E = 0, - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, - parameter bit BranchTargetALU = 0 + parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast, + parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( input logic clk_i, input logic rst_ni, @@ -31,8 +30,6 @@ module ibex_decoder #( output logic ecall_insn_o, // syscall instr encountered output logic wfi_insn_o, // wait for interrupt instr encountered output logic jump_set_o, // jump taken set signal - input logic branch_taken_i, // registered branch decision - output logic icache_inval_o, // from IF-ID pipeline register input logic instr_first_cycle_i, // instruction read is in its first cycle @@ -43,10 +40,8 @@ module ibex_decoder #( input logic illegal_c_insn_i, // compressed instruction decode failed // immediates - output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a - output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b - output ibex_pkg::op_a_sel_e bt_a_mux_sel_o, // branch target selection operand a - output ibex_pkg::imm_b_sel_e bt_b_mux_sel_o, // branch target selection operand b + output cve2_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a + output cve2_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b output logic [31:0] imm_i_type_o, output logic [31:0] imm_s_type_o, output logic [31:0] imm_b_type_o, @@ -55,7 +50,7 @@ module ibex_decoder #( output logic [31:0] zimm_rs1_type_o, // register file - output ibex_pkg::rf_wd_sel_e rf_wdata_sel_o, // RF write data selection + output cve2_pkg::rf_wd_sel_e rf_wdata_sel_o, // RF write data selection output logic rf_we_o, // write enable for regfile output logic [4:0] rf_raddr_a_o, output logic [4:0] rf_raddr_b_o, @@ -64,10 +59,10 @@ module ibex_decoder #( output logic rf_ren_b_o, // Instruction reads from RF addr B // ALU - output ibex_pkg::alu_op_e alu_operator_o, // ALU operation selection - output ibex_pkg::op_a_sel_e alu_op_a_mux_sel_o, // operand a selection: reg value, PC, + output cve2_pkg::alu_op_e alu_operator_o, // ALU operation selection + output cve2_pkg::op_a_sel_e alu_op_a_mux_sel_o, // operand a selection: reg value, PC, // immediate or zero - output ibex_pkg::op_b_sel_e alu_op_b_mux_sel_o, // operand b selection: reg value or + output cve2_pkg::op_b_sel_e alu_op_b_mux_sel_o, // operand b selection: reg value or // immediate output logic alu_multicycle_o, // ternary bitmanip instruction @@ -77,12 +72,12 @@ module ibex_decoder #( output logic mult_sel_o, // as above but static, for data muxes output logic div_sel_o, // as above but static, for data muxes - output ibex_pkg::md_op_e multdiv_operator_o, + output cve2_pkg::md_op_e multdiv_operator_o, output logic [1:0] multdiv_signed_mode_o, // CSRs output logic csr_access_o, // access to CSR - output ibex_pkg::csr_op_e csr_op_o, // operation to perform on CSR + output cve2_pkg::csr_op_e csr_op_o, // operation to perform on CSR // LSU output logic data_req_o, // start transaction to data memory @@ -97,7 +92,7 @@ module ibex_decoder #( output logic branch_in_dec_o ); - import ibex_pkg::*; + import cve2_pkg::*; logic illegal_insn; logic illegal_reg_rv32e; @@ -206,7 +201,6 @@ module ibex_decoder #( jump_in_dec_o = 1'b0; jump_set_o = 1'b0; branch_in_dec_o = 1'b0; - icache_inval_o = 1'b0; multdiv_operator_o = MD_OP_MULL; multdiv_signed_mode_o = 2'b00; @@ -244,8 +238,8 @@ module ibex_decoder #( jump_in_dec_o = 1'b1; if (instr_first_cycle_i) begin - // Calculate jump target (and store PC + 4 if BranchTargetALU is configured) - rf_we = BranchTargetALU; + // Calculate jump target (and store PC) + rf_we = 1'b0; jump_set_o = 1'b1; end else begin // Calculate and store PC+4 @@ -257,8 +251,8 @@ module ibex_decoder #( jump_in_dec_o = 1'b1; if (instr_first_cycle_i) begin - // Calculate jump target (and store PC + 4 if BranchTargetALU is configured) - rf_we = BranchTargetALU; + // Calculate jump target (and store PC) + rf_we = 1'b0; jump_set_o = 1'b1; end else begin // Calculate and store PC+4 @@ -572,14 +566,12 @@ module ibex_decoder #( // FENCE.I is implemented as a jump to the next PC, this gives the required flushing // behaviour (iside prefetch buffer flushed and response to any outstanding iside // requests will be ignored). - // If present, the ICache will also be flushed. jump_in_dec_o = 1'b1; rf_we = 1'b0; if (instr_first_cycle_i) begin jump_set_o = 1'b1; - icache_inval_o = 1'b1; end end default: begin @@ -676,10 +668,6 @@ module ibex_decoder #( imm_a_mux_sel_o = IMM_A_ZERO; imm_b_mux_sel_o = IMM_B_I; - bt_a_mux_sel_o = OP_A_CURRPC; - bt_b_mux_sel_o = IMM_B_I; - - opcode_alu = opcode_e'(instr_alu[6:0]); use_rs3_d = 1'b0; @@ -694,13 +682,8 @@ module ibex_decoder #( /////////// OPCODE_JAL: begin // Jump and Link - if (BranchTargetALU) begin - bt_a_mux_sel_o = OP_A_CURRPC; - bt_b_mux_sel_o = IMM_B_J; - end - // Jumps take two cycles without the BTALU - if (instr_first_cycle_i && !BranchTargetALU) begin + if (instr_first_cycle_i) begin // Calculate jump target alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; @@ -716,13 +699,8 @@ module ibex_decoder #( end OPCODE_JALR: begin // Jump and Link Register - if (BranchTargetALU) begin - bt_a_mux_sel_o = OP_A_REG_A; - bt_b_mux_sel_o = IMM_B_I; - end - // Jumps take two cycles without the BTALU - if (instr_first_cycle_i && !BranchTargetALU) begin + if (instr_first_cycle_i) begin // Calculate jump target alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_IMM; @@ -749,24 +727,18 @@ module ibex_decoder #( default: ; endcase - if (BranchTargetALU) begin - bt_a_mux_sel_o = OP_A_CURRPC; - // Not-taken branch will jump to next instruction (used in secure mode) - bt_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC; - end - // Without branch target ALU, a branch is a two-stage operation using the Main ALU in both // stages if (instr_first_cycle_i) begin // First evaluate the branch condition alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_REG_B; - end else if (!BranchTargetALU) begin + end else begin // Then calculate jump target alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; // Not-taken branch will jump to next instruction (used in secure mode) - imm_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC; + imm_b_mux_sel_o = IMM_B_B; alu_operator_o = ALU_ADD; end end @@ -1147,15 +1119,10 @@ module ibex_decoder #( end 3'b001: begin // FENCE.I will flush the IF stage, prefetch buffer and ICache if present. - if (BranchTargetALU) begin - bt_a_mux_sel_o = OP_A_CURRPC; - bt_b_mux_sel_o = IMM_B_INCR_PC; - end else begin alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_INCR_PC; alu_operator_o = ALU_ADD; - end end default: ; endcase diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_ex_block.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_ex_block.sv similarity index 80% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_ex_block.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_ex_block.sv index ee900164..98713a3d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_ex_block.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_ex_block.sv @@ -8,27 +8,21 @@ * * Execution block: Hosts ALU and MUL/DIV unit */ -module ibex_ex_block #( - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, - parameter bit BranchTargetALU = 0 +module cve2_ex_block #( + parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast, + parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( input logic clk_i, input logic rst_ni, // ALU - input ibex_pkg::alu_op_e alu_operator_i, + input cve2_pkg::alu_op_e alu_operator_i, input logic [31:0] alu_operand_a_i, input logic [31:0] alu_operand_b_i, input logic alu_instr_first_cycle_i, - // Branch Target ALU - // All of these signals are unusued when BranchTargetALU == 0 - input logic [31:0] bt_a_operand_i, - input logic [31:0] bt_b_operand_i, - // Multiplier/Divider - input ibex_pkg::md_op_e multdiv_operator_i, + input cve2_pkg::md_op_e multdiv_operator_i, input logic mult_en_i, // dynamic enable signal, for FSM control input logic div_en_i, // dynamic enable signal, for FSM control input logic mult_sel_i, // static decoder output, for data muxes @@ -36,8 +30,6 @@ module ibex_ex_block #( input logic [1:0] multdiv_signed_mode_i, input logic [31:0] multdiv_operand_a_i, input logic [31:0] multdiv_operand_b_i, - input logic multdiv_ready_id_i, - input logic data_ind_timing_i, // intermediate val reg output logic [1:0] imd_val_we_o, @@ -53,7 +45,7 @@ module ibex_ex_block #( output logic ex_valid_o // EX has valid output ); - import ibex_pkg::*; + import cve2_pkg::*; logic [31:0] alu_result, multdiv_result; @@ -91,29 +83,16 @@ module ibex_ex_block #( // branch handling assign branch_decision_o = alu_cmp_result; - if (BranchTargetALU) begin : g_branch_target_alu - logic [32:0] bt_alu_result; - logic unused_bt_carry; - - assign bt_alu_result = bt_a_operand_i + bt_b_operand_i; - - assign unused_bt_carry = bt_alu_result[32]; - assign branch_target_o = bt_alu_result[31:0]; - end else begin : g_no_branch_target_alu - // Unused bt_operand signals cause lint errors, this avoids them - logic [31:0] unused_bt_a_operand, unused_bt_b_operand; + // Unused bt_operand signals cause lint errors, this avoids them + //logic [31:0] unused_bt_a_operand, unused_bt_b_operand; - assign unused_bt_a_operand = bt_a_operand_i; - assign unused_bt_b_operand = bt_b_operand_i; - - assign branch_target_o = alu_adder_result_ex_o; - end + assign branch_target_o = alu_adder_result_ex_o; ///////// // ALU // ///////// - ibex_alu #( + cve2_alu #( .RV32B(RV32B) ) alu_i ( .operator_i (alu_operator_i), @@ -138,7 +117,7 @@ module ibex_ex_block #( //////////////// if (RV32M == RV32MSlow) begin : gen_multdiv_slow - ibex_multdiv_slow multdiv_i ( + cve2_multdiv_slow multdiv_i ( .clk_i (clk_i), .rst_ni (rst_ni), .mult_en_i (mult_en_i), @@ -152,18 +131,17 @@ module ibex_ex_block #( .alu_adder_ext_i (alu_adder_result_ext), .alu_adder_i (alu_adder_result_ex_o), .equal_to_zero_i (alu_is_equal_result), - .data_ind_timing_i (data_ind_timing_i), .valid_o (multdiv_valid), .alu_operand_a_o (multdiv_alu_operand_a), .alu_operand_b_o (multdiv_alu_operand_b), .imd_val_q_i (imd_val_q_i), .imd_val_d_o (multdiv_imd_val_d), .imd_val_we_o (multdiv_imd_val_we), - .multdiv_ready_id_i(multdiv_ready_id_i), + .multdiv_ready_id_i(1'b1), .multdiv_result_o (multdiv_result) ); end else if (RV32M == RV32MFast || RV32M == RV32MSingleCycle) begin : gen_multdiv_fast - ibex_multdiv_fast #( + cve2_multdiv_fast #( .RV32M(RV32M) ) multdiv_i ( .clk_i (clk_i), @@ -181,11 +159,9 @@ module ibex_ex_block #( .alu_adder_ext_i (alu_adder_result_ext), .alu_adder_i (alu_adder_result_ex_o), .equal_to_zero_i (alu_is_equal_result), - .data_ind_timing_i (data_ind_timing_i), .imd_val_q_i (imd_val_q_i), .imd_val_d_o (multdiv_imd_val_d), .imd_val_we_o (multdiv_imd_val_we), - .multdiv_ready_id_i(multdiv_ready_id_i), .valid_o (multdiv_valid), .multdiv_result_o (multdiv_result) ); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_fetch_fifo.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv similarity index 92% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_fetch_fifo.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv index 61179ed0..20b2b62b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_fetch_fifo.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv @@ -12,9 +12,8 @@ `include "prim_assert.sv" -module ibex_fetch_fifo #( - parameter int unsigned NUM_REQS = 2, - parameter bit ResetAll = 1'b0 +module cve2_fetch_fifo #( + parameter int unsigned NUM_REQS = 2 ) ( input logic clk_i, input logic rst_ni, @@ -149,19 +148,11 @@ module ibex_fetch_fifo #( assign instr_addr_d = clear_i ? in_addr_i[31:1] : instr_addr_next; - if (ResetAll) begin : g_instr_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_addr_q <= '0; - end else if (instr_addr_en) begin - instr_addr_q <= instr_addr_d; - end - end - end else begin : g_instr_addr_nr - always_ff @(posedge clk_i) begin - if (instr_addr_en) begin - instr_addr_q <= instr_addr_d; - end + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + instr_addr_q <= '0; + end else if (instr_addr_en) begin + instr_addr_q <= instr_addr_d; end end @@ -234,7 +225,7 @@ module ibex_fetch_fifo #( end for (genvar i = 0; i < DEPTH; i++) begin : g_fifo_regs - if (ResetAll) begin : g_rdata_ra + begin : g_rdata always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rdata_q[i] <= '0; @@ -244,13 +235,6 @@ module ibex_fetch_fifo #( err_q[i] <= err_d[i]; end end - end else begin : g_rdata_nr - always_ff @(posedge clk_i) begin - if (entry_en[i]) begin - rdata_q[i] <= rdata_d[i]; - err_q[i] <= err_d[i]; - end - end end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv similarity index 60% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_id_stage.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv index 1644d072..e989ff29 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv @@ -15,20 +15,17 @@ */ `include "prim_assert.sv" -//`include "dv_fcov_macros.svh" +`include "dv_fcov_macros.svh" -module ibex_id_stage #( +module cve2_id_stage #( parameter bit RV32E = 0, - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, - parameter bit DataIndTiming = 1'b0, - parameter bit BranchTargetALU = 0, - parameter bit WritebackStage = 0, - parameter bit BranchPredictor = 0 + parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast, + parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( input logic clk_i, input logic rst_ni, + input logic fetch_enable_i, output logic ctrl_busy_o, output logic illegal_insn_o, @@ -38,23 +35,19 @@ module ibex_id_stage #( input logic [31:0] instr_rdata_alu_i, // from IF-ID pipeline registers input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers input logic instr_is_compressed_i, - input logic instr_bp_taken_i, output logic instr_req_o, output logic instr_first_cycle_id_o, output logic instr_valid_clear_o, // kill instr in IF-ID reg output logic id_in_ready_o, // ID stage is ready for next instr - output logic icache_inval_o, // Jumps and branches input logic branch_decision_i, // IF and ID stage signals output logic pc_set_o, - output ibex_pkg::pc_sel_e pc_mux_o, - output logic nt_branch_mispredict_o, - output logic [31:0] nt_branch_addr_o, - output ibex_pkg::exc_pc_sel_e exc_pc_mux_o, - output ibex_pkg::exc_cause_e exc_cause_o, + output cve2_pkg::pc_sel_e pc_mux_o, + output cve2_pkg::exc_pc_sel_e exc_pc_mux_o, + output cve2_pkg::exc_cause_e exc_cause_o, input logic illegal_c_insn_i, input logic instr_fetch_err_i, @@ -66,7 +59,7 @@ module ibex_id_stage #( input logic ex_valid_i, // EX stage has valid output input logic lsu_resp_valid_i, // LSU has valid output, or is done // ALU - output ibex_pkg::alu_op_e alu_operator_ex_o, + output cve2_pkg::alu_op_e alu_operator_ex_o, output logic [31:0] alu_operand_a_ex_o, output logic [31:0] alu_operand_b_ex_o, @@ -75,36 +68,29 @@ module ibex_id_stage #( input logic [33:0] imd_val_d_ex_i[2], output logic [33:0] imd_val_q_ex_o[2], - // Branch target ALU - output logic [31:0] bt_a_operand_o, - output logic [31:0] bt_b_operand_o, - // MUL, DIV output logic mult_en_ex_o, output logic div_en_ex_o, output logic mult_sel_ex_o, output logic div_sel_ex_o, - output ibex_pkg::md_op_e multdiv_operator_ex_o, + output cve2_pkg::md_op_e multdiv_operator_ex_o, output logic [1:0] multdiv_signed_mode_ex_o, output logic [31:0] multdiv_operand_a_ex_o, output logic [31:0] multdiv_operand_b_ex_o, - output logic multdiv_ready_id_o, // CSR output logic csr_access_o, - output ibex_pkg::csr_op_e csr_op_o, + output cve2_pkg::csr_op_e csr_op_o, output logic csr_op_en_o, output logic csr_save_if_o, output logic csr_save_id_o, - output logic csr_save_wb_o, output logic csr_restore_mret_id_o, output logic csr_restore_dret_id_o, output logic csr_save_cause_o, output logic [31:0] csr_mtval_o, - input ibex_pkg::priv_lvl_e priv_mode_i, + input cve2_pkg::priv_lvl_e priv_mode_i, input logic csr_mstatus_tw_i, input logic illegal_csr_insn_i, - input logic data_ind_timing_i, // Interface to load store unit output logic lsu_req_o, @@ -113,18 +99,13 @@ module ibex_id_stage #( output logic lsu_sign_ext_o, output logic [31:0] lsu_wdata_o, - input logic lsu_req_done_i, // Data req to LSU is complete and - // instruction can move to writeback - // (only relevant where writeback stage is - // present) - input logic lsu_addr_incr_req_i, input logic [31:0] lsu_addr_last_i, // Interrupt signals input logic csr_mstatus_mie_i, input logic irq_pending_i, - input ibex_pkg::irqs_t irqs_i, + input cve2_pkg::irqs_t irqs_i, input logic irq_nm_i, output logic nmi_mode_o, @@ -133,7 +114,7 @@ module ibex_id_stage #( // Debug Signal output logic debug_mode_o, - output ibex_pkg::dbg_cause_e debug_cause_o, + output cve2_pkg::dbg_cause_e debug_cause_o, output logic debug_csr_save_o, input logic debug_req_i, input logic debug_single_step_i, @@ -141,9 +122,6 @@ module ibex_id_stage #( input logic debug_ebreaku_i, input logic trigger_match_i, - // Wakeup Signal - output logic wake_from_sleep_o, - // Write back signal input logic [31:0] result_ex_i, input logic [31:0] csr_rdata_i, @@ -160,20 +138,9 @@ module ibex_id_stage #( output logic [4:0] rf_waddr_id_o, output logic [31:0] rf_wdata_id_o, output logic rf_we_id_o, - output logic rf_rd_a_wb_match_o, - output logic rf_rd_b_wb_match_o, - - // Register write information from writeback (for resolving data hazards) - input logic [4:0] rf_waddr_wb_i, - input logic [31:0] rf_wdata_fwd_wb_i, - input logic rf_write_wb_i, output logic en_wb_o, - output ibex_pkg::wb_instr_type_e instr_type_wb_o, output logic instr_perf_count_id_o, - input logic ready_wb_i, - input logic outstanding_load_wb_i, - input logic outstanding_store_wb_i, // Performance Counters output logic perf_jump_o, // executing a jump instr @@ -181,12 +148,12 @@ module ibex_id_stage #( output logic perf_tbranch_o, // executing a taken branch instr output logic perf_dside_wait_o, // instruction in ID/EX is awaiting memory // access to finish before proceeding - output logic perf_mul_wait_o, + output logic perf_wfi_wait_o, output logic perf_div_wait_o, output logic instr_id_done_o ); - import ibex_pkg::*; + import cve2_pkg::*; // Decoder/Controller, ID stage internal signals logic illegal_insn_dec; @@ -196,14 +163,9 @@ module ibex_id_stage #( logic ecall_insn_dec; logic wfi_insn_dec; - logic wb_exception; - logic id_exception; - logic branch_in_dec; logic branch_set, branch_set_raw, branch_set_raw_d; logic branch_jump_set_done_q, branch_jump_set_done_d; - logic branch_not_set; - logic branch_taken; logic jump_in_dec; logic jump_set_dec; logic jump_set, jump_set_raw; @@ -213,13 +175,11 @@ module ibex_id_stage #( logic instr_executing; logic instr_done; logic controller_run; - logic stall_ld_hz; logic stall_mem; logic stall_multdiv; logic stall_branch; logic stall_jump; logic stall_id; - logic stall_wb; logic flush_id; logic multicycle_done; @@ -260,9 +220,6 @@ module ibex_id_stage #( logic [33:0] imd_val_q[2]; - op_a_sel_e bt_a_mux_sel; - imm_b_sel_e bt_b_mux_sel; - imm_a_sel_e imm_a_mux_sel; imm_b_sel_e imm_b_mux_sel, imm_b_mux_sel_dec; @@ -313,75 +270,30 @@ module ibex_id_stage #( endcase end - if (BranchTargetALU) begin : g_btalu_muxes - // Branch target ALU operand A mux - always_comb begin : bt_operand_a_mux - unique case (bt_a_mux_sel) - OP_A_REG_A: bt_a_operand_o = rf_rdata_a_fwd; - OP_A_CURRPC: bt_a_operand_o = pc_id_i; - default: bt_a_operand_o = pc_id_i; - endcase - end - - // Branch target ALU operand B mux - always_comb begin : bt_immediate_b_mux - unique case (bt_b_mux_sel) - IMM_B_I: bt_b_operand_o = imm_i_type; - IMM_B_B: bt_b_operand_o = imm_b_type; - IMM_B_J: bt_b_operand_o = imm_j_type; - IMM_B_INCR_PC: bt_b_operand_o = instr_is_compressed_i ? 32'h2 : 32'h4; - default: bt_b_operand_o = instr_is_compressed_i ? 32'h2 : 32'h4; - endcase - end - - // Reduced main ALU immediate MUX for Operand B - always_comb begin : immediate_b_mux - unique case (imm_b_mux_sel) - IMM_B_I: imm_b = imm_i_type; - IMM_B_S: imm_b = imm_s_type; - IMM_B_U: imm_b = imm_u_type; - IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4; - IMM_B_INCR_ADDR: imm_b = 32'h4; - default: imm_b = 32'h4; - endcase - end - `ASSERT(IbexImmBMuxSelValid, instr_valid_i |-> imm_b_mux_sel inside { - IMM_B_I, - IMM_B_S, - IMM_B_U, - IMM_B_INCR_PC, - IMM_B_INCR_ADDR}) - end else begin : g_nobtalu - op_a_sel_e unused_a_mux_sel; - imm_b_sel_e unused_b_mux_sel; - - assign unused_a_mux_sel = bt_a_mux_sel; - assign unused_b_mux_sel = bt_b_mux_sel; - assign bt_a_operand_o = '0; - assign bt_b_operand_o = '0; - - // Full main ALU immediate MUX for Operand B - always_comb begin : immediate_b_mux - unique case (imm_b_mux_sel) - IMM_B_I: imm_b = imm_i_type; - IMM_B_S: imm_b = imm_s_type; - IMM_B_B: imm_b = imm_b_type; - IMM_B_U: imm_b = imm_u_type; - IMM_B_J: imm_b = imm_j_type; - IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4; - IMM_B_INCR_ADDR: imm_b = 32'h4; - default: imm_b = 32'h4; - endcase - end - `ASSERT(IbexImmBMuxSelValid, instr_valid_i |-> imm_b_mux_sel inside { - IMM_B_I, - IMM_B_S, - IMM_B_B, - IMM_B_U, - IMM_B_J, - IMM_B_INCR_PC, - IMM_B_INCR_ADDR}) + op_a_sel_e unused_a_mux_sel; + imm_b_sel_e unused_b_mux_sel; + + // Full main ALU immediate MUX for Operand B + always_comb begin : immediate_b_mux + unique case (imm_b_mux_sel) + IMM_B_I: imm_b = imm_i_type; + IMM_B_S: imm_b = imm_s_type; + IMM_B_B: imm_b = imm_b_type; + IMM_B_U: imm_b = imm_u_type; + IMM_B_J: imm_b = imm_j_type; + IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4; + IMM_B_INCR_ADDR: imm_b = 32'h4; + default: imm_b = 32'h4; + endcase end + `ASSERT(IbexImmBMuxSelValid, instr_valid_i |-> imm_b_mux_sel inside { + IMM_B_I, + IMM_B_S, + IMM_B_B, + IMM_B_U, + IMM_B_J, + IMM_B_INCR_PC, + IMM_B_INCR_ADDR}) // ALU MUX for Operand B assign alu_operand_b = (alu_op_b_mux_sel == OP_B_IMM) ? imm_b : rf_rdata_b_fwd; @@ -422,11 +334,10 @@ module ibex_id_stage #( // Decoder // ///////////// - ibex_decoder #( + cve2_decoder #( .RV32E (RV32E), .RV32M (RV32M), - .RV32B (RV32B), - .BranchTargetALU(BranchTargetALU) + .RV32B (RV32B) ) decoder_i ( .clk_i (clk_i), .rst_ni(rst_ni), @@ -439,8 +350,6 @@ module ibex_id_stage #( .ecall_insn_o (ecall_insn_dec), .wfi_insn_o (wfi_insn_dec), .jump_set_o (jump_set_dec), - .branch_taken_i(branch_taken), - .icache_inval_o(icache_inval_o), // from IF-ID pipeline register .instr_first_cycle_i(instr_first_cycle), @@ -451,8 +360,6 @@ module ibex_id_stage #( // immediates .imm_a_mux_sel_o(imm_a_mux_sel), .imm_b_mux_sel_o(imm_b_mux_sel_dec), - .bt_a_mux_sel_o (bt_a_mux_sel), - .bt_b_mux_sel_o (bt_b_mux_sel), .imm_i_type_o (imm_i_type), .imm_s_type_o (imm_s_type), @@ -501,7 +408,7 @@ module ibex_id_stage #( ); ///////////////////////////////// - // CSR-related pipline flushes // + // CSR-related pipeline flushes // ///////////////////////////////// always_comb begin : csr_pipeline_flushes csr_pipe_flush = 1'b0; @@ -510,10 +417,15 @@ module ibex_id_stage #( // - When enabling interrupts, pending IRQs become visible to the controller only during // the next cycle. If during that cycle the core disables interrupts again, it does not // see any pending IRQs and consequently does not start to handle interrupts. + // - When modifying any PMP CSR, PMP check of the next instruction might get invalidated. + // Hence, a pipeline flush is needed to instantiate another PMP check with the updated CSRs. // - When modifying debug CSRs - TODO: Check if this is really needed if (csr_op_en_o == 1'b1 && (csr_op_o == CSR_OP_WRITE || csr_op_o == CSR_OP_SET)) begin - if (csr_num_e'(instr_rdata_i[31:20]) == CSR_MSTATUS || - csr_num_e'(instr_rdata_i[31:20]) == CSR_MIE) begin + if (csr_num_e'(instr_rdata_i[31:20]) == CSR_MSTATUS || + csr_num_e'(instr_rdata_i[31:20]) == CSR_MIE || + csr_num_e'(instr_rdata_i[31:20]) == CSR_MSECCFG || + // To catch all PMPCFG/PMPADDR registers, get the shared top most 7 bits. + instr_rdata_i[31:25] == 7'h1D) begin csr_pipe_flush = 1'b1; end end else if (csr_op_en_o == 1'b1 && csr_op_o != CSR_OP_READ) begin @@ -532,13 +444,12 @@ module ibex_id_stage #( assign illegal_insn_o = instr_valid_i & (illegal_insn_dec | illegal_csr_insn_i); - ibex_controller #( - .WritebackStage (WritebackStage), - .BranchPredictor(BranchPredictor) + cve2_controller #( ) controller_i ( .clk_i (clk_i), .rst_ni(rst_ni), + .fetch_enable_i(fetch_enable_i), .ctrl_busy_o(ctrl_busy_o), // decoder related signals @@ -555,7 +466,6 @@ module ibex_id_stage #( .instr_i (instr_rdata_i), .instr_compressed_i (instr_rdata_c_i), .instr_is_compressed_i (instr_is_compressed_i), - .instr_bp_taken_i (instr_bp_taken_i), .instr_fetch_err_i (instr_fetch_err_i), .instr_fetch_err_plus2_i(instr_fetch_err_plus2_i), .pc_id_i (pc_id_i), @@ -569,7 +479,6 @@ module ibex_id_stage #( .instr_req_o (instr_req_o), .pc_set_o (pc_set_o), .pc_mux_o (pc_mux_o), - .nt_branch_mispredict_o(nt_branch_mispredict_o), .exc_pc_mux_o (exc_pc_mux_o), .exc_cause_o (exc_cause_o), @@ -577,12 +486,8 @@ module ibex_id_stage #( .lsu_addr_last_i(lsu_addr_last_i), .load_err_i (lsu_load_err_i), .store_err_i (lsu_store_err_i), - .wb_exception_o (wb_exception), - .id_exception_o (id_exception), - // jump/branch control .branch_set_i (branch_set), - .branch_not_set_i (branch_not_set), .jump_set_i (jump_set), // interrupt signals @@ -595,7 +500,6 @@ module ibex_id_stage #( // CSR Controller Signals .csr_save_if_o (csr_save_if_o), .csr_save_id_o (csr_save_id_o), - .csr_save_wb_o (csr_save_wb_o), .csr_restore_mret_id_o(csr_restore_mret_id_o), .csr_restore_dret_id_o(csr_restore_dret_id_o), .csr_save_cause_o (csr_save_cause_o), @@ -613,13 +517,8 @@ module ibex_id_stage #( .debug_ebreaku_i (debug_ebreaku_i), .trigger_match_i (trigger_match_i), - // Wakeup Signal - .wake_from_sleep_o(wake_from_sleep_o), - .stall_id_i(stall_id), - .stall_wb_i(stall_wb), .flush_id_o(flush_id), - .ready_wb_i(ready_wb_i), // Performance Counters .perf_jump_o (perf_jump_o), @@ -659,31 +558,24 @@ module ibex_id_stage #( // Branch set control // //////////////////////// - if (BranchTargetALU && !DataIndTiming) begin : g_branch_set_direct - // Branch set fed straight to controller with branch target ALU - // (condition pass/fail used same cycle as generated instruction request) - assign branch_set_raw = branch_set_raw_d; - end else begin : g_branch_set_flop - // SEC_CM: CORE.DATA_REG_SW.SCA - // Branch set flopped without branch target ALU, or in fixed time execution mode - // (condition pass/fail used next cycle where branch target is calculated) - logic branch_set_raw_q; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - branch_set_raw_q <= 1'b0; - end else begin - branch_set_raw_q <= branch_set_raw_d; - end + // SEC_CM: CORE.DATA_REG_SW.SCA + // Branch set flopped without branch target ALU, or in fixed time execution mode + // (condition pass/fail used next cycle where branch target is calculated) + logic branch_set_raw_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + branch_set_raw_q <= 1'b0; + end else begin + branch_set_raw_q <= branch_set_raw_d; end + end - // Branches always take two cycles in fixed time execution mode, with or without the branch - // target ALU (to avoid a path from the branch decision into the branch target ALU operand - // muxing). - assign branch_set_raw = (BranchTargetALU && !data_ind_timing_i) ? branch_set_raw_d : - branch_set_raw_q; + // Branches always take two cycles in fixed time execution mode, with or without the branch + // target ALU (to avoid a path from the branch decision into the branch target ALU operand + // muxing). + assign branch_set_raw = branch_set_raw_q; - end // Track whether the current instruction in ID/EX has done a branch or jump set. assign branch_jump_set_done_d = (branch_set_raw | jump_set_raw | branch_jump_set_done_q) & @@ -707,46 +599,6 @@ module ibex_id_stage #( assign jump_set = jump_set_raw & ~branch_jump_set_done_q; assign branch_set = branch_set_raw & ~branch_jump_set_done_q; - // Branch condition is calculated in the first cycle and flopped for use in the second cycle - // (only used in fixed time execution mode to determine branch destination). - if (DataIndTiming) begin : g_sec_branch_taken - // SEC_CM: CORE.DATA_REG_SW.SCA - logic branch_taken_q; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - branch_taken_q <= 1'b0; - end else begin - branch_taken_q <= branch_decision_i; - end - end - - assign branch_taken = ~data_ind_timing_i | branch_taken_q; - - end else begin : g_nosec_branch_taken - - // Signal unused without fixed time execution mode - only taken branches will trigger - // branch_set_raw - assign branch_taken = 1'b1; - - end - - // Holding branch_set/jump_set high for more than one cycle should not cause a functional issue. - // However it could generate needless prefetch buffer flushes and instruction fetches. The ID/EX - // designs ensures that this never happens for non-predicted branches. - `ASSERT(NeverDoubleBranch, branch_set & ~instr_bp_taken_i |=> ~branch_set) - `ASSERT(NeverDoubleJump, jump_set & ~instr_bp_taken_i |=> ~jump_set) - - ////////////////////////////// - // Branch not-taken address // - ////////////////////////////// - - if (BranchPredictor) begin : g_calc_nt_addr - assign nt_branch_addr_o = pc_id_i + (instr_is_compressed_i ? 32'd2 : 32'd4); - end else begin : g_n_calc_nt_addr - assign nt_branch_addr_o = 32'd0; - end - /////////////// // ID-EX FSM // /////////////// @@ -775,7 +627,6 @@ module ibex_id_stage #( stall_branch = 1'b0; stall_alu = 1'b0; branch_set_raw_d = 1'b0; - branch_not_set = 1'b0; jump_set_raw = 1'b0; perf_branch_o = 1'b0; @@ -784,13 +635,9 @@ module ibex_id_stage #( FIRST_CYCLE: begin unique case (1'b1) lsu_req_dec: begin - if (!WritebackStage) begin + begin // LSU operation id_fsm_d = MULTI_CYCLE; - end else begin - if(~lsu_req_done_i) begin - id_fsm_d = MULTI_CYCLE; - end end end multdiv_en_dec: begin @@ -808,22 +655,17 @@ module ibex_id_stage #( // All branches take two cycles in fixed time execution mode, regardless of branch // condition. // SEC_CM: CORE.DATA_REG_SW.SCA - id_fsm_d = (data_ind_timing_i || (!BranchTargetALU && branch_decision_i)) ? + id_fsm_d = (branch_decision_i) ? MULTI_CYCLE : FIRST_CYCLE; - stall_branch = (~BranchTargetALU & branch_decision_i) | data_ind_timing_i; - branch_set_raw_d = (branch_decision_i | data_ind_timing_i); - - if (BranchPredictor) begin - branch_not_set = ~branch_decision_i; - end + stall_branch = branch_decision_i; + branch_set_raw_d = branch_decision_i; perf_branch_o = 1'b1; end jump_in_dec: begin // uncond branch operation - // BTALU means jumps only need one cycle - id_fsm_d = BranchTargetALU ? FIRST_CYCLE : MULTI_CYCLE; - stall_jump = ~BranchTargetALU; + id_fsm_d = MULTI_CYCLE; + stall_jump = 1'b1; jump_set_raw = jump_set_dec; end alu_multicycle_dec: begin @@ -842,7 +684,7 @@ module ibex_id_stage #( rf_we_raw = rf_we_dec & ex_valid_i; end - if (multicycle_done & ready_wb_i) begin + if (multicycle_done) begin id_fsm_d = FIRST_CYCLE; end else begin stall_multdiv = multdiv_en_dec; @@ -858,22 +700,19 @@ module ibex_id_stage #( end end - // Note for the two-stage configuration ready_wb_i is always set - assign multdiv_ready_id_o = ready_wb_i; - `ASSERT(StallIDIfMulticycle, (id_fsm_q == FIRST_CYCLE) & (id_fsm_d == MULTI_CYCLE) |-> stall_id) // Stall ID/EX stage for reason that relates to instruction in ID/EX, update assertion below if // modifying this. - assign stall_id = stall_ld_hz | stall_mem | stall_multdiv | stall_jump | stall_branch | + assign stall_id = stall_mem | stall_multdiv | stall_jump | stall_branch | stall_alu; // Generally illegal instructions have no reason to stall, however they must still stall waiting // for outstanding memory requests so exceptions related to them take priority over the illegal // instruction exception. `ASSERT(IllegalInsnStallMustBeMemStall, illegal_insn_o & stall_id |-> stall_mem & - ~(stall_ld_hz | stall_multdiv | stall_jump | stall_branch | stall_alu)) + ~(stall_multdiv | stall_jump | stall_branch | stall_alu)) assign instr_done = ~stall_id & ~flush_id & instr_executing; @@ -884,119 +723,6 @@ module ibex_id_stage #( // Used by ALU to access RS3 if ternary instruction. assign instr_first_cycle_id_o = instr_first_cycle; - if (WritebackStage) begin : gen_stall_mem - // Register read address matches write address in WB - logic rf_rd_a_wb_match; - logic rf_rd_b_wb_match; - // Hazard between registers being read and written - logic rf_rd_a_hz; - logic rf_rd_b_hz; - - logic outstanding_memory_access; - - logic instr_kill; - - assign multicycle_done = lsu_req_dec ? ~stall_mem : ex_valid_i; - - // Is a memory access ongoing that isn't finishing this cycle - assign outstanding_memory_access = (outstanding_load_wb_i | outstanding_store_wb_i) & - ~lsu_resp_valid_i; - - // Can start a new memory access if any previous one has finished or is finishing - assign data_req_allowed = ~outstanding_memory_access; - - // Instruction won't execute because: - // - There is a pending exception in writeback - // The instruction in ID/EX will be flushed and the core will jump to an exception handler - // - The controller isn't running instructions - // This either happens in preparation for a flush and jump to an exception handler e.g. in - // response to an IRQ or debug request or whilst the core is sleeping or resetting/fetching - // first instruction in which case any valid instruction in ID/EX should be ignored. - // - There was an error on instruction fetch - assign instr_kill = instr_fetch_err_i | - wb_exception | - id_exception | - ~controller_run; - - // With writeback stage instructions must be prevented from executing if there is: - // - A load hazard - // - A pending memory access - // If it receives an error response this results in a precise exception from WB so ID/EX - // instruction must not execute until error response is known). - // - A load/store error - // This will cause a precise exception for the instruction in WB so ID/EX instruction must not - // execute - // - // instr_executing_spec is a speculative signal. It indicates an instruction can execute - // assuming there are no exceptions from writeback and any outstanding memory access won't - // receive an error. It is required so branch and jump requests don't factor in an incoming dmem - // error (that in turn would factor directly into imem requests leading to a feedthrough path). - // - // instr_executing is the full signal, it will only allow execution once any potential - // exceptions from writeback have been resolved. - assign instr_executing_spec = instr_valid_i & - ~instr_fetch_err_i & - controller_run & - ~stall_ld_hz; - - assign instr_executing = instr_valid_i & - ~instr_kill & - ~stall_ld_hz & - ~outstanding_memory_access; - - `ASSERT(IbexExecutingSpecIfExecuting, instr_executing |-> instr_executing_spec) - - `ASSERT(IbexStallIfValidInstrNotExecuting, - instr_valid_i & ~instr_kill & ~instr_executing |-> stall_id) - - `ASSERT(IbexCannotRetireWithPendingExceptions, - instr_done |-> ~(wb_exception | outstanding_memory_access)) - - // Stall for reasons related to memory: - // * There is an outstanding memory access that won't resolve this cycle (need to wait to allow - // precise exceptions) - // * There is a load/store request not being granted or which is unaligned and waiting to issue - // a second request (needs to stay in ID for the address calculation) - assign stall_mem = instr_valid_i & - (outstanding_memory_access | (lsu_req_dec & ~lsu_req_done_i)); - - // If we stall a load in ID for any reason, it must not make an LSU request - // (otherwide we might issue two requests for the same instruction) - `ASSERT(IbexStallMemNoRequest, - instr_valid_i & lsu_req_dec & ~instr_done |-> ~lsu_req_done_i) - - assign rf_rd_a_wb_match = (rf_waddr_wb_i == rf_raddr_a_o) & |rf_raddr_a_o; - assign rf_rd_b_wb_match = (rf_waddr_wb_i == rf_raddr_b_o) & |rf_raddr_b_o; - - assign rf_rd_a_wb_match_o = rf_rd_a_wb_match; - assign rf_rd_b_wb_match_o = rf_rd_b_wb_match; - - // If instruction is reading register that load will be writing stall in - // ID until load is complete. No need to stall when reading zero register. - assign rf_rd_a_hz = rf_rd_a_wb_match & rf_ren_a; - assign rf_rd_b_hz = rf_rd_b_wb_match & rf_ren_b; - - // If instruction is read register that writeback is writing forward writeback data to read - // data. Note this doesn't factor in load data as it arrives too late, such hazards are - // resolved via a stall (see above). - assign rf_rdata_a_fwd = rf_rd_a_wb_match & rf_write_wb_i ? rf_wdata_fwd_wb_i : rf_rdata_a_i; - assign rf_rdata_b_fwd = rf_rd_b_wb_match & rf_write_wb_i ? rf_wdata_fwd_wb_i : rf_rdata_b_i; - - assign stall_ld_hz = outstanding_load_wb_i & (rf_rd_a_hz | rf_rd_b_hz); - - assign instr_type_wb_o = ~lsu_req_dec ? WB_INSTR_OTHER : - lsu_we ? WB_INSTR_STORE : - WB_INSTR_LOAD; - - assign instr_id_done_o = en_wb_o & ready_wb_i; - - // Stall ID/EX as instruction in ID/EX cannot proceed to writeback yet - assign stall_wb = en_wb_o & ~ready_wb_i; - - assign perf_dside_wait_o = instr_valid_i & ~instr_kill & - (outstanding_memory_access | stall_ld_hz); - end else begin : gen_no_stall_mem - assign multicycle_done = lsu_req_dec ? lsu_resp_valid_i : ex_valid_i; assign data_req_allowed = instr_first_cycle; @@ -1005,9 +731,6 @@ module ibex_id_stage #( // Then stall until it is complete assign stall_mem = instr_valid_i & (lsu_req_dec & (~lsu_resp_valid_i | instr_first_cycle)); - // No load hazards without Writeback Stage - assign stall_ld_hz = 1'b0; - // Without writeback stage any valid instruction that hasn't seen an error will execute assign instr_executing_spec = instr_valid_i & ~instr_fetch_err_i & controller_run; assign instr_executing = instr_executing_spec; @@ -1020,60 +743,34 @@ module ibex_id_stage #( assign rf_rdata_a_fwd = rf_rdata_a_i; assign rf_rdata_b_fwd = rf_rdata_b_i; - assign rf_rd_a_wb_match_o = 1'b0; - assign rf_rd_b_wb_match_o = 1'b0; - // Unused Writeback stage only IO & wiring // Assign inputs and internal wiring to unused signals to satisfy lint checks // Tie-off outputs to constant values logic unused_data_req_done_ex; - logic [4:0] unused_rf_waddr_wb; - logic unused_rf_write_wb; - logic unused_outstanding_load_wb; - logic unused_outstanding_store_wb; - logic unused_wb_exception; - logic [31:0] unused_rf_wdata_fwd_wb; - logic unused_id_exception; - - assign unused_data_req_done_ex = lsu_req_done_i; - assign unused_rf_waddr_wb = rf_waddr_wb_i; - assign unused_rf_write_wb = rf_write_wb_i; - assign unused_outstanding_load_wb = outstanding_load_wb_i; - assign unused_outstanding_store_wb = outstanding_store_wb_i; - assign unused_wb_exception = wb_exception; - assign unused_rf_wdata_fwd_wb = rf_wdata_fwd_wb_i; - assign unused_id_exception = id_exception; - - assign instr_type_wb_o = WB_INSTR_OTHER; - assign stall_wb = 1'b0; assign perf_dside_wait_o = instr_executing & lsu_req_dec & ~lsu_resp_valid_i; assign instr_id_done_o = instr_done; - end // Signal which instructions to count as retired in minstret, all traps along with ebrk and // ecall instructions are not counted. assign instr_perf_count_id_o = ~ebrk_insn & ~ecall_insn_dec & ~illegal_insn_dec & ~illegal_csr_insn_i & ~instr_fetch_err_i; - // An instruction is ready to move to the writeback stage (or retire if there is no writeback - // stage) + // An instruction is ready to move to the writeback assign en_wb_o = instr_done; - assign perf_mul_wait_o = stall_multdiv & mult_en_dec; + assign perf_wfi_wait_o = wfi_insn_dec; assign perf_div_wait_o = stall_multdiv & div_en_dec; ////////// // FCOV // ////////// - //`DV_FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz, - // (gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage) - //`DV_FCOV_SIGNAL(logic, branch_taken, - // instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i) - //`DV_FCOV_SIGNAL(logic, branch_not_taken, - // instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i) + `DV_FCOV_SIGNAL(logic, branch_taken, + instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i) + `DV_FCOV_SIGNAL(logic, branch_not_taken, + instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i) //////////////// // Assertions // @@ -1086,16 +783,6 @@ module ibex_id_stage #( OP_A_FWD, OP_A_CURRPC, OP_A_IMM}) - `ASSERT_KNOWN_IF(IbexBTAluAOpMuxSelKnown, bt_a_mux_sel, instr_valid_i) - `ASSERT(IbexBTAluAOpMuxSelValid, instr_valid_i |-> bt_a_mux_sel inside { - OP_A_REG_A, - OP_A_CURRPC}) - `ASSERT_KNOWN_IF(IbexBTAluBOpMuxSelKnown, bt_b_mux_sel, instr_valid_i) - `ASSERT(IbexBTAluBOpMuxSelValid, instr_valid_i |-> bt_b_mux_sel inside { - IMM_B_I, - IMM_B_B, - IMM_B_J, - IMM_B_INCR_PC}) `ASSERT(IbexRegfileWdataSelValid, instr_valid_i |-> rf_wdata_sel inside { RF_WD_EX, RF_WD_CSR}) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_if_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_if_stage.sv new file mode 100644 index 00000000..cbb05054 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_if_stage.sv @@ -0,0 +1,278 @@ +// Copyright lowRISC contributors. +// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Instruction Fetch Stage + * + * Instruction fetch unit: Selection of the next PC, and buffering (sampling) of + * the read instruction. + */ + +`include "prim_assert.sv" + +module cve2_if_stage import cve2_pkg::*; #( + parameter int unsigned DmHaltAddr = 32'h1A110800, + parameter int unsigned DmExceptionAddr = 32'h1A110808 +) ( + input logic clk_i, + input logic rst_ni, + + input logic [31:0] boot_addr_i, // also used for mtvec + input logic req_i, // instruction request control + + // instruction cache interface + output logic instr_req_o, + output logic [31:0] instr_addr_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + input logic [31:0] instr_rdata_i, + input logic instr_err_i, + + // output of ID stage + output logic instr_valid_id_o, // instr in IF-ID is valid + output logic instr_new_id_o, // instr in IF-ID is new + output logic [31:0] instr_rdata_id_o, // instr for ID stage + output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage + // to reduce fan-out + output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage + // (mtval), meaningful only if + // instr_is_compressed_id_o = 1'b1 + output logic instr_is_compressed_id_o, // compressed decoder thinks this + // is a compressed instr + output logic instr_fetch_err_o, // bus error on fetch + output logic instr_fetch_err_plus2_o, // bus error misaligned + output logic illegal_c_insn_id_o, // compressed decoder thinks this + // is an invalid instr + output logic [31:0] pc_if_o, + output logic [31:0] pc_id_o, + input logic pmp_err_if_i, + input logic pmp_err_if_plus2_i, + + // control signals + input logic instr_valid_clear_i, // clear instr valid bit in IF-ID + input logic pc_set_i, // set the PC to a new value + input pc_sel_e pc_mux_i, // selector for PC multiplexer + input exc_pc_sel_e exc_pc_mux_i, // selects ISR address + input exc_cause_e exc_cause, // selects ISR address for + // vectorized interrupt lines + // jump and branch target + input logic [31:0] branch_target_ex_i, // branch/jump target address + + // CSRs + input logic [31:0] csr_mepc_i, // PC to restore after handling + // the interrupt/exception + input logic [31:0] csr_depc_i, // PC to restore after handling + // the debug request + input logic [31:0] csr_mtvec_i, // base PC to jump to on exception + output logic csr_mtvec_init_o, // tell CS regfile to init mtvec + + // pipeline stall + input logic id_in_ready_i, // ID stage is ready for new instr + + // misc signals + output logic if_busy_o // IF stage is busy fetching instr +); + + logic instr_valid_id_d, instr_valid_id_q; + logic instr_new_id_d, instr_new_id_q; + + // prefetch buffer related signals + logic prefetch_busy; + logic branch_req; + logic [31:0] fetch_addr_n; + logic unused_fetch_addr_n0; + + logic fetch_valid; + logic fetch_ready; + logic [31:0] fetch_rdata; + logic [31:0] fetch_addr; + logic fetch_err; + logic fetch_err_plus2; + + logic [31:0] instr_decompressed; + logic illegal_c_insn; + logic instr_is_compressed; + + logic if_instr_pmp_err; + logic if_instr_err; + logic if_instr_err_plus2; + + logic [31:0] exc_pc; + + logic [6:0] irq_id; + logic unused_irq_bit; + + logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable + + cve2_pkg::pc_sel_e pc_mux_internal; + + logic [7:0] unused_boot_addr; + logic [7:0] unused_csr_mtvec; + + assign unused_boot_addr = boot_addr_i[7:0]; + assign unused_csr_mtvec = csr_mtvec_i[7:0]; + + // extract interrupt ID from exception cause + assign irq_id = {exc_cause}; + assign unused_irq_bit = irq_id[6]; // MSB distinguishes interrupts from exceptions + + // exception PC selection mux + always_comb begin : exc_pc_mux + unique case (exc_pc_mux_i) + EXC_PC_EXC: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; + EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], irq_id[5:0], 2'b00 }; + EXC_PC_DBD: exc_pc = DmHaltAddr; + EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr; + default: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; + endcase + end + + assign pc_mux_internal = + pc_mux_i; + + // fetch address selection mux + always_comb begin : fetch_addr_mux + unique case (pc_mux_internal) + PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h00 }; + PC_JUMP: fetch_addr_n = branch_target_ex_i; + PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler + PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC + PC_DRET: fetch_addr_n = csr_depc_i; + default: fetch_addr_n = { boot_addr_i[31:8], 8'h00 }; + endcase + end + + // tell CS register file to initialize mtvec on boot + assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i; + + // prefetch buffer, caches a fixed number of instructions + cve2_prefetch_buffer #( + ) prefetch_buffer_i ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + + .req_i ( req_i ), + + .branch_i ( branch_req ), + .addr_i ( {fetch_addr_n[31:1], 1'b0} ), + + .ready_i ( fetch_ready ), + .valid_o ( fetch_valid ), + .rdata_o ( fetch_rdata ), + .addr_o ( fetch_addr ), + .err_o ( fetch_err ), + .err_plus2_o ( fetch_err_plus2 ), + + .instr_req_o ( instr_req_o ), + .instr_addr_o ( instr_addr_o ), + .instr_gnt_i ( instr_gnt_i ), + .instr_rvalid_i ( instr_rvalid_i ), + .instr_rdata_i ( instr_rdata_i ), + .instr_err_i ( instr_err_i ), + + .busy_o ( prefetch_busy ) + ); + + assign unused_fetch_addr_n0 = fetch_addr_n[0]; + + assign branch_req = pc_set_i; + + assign pc_if_o = fetch_addr; + assign if_busy_o = prefetch_busy; + + // PMP errors + // An error can come from the instruction address, or the next instruction address for unaligned, + // uncompressed instructions. + assign if_instr_pmp_err = pmp_err_if_i | + (fetch_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i); + + // Combine bus errors and pmp errors + assign if_instr_err = fetch_err | if_instr_pmp_err; + + // Capture the second half of the address for errors on the second part of an instruction + assign if_instr_err_plus2 = ((fetch_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i) | + fetch_err_plus2) & ~pmp_err_if_i; + + // compressed instruction decoding, or more precisely compressed instruction + // expander + // + // since it does not matter where we decompress instructions, we do it here + // to ease timing closure + cve2_compressed_decoder compressed_decoder_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (fetch_valid & ~fetch_err), + .instr_i (fetch_rdata), + .instr_o (instr_decompressed), + .is_compressed_o(instr_is_compressed), + .illegal_instr_o(illegal_c_insn) + ); + + // The ID stage becomes valid as soon as any instruction is registered in the ID stage flops. + // Note that the current instruction is squashed by the incoming pc_set_i signal. + // Valid is held until it is explicitly cleared (due to an instruction completing or an exception) + assign instr_valid_id_d = (fetch_valid & id_in_ready_i & ~pc_set_i) | + (instr_valid_id_q & ~instr_valid_clear_i); + assign instr_new_id_d = fetch_valid & id_in_ready_i; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + instr_valid_id_q <= 1'b0; + instr_new_id_q <= 1'b0; + end else begin + instr_valid_id_q <= instr_valid_id_d; + instr_new_id_q <= instr_new_id_d; + end + end + + assign instr_valid_id_o = instr_valid_id_q; + // Signal when a new instruction enters the ID stage (only used for RVFI signalling). + assign instr_new_id_o = instr_new_id_q; + + // IF-ID pipeline registers, frozen when the ID stage is stalled + assign if_id_pipe_reg_we = instr_new_id_d; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + instr_rdata_id_o <= '0; + instr_rdata_alu_id_o <= '0; + instr_fetch_err_o <= '0; + instr_fetch_err_plus2_o <= '0; + instr_rdata_c_id_o <= '0; + instr_is_compressed_id_o <= '0; + illegal_c_insn_id_o <= '0; + pc_id_o <= '0; + end else if (if_id_pipe_reg_we) begin + instr_rdata_id_o <= instr_decompressed; + // To reduce fan-out and help timing from the instr_rdata_id flops they are replicated. + instr_rdata_alu_id_o <= instr_decompressed; + instr_fetch_err_o <= if_instr_err; + instr_fetch_err_plus2_o <= if_instr_err_plus2; + instr_rdata_c_id_o <= fetch_rdata[15:0]; //if_instr_rdata[15:0]; + instr_is_compressed_id_o <= instr_is_compressed; + illegal_c_insn_id_o <= illegal_c_insn; + pc_id_o <= pc_if_o; + end + end + + assign fetch_ready = id_in_ready_i; + + //////////////// + // Assertions // + //////////////// + + // Selectors must be known/valid. + `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i) + + // Boot address must be aligned to 256 bytes. + `ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00) + + // Address must not contain X when request is sent. + `ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o)) + + // Address must be word aligned when request is sent. + `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00)) + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_load_store_unit.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_load_store_unit.sv similarity index 96% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_load_store_unit.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_load_store_unit.sv index 6ec55b07..3575fadf 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_load_store_unit.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_load_store_unit.sv @@ -12,9 +12,9 @@ */ `include "prim_assert.sv" -//`include "dv_fcov_macros.svh" +`include "dv_fcov_macros.svh" -module ibex_load_store_unit +module cve2_load_store_unit ( input logic clk_i, input logic rst_ni, @@ -50,10 +50,6 @@ module ibex_load_store_unit // -> mtval // -> AGU for misaligned accesses - output logic lsu_req_done_o, // Signals that data request is complete - // (only need to await final data - // response) -> to ID/EX - output logic lsu_resp_valid_o, // LSU has response from transaction -> to ID/EX // exception signals @@ -453,8 +449,6 @@ module ibex_load_store_unit endcase end - assign lsu_req_done_o = (lsu_req_i | (ls_fsm_cs != IDLE)) & (ls_fsm_ns == IDLE); - // registers for FSM always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin @@ -503,8 +497,8 @@ module ibex_load_store_unit // FCOV // ////////// - //`DV_FCOV_SIGNAL(logic, ls_error_exception, (load_err_o | store_err_o) & ~pmp_err_q) - //`DV_FCOV_SIGNAL(logic, ls_pmp_exception, (load_err_o | store_err_o) & pmp_err_q) + `DV_FCOV_SIGNAL(logic, ls_error_exception, (load_err_o | store_err_o) & ~pmp_err_q) + `DV_FCOV_SIGNAL(logic, ls_pmp_exception, (load_err_o | store_err_o) & pmp_err_q) //////////////// // Assertions // diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_fast.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_fast.sv similarity index 96% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_fast.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_fast.sv index 3f0d27ac..d1d400a3 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_fast.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_fast.sv @@ -14,8 +14,8 @@ `include "prim_assert.sv" -module ibex_multdiv_fast #( - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast +module cve2_multdiv_fast #( + parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast ) ( input logic clk_i, input logic rst_ni, @@ -23,14 +23,13 @@ module ibex_multdiv_fast #( input logic div_en_i, // dynamic enable signal, for FSM control input logic mult_sel_i, // static decoder output, for data muxes input logic div_sel_i, // static decoder output, for data muxes - input ibex_pkg::md_op_e operator_i, + input cve2_pkg::md_op_e operator_i, input logic [1:0] signed_mode_i, input logic [31:0] op_a_i, input logic [31:0] op_b_i, input logic [33:0] alu_adder_ext_i, input logic [31:0] alu_adder_i, input logic equal_to_zero_i, - input logic data_ind_timing_i, output logic [32:0] alu_operand_a_o, output logic [32:0] alu_operand_b_o, @@ -39,13 +38,11 @@ module ibex_multdiv_fast #( output logic [33:0] imd_val_d_o[2], output logic [1:0] imd_val_we_o, - input logic multdiv_ready_id_i, - output logic [31:0] multdiv_result_o, output logic valid_o ); - import ibex_pkg::*; + import cve2_pkg::*; // Both multiplier variants logic signed [34:0] mac_res_signed; @@ -210,7 +207,7 @@ module ibex_multdiv_fast #( mult_valid = 1'b0; mult_state_d = MULH; end else begin - mult_hold = ~multdiv_ready_id_i; + mult_hold = 1'b0; end end @@ -229,7 +226,7 @@ module ibex_multdiv_fast #( mult_state_d = MULL; mult_valid = 1'b1; - mult_hold = ~multdiv_ready_id_i; + mult_hold = 1'b0; end default: begin @@ -328,7 +325,7 @@ module ibex_multdiv_fast #( // Note no state transition will occur if mult_hold is set mult_state_d = ALBL; - mult_hold = ~multdiv_ready_id_i; + mult_hold = 1'b0; end else begin accum = imd_val_q_i[0]; mac_res_d = mac_res; @@ -351,7 +348,7 @@ module ibex_multdiv_fast #( // Note no state transition will occur if mult_hold is set mult_state_d = ALBL; - mult_hold = ~multdiv_ready_id_i; + mult_hold = 1'b0; end default: begin mult_state_d = ALBL; @@ -424,7 +421,7 @@ module ibex_multdiv_fast #( // normal and will naturally return -1 op_remainder_d = '1; // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A; + md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A; // Record that this is a div by zero to stop the sign change at the end of the // division (in data_ind_timing mode). div_by_zero_d = equal_to_zero_i; @@ -435,7 +432,7 @@ module ibex_multdiv_fast #( // normal and will naturally return operand a op_remainder_d = {2'b0, op_a_i}; // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A; + md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A; end // 0 - B = 0 iff B == 0 alu_operand_a_o = {32'h0 , 1'b1}; @@ -508,7 +505,7 @@ module ibex_multdiv_fast #( // Hold result until ID stage is ready to accept it // Note no state transition will occur if div_hold is set md_state_d = MD_IDLE; - div_hold = ~multdiv_ready_id_i; + div_hold = 1'b0; div_valid = 1'b1; end @@ -530,4 +527,4 @@ module ibex_multdiv_fast #( `endif `endif -endmodule // ibex_mult +endmodule // cve2_mult diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_slow.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_slow.sv similarity index 96% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_slow.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_slow.sv index 214d3f59..70732cc6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_multdiv_slow.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_multdiv_slow.sv @@ -11,7 +11,7 @@ `include "prim_assert.sv" -module ibex_multdiv_slow +module cve2_multdiv_slow ( input logic clk_i, input logic rst_ni, @@ -19,14 +19,13 @@ module ibex_multdiv_slow input logic div_en_i, // dynamic enable signal, for FSM control input logic mult_sel_i, // static decoder output, for data muxes input logic div_sel_i, // static decoder output, for data muxes - input ibex_pkg::md_op_e operator_i, + input cve2_pkg::md_op_e operator_i, input logic [1:0] signed_mode_i, input logic [31:0] op_a_i, input logic [31:0] op_b_i, input logic [33:0] alu_adder_ext_i, input logic [31:0] alu_adder_i, input logic equal_to_zero_i, - input logic data_ind_timing_i, output logic [32:0] alu_operand_a_o, output logic [32:0] alu_operand_b_o, @@ -42,7 +41,7 @@ module ibex_multdiv_slow output logic valid_o ); - import ibex_pkg::*; + import cve2_pkg::*; typedef enum logic [2:0] { MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH @@ -191,7 +190,7 @@ module ibex_multdiv_slow op_b_shift_d = op_b_ext >> 1; // Proceed with multiplication by 0/1 in data-independent time mode // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = (!data_ind_timing_i && ((op_b_ext >> 1) == 0)) ? MD_LAST : MD_COMP; + md_state_d = ((op_b_ext >> 1) == 0) ? MD_LAST : MD_COMP; end MD_OP_MULH: begin op_a_shift_d = op_a_ext; @@ -207,7 +206,7 @@ module ibex_multdiv_slow // normal and will naturally return -1 accum_window_d = {33{1'b1}}; // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A; + md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A; // Record that this is a div by zero to stop the sign change at the end of the // division (in data_ind_timing mode). div_by_zero_d = equal_to_zero_i; @@ -219,7 +218,7 @@ module ibex_multdiv_slow // normal and will naturally return operand a accum_window_d = op_a_ext; // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A; + md_state_d = equal_to_zero_i ? MD_FINISH : MD_ABS_A; end default:; endcase @@ -252,7 +251,7 @@ module ibex_multdiv_slow // Multiplication is complete once op_b is zero, unless in data_ind_timing mode where // the maximum possible shift-add operations will be completed regardless of op_b // SEC_CM: CORE.DATA_REG_SW.SCA - md_state_d = ((!data_ind_timing_i && (op_b_shift_d == 0)) || + md_state_d = ((op_b_shift_d == 0) || (multdiv_count_q == 5'd1)) ? MD_LAST : MD_COMP; end MD_OP_MULH: begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv similarity index 74% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pkg.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv index fec80fdf..6cd8f4b1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv @@ -6,7 +6,7 @@ /** * Package with constants used by Ibex */ -package ibex_pkg; +package cve2_pkg; //////////////// // IO Structs // @@ -31,12 +31,6 @@ package ibex_pkg; // Parameter Enums // ///////////////////// - typedef enum integer { - RegFileFF = 0, - RegFileFPGA = 1, - RegFileLatch = 2 - } regfile_e; - typedef enum integer { RV32MNone = 0, RV32MSlow = 1, @@ -298,26 +292,25 @@ package ibex_pkg; logic irq_software; logic irq_timer; logic irq_external; - logic [14:0] irq_fast; // 15 fast interrupts, - // one interrupt is reserved for NMI (not visible through mip/mie) + logic [15:0] irq_fast; // 16 fast interrupts } irqs_t; // Exception cause - typedef enum logic [5:0] { - EXC_CAUSE_IRQ_SOFTWARE_M = {1'b1, 5'd03}, - EXC_CAUSE_IRQ_TIMER_M = {1'b1, 5'd07}, - EXC_CAUSE_IRQ_EXTERNAL_M = {1'b1, 5'd11}, - // EXC_CAUSE_IRQ_FAST_0 = {1'b1, 5'd16}, - // EXC_CAUSE_IRQ_FAST_14 = {1'b1, 5'd30}, - EXC_CAUSE_IRQ_NM = {1'b1, 5'd31}, // == EXC_CAUSE_IRQ_FAST_15 - EXC_CAUSE_INSN_ADDR_MISA = {1'b0, 5'd00}, - EXC_CAUSE_INSTR_ACCESS_FAULT = {1'b0, 5'd01}, - EXC_CAUSE_ILLEGAL_INSN = {1'b0, 5'd02}, - EXC_CAUSE_BREAKPOINT = {1'b0, 5'd03}, - EXC_CAUSE_LOAD_ACCESS_FAULT = {1'b0, 5'd05}, - EXC_CAUSE_STORE_ACCESS_FAULT = {1'b0, 5'd07}, - EXC_CAUSE_ECALL_UMODE = {1'b0, 5'd08}, - EXC_CAUSE_ECALL_MMODE = {1'b0, 5'd11} + typedef enum logic [6:0] { + EXC_CAUSE_IRQ_SOFTWARE_M = {1'b1, 6'd03}, + EXC_CAUSE_IRQ_TIMER_M = {1'b1, 6'd07}, + EXC_CAUSE_IRQ_EXTERNAL_M = {1'b1, 6'd11}, + // EXC_CAUSE_IRQ_FAST_0 = {1'b1, 6'd16}, + // EXC_CAUSE_IRQ_FAST_15 = {1'b1, 6'd31}, + EXC_CAUSE_IRQ_NM = {1'b1, 6'd32}, + EXC_CAUSE_INSN_ADDR_MISA = {1'b0, 6'd00}, + EXC_CAUSE_INSTR_ACCESS_FAULT = {1'b0, 6'd01}, + EXC_CAUSE_ILLEGAL_INSN = {1'b0, 6'd02}, + EXC_CAUSE_BREAKPOINT = {1'b0, 6'd03}, + EXC_CAUSE_LOAD_ACCESS_FAULT = {1'b0, 6'd05}, + EXC_CAUSE_STORE_ACCESS_FAULT = {1'b0, 6'd07}, + EXC_CAUSE_ECALL_UMODE = {1'b0, 6'd08}, + EXC_CAUSE_ECALL_MMODE = {1'b0, 6'd11} } exc_cause_e; // Debug cause @@ -329,27 +322,6 @@ package ibex_pkg; DBG_CAUSE_STEP = 3'h4 } dbg_cause_e; - // ICache constants - parameter int unsigned ADDR_W = 32; - parameter int unsigned BUS_SIZE = 32; - parameter int unsigned BUS_BYTES = BUS_SIZE/8; - parameter int unsigned BUS_W = $clog2(BUS_BYTES); - parameter int unsigned IC_SIZE_BYTES = 4096; - parameter int unsigned IC_NUM_WAYS = 2; - parameter int unsigned IC_LINE_SIZE = 64; - parameter int unsigned IC_LINE_BYTES = IC_LINE_SIZE/8; - parameter int unsigned IC_LINE_W = $clog2(IC_LINE_BYTES); - parameter int unsigned IC_NUM_LINES = IC_SIZE_BYTES / IC_NUM_WAYS / IC_LINE_BYTES; - parameter int unsigned IC_LINE_BEATS = IC_LINE_BYTES / BUS_BYTES; - parameter int unsigned IC_LINE_BEATS_W = $clog2(IC_LINE_BEATS); - parameter int unsigned IC_INDEX_W = $clog2(IC_NUM_LINES); - parameter int unsigned IC_INDEX_HI = IC_INDEX_W + IC_LINE_W - 1; - parameter int unsigned IC_TAG_SIZE = ADDR_W - IC_INDEX_W - IC_LINE_W + 1; // 1 valid bit - parameter int unsigned IC_OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords - // ICache Scrambling Parameters - parameter int unsigned SCRAMBLE_KEY_W = 128; - parameter int unsigned SCRAMBLE_NONCE_W = 64; - // PMP constants parameter int unsigned PMP_MAX_REGIONS = 16; parameter int unsigned PMP_CFG_W = 8; @@ -391,10 +363,11 @@ package ibex_pkg; // CSRs typedef enum logic[11:0] { // Machine information - CSR_MVENDORID = 12'hF11, - CSR_MARCHID = 12'hF12, - CSR_MIMPID = 12'hF13, - CSR_MHARTID = 12'hF14, + CSR_MVENDORID = 12'hF11, + CSR_MARCHID = 12'hF12, + CSR_MIMPID = 12'hF13, + CSR_MHARTID = 12'hF14, + CSR_MCONFIGPTR = 12'hF15, // Machine trap setup CSR_MSTATUS = 12'h300, @@ -402,6 +375,10 @@ package ibex_pkg; CSR_MIE = 12'h304, CSR_MTVEC = 12'h305, CSR_MCOUNTEREN= 12'h306, + CSR_MSTATUSH = 12'h310, + + CSR_MENVCFG = 12'h30A, + CSR_MENVCFGH = 12'h31A, // Machine trap handling CSR_MSCRATCH = 12'h340, @@ -569,52 +546,33 @@ package ibex_pkg; parameter int unsigned CSR_MTIX_BIT = 7; parameter int unsigned CSR_MEIX_BIT = 11; parameter int unsigned CSR_MFIX_BIT_LOW = 16; - parameter int unsigned CSR_MFIX_BIT_HIGH = 30; + parameter int unsigned CSR_MFIX_BIT_HIGH = 31; // CSR Machine Security Configuration bits parameter int unsigned CSR_MSECCFG_MML_BIT = 0; parameter int unsigned CSR_MSECCFG_MMWP_BIT = 1; parameter int unsigned CSR_MSECCFG_RLB_BIT = 2; - // Vendor ID - // No JEDEC ID has been allocated to lowRISC so the value is 0 to indicate the field is not - // implemented - localparam logic [31:0] CSR_MVENDORID_VALUE = 32'b0; + // Machine Vendor ID - OpenHW JEDEC ID is '2 decimal (bank 13)' + parameter MVENDORID_OFFSET = 7'h2; // Final byte without parity bit + parameter MVENDORID_BANK = 25'hC; // Number of continuation codes + + // Machine Architecture ID (https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md) + parameter MARCHID = 32'd35; - // Architecture ID - // Top bit is unset to indicate an open source project. The lower bits are an ID allocated by the - // RISC-V Foundation. Note this is allocated specifically to Ibex, should significant changes be - // made a different architecture ID should be supplied. - localparam logic [31:0] CSR_MARCHID_VALUE = {1'b0, 31'd22}; + localparam logic [31:0] CSR_MVENDORID_VALUE = {MVENDORID_BANK, MVENDORID_OFFSET}; + localparam logic [31:0] CSR_MARCHID_VALUE = MARCHID; // Implementation ID - // 0 indicates this field is not implemeted. Ibex implementors may wish to indicate an RTL/netlist + // 0 indicates this field is not implemeted. cve2 implementors may wish to indicate an RTL/netlist // version here using their own unique encoding (e.g. 32 bits of the git hash of the implemented // commit). localparam logic [31:0] CSR_MIMPID_VALUE = 32'b0; - // These LFSR parameters have been generated with - // $ opentitan/util/design/gen-lfsr-seed.py --width 32 --seed 2480124384 --prefix "" - parameter int LfsrWidth = 32; - typedef logic [LfsrWidth-1:0] lfsr_seed_t; - typedef logic [LfsrWidth-1:0][$clog2(LfsrWidth)-1:0] lfsr_perm_t; - parameter lfsr_seed_t RndCnstLfsrSeedDefault = 32'hac533bf4; - parameter lfsr_perm_t RndCnstLfsrPermDefault = { - 160'h1e35ecba467fd1b12e958152c04fa43878a8daed - }; - parameter logic [SCRAMBLE_KEY_W-1:0] RndCnstIbexKeyDefault = - 128'h14e8cecae3040d5e12286bb3cc113298; - parameter logic [SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonceDefault = - 64'hf79780bc735f3843; - - // Fetch enable. Mult-bit signal used for security hardening. For non-secure implementation all - // bits other than the bottom bit are ignored. - typedef logic [3:0] fetch_enable_t; - - // Note that if adjusting these parameters it is assumed the bottom bit is set for On and unset - // for Off. This allows the use of FetchEnableOn/FetchEnableOff to work for both secure and - // non-secure Ibex. If this assumption is broken the RTL that uses the fetch_enable signal within - // `ibex_core` may need adjusting. - parameter fetch_enable_t FetchEnableOn = 4'b1001; - parameter fetch_enable_t FetchEnableOff = 4'b0110; + // Machine Configuration Pointer + // 0 indicates the configuration data structure does not eixst. cve2 implementors may wish to + // alter this to point to their system specific configuration data structure. + localparam logic [31:0] CSR_MCONFIGPTR_VALUE = 32'b0; + endpackage + diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pmp.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pmp.sv similarity index 95% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pmp.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pmp.sv index 16e806a2..b531eefd 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pmp.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pmp.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module ibex_pmp #( +module cve2_pmp #( // Granularity of NAPOT access, // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc. parameter int unsigned PMPGranularity = 0, @@ -16,19 +16,19 @@ module ibex_pmp #( input logic rst_ni, // Interface to CSRs - input ibex_pkg::pmp_cfg_t csr_pmp_cfg_i [PMPNumRegions], + input cve2_pkg::pmp_cfg_t csr_pmp_cfg_i [PMPNumRegions], input logic [33:0] csr_pmp_addr_i [PMPNumRegions], - input ibex_pkg::pmp_mseccfg_t csr_pmp_mseccfg_i, + input cve2_pkg::pmp_mseccfg_t csr_pmp_mseccfg_i, - input ibex_pkg::priv_lvl_e priv_mode_i [PMPNumChan], + input cve2_pkg::priv_lvl_e priv_mode_i [PMPNumChan], // Access checking channels input logic [33:0] pmp_req_addr_i [PMPNumChan], - input ibex_pkg::pmp_req_e pmp_req_type_i [PMPNumChan], + input cve2_pkg::pmp_req_e pmp_req_type_i [PMPNumChan], output logic pmp_req_err_o [PMPNumChan] ); - import ibex_pkg::*; + import cve2_pkg::*; // Access Checking Signals logic [33:0] region_start_addr [PMPNumRegions]; @@ -177,7 +177,7 @@ module ibex_pmp #( assign pmp_req_err_o[c] = access_fault[c]; end - // RLB, rule locking bypass, is only relevant to ibex_cs_registers which controls writes to the + // RLB, rule locking bypass, is only relevant to cve2_cs_registers which controls writes to the // PMP CSRs. Tie to unused signal here to prevent lint warnings. logic unused_csr_pmp_mseccfg_rlb; assign unused_csr_pmp_mseccfg_rlb = csr_pmp_mseccfg_i.rlb; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pmp_reset_default.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pmp_reset_default.svh similarity index 100% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_pmp_reset_default.svh rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pmp_reset_default.svh diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_prefetch_buffer.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_prefetch_buffer.sv similarity index 81% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_prefetch_buffer.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_prefetch_buffer.sv index 5b834ce2..51b1195c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_prefetch_buffer.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_prefetch_buffer.sv @@ -9,8 +9,7 @@ * Prefetch Buffer that caches instructions. This cuts overly long critical * paths to the instruction cache. */ -module ibex_prefetch_buffer #( - parameter bit ResetAll = 1'b0 +module cve2_prefetch_buffer #( ) ( input logic clk_i, input logic rst_ni, @@ -18,8 +17,6 @@ module ibex_prefetch_buffer #( input logic req_i, input logic branch_i, - input logic branch_mispredict_i, - input logic [31:0] mispredict_addr_i, input logic [31:0] addr_i, @@ -65,16 +62,12 @@ module ibex_prefetch_buffer #( logic valid_raw; - logic branch_or_mispredict; - //////////////////////////// // Prefetch buffer status // //////////////////////////// assign busy_o = (|rdata_outstanding_q) | instr_req_o; - assign branch_or_mispredict = branch_i | branch_mispredict_i; - ////////////////////////////////////////////// // Fetch fifo - consumes addresses and data // ////////////////////////////////////////////// @@ -82,7 +75,7 @@ module ibex_prefetch_buffer #( // A branch will invalidate any previously fetched instructions. // Note that the FENCE.I instruction relies on this flushing behaviour on branch. If it is // altered the FENCE.I implementation may require changes. - assign fifo_clear = branch_or_mispredict; + assign fifo_clear = branch_i; // Reversed version of rdata_outstanding_q which can be overlaid with fifo fill state for (genvar i = 0; i < NUM_REQS; i++) begin : gen_rd_rev @@ -94,9 +87,8 @@ module ibex_prefetch_buffer #( // Overlay the fifo fill state with the outstanding requests to see if there is space. assign fifo_ready = ~&(fifo_busy | rdata_outstanding_rev); - ibex_fetch_fifo #( - .NUM_REQS (NUM_REQS), - .ResetAll (ResetAll) + cve2_fetch_fifo #( + .NUM_REQS (NUM_REQS) ) fifo_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -122,7 +114,7 @@ module ibex_prefetch_buffer #( ////////////// // Make a new request any time there is space in the FIFO, and space in the request queue - assign valid_new_req = req_i & (fifo_ready | branch_or_mispredict) & + assign valid_new_req = req_i & (fifo_ready | branch_i) & ~rdata_outstanding_q[NUM_REQS-1]; assign valid_req = valid_req_q | valid_new_req; @@ -131,7 +123,7 @@ module ibex_prefetch_buffer #( assign valid_req_d = valid_req & ~instr_gnt_i; // Record whether an outstanding bus request is cancelled by a branch - assign discard_req_d = valid_req_q & (branch_or_mispredict | discard_req_q); + assign discard_req_d = valid_req_q & (branch_i | discard_req_q); //////////////// // Fetch addr // @@ -156,52 +148,34 @@ module ibex_prefetch_buffer #( assign stored_addr_d = instr_addr; // CPU resets with a branch, so no need to reset these addresses - if (ResetAll) begin : g_stored_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - stored_addr_q <= '0; - end else if (stored_addr_en) begin - stored_addr_q <= stored_addr_d; - end - end - end else begin : g_stored_addr_nr - always_ff @(posedge clk_i) begin - if (stored_addr_en) begin - stored_addr_q <= stored_addr_d; - end + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + stored_addr_q <= '0; + end else if (stored_addr_en) begin + stored_addr_q <= stored_addr_d; end end // 2. fetch_addr_q // Update on a branch or as soon as a request is issued - assign fetch_addr_en = branch_or_mispredict | (valid_new_req & ~valid_req_q); + assign fetch_addr_en = branch_i | (valid_new_req & ~valid_req_q); assign fetch_addr_d = (branch_i ? addr_i : - branch_mispredict_i ? {mispredict_addr_i[31:2], 2'b00} : {fetch_addr_q[31:2], 2'b00}) + // Current address + 4 {{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00}; - if (ResetAll) begin : g_fetch_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fetch_addr_q <= '0; - end else if (fetch_addr_en) begin - fetch_addr_q <= fetch_addr_d; - end - end - end else begin : g_fetch_addr_nr - always_ff @(posedge clk_i) begin - if (fetch_addr_en) begin - fetch_addr_q <= fetch_addr_d; - end + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + fetch_addr_q <= '0; + end else if (fetch_addr_en) begin + fetch_addr_q <= fetch_addr_d; end end // Address mux assign instr_addr = valid_req_q ? stored_addr_q : branch_i ? addr_i : - branch_mispredict_i ? mispredict_addr_i : fetch_addr_q; assign instr_addr_w_aligned = {instr_addr[31:2], 2'b00}; @@ -220,7 +194,7 @@ module ibex_prefetch_buffer #( // If a branch is received at any point while a request is outstanding, it must be tracked // to ensure we discard the data once received assign branch_discard_n[i] = (valid_req & instr_gnt_i & discard_req_d) | - (branch_or_mispredict & rdata_outstanding_q[i]) | + (branch_i & rdata_outstanding_q[i]) | branch_discard_q[i]; end else begin : g_reqtop @@ -232,7 +206,7 @@ module ibex_prefetch_buffer #( rdata_outstanding_q[i]; assign branch_discard_n[i] = (valid_req & instr_gnt_i & discard_req_d & rdata_outstanding_q[i-1]) | - (branch_or_mispredict & rdata_outstanding_q[i]) | + (branch_i & rdata_outstanding_q[i]) | branch_discard_q[i]; end end @@ -246,7 +220,7 @@ module ibex_prefetch_buffer #( // Push a new entry to the FIFO once complete (and not cancelled by a branch) assign fifo_valid = instr_rvalid_i & ~branch_discard_q[0]; - assign fifo_addr = branch_i ? addr_i : mispredict_addr_i; + assign fifo_addr = addr_i; /////////////// // Registers // @@ -273,6 +247,6 @@ module ibex_prefetch_buffer #( assign instr_req_o = valid_req; assign instr_addr_o = instr_addr_w_aligned; - assign valid_o = valid_raw & ~branch_mispredict_i; + assign valid_o = valid_raw; endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_ff.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_register_file_ff.sv similarity index 66% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_ff.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_register_file_ff.sv index 90b0c719..148ba225 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_ff.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_register_file_ff.sv @@ -10,10 +10,9 @@ * This register file is based on flip flops. Use this register file when * targeting FPGA synthesis or Verilator simulation. */ -module ibex_register_file_ff #( +module cve2_register_file_ff #( parameter bit RV32E = 0, parameter int unsigned DataWidth = 32, - parameter bit DummyInstructions = 0, parameter logic [DataWidth-1:0] WordZeroVal = '0 ) ( // Clock and Reset @@ -21,7 +20,6 @@ module ibex_register_file_ff #( input logic rst_ni, input logic test_en_i, - input logic dummy_instr_id_i, //Read port R1 input logic [4:0] raddr_a_i, @@ -63,34 +61,8 @@ module ibex_register_file_ff #( end end - // With dummy instructions enabled, R0 behaves as a real register but will always return 0 for - // real instructions. - if (DummyInstructions) begin : g_dummy_r0 - // SEC_CM: CTRL_FLOW.UNPREDICTABLE - logic we_r0_dummy; - logic [DataWidth-1:0] rf_r0_q; - - // Write enable for dummy R0 register (waddr_a_i will always be 0 for dummy instructions) - assign we_r0_dummy = we_a_i & dummy_instr_id_i; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rf_r0_q <= WordZeroVal; - end else if (we_r0_dummy) begin - rf_r0_q <= wdata_a_i; - end - end - - // Output the dummy data for dummy instructions, otherwise R0 reads as zero - assign rf_reg[0] = dummy_instr_id_i ? rf_r0_q : WordZeroVal; - - end else begin : g_normal_r0 - logic unused_dummy_instr_id; - assign unused_dummy_instr_id = dummy_instr_id_i; - - // R0 is nil - assign rf_reg[0] = WordZeroVal; - end + // R0 is nil + assign rf_reg[0] = WordZeroVal; assign rf_reg[NUM_WORDS-1:1] = rf_reg_q[NUM_WORDS-1:1]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_sleep_unit.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_sleep_unit.sv deleted file mode 100644 index 80388031..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_sleep_unit.sv +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2020 Silicon Labs, Inc. -// -// This file, and derivatives thereof are licensed under the -// Solderpad License, Version 2.0 (the "License"). -// -// Use of this file means you agree to the terms and conditions -// of the license and are in full compliance with the License. -// -// You may obtain a copy of the License at: -// -// https://solderpad.org/licenses/SHL-2.0/ -// -// Unless required by applicable law or agreed to in writing, software -// and hardware implementations thereof distributed under the License -// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. -// -// See the License for the specific language governing permissions and -// limitations under the License. - -//////////////////////////////////////////////////////////////////////////////// -// Engineer: Arjan Bink - arjan.bink@silabs.com // -// // -// Design Name: Sleep Unit // -// Project Name: CVE2 // -// Language: SystemVerilog // -// // -// Description: Sleep unit containing the instantiated clock gate which // -// provides the gated clock (clk_gated_o) for the rest // -// of the design. Forked version of cv32e40p // -// // -// The clock is gated for the following scenarios: // -// // -// - While waiting for fetch to become enabled // -// - While blocked on a WFI (PULP_CLUSTER = 0) // -// - While clock_en_i = 0 during a p.elw (PULP_CLUSTER = 1) // -// // -// Sleep is signaled via core_sleep_o when: // -// - During a WFI (except in debug) // -// // -// // -//////////////////////////////////////////////////////////////////////////////// - -module cve2_sleep_unit ( - // Clock, reset interface - input logic clk_ungated_i, // Free running clock - input logic rst_n, - output logic clk_gated_o, // Gated clock - input logic scan_cg_en_i, // Enable all clock gates for testing - - // Core sleep - output logic core_sleep_o, - - // Fetch enable - input logic fetch_enable_i, - output logic fetch_enable_o, - - // Core status - input logic if_busy_i, - input logic ctrl_busy_i, - input logic lsu_busy_i, - - // WFI wake - input logic wake_from_sleep_i -); - - logic fetch_enable_q; // Sticky version of fetch_enable_i - logic fetch_enable_d; - logic core_busy_q; // Is core still busy (and requires a clock) with what needs to finish before entering sleep? - logic core_busy_d; - logic clock_en; // Final clock enable - - ////////////////////////////////////////////////////////////////////////////// - // Sleep FSM - ////////////////////////////////////////////////////////////////////////////// - - // Make sticky version of fetch_enable_i - assign fetch_enable_d = fetch_enable_i ? 1'b1 : fetch_enable_q; - - - // Busy when any of the sub units is busy (typically wait for the instruction buffer to fill up) - assign core_busy_d = if_busy_i || ctrl_busy_i || lsu_busy_i; - - // Enable the clock only after the initial fetch enable while busy or waking up to become busy - assign clock_en = fetch_enable_q && (wake_from_sleep_i || core_busy_q); - - // Sleep only in response to WFI which leads to clock disable; debug_wfi_no_sleep_o in - // cv32e40p_controller determines the scenarios for which WFI can(not) cause sleep. - assign core_sleep_o = fetch_enable_q && !clock_en; - - - always_ff @(posedge clk_ungated_i, negedge rst_n) begin - if (rst_n == 1'b0) begin - core_busy_q <= 1'b0; - fetch_enable_q <= 1'b0; - end else begin - core_busy_q <= core_busy_d; - fetch_enable_q <= fetch_enable_d; - end - end - - // Fetch enable for Controller - assign fetch_enable_o = fetch_enable_q; - - // Main clock gate of CV32E40P - cve2_clock_gate core_clock_gate_i ( - .clk_i (clk_ungated_i), - .en_i (clock_en), - .scan_cg_en_i(scan_cg_en_i), - .clk_o (clk_gated_o) - ); - - //---------------------------------------------------------------------------- - // Assertions - TODO - //---------------------------------------------------------------------------- - - -endmodule // cve2_sleep_unit diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top.sv new file mode 100644 index 00000000..00c38a4a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top.sv @@ -0,0 +1,272 @@ +// Copyright lowRISC contributors. +// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifdef RISCV_FORMAL + `define RVFI +`endif + +`include "prim_assert.sv" + +/** + * Top level module of the ibex RISC-V core + */ +module cve2_top import cve2_pkg::*; #( + parameter int unsigned MHPMCounterNum = 0, + parameter int unsigned MHPMCounterWidth = 40, + parameter bit RV32E = 1'b0, + parameter rv32m_e RV32M = RV32MFast, + parameter int unsigned DmHaltAddr = 32'h1A110800, + parameter int unsigned DmExceptionAddr = 32'h1A110808 +) ( + // Clock and Reset + input logic clk_i, + input logic rst_ni, + + input logic test_en_i, // enable all clock gates for testing + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, + + input logic [31:0] hart_id_i, + input logic [31:0] boot_addr_i, + + // Instruction memory interface + output logic instr_req_o, + input logic instr_gnt_i, + input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + input logic [31:0] instr_rdata_i, + input logic instr_err_i, + + // Data memory interface + output logic data_req_o, + input logic data_gnt_i, + input logic data_rvalid_i, + output logic data_we_o, + output logic [3:0] data_be_o, + output logic [31:0] data_addr_o, + output logic [31:0] data_wdata_o, + input logic [31:0] data_rdata_i, + input logic data_err_i, + + // Interrupt inputs + input logic irq_software_i, + input logic irq_timer_i, + input logic irq_external_i, + input logic [15:0] irq_fast_i, + input logic irq_nm_i, // non-maskeable interrupt + + // Debug Interface + input logic debug_req_i, + output crash_dump_t crash_dump_o, + + // RISC-V Formal Interface + // Does not comply with the coding standards of _i/_o suffixes, but follows + // the convention of RISC-V Formal Interface Specification. +`ifdef RVFI + output logic rvfi_valid, + output logic [63:0] rvfi_order, + output logic [31:0] rvfi_insn, + output logic rvfi_trap, + output logic rvfi_halt, + output logic rvfi_intr, + output logic [ 1:0] rvfi_mode, + output logic [ 1:0] rvfi_ixl, + output logic [ 4:0] rvfi_rs1_addr, + output logic [ 4:0] rvfi_rs2_addr, + output logic [ 4:0] rvfi_rs3_addr, + output logic [31:0] rvfi_rs1_rdata, + output logic [31:0] rvfi_rs2_rdata, + output logic [31:0] rvfi_rs3_rdata, + output logic [ 4:0] rvfi_rd_addr, + output logic [31:0] rvfi_rd_wdata, + output logic [31:0] rvfi_pc_rdata, + output logic [31:0] rvfi_pc_wdata, + output logic [31:0] rvfi_mem_addr, + output logic [ 3:0] rvfi_mem_rmask, + output logic [ 3:0] rvfi_mem_wmask, + output logic [31:0] rvfi_mem_rdata, + output logic [31:0] rvfi_mem_wdata, + output logic [31:0] rvfi_ext_mip, + output logic rvfi_ext_nmi, + output logic rvfi_ext_debug_req, + output logic [63:0] rvfi_ext_mcycle, +`endif + + // CPU Control Signals + input logic fetch_enable_i, + output logic core_sleep_o +); + + // Scrambling Parameter + localparam int unsigned NumAddrScrRounds = 0; + + // Physical Memory Protection + localparam bit PMPEnable = 1'b0; + localparam int unsigned PMPGranularity = 0; + localparam int unsigned PMPNumRegions = 4; + + // Trigger support + localparam bit DbgTriggerEn = 1'b1; + localparam int unsigned DbgHwBreakNum = 1; + + // Bit manipulation extension + localparam rv32b_e RV32B = RV32BNone; + + // Clock signals + logic clk; + logic core_busy_d, core_busy_q; + logic clock_en; + logic fetch_enable_d, fetch_enable_q; + logic irq_pending; + + ///////////////////// + // Main clock gate // + ///////////////////// + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + core_busy_q <= 1'b0; + fetch_enable_q <= 1'b0; + end else begin + core_busy_q <= core_busy_d; + fetch_enable_q <= fetch_enable_d; + end + end + + assign clock_en = fetch_enable_q & (core_busy_q | debug_req_i | irq_pending | irq_nm_i); + assign core_sleep_o = fetch_enable_q & !clock_en; + assign fetch_enable_d = fetch_enable_i ? 1'b1 : fetch_enable_q; + + cve2_clock_gate core_clock_gate_i ( + .clk_i (clk_i), + .en_i (clock_en), + .scan_cg_en_i(test_en_i), + .clk_o (clk) + ); + + //////////////////////// + // Core instantiation // + //////////////////////// + + cve2_core #( + .PMPEnable (PMPEnable), + .PMPGranularity (PMPGranularity), + .PMPNumRegions (PMPNumRegions), + .MHPMCounterNum (MHPMCounterNum), + .MHPMCounterWidth (MHPMCounterWidth), + .RV32E (RV32E), + .RV32M (RV32M), + .RV32B (RV32B), + .DbgTriggerEn (DbgTriggerEn), + .DbgHwBreakNum (DbgHwBreakNum), + .DmHaltAddr (DmHaltAddr), + .DmExceptionAddr (DmExceptionAddr) + ) u_cve2_core ( + .clk_i(clk), + .rst_ni, + .test_en_i, + + .hart_id_i, + .boot_addr_i, + + .instr_req_o, + .instr_gnt_i, + .instr_rvalid_i, + .instr_addr_o, + .instr_rdata_i, + .instr_err_i, + + .data_req_o, + .data_gnt_i, + .data_rvalid_i, + .data_we_o, + .data_be_o, + .data_addr_o, + .data_wdata_o, + .data_rdata_i, + .data_err_i, + + .irq_software_i, + .irq_timer_i, + .irq_external_i, + .irq_fast_i, + .irq_nm_i, + .irq_pending_o(irq_pending), + + .debug_req_i, + .crash_dump_o, + +`ifdef RVFI + .rvfi_valid, + .rvfi_order, + .rvfi_insn, + .rvfi_trap, + .rvfi_halt, + .rvfi_intr, + .rvfi_mode, + .rvfi_ixl, + .rvfi_rs1_addr, + .rvfi_rs2_addr, + .rvfi_rs3_addr, + .rvfi_rs1_rdata, + .rvfi_rs2_rdata, + .rvfi_rs3_rdata, + .rvfi_rd_addr, + .rvfi_rd_wdata, + .rvfi_pc_rdata, + .rvfi_pc_wdata, + .rvfi_mem_addr, + .rvfi_mem_rmask, + .rvfi_mem_wmask, + .rvfi_mem_rdata, + .rvfi_mem_wdata, + .rvfi_ext_mip, + .rvfi_ext_nmi, + .rvfi_ext_debug_req, + .rvfi_ext_mcycle, +`endif + + .fetch_enable_i (fetch_enable_q), + .core_busy_o (core_busy_d) + ); + + //////////////////////// + // Rams Instantiation // + //////////////////////// + + prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg; + logic unused_ram_inputs; + + assign unused_ram_cfg = ram_cfg_i; + assign unused_ram_inputs = (|NumAddrScrRounds); + + + // X checks for top-level outputs + `ASSERT_KNOWN(IbexInstrReqX, instr_req_o) + `ASSERT_KNOWN_IF(IbexInstrReqPayloadX, instr_addr_o, instr_req_o) + + `ASSERT_KNOWN(IbexDataReqX, data_req_o) + `ASSERT_KNOWN_IF(IbexDataReqPayloadX, + {data_we_o, data_be_o, data_addr_o, data_wdata_o}, data_req_o) + + `ASSERT_KNOWN(IbexCoreSleepX, core_sleep_o) + + // X check for top-level inputs + `ASSERT_KNOWN(IbexTestEnX, test_en_i) + `ASSERT_KNOWN(IbexRamCfgX, ram_cfg_i) + `ASSERT_KNOWN(IbexHartIdX, hart_id_i) + `ASSERT_KNOWN(IbexBootAddrX, boot_addr_i) + + `ASSERT_KNOWN(IbexInstrGntX, instr_gnt_i) + `ASSERT_KNOWN(IbexInstrRValidX, instr_rvalid_i) + `ASSERT_KNOWN_IF(IbexInstrRPayloadX, + {instr_rdata_i, instr_err_i}, instr_rvalid_i) + + `ASSERT_KNOWN(IbexDataGntX, data_gnt_i) + `ASSERT_KNOWN(IbexDataRValidX, data_rvalid_i) + + `ASSERT_KNOWN(IbexIrqX, {irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i}) + + `ASSERT_KNOWN(IbexDebugReqX, debug_req_i) +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top_tracing.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv similarity index 66% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top_tracing.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv index f4384653..989e83d7 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top_tracing.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv @@ -3,30 +3,15 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Top level module of the ibex RISC-V core with tracing enabled + * Top level module of the cve2 RISC-V core with tracing enabled */ -module ibex_top_tracing import ibex_pkg::*; #( - parameter bit PMPEnable = 1'b0, - parameter int unsigned PMPGranularity = 0, - parameter int unsigned PMPNumRegions = 4, +module cve2_top_tracing import cve2_pkg::*; #( parameter int unsigned MHPMCounterNum = 0, parameter int unsigned MHPMCounterWidth = 40, parameter bit RV32E = 1'b0, parameter rv32m_e RV32M = RV32MFast, - parameter rv32b_e RV32B = RV32BNone, - parameter regfile_e RegFile = RegFileFF, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, parameter bit BranchPredictor = 1'b0, - parameter bit DbgTriggerEn = 1'b0, - parameter int unsigned DbgHwBreakNum = 1, - parameter bit SecureIbex = 1'b0, - parameter bit ICacheScramble = 1'b0, - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -35,7 +20,6 @@ module ibex_top_tracing import ibex_pkg::*; #( input logic rst_ni, input logic test_en_i, // enable all clock gates for testing - input logic scan_rst_ni, input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, @@ -48,7 +32,6 @@ module ibex_top_tracing import ibex_pkg::*; #( input logic instr_rvalid_i, output logic [31:0] instr_addr_o, input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, input logic instr_err_i, // Data memory interface @@ -59,39 +42,27 @@ module ibex_top_tracing import ibex_pkg::*; #( output logic [3:0] data_be_o, output logic [31:0] data_addr_o, output logic [31:0] data_wdata_o, - output logic [6:0] data_wdata_intg_o, input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, input logic data_err_i, // Interrupt inputs input logic irq_software_i, input logic irq_timer_i, input logic irq_external_i, - input logic [14:0] irq_fast_i, + input logic [15:0] irq_fast_i, input logic irq_nm_i, // non-maskeable interrupt - // Scrambling Interface - input logic scramble_key_valid_i, - input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, - input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, - output logic scramble_req_o, - // Debug Interface input logic debug_req_i, output crash_dump_t crash_dump_o, - output logic double_fault_seen_o, // CPU Control Signals - input fetch_enable_t fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, + input logic fetch_enable_i, output logic core_sleep_o ); - // ibex_tracer relies on the signals from the RISC-V Formal Interface + // cve2_tracer relies on the signals from the RISC-V Formal Interface `ifndef RVFI $fatal("Fatal error: RVFI needs to be defined globally."); `endif @@ -136,35 +107,19 @@ module ibex_top_tracing import ibex_pkg::*; #( assign unused_rvfi_ext_debug_req = rvfi_ext_debug_req; assign unused_rvfi_ext_mcycle = rvfi_ext_mcycle; - ibex_top #( - .PMPEnable ( PMPEnable ), - .PMPGranularity ( PMPGranularity ), - .PMPNumRegions ( PMPNumRegions ), + cve2_top #( .MHPMCounterNum ( MHPMCounterNum ), .MHPMCounterWidth ( MHPMCounterWidth ), .RV32E ( RV32E ), .RV32M ( RV32M ), - .RV32B ( RV32B ), - .RegFile ( RegFile ), - .BranchTargetALU ( BranchTargetALU ), - .ICache ( ICache ), - .ICacheECC ( ICacheECC ), .BranchPredictor ( BranchPredictor ), - .DbgTriggerEn ( DbgTriggerEn ), - .DbgHwBreakNum ( DbgHwBreakNum ), - .WritebackStage ( WritebackStage ), - .SecureIbex ( SecureIbex ), - .ICacheScramble ( ICacheScramble ), - .RndCnstLfsrSeed ( RndCnstLfsrSeed ), - .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) - ) u_ibex_top ( + ) u_cve2_top ( .clk_i, .rst_ni, .test_en_i, - .scan_rst_ni, .ram_cfg_i, .hart_id_i, @@ -175,7 +130,6 @@ module ibex_top_tracing import ibex_pkg::*; #( .instr_rvalid_i, .instr_addr_o, .instr_rdata_i, - .instr_rdata_intg_i, .instr_err_i, .data_req_o, @@ -185,9 +139,7 @@ module ibex_top_tracing import ibex_pkg::*; #( .data_be_o, .data_addr_o, .data_wdata_o, - .data_wdata_intg_o, .data_rdata_i, - .data_rdata_intg_i, .data_err_i, .irq_software_i, @@ -196,14 +148,8 @@ module ibex_top_tracing import ibex_pkg::*; #( .irq_fast_i, .irq_nm_i, - .scramble_key_valid_i, - .scramble_key_i, - .scramble_nonce_i, - .scramble_req_o, - .debug_req_i, .crash_dump_o, - .double_fault_seen_o, .rvfi_valid, .rvfi_order, @@ -234,14 +180,11 @@ module ibex_top_tracing import ibex_pkg::*; #( .rvfi_ext_mcycle, .fetch_enable_i, - .alert_minor_o, - .alert_major_internal_o, - .alert_major_bus_o, .core_sleep_o ); - ibex_tracer - u_ibex_tracer ( + cve2_tracer + u_cve2_tracer ( .clk_i, .rst_ni, diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer.sv similarity index 98% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer.sv index bd36a214..707419e4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer.sv @@ -12,12 +12,12 @@ * All traced instructions are written to a log file. By default, the log file is named * trace_core_.log, with being the 8 digit hart ID of the core being traced. * - * The file name base, defaulting to "trace_core" can be set using the "ibex_tracer_file_base" - * plusarg passed to the simulation, e.g. "+ibex_tracer_file_base=ibex_my_trace". The exact syntax + * The file name base, defaulting to "trace_core" can be set using the "cve2_tracer_file_base" + * plusarg passed to the simulation, e.g. "+cve2_tracer_file_base=cve2_my_trace". The exact syntax * of passing plusargs to a simulation depends on the simulator. * * The creation of the instruction trace is enabled by default but can be disabled for a simulation. - * This behaviour is controlled by the plusarg "ibex_tracer_enable". Use "ibex_tracer_enable=0" to + * This behaviour is controlled by the plusarg "cve2_tracer_enable". Use "cve2_tracer_enable=0" to * disable the tracer. * * The trace contains six columns, separated by tabs: @@ -34,7 +34,7 @@ * to the one produced by objdump. This simplifies the correlation between the static program * information from the objdump-generated disassembly, and the runtime information from this tracer. */ -module ibex_tracer ( +module cve2_tracer ( input logic clk_i, input logic rst_ni, @@ -79,7 +79,7 @@ module ibex_tracer ( logic [ 1:0] unused_rvfi_mode = rvfi_mode; logic [ 1:0] unused_rvfi_ixl = rvfi_ixl; - import ibex_tracer_pkg::*; + import cve2_tracer_pkg::*; int file_handle; string file_name; @@ -98,7 +98,7 @@ module ibex_tracer ( logic trace_log_enable; initial begin - if ($value$plusargs("ibex_tracer_enable=%b", trace_log_enable)) begin + if ($value$plusargs("cve2_tracer_enable=%b", trace_log_enable)) begin if (trace_log_enable == 1'b0) begin $display("%m: Instruction trace disabled."); end @@ -112,7 +112,7 @@ module ibex_tracer ( if (file_handle == 32'h0) begin string file_name_base = "trace_core"; - void'($value$plusargs("ibex_tracer_file_base=%s", file_name_base)); + void'($value$plusargs("cve2_tracer_file_base=%s", file_name_base)); $sformat(file_name, "%s_%h.log", file_name_base, hart_id_i); $display("%m: Writing execution trace to %s", file_name); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer_pkg.sv similarity index 99% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer_pkg.sv rename to hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer_pkg.sv index 6dbbfc90..700dd37b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_tracer_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_tracer_pkg.sv @@ -3,8 +3,8 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -package ibex_tracer_pkg; - import ibex_pkg::*; +package cve2_tracer_pkg; + import cve2_pkg::*; parameter logic [1:0] OPCODE_C0 = 2'b00; parameter logic [1:0] OPCODE_C1 = 2'b01; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_wb.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_wb.sv new file mode 100644 index 00000000..dee73f74 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_wb.sv @@ -0,0 +1,69 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Writeback passthrough + * + * The writeback stage is not present therefore this module acts as + * a simple passthrough to write data direct to the register file. + */ + +`include "prim_assert.sv" +`include "dv_fcov_macros.svh" + +module cve2_wb #( +) ( + input logic clk_i, + input logic rst_ni, + input logic en_wb_i, + + input logic instr_is_compressed_id_i, + input logic instr_perf_count_id_i, + + output logic perf_instr_ret_wb_o, + output logic perf_instr_ret_compressed_wb_o, + + input logic [4:0] rf_waddr_id_i, + input logic [31:0] rf_wdata_id_i, + input logic rf_we_id_i, + + input logic [31:0] rf_wdata_lsu_i, + input logic rf_we_lsu_i, + + output logic [4:0] rf_waddr_wb_o, + output logic [31:0] rf_wdata_wb_o, + output logic rf_we_wb_o, + + input logic lsu_resp_valid_i, + input logic lsu_resp_err_i +); + + import cve2_pkg::*; + + // 0 == RF write from ID + // 1 == RF write from LSU + logic [31:0] rf_wdata_wb_mux [2]; + logic [1:0] rf_wdata_wb_mux_we; + + // without writeback stage just pass through register write signals + assign rf_waddr_wb_o = rf_waddr_id_i; + assign rf_wdata_wb_mux[0] = rf_wdata_id_i; + assign rf_wdata_wb_mux_we[0] = rf_we_id_i; + + // Increment instruction retire counters for valid instructions which are not lsu errors. + assign perf_instr_ret_wb_o = instr_perf_count_id_i & en_wb_i & + ~(lsu_resp_valid_i & lsu_resp_err_i); + assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & instr_is_compressed_id_i; + + assign rf_wdata_wb_mux[1] = rf_wdata_lsu_i; + assign rf_wdata_wb_mux_we[1] = rf_we_lsu_i; + + // RF write data can come from ID results (all RF writes that aren't because of loads will come + // from here) or the LSU (RF writes for load data) + assign rf_wdata_wb_o = ({32{rf_wdata_wb_mux_we[0]}} & rf_wdata_wb_mux[0]) | + ({32{rf_wdata_wb_mux_we[1]}} & rf_wdata_wb_mux[1]); + assign rf_we_wb_o = |rf_wdata_wb_mux_we; + + `ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we)) +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.f b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.f deleted file mode 100644 index 83e8396b..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_core.f +++ /dev/null @@ -1,17 +0,0 @@ -ibex_pkg.sv -ibex_alu.sv -ibex_compressed_decoder.sv -ibex_controller.sv -ibex_counter.sv -ibex_cs_registers.sv -ibex_decoder.sv -ibex_ex_block.sv -ibex_id_stage.sv -ibex_if_stage.sv -ibex_load_store_unit.sv -ibex_multdiv_slow.sv -ibex_multdiv_fast.sv -ibex_prefetch_buffer.sv -ibex_fetch_fifo.sv -ibex_register_file_ff.sv -ibex_core.sv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_dummy_instr.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_dummy_instr.sv deleted file mode 100644 index ba33adc4..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_dummy_instr.sv +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * Dummy instruction module - * - * Provides pseudo-randomly inserted fake instructions for secure code obfuscation - */ - -// SEC_CM: CTRL_FLOW.UNPREDICTABLE -module ibex_dummy_instr import ibex_pkg::*; #( - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault -) ( - // Clock and reset - input logic clk_i, - input logic rst_ni, - - // Interface to CSRs - input logic dummy_instr_en_i, - input logic [2:0] dummy_instr_mask_i, - input logic dummy_instr_seed_en_i, - input logic [31:0] dummy_instr_seed_i, - - // Interface to IF stage - input logic fetch_valid_i, - input logic id_in_ready_i, - output logic insert_dummy_instr_o, - output logic [31:0] dummy_instr_data_o -); - - localparam int unsigned TIMEOUT_CNT_W = 5; - localparam int unsigned OP_W = 5; - - typedef enum logic [1:0] { - DUMMY_ADD = 2'b00, - DUMMY_MUL = 2'b01, - DUMMY_DIV = 2'b10, - DUMMY_AND = 2'b11 - } dummy_instr_e; - - typedef struct packed { - dummy_instr_e instr_type; - logic [OP_W-1:0] op_b; - logic [OP_W-1:0] op_a; - logic [TIMEOUT_CNT_W-1:0] cnt; - } lfsr_data_t; - localparam int unsigned LFSR_OUT_W = $bits(lfsr_data_t); - - lfsr_data_t lfsr_data; - logic [TIMEOUT_CNT_W-1:0] dummy_cnt_incr, dummy_cnt_threshold; - logic [TIMEOUT_CNT_W-1:0] dummy_cnt_d, dummy_cnt_q; - logic dummy_cnt_en; - logic lfsr_en; - logic [LFSR_OUT_W-1:0] lfsr_state; - logic insert_dummy_instr; - logic [6:0] dummy_set; - logic [2:0] dummy_opcode; - logic [31:0] dummy_instr; - logic [31:0] dummy_instr_seed_q, dummy_instr_seed_d; - - // Shift the LFSR every time we insert an instruction - assign lfsr_en = insert_dummy_instr & id_in_ready_i; - - assign dummy_instr_seed_d = dummy_instr_seed_q ^ dummy_instr_seed_i; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - dummy_instr_seed_q <= '0; - end else if (dummy_instr_seed_en_i) begin - dummy_instr_seed_q <= dummy_instr_seed_d; - end - end - - prim_lfsr #( - .LfsrDw ( LfsrWidth ), - .StateOutDw ( LFSR_OUT_W ), - .DefaultSeed ( RndCnstLfsrSeed ), - .StatePermEn ( 1'b1 ), - .StatePerm ( RndCnstLfsrPerm ) - ) lfsr_i ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .seed_en_i ( dummy_instr_seed_en_i ), - .seed_i ( dummy_instr_seed_d ), - .lfsr_en_i ( lfsr_en ), - .entropy_i ( '0 ), - .state_o ( lfsr_state ) - ); - - // Extract fields from LFSR - assign lfsr_data = lfsr_data_t'(lfsr_state); - - // Set count threshold for inserting a new instruction. This is the pseudo-random value from the - // LFSR with a mask applied (based on CSR config data) to shorten the period if required. - assign dummy_cnt_threshold = lfsr_data.cnt & {dummy_instr_mask_i,{TIMEOUT_CNT_W-3{1'b1}}}; - assign dummy_cnt_incr = dummy_cnt_q + {{TIMEOUT_CNT_W-1{1'b0}},1'b1}; - // Clear the counter everytime a new instruction is inserted - assign dummy_cnt_d = insert_dummy_instr ? '0 : dummy_cnt_incr; - // Increment the counter for each executed instruction while dummy instuctions are - // enabled. - assign dummy_cnt_en = dummy_instr_en_i & id_in_ready_i & - (fetch_valid_i | insert_dummy_instr); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - dummy_cnt_q <= '0; - end else if (dummy_cnt_en) begin - dummy_cnt_q <= dummy_cnt_d; - end - end - - // Insert a dummy instruction each time the counter hits the threshold - assign insert_dummy_instr = dummy_instr_en_i & (dummy_cnt_q == dummy_cnt_threshold); - - // Encode instruction - always_comb begin - unique case (lfsr_data.instr_type) - DUMMY_ADD: begin - dummy_set = 7'b0000000; - dummy_opcode = 3'b000; - end - DUMMY_MUL: begin - dummy_set = 7'b0000001; - dummy_opcode = 3'b000; - end - DUMMY_DIV: begin - dummy_set = 7'b0000001; - dummy_opcode = 3'b100; - end - DUMMY_AND: begin - dummy_set = 7'b0000000; - dummy_opcode = 3'b111; - end - default: begin - dummy_set = 7'b0000000; - dummy_opcode = 3'b000; - end - endcase - end - - // SET RS2 RS1 OP RD - assign dummy_instr = {dummy_set, lfsr_data.op_b, lfsr_data.op_a, dummy_opcode, 5'h00, 7'h33}; - - // Assign outputs - assign insert_dummy_instr_o = insert_dummy_instr; - assign dummy_instr_data_o = dummy_instr; - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_icache.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_icache.sv deleted file mode 100644 index c15a29b5..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_icache.sv +++ /dev/null @@ -1,1165 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * Instruction cache - * - * Provides an instruction cache along with cache management, instruction buffering and prefetching - */ - -`include "prim_assert.sv" - -module ibex_icache import ibex_pkg::*; #( - parameter bit ICacheECC = 1'b0, - parameter bit ResetAll = 1'b0, - parameter int unsigned BusSizeECC = BUS_SIZE, - parameter int unsigned TagSizeECC = IC_TAG_SIZE, - parameter int unsigned LineSizeECC = IC_LINE_SIZE, - // Only cache branch targets - parameter bit BranchCache = 1'b0 -) ( - // Clock and reset - input logic clk_i, - input logic rst_ni, - - // Signal that the core would like instructions - input logic req_i, - - // Set the cache's address counter - input logic branch_i, - input logic branch_mispredict_i, - input logic [31:0] mispredict_addr_i, - input logic [31:0] addr_i, - - // IF stage interface: Pass fetched instructions to the core - input logic ready_i, - output logic valid_o, - output logic [31:0] rdata_o, - output logic [31:0] addr_o, - output logic err_o, - output logic err_plus2_o, - - // Instruction memory / interconnect interface: Fetch instruction data from memory - output logic instr_req_o, - input logic instr_gnt_i, - output logic [31:0] instr_addr_o, - input logic [BUS_SIZE-1:0] instr_rdata_i, - input logic instr_err_i, - input logic instr_rvalid_i, - - // RAM IO - output logic [IC_NUM_WAYS-1:0] ic_tag_req_o, - output logic ic_tag_write_o, - output logic [IC_INDEX_W-1:0] ic_tag_addr_o, - output logic [TagSizeECC-1:0] ic_tag_wdata_o, - input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS], - output logic [IC_NUM_WAYS-1:0] ic_data_req_o, - output logic ic_data_write_o, - output logic [IC_INDEX_W-1:0] ic_data_addr_o, - output logic [LineSizeECC-1:0] ic_data_wdata_o, - input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS], - input logic ic_scr_key_valid_i, - - // Cache status - input logic icache_enable_i, - input logic icache_inval_i, - output logic busy_o, - output logic ecc_error_o -); - - // Number of fill buffers (must be >= 2) - localparam int unsigned NUM_FB = 4; - // Request throttling threshold - localparam int unsigned FB_THRESHOLD = NUM_FB - 2; - - // Prefetch signals - logic [ADDR_W-1:0] lookup_addr_aligned; - logic [ADDR_W-1:0] prefetch_addr_d, prefetch_addr_q; - logic prefetch_addr_en; - logic branch_or_mispredict; - // Cache pipelipe IC0 signals - logic lookup_throttle; - logic lookup_req_ic0; - logic [ADDR_W-1:0] lookup_addr_ic0; - logic [IC_INDEX_W-1:0] lookup_index_ic0; - logic fill_req_ic0; - logic [IC_INDEX_W-1:0] fill_index_ic0; - logic [IC_TAG_SIZE-1:0] fill_tag_ic0; - logic [IC_LINE_SIZE-1:0] fill_wdata_ic0; - logic lookup_grant_ic0; - logic lookup_actual_ic0; - logic fill_grant_ic0; - logic tag_req_ic0; - logic [IC_INDEX_W-1:0] tag_index_ic0; - logic [IC_NUM_WAYS-1:0] tag_banks_ic0; - logic tag_write_ic0; - logic [TagSizeECC-1:0] tag_wdata_ic0; - logic data_req_ic0; - logic [IC_INDEX_W-1:0] data_index_ic0; - logic [IC_NUM_WAYS-1:0] data_banks_ic0; - logic data_write_ic0; - logic [LineSizeECC-1:0] data_wdata_ic0; - // Cache pipelipe IC1 signals - logic [TagSizeECC-1:0] tag_rdata_ic1 [IC_NUM_WAYS]; - logic [LineSizeECC-1:0] data_rdata_ic1 [IC_NUM_WAYS]; - logic [LineSizeECC-1:0] hit_data_ecc_ic1; - logic [IC_LINE_SIZE-1:0] hit_data_ic1; - logic lookup_valid_ic1; - logic [ADDR_W-1:IC_INDEX_HI+1] lookup_addr_ic1; - logic [IC_NUM_WAYS-1:0] tag_match_ic1; - logic tag_hit_ic1; - logic [IC_NUM_WAYS-1:0] tag_invalid_ic1; - logic [IC_NUM_WAYS-1:0] lowest_invalid_way_ic1; - logic [IC_NUM_WAYS-1:0] round_robin_way_ic1, round_robin_way_q; - logic [IC_NUM_WAYS-1:0] sel_way_ic1; - logic ecc_err_ic1; - logic ecc_write_req; - logic [IC_NUM_WAYS-1:0] ecc_write_ways; - logic [IC_INDEX_W-1:0] ecc_write_index; - // Fill buffer signals - logic [$clog2(NUM_FB)-1:0] fb_fill_level; - logic fill_cache_new; - logic fill_new_alloc; - logic fill_spec_req, fill_spec_done, fill_spec_hold; - logic [NUM_FB-1:0][NUM_FB-1:0] fill_older_d, fill_older_q; - logic [NUM_FB-1:0] fill_alloc_sel, fill_alloc; - logic [NUM_FB-1:0] fill_busy_d, fill_busy_q; - logic [NUM_FB-1:0] fill_done; - logic [NUM_FB-1:0] fill_in_ic1; - logic [NUM_FB-1:0] fill_stale_d, fill_stale_q; - logic [NUM_FB-1:0] fill_cache_d, fill_cache_q; - logic [NUM_FB-1:0] fill_hit_ic1, fill_hit_d, fill_hit_q; - logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_ext_cnt_d, fill_ext_cnt_q; - logic [NUM_FB-1:0] fill_ext_hold_d, fill_ext_hold_q; - logic [NUM_FB-1:0] fill_ext_done_d, fill_ext_done_q; - logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_rvd_cnt_d, fill_rvd_cnt_q; - logic [NUM_FB-1:0] fill_rvd_done; - logic [NUM_FB-1:0] fill_ram_done_d, fill_ram_done_q; - logic [NUM_FB-1:0] fill_out_grant; - logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_out_cnt_d, fill_out_cnt_q; - logic [NUM_FB-1:0] fill_out_done; - logic [NUM_FB-1:0] fill_ext_req, fill_rvd_exp, fill_ram_req, fill_out_req; - logic [NUM_FB-1:0] fill_data_sel, fill_data_reg; - logic [NUM_FB-1:0] fill_data_hit, fill_data_rvd; - logic [NUM_FB-1:0][IC_LINE_BEATS_W-1:0] fill_ext_off, fill_rvd_off; - logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_ext_beat, fill_rvd_beat; - logic [NUM_FB-1:0] fill_ext_arb, fill_ram_arb, fill_out_arb; - logic [NUM_FB-1:0] fill_rvd_arb; - logic [NUM_FB-1:0] fill_entry_en; - logic [NUM_FB-1:0] fill_addr_en; - logic [NUM_FB-1:0] fill_way_en; - logic [NUM_FB-1:0][IC_LINE_BEATS-1:0] fill_data_en; - logic [NUM_FB-1:0][IC_LINE_BEATS-1:0] fill_err_d, fill_err_q; - logic [ADDR_W-1:0] fill_addr_q [NUM_FB]; - logic [IC_NUM_WAYS-1:0] fill_way_q [NUM_FB]; - logic [IC_LINE_SIZE-1:0] fill_data_d [NUM_FB]; - logic [IC_LINE_SIZE-1:0] fill_data_q [NUM_FB]; - logic [ADDR_W-1:BUS_W] fill_ext_req_addr; - logic [ADDR_W-1:0] fill_ram_req_addr; - logic [IC_NUM_WAYS-1:0] fill_ram_req_way; - logic [IC_LINE_SIZE-1:0] fill_ram_req_data; - logic [IC_LINE_SIZE-1:0] fill_out_data; - logic [IC_LINE_BEATS-1:0] fill_out_err; - // External req signals - logic instr_req; - logic [ADDR_W-1:BUS_W] instr_addr; - // Data output signals - logic skid_complete_instr; - logic skid_ready; - logic output_compressed; - logic skid_valid_d, skid_valid_q, skid_en; - logic [15:0] skid_data_d, skid_data_q; - logic skid_err_q; - logic output_valid; - logic addr_incr_two; - logic output_addr_en; - logic [ADDR_W-1:1] output_addr_incr; - logic [ADDR_W-1:1] output_addr_d, output_addr_q; - logic [15:0] output_data_lo, output_data_hi; - logic data_valid, output_ready; - logic [IC_LINE_SIZE-1:0] line_data; - logic [IC_LINE_BEATS-1:0] line_err; - logic [31:0] line_data_muxed; - logic line_err_muxed; - logic [31:0] output_data; - logic output_err; - // Invalidations - logic start_inval, inval_done; - logic inval_lock, inval_req_d, inval_req_q; - logic reset_inval_q; - logic inval_prog_d, inval_prog_q; - logic [IC_INDEX_W-1:0] inval_index_d, inval_index_q; - - ////////////////////////// - // Instruction prefetch // - ////////////////////////// - - assign branch_or_mispredict = branch_i | branch_mispredict_i; - - assign lookup_addr_aligned = {lookup_addr_ic0[ADDR_W-1:IC_LINE_W], {IC_LINE_W{1'b0}}}; - - // The prefetch address increments by one cache line for each granted request. - // This address is also updated if there is a branch that is not granted, since the target - // address (addr_i) is only valid for one cycle while branch_i is high. - - // The captured branch target address is not forced to be aligned since the offset in the cache - // line must also be recorded for later use by the fill buffers. - assign prefetch_addr_d = - lookup_grant_ic0 ? (lookup_addr_aligned + - {{ADDR_W-IC_LINE_W-1{1'b0}}, 1'b1, {IC_LINE_W{1'b0}}}) : - branch_i ? addr_i : - mispredict_addr_i; - - assign prefetch_addr_en = branch_or_mispredict | lookup_grant_ic0; - - if (ResetAll) begin : g_prefetch_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - prefetch_addr_q <= '0; - end else if (prefetch_addr_en) begin - prefetch_addr_q <= prefetch_addr_d; - end - end - end else begin : g_prefetch_addr_nr - always_ff @(posedge clk_i) begin - if (prefetch_addr_en) begin - prefetch_addr_q <= prefetch_addr_d; - end - end - end - - //////////////////////// - // Pipeline stage IC0 // - //////////////////////// - - // Cache lookup - assign lookup_throttle = (fb_fill_level > FB_THRESHOLD[$clog2(NUM_FB)-1:0]); - - assign lookup_req_ic0 = req_i & ~&fill_busy_q & (branch_or_mispredict | ~lookup_throttle) & - ~ecc_write_req; - assign lookup_addr_ic0 = branch_i ? addr_i : - branch_mispredict_i ? mispredict_addr_i : - prefetch_addr_q; - assign lookup_index_ic0 = lookup_addr_ic0[IC_INDEX_HI:IC_LINE_W]; - - // Cache write - assign fill_req_ic0 = (|fill_ram_req); - assign fill_index_ic0 = fill_ram_req_addr[IC_INDEX_HI:IC_LINE_W]; - assign fill_tag_ic0 = {(~inval_prog_q & ~ecc_write_req), - fill_ram_req_addr[ADDR_W-1:IC_INDEX_HI+1]}; - assign fill_wdata_ic0 = fill_ram_req_data; - - // Arbitrated signals - lookups have highest priority - assign lookup_grant_ic0 = lookup_req_ic0; - assign fill_grant_ic0 = fill_req_ic0 & ~lookup_req_ic0 & ~inval_prog_q & - ~ecc_write_req; - // Qualified lookup grant to mask ram signals in IC1 if access was not made - assign lookup_actual_ic0 = lookup_grant_ic0 & icache_enable_i & ~inval_prog_q & - ~icache_inval_i & ~inval_lock & ~start_inval; - - // Tagram - assign tag_req_ic0 = lookup_req_ic0 | fill_req_ic0 | inval_prog_q | ecc_write_req; - assign tag_index_ic0 = inval_prog_q ? inval_index_q : - ecc_write_req ? ecc_write_index : - fill_grant_ic0 ? fill_index_ic0 : - lookup_index_ic0; - assign tag_banks_ic0 = ecc_write_req ? ecc_write_ways : - fill_grant_ic0 ? fill_ram_req_way : - {IC_NUM_WAYS{1'b1}}; - assign tag_write_ic0 = fill_grant_ic0 | inval_prog_q | ecc_write_req; - - // Dataram - assign data_req_ic0 = lookup_req_ic0 | fill_req_ic0; - assign data_index_ic0 = tag_index_ic0; - assign data_banks_ic0 = tag_banks_ic0; - assign data_write_ic0 = tag_write_ic0; - - // Append ECC checkbits to write data if required - if (ICacheECC) begin : gen_ecc_wdata - // SEC_CM: ICACHE.MEM.INTEGRITY - // Tagram ECC - // Reuse the same ecc encoding module for larger cache sizes by padding with zeros - logic [21:0] tag_ecc_input_padded; - logic [27:0] tag_ecc_output_padded; - logic [22-IC_TAG_SIZE:0] unused_tag_ecc_output; - - assign tag_ecc_input_padded = {{22-IC_TAG_SIZE{1'b0}},fill_tag_ic0}; - assign unused_tag_ecc_output = tag_ecc_output_padded[21:IC_TAG_SIZE-1]; - - prim_secded_inv_28_22_enc tag_ecc_enc ( - .data_i (tag_ecc_input_padded), - .data_o (tag_ecc_output_padded) - ); - - assign tag_wdata_ic0 = {tag_ecc_output_padded[27:22],tag_ecc_output_padded[IC_TAG_SIZE-1:0]}; - - // Dataram ECC - for (genvar bank = 0; bank < IC_LINE_BEATS; bank++) begin : gen_ecc_banks - prim_secded_inv_39_32_enc data_ecc_enc ( - .data_i (fill_wdata_ic0[bank*BUS_SIZE+:BUS_SIZE]), - .data_o (data_wdata_ic0[bank*BusSizeECC+:BusSizeECC]) - ); - end - - end else begin : gen_noecc_wdata - assign tag_wdata_ic0 = fill_tag_ic0; - assign data_wdata_ic0 = fill_wdata_ic0; - end - - //////////////// - // IC0 -> IC1 // - //////////////// - - // Tag RAMs outputs - assign ic_tag_req_o = {IC_NUM_WAYS{tag_req_ic0}} & tag_banks_ic0; - assign ic_tag_write_o = tag_write_ic0; - assign ic_tag_addr_o = tag_index_ic0; - assign ic_tag_wdata_o = tag_wdata_ic0; - - // Tag RAMs inputs - assign tag_rdata_ic1 = ic_tag_rdata_i; - - // Data RAMs outputs - assign ic_data_req_o = {IC_NUM_WAYS{data_req_ic0}} & data_banks_ic0; - assign ic_data_write_o = data_write_ic0; - assign ic_data_addr_o = data_index_ic0; - assign ic_data_wdata_o = data_wdata_ic0; - - // Data RAMs inputs - assign data_rdata_ic1 = ic_data_rdata_i; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - lookup_valid_ic1 <= 1'b0; - end else begin - lookup_valid_ic1 <= lookup_actual_ic0; - end - end - - if (ResetAll) begin : g_lookup_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - lookup_addr_ic1 <= '0; - fill_in_ic1 <= '0; - end else if (lookup_grant_ic0) begin - lookup_addr_ic1 <= lookup_addr_ic0[ADDR_W-1:IC_INDEX_HI+1]; - fill_in_ic1 <= fill_alloc_sel; - end - end - end else begin : g_lookup_addr_nr - always_ff @(posedge clk_i) begin - if (lookup_grant_ic0) begin - lookup_addr_ic1 <= lookup_addr_ic0[ADDR_W-1:IC_INDEX_HI+1]; - fill_in_ic1 <= fill_alloc_sel; - end - end - end - - //////////////////////// - // Pipeline stage IC1 // - //////////////////////// - - // Tag matching - for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_tag_match - assign tag_match_ic1[way] = (tag_rdata_ic1[way][IC_TAG_SIZE-1:0] == - {1'b1,lookup_addr_ic1[ADDR_W-1:IC_INDEX_HI+1]}); - assign tag_invalid_ic1[way] = ~tag_rdata_ic1[way][IC_TAG_SIZE-1]; - end - - assign tag_hit_ic1 = |tag_match_ic1; - - // Hit data mux - always_comb begin - hit_data_ecc_ic1 = 'b0; - for (int way = 0; way < IC_NUM_WAYS; way++) begin - if (tag_match_ic1[way]) begin - hit_data_ecc_ic1 |= data_rdata_ic1[way]; - end - end - end - - // Way selection for allocations to the cache (onehot signals) - // 1 first invalid way - // 2 global round-robin (pseudorandom) way - assign lowest_invalid_way_ic1[0] = tag_invalid_ic1[0]; - assign round_robin_way_ic1[0] = round_robin_way_q[IC_NUM_WAYS-1]; - for (genvar way = 1; way < IC_NUM_WAYS; way++) begin : gen_lowest_way - assign lowest_invalid_way_ic1[way] = tag_invalid_ic1[way] & ~|tag_invalid_ic1[way-1:0]; - assign round_robin_way_ic1[way] = round_robin_way_q[way-1]; - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - round_robin_way_q <= {{IC_NUM_WAYS-1{1'b0}}, 1'b1}; - end else if (lookup_valid_ic1) begin - round_robin_way_q <= round_robin_way_ic1; - end - end - - assign sel_way_ic1 = |tag_invalid_ic1 ? lowest_invalid_way_ic1 : - round_robin_way_q; - - // ECC checking logic - if (ICacheECC) begin : gen_data_ecc_checking - // SEC_CM: ICACHE.MEM.INTEGRITY - logic [IC_NUM_WAYS-1:0] tag_err_ic1; - logic [IC_LINE_BEATS*2-1:0] data_err_ic1; - logic ecc_correction_write_d, ecc_correction_write_q; - logic [IC_NUM_WAYS-1:0] ecc_correction_ways_d, ecc_correction_ways_q; - logic [IC_INDEX_W-1:0] lookup_index_ic1, ecc_correction_index_q; - - // Tag ECC checking - for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_tag_ecc - logic [1:0] tag_err_bank_ic1; - logic [27:0] tag_rdata_padded_ic1; - - // Expand the tag rdata with extra padding if the tag size is less than the maximum - assign tag_rdata_padded_ic1 = {tag_rdata_ic1[way][TagSizeECC-1-:6], - {22-IC_TAG_SIZE{1'b0}}, - tag_rdata_ic1[way][IC_TAG_SIZE-1:0]}; - - prim_secded_inv_28_22_dec data_ecc_dec ( - .data_i (tag_rdata_padded_ic1), - .data_o (), - .syndrome_o (), - .err_o (tag_err_bank_ic1) - ); - assign tag_err_ic1[way] = |tag_err_bank_ic1; - end - - // Data ECC checking - // Note - could generate for all ways and mux after - for (genvar bank = 0; bank < IC_LINE_BEATS; bank++) begin : gen_ecc_banks - prim_secded_inv_39_32_dec data_ecc_dec ( - .data_i (hit_data_ecc_ic1[bank*BusSizeECC+:BusSizeECC]), - .data_o (), - .syndrome_o (), - .err_o (data_err_ic1[bank*2+:2]) - ); - - assign hit_data_ic1[bank*BUS_SIZE+:BUS_SIZE] = - hit_data_ecc_ic1[bank*BusSizeECC+:BUS_SIZE]; - - end - - // Tag ECC across all ways is always expected to be correct so the check does not need to be - // qualified by hit or tag valid. Initial (invalid with correct ECC) tags are written on reset - // and all further tag writes produce correct ECC. For data ECC no initialisation is done on - // reset so unused data (in particular those ways that don't have a valid tag) may have - // incorrect ECC. We only check data ECC where tags indicate it is valid and we have hit on it. - assign ecc_err_ic1 = lookup_valid_ic1 & (((|data_err_ic1) & tag_hit_ic1) | (|tag_err_ic1)); - - // Error correction - // All ways will be invalidated on a tag error to prevent X-propagation from data_err_ic1 on - // spurious hits. Also prevents the same line being allocated twice when there was a true - // hit and a spurious hit. - assign ecc_correction_ways_d = {IC_NUM_WAYS{|tag_err_ic1}} | - (tag_match_ic1 & {IC_NUM_WAYS{|data_err_ic1}}); - assign ecc_correction_write_d = ecc_err_ic1; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - ecc_correction_write_q <= 1'b0; - end else begin - ecc_correction_write_q <= ecc_correction_write_d; - end - end - - // The index is required in IC1 only when ECC is configured so is registered here - if (ResetAll) begin : g_lookup_ind_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - lookup_index_ic1 <= '0; - end else if (lookup_grant_ic0) begin - lookup_index_ic1 <= lookup_addr_ic0[IC_INDEX_HI-:IC_INDEX_W]; - end - end - end else begin : g_lookup_ind_nr - always_ff @(posedge clk_i) begin - if (lookup_grant_ic0) begin - lookup_index_ic1 <= lookup_addr_ic0[IC_INDEX_HI-:IC_INDEX_W]; - end - end - end - - // Store the ways with errors to be invalidated - if (ResetAll) begin : g_ecc_correction_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - ecc_correction_ways_q <= '0; - ecc_correction_index_q <= '0; - end else if (ecc_err_ic1) begin - ecc_correction_ways_q <= ecc_correction_ways_d; - ecc_correction_index_q <= lookup_index_ic1; - end - end - end else begin : g_ecc_correction_nr - always_ff @(posedge clk_i) begin - if (ecc_err_ic1) begin - ecc_correction_ways_q <= ecc_correction_ways_d; - ecc_correction_index_q <= lookup_index_ic1; - end - end - end - - assign ecc_write_req = ecc_correction_write_q; - assign ecc_write_ways = ecc_correction_ways_q; - assign ecc_write_index = ecc_correction_index_q; - - assign ecc_error_o = ecc_err_ic1; - end else begin : gen_no_data_ecc - assign ecc_err_ic1 = 1'b0; - assign ecc_write_req = 1'b0; - assign ecc_write_ways = '0; - assign ecc_write_index = '0; - assign hit_data_ic1 = hit_data_ecc_ic1; - - assign ecc_error_o = 1'b0; - end - - /////////////////////////////// - // Cache allocation decision // - /////////////////////////////// - - if (BranchCache) begin : gen_caching_logic - - // Cache branch target + a number of subsequent lines - localparam int unsigned CACHE_AHEAD = 2; - localparam int unsigned CACHE_CNT_W = (CACHE_AHEAD == 1) ? 1 : $clog2(CACHE_AHEAD) + 1; - logic cache_cnt_dec; - logic [CACHE_CNT_W-1:0] cache_cnt_d, cache_cnt_q; - - assign cache_cnt_dec = lookup_grant_ic0 & (|cache_cnt_q); - assign cache_cnt_d = branch_i ? CACHE_AHEAD[CACHE_CNT_W-1:0] : - (cache_cnt_q - {{CACHE_CNT_W-1{1'b0}},cache_cnt_dec}); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - cache_cnt_q <= '0; - end else begin - cache_cnt_q <= cache_cnt_d; - end - end - - assign fill_cache_new = (branch_i | (|cache_cnt_q)) & icache_enable_i & - ~icache_inval_i & ~inval_lock & ~inval_prog_q; - - end else begin : gen_cache_all - - // Cache all missing fetches - assign fill_cache_new = icache_enable_i & ~start_inval & ~inval_prog_q; - end - - ////////////////////////// - // Fill buffer tracking // - ////////////////////////// - - always_comb begin - fb_fill_level = '0; - for (int i = 0; i < NUM_FB; i++) begin - if (fill_busy_q[i] & ~fill_stale_q[i]) begin - fb_fill_level += {{$clog2(NUM_FB) - 1{1'b0}}, 1'b1}; - end - end - end - - // Allocate a new buffer for every granted lookup - assign fill_new_alloc = lookup_grant_ic0; - // Track whether a speculative external request was made from IC0, and whether it was granted - // Speculative requests are only made for branches, or if the cache is disabled - assign fill_spec_req = (~icache_enable_i | branch_or_mispredict) & ~|fill_ext_req; - assign fill_spec_done = fill_spec_req & instr_gnt_i; - assign fill_spec_hold = fill_spec_req & ~instr_gnt_i; - - for (genvar fb = 0; fb < NUM_FB; fb++) begin : gen_fbs - - ///////////////////////////// - // Fill buffer allocations // - ///////////////////////////// - - // Allocate the lowest available buffer - if (fb == 0) begin : gen_fb_zero - assign fill_alloc_sel[fb] = ~fill_busy_q[fb]; - end else begin : gen_fb_rest - assign fill_alloc_sel[fb] = ~fill_busy_q[fb] & (&fill_busy_q[fb-1:0]); - end - - assign fill_alloc[fb] = fill_alloc_sel[fb] & fill_new_alloc; - assign fill_busy_d[fb] = fill_alloc[fb] | (fill_busy_q[fb] & ~fill_done[fb]); - - // Track which other fill buffers are older than this one (for age-based arbitration) - // TODO sparsify - assign fill_older_d[fb] = (fill_alloc[fb] ? fill_busy_q : fill_older_q[fb]) & ~fill_done; - - // A fill buffer can release once all its actions are completed - // all data written to the cache (unless hit or error) - assign fill_done[fb] = (fill_ram_done_q[fb] | fill_hit_q[fb] | ~fill_cache_q[fb] | - (|fill_err_q[fb])) & - // all data output unless stale due to intervening branch - (fill_out_done[fb] | fill_stale_q[fb] | branch_or_mispredict) & - // all external requests completed - fill_rvd_done[fb]; - - ///////////////////////////////// - // Fill buffer status tracking // - ///////////////////////////////// - - // Track staleness (requests become stale when a branch intervenes) - assign fill_stale_d[fb] = fill_busy_q[fb] & (branch_or_mispredict | fill_stale_q[fb]); - // Track whether or not this request should allocate to the cache - // Any invalidation or disabling of the cache while the buffer is busy will stop allocation - assign fill_cache_d[fb] = (fill_alloc[fb] & fill_cache_new) | - (fill_cache_q[fb] & fill_busy_q[fb] & - icache_enable_i & ~icache_inval_i & ~inval_lock); - // Record whether the request hit in the cache - assign fill_hit_ic1[fb] = lookup_valid_ic1 & fill_in_ic1[fb] & tag_hit_ic1 & ~ecc_err_ic1; - assign fill_hit_d[fb] = fill_hit_ic1[fb] | (fill_hit_q[fb] & fill_busy_q[fb]); - - /////////////////////////////////////////// - // Fill buffer external request tracking // - /////////////////////////////////////////// - - // Make an external request - assign fill_ext_req[fb] = fill_busy_q[fb] & ~fill_ext_done_d[fb]; - - // Count the number of completed external requests (each line requires IC_LINE_BEATS requests) - assign fill_ext_cnt_d[fb] = fill_alloc[fb] ? - {{IC_LINE_BEATS_W{1'b0}},fill_spec_done} : - (fill_ext_cnt_q[fb] + {{IC_LINE_BEATS_W{1'b0}}, - fill_ext_arb[fb] & instr_gnt_i}); - // External request must be held until granted - assign fill_ext_hold_d[fb] = (fill_alloc[fb] & fill_spec_hold) | - (fill_ext_arb[fb] & ~instr_gnt_i); - // External requests are completed when the counter is filled or when the request is cancelled - assign fill_ext_done_d[fb] = (fill_ext_cnt_q[fb][IC_LINE_BEATS_W] | - // external requests are considered complete if the request hit - fill_hit_ic1[fb] | fill_hit_q[fb] | - // cancel if the line won't be cached and, it is stale - (~fill_cache_q[fb] & (branch_or_mispredict | fill_stale_q[fb] | - // or we're already at the end of the line - fill_ext_beat[fb][IC_LINE_BEATS_W]))) & - // can't cancel while we are waiting for a grant on the bus - ~fill_ext_hold_q[fb] & fill_busy_q[fb]; - // Track whether this fill buffer expects to receive beats of data - assign fill_rvd_exp[fb] = fill_busy_q[fb] & ~fill_rvd_done[fb]; - // Count the number of rvalid beats received - assign fill_rvd_cnt_d[fb] = fill_alloc[fb] ? '0 : - (fill_rvd_cnt_q[fb] + - {{IC_LINE_BEATS_W{1'b0}},fill_rvd_arb[fb]}); - // External data is complete when all issued external requests have received their data - assign fill_rvd_done[fb] = (fill_ext_done_q[fb] & ~fill_ext_hold_q[fb]) & - (fill_rvd_cnt_q[fb] == fill_ext_cnt_q[fb]); - - ////////////////////////////////////// - // Fill buffer data output tracking // - ////////////////////////////////////// - - // Send data to the IF stage for requests that are not stale, have not completed their - // data output, and have data available to send. - // Data is available if: - // - The request hit in the cache - // - Buffered data is available (fill_rvd_cnt_q is ahead of fill_out_cnt_q) - // - Data is available from the bus this cycle (fill_rvd_arb) - assign fill_out_req[fb] = fill_busy_q[fb] & ~fill_stale_q[fb] & ~fill_out_done[fb] & - (fill_hit_ic1[fb] | fill_hit_q[fb] | - (fill_rvd_beat[fb] > fill_out_cnt_q[fb]) | fill_rvd_arb[fb]); - - // Calculate when a beat of data is output. Any ECC error squashes the output that cycle. - assign fill_out_grant[fb] = fill_out_arb[fb] & output_ready; - - // Count the beats of data output to the IF stage - assign fill_out_cnt_d[fb] = fill_alloc[fb] ? {1'b0,lookup_addr_ic0[IC_LINE_W-1:BUS_W]} : - (fill_out_cnt_q[fb] + - {{IC_LINE_BEATS_W{1'b0}},fill_out_grant[fb]}); - // Data output complete when the counter fills - assign fill_out_done[fb] = fill_out_cnt_q[fb][IC_LINE_BEATS_W]; - - ////////////////////////////////////// - // Fill buffer ram request tracking // - ////////////////////////////////////// - - // make a fill request once all data beats received - assign fill_ram_req[fb] = fill_busy_q[fb] & fill_rvd_cnt_q[fb][IC_LINE_BEATS_W] & - // unless the request hit, was non-allocating or got an error - ~fill_hit_q[fb] & fill_cache_q[fb] & ~|fill_err_q[fb] & - // or the request was already completed - ~fill_ram_done_q[fb]; - - // Record when a cache allocation request has been completed - assign fill_ram_done_d[fb] = fill_ram_arb[fb] | (fill_ram_done_q[fb] & fill_busy_q[fb]); - - ////////////////////////////// - // Fill buffer line offsets // - ////////////////////////////// - - // When we branch into the middle of a line, the output count will not start from zero. This - // beat count is used to know which incoming rdata beats are relevant. - assign fill_ext_beat[fb] = {1'b0,fill_addr_q[fb][IC_LINE_W-1:BUS_W]} + - fill_ext_cnt_q[fb][IC_LINE_BEATS_W:0]; - assign fill_ext_off[fb] = fill_ext_beat[fb][IC_LINE_BEATS_W-1:0]; - assign fill_rvd_beat[fb] = {1'b0,fill_addr_q[fb][IC_LINE_W-1:BUS_W]} + - fill_rvd_cnt_q[fb][IC_LINE_BEATS_W:0]; - assign fill_rvd_off[fb] = fill_rvd_beat[fb][IC_LINE_BEATS_W-1:0]; - - ///////////////////////////// - // Fill buffer arbitration // - ///////////////////////////// - - // Age based arbitration - all these signals are one-hot - assign fill_ext_arb[fb] = fill_ext_req[fb] & ~|(fill_ext_req & fill_older_q[fb]); - assign fill_ram_arb[fb] = fill_ram_req[fb] & fill_grant_ic0 & - ~|(fill_ram_req & fill_older_q[fb]); - // Calculate which fill buffer is the oldest one which still needs to output data to IF - assign fill_data_sel[fb] = ~|(fill_busy_q & ~fill_out_done & ~fill_stale_q & - fill_older_q[fb]); - // Arbitrate the request which has data available to send, and is the oldest outstanding - assign fill_out_arb[fb] = fill_out_req[fb] & fill_data_sel[fb]; - // Assign incoming rvalid data to the oldest fill buffer expecting it - assign fill_rvd_arb[fb] = instr_rvalid_i & fill_rvd_exp[fb] & - ~|(fill_rvd_exp & fill_older_q[fb]); - - ///////////////////////////// - // Fill buffer data muxing // - ///////////////////////////// - - // Output data muxing controls - // 1. Select data from the fill buffer data register - assign fill_data_reg[fb] = fill_busy_q[fb] & ~fill_stale_q[fb] & - ~fill_out_done[fb] & fill_data_sel[fb] & - // The incoming data is already ahead of the output count - ((fill_rvd_beat[fb] > fill_out_cnt_q[fb]) | fill_hit_q[fb] | - (|fill_err_q[fb])); - // 2. Select IC1 hit data - assign fill_data_hit[fb] = fill_busy_q[fb] & fill_hit_ic1[fb] & fill_data_sel[fb]; - // 3. Select incoming instr_rdata_i - assign fill_data_rvd[fb] = fill_busy_q[fb] & fill_rvd_arb[fb] & ~fill_hit_q[fb] & - ~fill_hit_ic1[fb] & ~fill_stale_q[fb] & ~fill_out_done[fb] & - // The incoming data lines up with the output count - (fill_rvd_beat[fb] == fill_out_cnt_q[fb]) & fill_data_sel[fb]; - - - /////////////////////////// - // Fill buffer registers // - /////////////////////////// - - // Fill buffer general enable - assign fill_entry_en[fb] = fill_alloc[fb] | fill_busy_q[fb]; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_busy_q[fb] <= 1'b0; - fill_older_q[fb] <= '0; - fill_stale_q[fb] <= 1'b0; - fill_cache_q[fb] <= 1'b0; - fill_hit_q[fb] <= 1'b0; - fill_ext_cnt_q[fb] <= '0; - fill_ext_hold_q[fb] <= 1'b0; - fill_ext_done_q[fb] <= 1'b0; - fill_rvd_cnt_q[fb] <= '0; - fill_ram_done_q[fb] <= 1'b0; - fill_out_cnt_q[fb] <= '0; - end else if (fill_entry_en[fb]) begin - fill_busy_q[fb] <= fill_busy_d[fb]; - fill_older_q[fb] <= fill_older_d[fb]; - fill_stale_q[fb] <= fill_stale_d[fb]; - fill_cache_q[fb] <= fill_cache_d[fb]; - fill_hit_q[fb] <= fill_hit_d[fb]; - fill_ext_cnt_q[fb] <= fill_ext_cnt_d[fb]; - fill_ext_hold_q[fb] <= fill_ext_hold_d[fb]; - fill_ext_done_q[fb] <= fill_ext_done_d[fb]; - fill_rvd_cnt_q[fb] <= fill_rvd_cnt_d[fb]; - fill_ram_done_q[fb] <= fill_ram_done_d[fb]; - fill_out_cnt_q[fb] <= fill_out_cnt_d[fb]; - end - end - - //////////////////////////////////////// - // Fill buffer address / data storage // - //////////////////////////////////////// - - assign fill_addr_en[fb] = fill_alloc[fb]; - assign fill_way_en[fb] = (lookup_valid_ic1 & fill_in_ic1[fb]); - - if (ResetAll) begin : g_fill_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_addr_q[fb] <= '0; - end else if (fill_addr_en[fb]) begin - fill_addr_q[fb] <= lookup_addr_ic0; - end - end - end else begin : g_fill_addr_nr - always_ff @(posedge clk_i) begin - if (fill_addr_en[fb]) begin - fill_addr_q[fb] <= lookup_addr_ic0; - end - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_way_q[fb] <= '0; - end else if (fill_way_en[fb]) begin - fill_way_q[fb] <= sel_way_ic1; - end - end - - // Data either comes from the cache or the bus. If there was an ECC error, we must take - // the incoming bus data since the cache hit data is corrupted. - assign fill_data_d[fb] = fill_hit_ic1[fb] ? hit_data_ic1 : - {IC_LINE_BEATS{instr_rdata_i}}; - - for (genvar b = 0; b < IC_LINE_BEATS; b++) begin : gen_data_buf - // Error tracking (per beat) - assign fill_err_d[fb][b] = (fill_rvd_arb[fb] & instr_err_i & - (fill_rvd_off[fb] == b[IC_LINE_BEATS_W-1:0])) | - // Hold the error once recorded - (fill_busy_q[fb] & fill_err_q[fb][b]); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_err_q[fb][b] <= '0; - end else if (fill_entry_en[fb]) begin - fill_err_q[fb][b] <= fill_err_d[fb][b]; - end - end - - // Enable the relevant part of the data register (or all for cache hits) - // Ignore incoming rvalid data when we already have cache hit data - assign fill_data_en[fb][b] = fill_hit_ic1[fb] | - (fill_rvd_arb[fb] & ~fill_hit_q[fb] & - (fill_rvd_off[fb] == b[IC_LINE_BEATS_W-1:0])); - - if (ResetAll) begin : g_fill_data_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - fill_data_q[fb][b*BUS_SIZE+:BUS_SIZE] <= '0; - end else if (fill_data_en[fb][b]) begin - fill_data_q[fb][b*BUS_SIZE+:BUS_SIZE] <= fill_data_d[fb][b*BUS_SIZE+:BUS_SIZE]; - end - end - end else begin : g_fill_data_nr - always_ff @(posedge clk_i) begin - if (fill_data_en[fb][b]) begin - fill_data_q[fb][b*BUS_SIZE+:BUS_SIZE] <= fill_data_d[fb][b*BUS_SIZE+:BUS_SIZE]; - end - end - end - - end - end - - //////////////////////////////// - // Fill buffer one-hot muxing // - //////////////////////////////// - - // External req info - always_comb begin - fill_ext_req_addr = '0; - for (int i = 0; i < NUM_FB; i++) begin - if (fill_ext_arb[i]) begin - fill_ext_req_addr |= {fill_addr_q[i][ADDR_W-1:IC_LINE_W], fill_ext_off[i]}; - end - end - end - - // Cache req info - always_comb begin - fill_ram_req_addr = '0; - fill_ram_req_way = '0; - fill_ram_req_data = '0; - for (int i = 0; i < NUM_FB; i++) begin - if (fill_ram_arb[i]) begin - fill_ram_req_addr |= fill_addr_q[i]; - fill_ram_req_way |= fill_way_q[i]; - fill_ram_req_data |= fill_data_q[i]; - end - end - end - - // IF stage output data - always_comb begin - fill_out_data = '0; - fill_out_err = '0; - for (int i = 0; i < NUM_FB; i++) begin - if (fill_data_reg[i]) begin - fill_out_data |= fill_data_q[i]; - // Ignore any speculative errors accumulated on cache hits - fill_out_err |= (fill_err_q[i] & ~{IC_LINE_BEATS{fill_hit_q[i]}}); - end - end - end - - /////////////////////// - // External requests // - /////////////////////// - - assign instr_req = ((~icache_enable_i | branch_or_mispredict) & lookup_grant_ic0) | - (|fill_ext_req); - - assign instr_addr = |fill_ext_req ? fill_ext_req_addr : - lookup_addr_ic0[ADDR_W-1:BUS_W]; - - assign instr_req_o = instr_req; - assign instr_addr_o = {instr_addr[ADDR_W-1:BUS_W],{BUS_W{1'b0}}}; - - //////////////////////// - // Output data muxing // - //////////////////////// - - // Mux between line-width data sources - assign line_data = |fill_data_hit ? hit_data_ic1 : fill_out_data; - assign line_err = |fill_data_hit ? {IC_LINE_BEATS{1'b0}} : fill_out_err; - - // Mux the relevant beat of line data, based on the output address - always_comb begin - line_data_muxed = '0; - line_err_muxed = 1'b0; - for (int unsigned i = 0; i < IC_LINE_BEATS; i++) begin - // When data has been skidded, the output address is behind by one - if ((output_addr_q[IC_LINE_W-1:BUS_W] + {{IC_LINE_BEATS_W-1{1'b0}},skid_valid_q}) == - i[IC_LINE_BEATS_W-1:0]) begin - line_data_muxed |= line_data[i*32+:32]; - line_err_muxed |= line_err[i]; - end - end - end - - // Mux between incoming rdata and the muxed line data - assign output_data = |fill_data_rvd ? instr_rdata_i : line_data_muxed; - assign output_err = |fill_data_rvd ? instr_err_i : line_err_muxed; - - // Output data is valid (from any of the three possible sources). Note that fill_out_arb - // must be used here rather than fill_out_req because data can become valid out of order - // (e.g. cache hit data can become available ahead of an older outstanding miss). - assign data_valid = |fill_out_arb; - - // Skid buffer data - assign skid_data_d = output_data[31:16]; - - assign skid_en = data_valid & (ready_i | skid_ready); - - if (ResetAll) begin : g_skid_data_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - skid_data_q <= '0; - skid_err_q <= '0; - end else if (skid_en) begin - skid_data_q <= skid_data_d; - skid_err_q <= output_err; - end - end - end else begin : g_skid_data_nr - always_ff @(posedge clk_i) begin - if (skid_en) begin - skid_data_q <= skid_data_d; - skid_err_q <= output_err; - end - end - end - - // The data in the skid buffer is ready if it's a complete compressed instruction or if there's - // an error (no need to wait for the second half) - assign skid_complete_instr = skid_valid_q & ((skid_data_q[1:0] != 2'b11) | skid_err_q); - - // Data can be loaded into the skid buffer for an unaligned uncompressed instruction - assign skid_ready = output_addr_q[1] & ~skid_valid_q & (~output_compressed | output_err); - - assign output_ready = (ready_i | skid_ready) & ~skid_complete_instr; - - assign output_compressed = (rdata_o[1:0] != 2'b11); - - assign skid_valid_d = - // Branches invalidate the skid buffer - branch_or_mispredict ? 1'b0 : - // Once valid, the skid buffer stays valid until a compressed instruction realigns the stream - (skid_valid_q ? ~(ready_i & ((skid_data_q[1:0] != 2'b11) | skid_err_q)) : - // The skid buffer becomes valid when: - // - we branch to an unaligned uncompressed instruction - (data_valid & - (((output_addr_q[1] & (~output_compressed | output_err)) | - // - a compressed instruction misaligns the stream - (~output_addr_q[1] & output_compressed & ~output_err & ready_i))))); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - skid_valid_q <= 1'b0; - end else begin - skid_valid_q <= skid_valid_d; - end - end - - // Signal that valid data is available to the IF stage - // Note that if the first half of an unaligned instruction reports an error, we do not need - // to wait for the second half - // Compressed instruction completely satisfied by skid buffer - assign output_valid = skid_complete_instr | - // Output data available and, output stream aligned, or skid data available, - (data_valid & (~output_addr_q[1] | skid_valid_q | - // or this is an error or an unaligned compressed instruction - output_err | (output_data[17:16] != 2'b11))); - - // Update the address on branches and every time an instruction is driven - assign output_addr_en = branch_or_mispredict | (ready_i & valid_o); - - // Increment the address by two every time a compressed instruction is popped - assign addr_incr_two = output_compressed & ~err_o; - - // Next IF stage PC - assign output_addr_incr = (output_addr_q[31:1] + - // Increment address by 4 or 2 - {29'd0, ~addr_incr_two, addr_incr_two}); - - // Redirect the address on branches or mispredicts - assign output_addr_d = branch_i ? addr_i[31:1] : - branch_mispredict_i ? mispredict_addr_i[31:1] : - output_addr_incr; - - if (ResetAll) begin : g_output_addr_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - output_addr_q <= '0; - end else if (output_addr_en) begin - output_addr_q <= output_addr_d; - end - end - end else begin : g_output_addr_nr - always_ff @(posedge clk_i) begin - if (output_addr_en) begin - output_addr_q <= output_addr_d; - end - end - end - - // Mux the data from BUS_SIZE to halfword - // This muxing realigns data when instruction words are split across BUS_W e.g. - // word 1 |----|*h1*| - // word 0 |*h0*|----| --> |*h1*|*h0*| - // 31 15 0 31 15 0 - always_comb begin - output_data_lo = '0; - for (int unsigned i = 0; i < IC_OUTPUT_BEATS; i++) begin - if (output_addr_q[BUS_W-1:1] == i[BUS_W-2:0]) begin - output_data_lo |= output_data[i*16+:16]; - end - end - end - - always_comb begin - output_data_hi = '0; - for (int unsigned i = 0; i < IC_OUTPUT_BEATS - 1; i++) begin - if (output_addr_q[BUS_W-1:1] == i[BUS_W-2:0]) begin - output_data_hi |= output_data[(i+1)*16+:16]; - end - end - if (&output_addr_q[BUS_W-1:1]) begin - output_data_hi |= output_data[15:0]; - end - end - - assign valid_o = output_valid & ~branch_mispredict_i; - assign rdata_o = {output_data_hi, (skid_valid_q ? skid_data_q : output_data_lo)}; - assign addr_o = {output_addr_q, 1'b0}; - assign err_o = (skid_valid_q & skid_err_q) | (~skid_complete_instr & output_err); - // Error caused by the second half of a misaligned uncompressed instruction - // (only relevant when err_o is set) - assign err_plus2_o = skid_valid_q & ~skid_err_q; - - /////////////////// - // Invalidations // - /////////////////// - - - // We need to save the invalidation request inside a register. That way we can wait - // until we have a valid scrambling key to do it. Since the key itself is needed for - // starting to fill in the RAMs and read from them, ICache also needs to stop operating. - assign inval_req_d = (inval_req_q | icache_inval_i) & ~(inval_done & inval_prog_q); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - inval_req_q <= 1'b0; - end else begin - inval_req_q <= inval_req_d; - end - end - - // This will act like a lock mechanism. - // Main idea is to lock the invalidation request until we got a valid scrambling key. - assign inval_lock = inval_req_d & ~ic_scr_key_valid_i; - - // Invalidate on reset, or when instructed. If an invalidation request is received while a - // previous invalidation is ongoing, it does not need to be restarted. Do not start - // this process until inval lock is removed meaning the scrambling key is valid. - assign start_inval = ~inval_lock & (~reset_inval_q | inval_req_q) & ~inval_prog_q ; - assign inval_prog_d = ~inval_lock & (start_inval | (inval_prog_q & ~inval_done)); - assign inval_done = &inval_index_q; - assign inval_index_d = start_inval ? '0 : (inval_index_q + {{IC_INDEX_W-1{1'b0}},1'b1}); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - inval_prog_q <= 1'b0; - reset_inval_q <= 1'b0; - end else begin - inval_prog_q <= inval_prog_d; - reset_inval_q <= 1'b1; - end - end - - if (ResetAll) begin : g_inval_index_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - inval_index_q <= '0; - end else if (inval_prog_d) begin - inval_index_q <= inval_index_d; - end - end - end else begin : g_inval_index_nr - always_ff @(posedge clk_i) begin - if (inval_prog_d) begin - inval_index_q <= inval_index_d; - end - end - end - - ///////////////// - // Busy status // - ///////////////// - - // Only busy (for WFI purposes) while an invalidation is in-progress, or external requests are - // outstanding. - assign busy_o = inval_req_q | (|(fill_busy_q & ~fill_rvd_done)); - - //////////////// - // Assertions // - //////////////// - - `ASSERT_INIT(size_param_legal, (IC_LINE_SIZE > 32)) - - // ECC primitives will need to be changed for different sizes - `ASSERT_INIT(ecc_tag_param_legal, (IC_TAG_SIZE <= 27)) - `ASSERT_INIT(ecc_data_param_legal, !ICacheECC || (BUS_SIZE == 32)) - - // Lookups in the tag ram should always give a known result - `ASSERT_KNOWN(TagHitKnown, lookup_valid_ic1 & tag_hit_ic1) - `ASSERT_KNOWN(TagInvalidKnown, lookup_valid_ic1 & tag_invalid_ic1) - - // This is only used for the Yosys-based formal flow. Once we have working bind support, we can - // get rid of it. -`ifdef FORMAL - `ifdef YOSYS - // Unfortunately, Yosys doesn't support passing unpacked arrays as ports. Explicitly pack up the - // signals we need. - logic [NUM_FB-1:0][ADDR_W-1:0] packed_fill_addr_q; - always_comb begin - for (int i = 0; i < NUM_FB; i++) begin - packed_fill_addr_q[i][ADDR_W-1:0] = fill_addr_q[i]; - end - end - - `include "formal_tb_frag.svh" - `endif -`endif - - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_if_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_if_stage.sv deleted file mode 100644 index c430b669..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_if_stage.sv +++ /dev/null @@ -1,750 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * Instruction Fetch Stage - * - * Instruction fetch unit: Selection of the next PC, and buffering (sampling) of - * the read instruction. - */ - -`include "prim_assert.sv" - -module ibex_if_stage import ibex_pkg::*; #( - parameter int unsigned DmHaltAddr = 32'h1A110800, - parameter int unsigned DmExceptionAddr = 32'h1A110808, - parameter bit DummyInstructions = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter int unsigned BusSizeECC = BUS_SIZE, - parameter int unsigned TagSizeECC = IC_TAG_SIZE, - parameter int unsigned LineSizeECC = IC_LINE_SIZE, - parameter bit PCIncrCheck = 1'b0, - parameter bit ResetAll = 1'b0, - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, - parameter bit BranchPredictor = 1'b0 -) ( - input logic clk_i, - input logic rst_ni, - - input logic [31:0] boot_addr_i, // also used for mtvec - input logic req_i, // instruction request control - - // instruction cache interface - output logic instr_req_o, - output logic [31:0] instr_addr_o, - input logic instr_gnt_i, - input logic instr_rvalid_i, - input logic [31:0] instr_rdata_i, - input logic instr_err_i, - - // ICache RAM IO - output logic [IC_NUM_WAYS-1:0] ic_tag_req_o, - output logic ic_tag_write_o, - output logic [IC_INDEX_W-1:0] ic_tag_addr_o, - output logic [TagSizeECC-1:0] ic_tag_wdata_o, - input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS], - output logic [IC_NUM_WAYS-1:0] ic_data_req_o, - output logic ic_data_write_o, - output logic [IC_INDEX_W-1:0] ic_data_addr_o, - output logic [LineSizeECC-1:0] ic_data_wdata_o, - input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS], - input logic ic_scr_key_valid_i, - - // output of ID stage - output logic instr_valid_id_o, // instr in IF-ID is valid - output logic instr_new_id_o, // instr in IF-ID is new - output logic [31:0] instr_rdata_id_o, // instr for ID stage - output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage - // to reduce fan-out - output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage - // (mtval), meaningful only if - // instr_is_compressed_id_o = 1'b1 - output logic instr_is_compressed_id_o, // compressed decoder thinks this - // is a compressed instr - output logic instr_bp_taken_o, // instruction was predicted to be - // a taken branch - output logic instr_fetch_err_o, // bus error on fetch - output logic instr_fetch_err_plus2_o, // bus error misaligned - output logic illegal_c_insn_id_o, // compressed decoder thinks this - // is an invalid instr - output logic dummy_instr_id_o, // Instruction is a dummy - output logic [31:0] pc_if_o, - output logic [31:0] pc_id_o, - input logic pmp_err_if_i, - input logic pmp_err_if_plus2_i, - - // control signals - input logic instr_valid_clear_i, // clear instr valid bit in IF-ID - input logic pc_set_i, // set the PC to a new value - input pc_sel_e pc_mux_i, // selector for PC multiplexer - input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was - // mispredicted (predicted taken) - input logic [31:0] nt_branch_addr_i, // Not-taken branch address in ID/EX - input exc_pc_sel_e exc_pc_mux_i, // selects ISR address - input exc_cause_e exc_cause, // selects ISR address for - // vectorized interrupt lines - input logic dummy_instr_en_i, - input logic [2:0] dummy_instr_mask_i, - input logic dummy_instr_seed_en_i, - input logic [31:0] dummy_instr_seed_i, - input logic icache_enable_i, - input logic icache_inval_i, - output logic icache_ecc_error_o, - - // jump and branch target - input logic [31:0] branch_target_ex_i, // branch/jump target address - - // CSRs - input logic [31:0] csr_mepc_i, // PC to restore after handling - // the interrupt/exception - input logic [31:0] csr_depc_i, // PC to restore after handling - // the debug request - input logic [31:0] csr_mtvec_i, // base PC to jump to on exception - output logic csr_mtvec_init_o, // tell CS regfile to init mtvec - - // pipeline stall - input logic id_in_ready_i, // ID stage is ready for new instr - - // misc signals - output logic pc_mismatch_alert_o, - output logic if_busy_o // IF stage is busy fetching instr -); - - logic instr_valid_id_d, instr_valid_id_q; - logic instr_new_id_d, instr_new_id_q; - - // prefetch buffer related signals - logic prefetch_busy; - logic branch_req; - logic [31:0] fetch_addr_n; - logic unused_fetch_addr_n0; - - logic fetch_valid; - logic fetch_ready; - logic [31:0] fetch_rdata; - logic [31:0] fetch_addr; - logic fetch_err; - logic fetch_err_plus2; - - logic [31:0] instr_decompressed; - logic illegal_c_insn; - logic instr_is_compressed; - - logic if_instr_valid; - logic [31:0] if_instr_rdata; - logic [31:0] if_instr_addr; - logic if_instr_bus_err; - logic if_instr_pmp_err; - logic if_instr_err; - logic if_instr_err_plus2; - - logic [31:0] exc_pc; - - logic [5:0] irq_id; - logic unused_irq_bit; - - logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable - - // Dummy instruction signals - logic stall_dummy_instr; - logic [31:0] instr_out; - logic instr_is_compressed_out; - logic illegal_c_instr_out; - logic instr_err_out; - - logic predict_branch_taken; - logic [31:0] predict_branch_pc; - - ibex_pkg::pc_sel_e pc_mux_internal; - - logic [7:0] unused_boot_addr; - logic [7:0] unused_csr_mtvec; - - assign unused_boot_addr = boot_addr_i[7:0]; - assign unused_csr_mtvec = csr_mtvec_i[7:0]; - - // extract interrupt ID from exception cause - assign irq_id = {exc_cause}; - assign unused_irq_bit = irq_id[5]; // MSB distinguishes interrupts from exceptions - - // exception PC selection mux - always_comb begin : exc_pc_mux - unique case (exc_pc_mux_i) - EXC_PC_EXC: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; - EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 }; - EXC_PC_DBD: exc_pc = DmHaltAddr; - EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr; - default: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; - endcase - end - - // The Branch predictor can provide a new PC which is internal to if_stage. Only override the mux - // select to choose this if the core isn't already trying to set a PC. - assign pc_mux_internal = - (BranchPredictor && predict_branch_taken && !pc_set_i) ? PC_BP : pc_mux_i; - - // fetch address selection mux - always_comb begin : fetch_addr_mux - unique case (pc_mux_internal) - PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h00 }; - PC_JUMP: fetch_addr_n = branch_target_ex_i; - PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler - PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC - PC_DRET: fetch_addr_n = csr_depc_i; - // Without branch predictor will never get pc_mux_internal == PC_BP. We still handle no branch - // predictor case here to ensure redundant mux logic isn't synthesised. - PC_BP: fetch_addr_n = BranchPredictor ? predict_branch_pc : { boot_addr_i[31:8], 8'h00 }; - default: fetch_addr_n = { boot_addr_i[31:8], 8'h00 }; - endcase - end - - // tell CS register file to initialize mtvec on boot - assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i; - - if (ICache) begin : gen_icache - // Full I-Cache option - ibex_icache #( - .ICacheECC (ICacheECC), - .ResetAll (ResetAll), - .BusSizeECC (BusSizeECC), - .TagSizeECC (TagSizeECC), - .LineSizeECC (LineSizeECC) - ) icache_i ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - - .req_i ( req_i ), - - .branch_i ( branch_req ), - .branch_mispredict_i ( nt_branch_mispredict_i ), - .mispredict_addr_i ( nt_branch_addr_i ), - .addr_i ( {fetch_addr_n[31:1], 1'b0} ), - - .ready_i ( fetch_ready ), - .valid_o ( fetch_valid ), - .rdata_o ( fetch_rdata ), - .addr_o ( fetch_addr ), - .err_o ( fetch_err ), - .err_plus2_o ( fetch_err_plus2 ), - - .instr_req_o ( instr_req_o ), - .instr_addr_o ( instr_addr_o ), - .instr_gnt_i ( instr_gnt_i ), - .instr_rvalid_i ( instr_rvalid_i ), - .instr_rdata_i ( instr_rdata_i ), - .instr_err_i ( instr_err_i ), - - .ic_tag_req_o ( ic_tag_req_o ), - .ic_tag_write_o ( ic_tag_write_o ), - .ic_tag_addr_o ( ic_tag_addr_o ), - .ic_tag_wdata_o ( ic_tag_wdata_o ), - .ic_tag_rdata_i ( ic_tag_rdata_i ), - .ic_data_req_o ( ic_data_req_o ), - .ic_data_write_o ( ic_data_write_o ), - .ic_data_addr_o ( ic_data_addr_o ), - .ic_data_wdata_o ( ic_data_wdata_o ), - .ic_data_rdata_i ( ic_data_rdata_i ), - .ic_scr_key_valid_i ( ic_scr_key_valid_i ), - - .icache_enable_i ( icache_enable_i ), - .icache_inval_i ( icache_inval_i ), - .busy_o ( prefetch_busy ), - .ecc_error_o ( icache_ecc_error_o ) - ); - end else begin : gen_prefetch_buffer - // prefetch buffer, caches a fixed number of instructions - ibex_prefetch_buffer #( - .ResetAll (ResetAll) - ) prefetch_buffer_i ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - - .req_i ( req_i ), - - .branch_i ( branch_req ), - .branch_mispredict_i ( nt_branch_mispredict_i ), - .mispredict_addr_i ( nt_branch_addr_i ), - .addr_i ( {fetch_addr_n[31:1], 1'b0} ), - - .ready_i ( fetch_ready ), - .valid_o ( fetch_valid ), - .rdata_o ( fetch_rdata ), - .addr_o ( fetch_addr ), - .err_o ( fetch_err ), - .err_plus2_o ( fetch_err_plus2 ), - - .instr_req_o ( instr_req_o ), - .instr_addr_o ( instr_addr_o ), - .instr_gnt_i ( instr_gnt_i ), - .instr_rvalid_i ( instr_rvalid_i ), - .instr_rdata_i ( instr_rdata_i ), - .instr_err_i ( instr_err_i ), - - .busy_o ( prefetch_busy ) - ); - // ICache tieoffs - logic unused_icen, unused_icinv, unused_scr_key_valid; - logic [TagSizeECC-1:0] unused_tag_ram_input [IC_NUM_WAYS]; - logic [LineSizeECC-1:0] unused_data_ram_input [IC_NUM_WAYS]; - assign unused_icen = icache_enable_i; - assign unused_icinv = icache_inval_i; - assign unused_tag_ram_input = ic_tag_rdata_i; - assign unused_data_ram_input = ic_data_rdata_i; - assign unused_scr_key_valid = ic_scr_key_valid_i; - assign ic_tag_req_o = 'b0; - assign ic_tag_write_o = 'b0; - assign ic_tag_addr_o = 'b0; - assign ic_tag_wdata_o = 'b0; - assign ic_data_req_o = 'b0; - assign ic_data_write_o = 'b0; - assign ic_data_addr_o = 'b0; - assign ic_data_wdata_o = 'b0; - assign icache_ecc_error_o = 'b0; - -`ifndef SYNTHESIS - // If we don't instantiate an icache and this is a simulation then we have a problem because the - // simulator might discard the icache module entirely, including some DPI exports that it - // implies. This then causes problems for linking against C++ testbench code that expected them. - // As a slightly ugly hack, let's define the DPI functions here (the real versions are defined - // in prim_util_get_scramble_params.svh) - export "DPI-C" function simutil_get_scramble_key; - export "DPI-C" function simutil_get_scramble_nonce; - function automatic int simutil_get_scramble_key(output bit [127:0] val); - return 0; - endfunction - function automatic int simutil_get_scramble_nonce(output bit [319:0] nonce); - return 0; - endfunction -`endif - end - - assign unused_fetch_addr_n0 = fetch_addr_n[0]; - - assign branch_req = pc_set_i | predict_branch_taken; - - assign pc_if_o = if_instr_addr; - assign if_busy_o = prefetch_busy; - - // PMP errors - // An error can come from the instruction address, or the next instruction address for unaligned, - // uncompressed instructions. - assign if_instr_pmp_err = pmp_err_if_i | - (if_instr_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i); - - // Combine bus errors and pmp errors - assign if_instr_err = if_instr_bus_err | if_instr_pmp_err; - - // Capture the second half of the address for errors on the second part of an instruction - assign if_instr_err_plus2 = ((if_instr_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i) | - fetch_err_plus2) & ~pmp_err_if_i; - - // compressed instruction decoding, or more precisely compressed instruction - // expander - // - // since it does not matter where we decompress instructions, we do it here - // to ease timing closure - ibex_compressed_decoder compressed_decoder_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .valid_i (fetch_valid & ~fetch_err), - .instr_i (if_instr_rdata), - .instr_o (instr_decompressed), - .is_compressed_o(instr_is_compressed), - .illegal_instr_o(illegal_c_insn) - ); - - // Dummy instruction insertion - if (DummyInstructions) begin : gen_dummy_instr - // SEC_CM: CTRL_FLOW.UNPREDICTABLE - logic insert_dummy_instr; - logic [31:0] dummy_instr_data; - - ibex_dummy_instr #( - .RndCnstLfsrSeed (RndCnstLfsrSeed), - .RndCnstLfsrPerm (RndCnstLfsrPerm) - ) dummy_instr_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .dummy_instr_en_i (dummy_instr_en_i), - .dummy_instr_mask_i (dummy_instr_mask_i), - .dummy_instr_seed_en_i(dummy_instr_seed_en_i), - .dummy_instr_seed_i (dummy_instr_seed_i), - .fetch_valid_i (fetch_valid), - .id_in_ready_i (id_in_ready_i), - .insert_dummy_instr_o (insert_dummy_instr), - .dummy_instr_data_o (dummy_instr_data) - ); - - // Mux between actual instructions and dummy instructions - assign instr_out = insert_dummy_instr ? dummy_instr_data : instr_decompressed; - assign instr_is_compressed_out = insert_dummy_instr ? 1'b0 : instr_is_compressed; - assign illegal_c_instr_out = insert_dummy_instr ? 1'b0 : illegal_c_insn; - assign instr_err_out = insert_dummy_instr ? 1'b0 : if_instr_err; - - // Stall the IF stage if we insert a dummy instruction. The dummy will execute between whatever - // is currently in the ID stage and whatever is valid from the prefetch buffer this cycle. The - // PC of the dummy instruction will match whatever is next from the prefetch buffer. - assign stall_dummy_instr = insert_dummy_instr; - - // Register the dummy instruction indication into the ID stage - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - dummy_instr_id_o <= 1'b0; - end else if (if_id_pipe_reg_we) begin - dummy_instr_id_o <= insert_dummy_instr; - end - end - - end else begin : gen_no_dummy_instr - logic unused_dummy_en; - logic [2:0] unused_dummy_mask; - logic unused_dummy_seed_en; - logic [31:0] unused_dummy_seed; - - assign unused_dummy_en = dummy_instr_en_i; - assign unused_dummy_mask = dummy_instr_mask_i; - assign unused_dummy_seed_en = dummy_instr_seed_en_i; - assign unused_dummy_seed = dummy_instr_seed_i; - assign instr_out = instr_decompressed; - assign instr_is_compressed_out = instr_is_compressed; - assign illegal_c_instr_out = illegal_c_insn; - assign instr_err_out = if_instr_err; - assign stall_dummy_instr = 1'b0; - assign dummy_instr_id_o = 1'b0; - end - - // The ID stage becomes valid as soon as any instruction is registered in the ID stage flops. - // Note that the current instruction is squashed by the incoming pc_set_i signal. - // Valid is held until it is explicitly cleared (due to an instruction completing or an exception) - assign instr_valid_id_d = (if_instr_valid & id_in_ready_i & ~pc_set_i) | - (instr_valid_id_q & ~instr_valid_clear_i); - assign instr_new_id_d = if_instr_valid & id_in_ready_i; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_valid_id_q <= 1'b0; - instr_new_id_q <= 1'b0; - end else begin - instr_valid_id_q <= instr_valid_id_d; - instr_new_id_q <= instr_new_id_d; - end - end - - assign instr_valid_id_o = instr_valid_id_q; - // Signal when a new instruction enters the ID stage (only used for RVFI signalling). - assign instr_new_id_o = instr_new_id_q; - - // IF-ID pipeline registers, frozen when the ID stage is stalled - assign if_id_pipe_reg_we = instr_new_id_d; - - if (ResetAll) begin : g_instr_rdata_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_rdata_id_o <= '0; - instr_rdata_alu_id_o <= '0; - instr_fetch_err_o <= '0; - instr_fetch_err_plus2_o <= '0; - instr_rdata_c_id_o <= '0; - instr_is_compressed_id_o <= '0; - illegal_c_insn_id_o <= '0; - pc_id_o <= '0; - end else if (if_id_pipe_reg_we) begin - instr_rdata_id_o <= instr_out; - // To reduce fan-out and help timing from the instr_rdata_id flops they are replicated. - instr_rdata_alu_id_o <= instr_out; - instr_fetch_err_o <= instr_err_out; - instr_fetch_err_plus2_o <= if_instr_err_plus2; - instr_rdata_c_id_o <= if_instr_rdata[15:0]; - instr_is_compressed_id_o <= instr_is_compressed_out; - illegal_c_insn_id_o <= illegal_c_instr_out; - pc_id_o <= pc_if_o; - end - end - end else begin : g_instr_rdata_nr - always_ff @(posedge clk_i) begin - if (if_id_pipe_reg_we) begin - instr_rdata_id_o <= instr_out; - // To reduce fan-out and help timing from the instr_rdata_id flops they are replicated. - instr_rdata_alu_id_o <= instr_out; - instr_fetch_err_o <= instr_err_out; - instr_fetch_err_plus2_o <= if_instr_err_plus2; - instr_rdata_c_id_o <= if_instr_rdata[15:0]; - instr_is_compressed_id_o <= instr_is_compressed_out; - illegal_c_insn_id_o <= illegal_c_instr_out; - pc_id_o <= pc_if_o; - end - end - end - - // Check for expected increments of the PC when security hardening enabled - if (PCIncrCheck) begin : g_secure_pc - // SEC_CM: PC.CTRL_FLOW.CONSISTENCY - logic [31:0] prev_instr_addr_incr, prev_instr_addr_incr_buf; - logic prev_instr_seq_q, prev_instr_seq_d; - - // Do not check for sequential increase after a branch, jump, exception, interrupt or debug - // request, all of which will set branch_req. Also do not check after reset or for dummys. - assign prev_instr_seq_d = (prev_instr_seq_q | instr_new_id_d) & - ~branch_req & ~if_instr_err & ~stall_dummy_instr; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - prev_instr_seq_q <= 1'b0; - end else begin - prev_instr_seq_q <= prev_instr_seq_d; - end - end - - assign prev_instr_addr_incr = pc_id_o + (instr_is_compressed_id_o ? 32'd2 : 32'd4); - - // Buffer anticipated next PC address to ensure optimiser cannot remove the check. - prim_buf #(.Width(32)) u_prev_instr_addr_incr_buf ( - .in_i (prev_instr_addr_incr), - .out_o(prev_instr_addr_incr_buf) - ); - - // Check that the address equals the previous address +2/+4 - assign pc_mismatch_alert_o = prev_instr_seq_q & (pc_if_o != prev_instr_addr_incr_buf); - - end else begin : g_no_secure_pc - assign pc_mismatch_alert_o = 1'b0; - end - - if (BranchPredictor) begin : g_branch_predictor - logic [31:0] instr_skid_data_q; - logic [31:0] instr_skid_addr_q; - logic instr_skid_bp_taken_q; - logic instr_skid_valid_q, instr_skid_valid_d; - logic instr_skid_en; - logic instr_bp_taken_q, instr_bp_taken_d; - - logic predict_branch_taken_raw; - - // ID stages needs to know if branch was predicted taken so it can signal mispredicts - if (ResetAll) begin : g_bp_taken_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_bp_taken_q <= '0; - end else if (if_id_pipe_reg_we) begin - instr_bp_taken_q <= instr_bp_taken_d; - end - end - end else begin : g_bp_taken_nr - always_ff @(posedge clk_i) begin - if (if_id_pipe_reg_we) begin - instr_bp_taken_q <= instr_bp_taken_d; - end - end - end - - // When branch prediction is enabled a skid buffer between the IF and ID/EX stage is introduced. - // If an instruction in IF is predicted to be a taken branch and ID/EX is not ready the - // instruction in IF is moved to the skid buffer which becomes the output of the IF stage until - // the ID/EX stage accepts the instruction. The skid buffer is required as otherwise the ID/EX - // ready signal is coupled to the instr_req_o output which produces a feedthrough path from - // data_gnt_i -> instr_req_o (which needs to be avoided as for some interconnects this will - // result in a combinational loop). - - assign instr_skid_en = predict_branch_taken & ~pc_set_i & ~id_in_ready_i & ~instr_skid_valid_q; - - assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i & ~stall_dummy_instr) | - instr_skid_en; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_skid_valid_q <= 1'b0; - end else begin - instr_skid_valid_q <= instr_skid_valid_d; - end - end - - if (ResetAll) begin : g_instr_skid_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_skid_bp_taken_q <= '0; - instr_skid_data_q <= '0; - instr_skid_addr_q <= '0; - end else if (instr_skid_en) begin - instr_skid_bp_taken_q <= predict_branch_taken; - instr_skid_data_q <= fetch_rdata; - instr_skid_addr_q <= fetch_addr; - end - end - end else begin : g_instr_skid_nr - always_ff @(posedge clk_i) begin - if (instr_skid_en) begin - instr_skid_bp_taken_q <= predict_branch_taken; - instr_skid_data_q <= fetch_rdata; - instr_skid_addr_q <= fetch_addr; - end - end - end - - ibex_branch_predict branch_predict_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .fetch_rdata_i(fetch_rdata), - .fetch_pc_i (fetch_addr), - .fetch_valid_i(fetch_valid), - - .predict_branch_taken_o(predict_branch_taken_raw), - .predict_branch_pc_o (predict_branch_pc) - ); - - // If there is an instruction in the skid buffer there must be no branch prediction. - // Instructions are only placed in the skid after they have been predicted to be a taken branch - // so with the skid valid any prediction has already occurred. - // Do not branch predict on instruction errors. - assign predict_branch_taken = predict_branch_taken_raw & ~instr_skid_valid_q & ~fetch_err; - - assign if_instr_valid = fetch_valid | (instr_skid_valid_q & ~nt_branch_mispredict_i); - assign if_instr_rdata = instr_skid_valid_q ? instr_skid_data_q : fetch_rdata; - assign if_instr_addr = instr_skid_valid_q ? instr_skid_addr_q : fetch_addr; - - // Don't branch predict on instruction error so only instructions without errors end up in the - // skid buffer. - assign if_instr_bus_err = ~instr_skid_valid_q & fetch_err; - assign instr_bp_taken_d = instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken; - - assign fetch_ready = id_in_ready_i & ~stall_dummy_instr & ~instr_skid_valid_q; - - assign instr_bp_taken_o = instr_bp_taken_q; - - `ASSERT(NoPredictSkid, instr_skid_valid_q |-> ~predict_branch_taken) - `ASSERT(NoPredictIllegal, predict_branch_taken |-> ~illegal_c_insn) - end else begin : g_no_branch_predictor - assign instr_bp_taken_o = 1'b0; - assign predict_branch_taken = 1'b0; - assign predict_branch_pc = 32'b0; - - assign if_instr_valid = fetch_valid; - assign if_instr_rdata = fetch_rdata; - assign if_instr_addr = fetch_addr; - assign if_instr_bus_err = fetch_err; - assign fetch_ready = id_in_ready_i & ~stall_dummy_instr; - end - - //////////////// - // Assertions // - //////////////// - - // Selectors must be known/valid. - `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i) - - if (BranchPredictor) begin : g_branch_predictor_asserts - `ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside { - PC_BOOT, - PC_JUMP, - PC_EXC, - PC_ERET, - PC_DRET, - PC_BP}, - pc_set_i) - -`ifdef INC_ASSERT - /** - * Checks for branch prediction interface to fetch_fifo/icache - * - * The interface has two signals: - * - predicted_branch_i: When set with a branch (branch_i) indicates the branch is a predicted - * one, it should be ignored when a branch_i isn't set. - * - branch_mispredict_i: Indicates the previously predicted branch was mis-predicted and - * execution should resume with the not-taken side of the branch (i.e. continue with the PC - * that followed the predicted branch). This must be raised before the instruction that is - * made available following a predicted branch is accepted (Following a cycle with branch_i - * & predicted_branch_i, branch_mispredict_i can only be asserted before or on the same cycle - * as seeing fetch_valid & fetch_ready). When branch_mispredict_i is asserted, fetch_valid may - * be asserted in response. If fetch_valid is asserted on the same cycle as - * branch_mispredict_i this indicates the fetch_fifo/icache has the not-taken side of the - * branch immediately ready for use - */ - logic predicted_branch_live_q, predicted_branch_live_d; - logic [31:0] predicted_branch_nt_pc_q, predicted_branch_nt_pc_d; - logic [31:0] awaiting_instr_after_mispredict_q, awaiting_instr_after_mispredict_d; - logic [31:0] next_pc; - - logic mispredicted, mispredicted_d, mispredicted_q; - - assign next_pc = fetch_addr + (instr_is_compressed_out ? 32'd2 : 32'd4); - - logic predicted_branch; - - // pc_set_i takes precendence over branch prediction - assign predicted_branch = predict_branch_taken & ~pc_set_i; - - always_comb begin - predicted_branch_live_d = predicted_branch_live_q; - mispredicted_d = mispredicted_q; - - if (branch_req & predicted_branch) begin - predicted_branch_live_d = 1'b1; - mispredicted_d = 1'b0; - end else if (predicted_branch_live_q) begin - if (fetch_valid & fetch_ready) begin - predicted_branch_live_d = 1'b0; - end else if (nt_branch_mispredict_i) begin - mispredicted_d = 1'b1; - end - end - end - - always @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - predicted_branch_live_q <= 1'b0; - mispredicted_q <= 1'b0; - end else begin - predicted_branch_live_q <= predicted_branch_live_d; - mispredicted_q <= mispredicted_d; - end - end - - always @(posedge clk_i) begin - if (branch_req & predicted_branch) begin - predicted_branch_nt_pc_q <= next_pc; - end - end - - // Must only see mispredict after we've performed a predicted branch but before we've accepted - // any instruction (with fetch_ready & fetch_valid) that follows that predicted branch. - `ASSERT(MispredictOnlyImmediatelyAfterPredictedBranch, - nt_branch_mispredict_i |-> predicted_branch_live_q) - // Check that on mispredict we get the correct PC for the non-taken side of the branch when - // prefetch buffer/icache makes that PC available. - `ASSERT(CorrectPCOnMispredict, - predicted_branch_live_q & mispredicted_d & fetch_valid |-> - fetch_addr == predicted_branch_nt_pc_q) - // Must not signal mispredict over multiple cycles but it's possible to have back to back - // mispredicts for different branches (core signals mispredict, prefetch buffer/icache immediate - // has not-taken side of the mispredicted branch ready, which itself is a predicted branch, - // following cycle core signal that that branch has mispredicted). - `ASSERT(MispredictSingleCycle, - nt_branch_mispredict_i & ~(fetch_valid & fetch_ready) |=> ~nt_branch_mispredict_i) - // Note that we should never see a mispredict and an incoming branch on the same cycle. - // The mispredict also cancels any predicted branch so overall branch_req must be low. - `ASSERT(NoMispredBranch, nt_branch_mispredict_i |-> ~branch_req) -`endif - - end else begin : g_no_branch_predictor_asserts - `ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside { - PC_BOOT, - PC_JUMP, - PC_EXC, - PC_ERET, - PC_DRET}, - pc_set_i) - end - - // Boot address must be aligned to 256 bytes. - `ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00) - - // Address must not contain X when request is sent. - `ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o)) - - // Address must be word aligned when request is sent. - `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00)) - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_lockstep.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_lockstep.sv deleted file mode 100644 index 4f986d0c..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_lockstep.sv +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Ibex lockstep module -// This module instantiates a second copy of the core logic, and compares it's outputs against -// those from the main core. The second core runs synchronously with the main core, delayed by -// LockstepOffset cycles. - -// SEC_CM: LOGIC.SHADOW -module ibex_lockstep import ibex_pkg::*; #( - parameter int unsigned LockstepOffset = 2, - parameter bit PMPEnable = 1'b0, - parameter int unsigned PMPGranularity = 0, - parameter int unsigned PMPNumRegions = 4, - parameter int unsigned MHPMCounterNum = 0, - parameter int unsigned MHPMCounterWidth = 40, - parameter bit RV32E = 1'b0, - parameter rv32m_e RV32M = RV32MFast, - parameter rv32b_e RV32B = RV32BNone, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter int unsigned BusSizeECC = BUS_SIZE, - parameter int unsigned TagSizeECC = IC_TAG_SIZE, - parameter int unsigned LineSizeECC = IC_LINE_SIZE, - parameter bit BranchPredictor = 1'b0, - parameter bit DbgTriggerEn = 1'b0, - parameter int unsigned DbgHwBreakNum = 1, - parameter bit ResetAll = 1'b0, - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, - parameter bit SecureIbex = 1'b0, - parameter bit DummyInstructions = 1'b0, - parameter bit RegFileECC = 1'b0, - parameter int unsigned RegFileDataWidth = 32, - parameter int unsigned DmHaltAddr = 32'h1A110800, - parameter int unsigned DmExceptionAddr = 32'h1A110808 -) ( - input logic clk_i, - input logic rst_ni, - - input logic [31:0] hart_id_i, - input logic [31:0] boot_addr_i, - - input logic instr_req_i, - input logic instr_gnt_i, - input logic instr_rvalid_i, - input logic [31:0] instr_addr_i, - input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, - input logic instr_err_i, - - input logic data_req_i, - input logic data_gnt_i, - input logic data_rvalid_i, - input logic data_we_i, - input logic [3:0] data_be_i, - input logic [31:0] data_addr_i, - input logic [31:0] data_wdata_i, - output logic [6:0] data_wdata_intg_o, - input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, - input logic data_err_i, - - input logic dummy_instr_id_i, - input logic [4:0] rf_raddr_a_i, - input logic [4:0] rf_raddr_b_i, - input logic [4:0] rf_waddr_wb_i, - input logic rf_we_wb_i, - input logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_i, - input logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_i, - input logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_i, - - input logic [IC_NUM_WAYS-1:0] ic_tag_req_i, - input logic ic_tag_write_i, - input logic [IC_INDEX_W-1:0] ic_tag_addr_i, - input logic [TagSizeECC-1:0] ic_tag_wdata_i, - input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS], - input logic [IC_NUM_WAYS-1:0] ic_data_req_i, - input logic ic_data_write_i, - input logic [IC_INDEX_W-1:0] ic_data_addr_i, - input logic [LineSizeECC-1:0] ic_data_wdata_i, - input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS], - input logic ic_scr_key_valid_i, - - input logic irq_software_i, - input logic irq_timer_i, - input logic irq_external_i, - input logic [14:0] irq_fast_i, - input logic irq_nm_i, - input logic irq_pending_i, - - input logic debug_req_i, - input crash_dump_t crash_dump_i, - input logic double_fault_seen_i, - - input fetch_enable_t fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, - input logic icache_inval_i, - input logic core_busy_i, - input logic test_en_i, - input logic scan_rst_ni -); - - localparam int unsigned LockstepOffsetW = $clog2(LockstepOffset); - // Core outputs are delayed for an extra cycle due to shadow output registers - localparam int unsigned OutputsOffset = LockstepOffset + 1; - - ////////////////////// - // Reset generation // - ////////////////////// - - // Upon reset, the comparison is stopped and the shadow core is reset, both immediately. A - // counter is started. After LockstepOffset clock cycles: - // - The counter is stopped. - // - The reset of the shadow core is synchronously released. - // The comparison is started in the following clock cycle. - - logic [LockstepOffsetW-1:0] rst_shadow_cnt_d, rst_shadow_cnt_q, rst_shadow_cnt_incr; - // Internally generated resets cause IMPERFECTSCH warnings - /* verilator lint_off IMPERFECTSCH */ - logic rst_shadow_set_d, rst_shadow_set_q; - logic rst_shadow_n, enable_cmp_q; - /* verilator lint_on IMPERFECTSCH */ - - assign rst_shadow_cnt_incr = rst_shadow_cnt_q + LockstepOffsetW'(1); - - assign rst_shadow_set_d = (rst_shadow_cnt_q == LockstepOffsetW'(LockstepOffset - 1)); - assign rst_shadow_cnt_d = rst_shadow_set_d ? rst_shadow_cnt_q : rst_shadow_cnt_incr; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rst_shadow_cnt_q <= '0; - enable_cmp_q <= '0; - end else begin - rst_shadow_cnt_q <= rst_shadow_cnt_d; - enable_cmp_q <= rst_shadow_set_q; - end - end - - // The primitives below are used to place size-only constraints in order to prevent - // synthesis optimizations and preserve anchor points for constraining backend tools. - prim_flop #( - .Width(1), - .ResetValue(1'b0) - ) u_prim_rst_shadow_set_flop ( - .clk_i (clk_i), - .rst_ni(rst_ni), - .d_i (rst_shadow_set_d), - .q_o (rst_shadow_set_q) - ); - - prim_clock_mux2 #( - .NoFpgaBufG(1'b1) - ) u_prim_rst_shadow_n_mux2 ( - .clk0_i(rst_shadow_set_q), - .clk1_i(scan_rst_ni), - .sel_i (test_en_i), - .clk_o (rst_shadow_n) - ); - - ////////////////// - // Input delays // - ////////////////// - - typedef struct packed { - logic instr_gnt; - logic instr_rvalid; - logic [31:0] instr_rdata; - logic instr_err; - logic data_gnt; - logic data_rvalid; - logic [31:0] data_rdata; - logic data_err; - logic [RegFileDataWidth-1:0] rf_rdata_a_ecc; - logic [RegFileDataWidth-1:0] rf_rdata_b_ecc; - logic irq_software; - logic irq_timer; - logic irq_external; - logic [14:0] irq_fast; - logic irq_nm; - logic debug_req; - fetch_enable_t fetch_enable; - logic ic_scr_key_valid; - } delayed_inputs_t; - - delayed_inputs_t [LockstepOffset-1:0] shadow_inputs_q; - delayed_inputs_t shadow_inputs_in; - logic [6:0] instr_rdata_intg_q, data_rdata_intg_q; - // Packed arrays must be dealt with separately - logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS][LockstepOffset]; - logic [LineSizeECC-1:0] shadow_data_rdata_q [IC_NUM_WAYS][LockstepOffset]; - - // Assign the inputs to the delay structure - assign shadow_inputs_in.instr_gnt = instr_gnt_i; - assign shadow_inputs_in.instr_rvalid = instr_rvalid_i; - assign shadow_inputs_in.instr_rdata = instr_rdata_i; - assign shadow_inputs_in.instr_err = instr_err_i; - assign shadow_inputs_in.data_gnt = data_gnt_i; - assign shadow_inputs_in.data_rvalid = data_rvalid_i; - assign shadow_inputs_in.data_rdata = data_rdata_i; - assign shadow_inputs_in.data_err = data_err_i; - assign shadow_inputs_in.rf_rdata_a_ecc = rf_rdata_a_ecc_i; - assign shadow_inputs_in.rf_rdata_b_ecc = rf_rdata_b_ecc_i; - assign shadow_inputs_in.irq_software = irq_software_i; - assign shadow_inputs_in.irq_timer = irq_timer_i; - assign shadow_inputs_in.irq_external = irq_external_i; - assign shadow_inputs_in.irq_fast = irq_fast_i; - assign shadow_inputs_in.irq_nm = irq_nm_i; - assign shadow_inputs_in.debug_req = debug_req_i; - assign shadow_inputs_in.fetch_enable = fetch_enable_i; - assign shadow_inputs_in.ic_scr_key_valid = ic_scr_key_valid_i; - - // Delay the inputs - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - instr_rdata_intg_q <= '0; - data_rdata_intg_q <= '0; - for (int unsigned i = 0; i < LockstepOffset; i++) begin - shadow_inputs_q[i] <= delayed_inputs_t'('0); - shadow_tag_rdata_q[i] <= '{default: 0}; - shadow_data_rdata_q[i] <= '{default: 0}; - end - end else begin - instr_rdata_intg_q <= instr_rdata_intg_i; - data_rdata_intg_q <= data_rdata_intg_i; - for (int unsigned i = 0; i < LockstepOffset - 1; i++) begin - shadow_inputs_q[i] <= shadow_inputs_q[i+1]; - shadow_tag_rdata_q[i] <= shadow_tag_rdata_q[i+1]; - shadow_data_rdata_q[i] <= shadow_data_rdata_q[i+1]; - end - shadow_inputs_q[LockstepOffset-1] <= shadow_inputs_in; - shadow_tag_rdata_q[LockstepOffset-1] <= ic_tag_rdata_i; - shadow_data_rdata_q[LockstepOffset-1] <= ic_data_rdata_i; - end - end - - //////////////////////////// - // Bus integrity checking // - //////////////////////////// - - // SEC_CM: BUS.INTEGRITY - logic bus_intg_err; - logic [1:0] instr_intg_err, data_intg_err; - logic [31:0] unused_wdata; - - // Checks on incoming data - prim_secded_inv_39_32_dec u_instr_intg_dec ( - .data_i ({instr_rdata_intg_q, shadow_inputs_q[LockstepOffset-1].instr_rdata}), - .data_o (), - .syndrome_o (), - .err_o (instr_intg_err) - ); - - prim_secded_inv_39_32_dec u_data_intg_dec ( - .data_i ({data_rdata_intg_q, shadow_inputs_q[LockstepOffset-1].data_rdata}), - .data_o (), - .syndrome_o (), - .err_o (data_intg_err) - ); - - assign bus_intg_err = (shadow_inputs_q[LockstepOffset-1].instr_rvalid & |instr_intg_err) | - (shadow_inputs_q[LockstepOffset-1].data_rvalid & |data_intg_err); - - // Generate integrity bits - prim_secded_inv_39_32_enc u_data_gen ( - .data_i (data_wdata_i), - .data_o ({data_wdata_intg_o, unused_wdata}) - ); - - /////////////////// - // Output delays // - /////////////////// - - typedef struct packed { - logic instr_req; - logic [31:0] instr_addr; - logic data_req; - logic data_we; - logic [3:0] data_be; - logic [31:0] data_addr; - logic [31:0] data_wdata; - logic dummy_instr_id; - logic [4:0] rf_raddr_a; - logic [4:0] rf_raddr_b; - logic [4:0] rf_waddr_wb; - logic rf_we_wb; - logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc; - logic [IC_NUM_WAYS-1:0] ic_tag_req; - logic ic_tag_write; - logic [IC_INDEX_W-1:0] ic_tag_addr; - logic [TagSizeECC-1:0] ic_tag_wdata; - logic [IC_NUM_WAYS-1:0] ic_data_req; - logic ic_data_write; - logic [IC_INDEX_W-1:0] ic_data_addr; - logic [LineSizeECC-1:0] ic_data_wdata; - logic irq_pending; - crash_dump_t crash_dump; - logic double_fault_seen; - logic icache_inval; - logic core_busy; - } delayed_outputs_t; - - delayed_outputs_t [OutputsOffset-1:0] core_outputs_q; - delayed_outputs_t core_outputs_in; - delayed_outputs_t shadow_outputs_d, shadow_outputs_q; - - // Assign core outputs to the structure - assign core_outputs_in.instr_req = instr_req_i; - assign core_outputs_in.instr_addr = instr_addr_i; - assign core_outputs_in.data_req = data_req_i; - assign core_outputs_in.data_we = data_we_i; - assign core_outputs_in.data_be = data_be_i; - assign core_outputs_in.data_addr = data_addr_i; - assign core_outputs_in.data_wdata = data_wdata_i; - assign core_outputs_in.dummy_instr_id = dummy_instr_id_i; - assign core_outputs_in.rf_raddr_a = rf_raddr_a_i; - assign core_outputs_in.rf_raddr_b = rf_raddr_b_i; - assign core_outputs_in.rf_waddr_wb = rf_waddr_wb_i; - assign core_outputs_in.rf_we_wb = rf_we_wb_i; - assign core_outputs_in.rf_wdata_wb_ecc = rf_wdata_wb_ecc_i; - assign core_outputs_in.ic_tag_req = ic_tag_req_i; - assign core_outputs_in.ic_tag_write = ic_tag_write_i; - assign core_outputs_in.ic_tag_addr = ic_tag_addr_i; - assign core_outputs_in.ic_tag_wdata = ic_tag_wdata_i; - assign core_outputs_in.ic_data_req = ic_data_req_i; - assign core_outputs_in.ic_data_write = ic_data_write_i; - assign core_outputs_in.ic_data_addr = ic_data_addr_i; - assign core_outputs_in.ic_data_wdata = ic_data_wdata_i; - assign core_outputs_in.irq_pending = irq_pending_i; - assign core_outputs_in.crash_dump = crash_dump_i; - assign core_outputs_in.double_fault_seen = double_fault_seen_i; - assign core_outputs_in.icache_inval = icache_inval_i; - assign core_outputs_in.core_busy = core_busy_i; - - // Delay the outputs - always_ff @(posedge clk_i) begin - for (int unsigned i = 0; i < OutputsOffset - 1; i++) begin - core_outputs_q[i] <= core_outputs_q[i+1]; - end - core_outputs_q[OutputsOffset-1] <= core_outputs_in; - end - - /////////////////////////////// - // Shadow core instantiation // - /////////////////////////////// - - logic shadow_alert_minor, shadow_alert_major; - - ibex_core #( - .PMPEnable ( PMPEnable ), - .PMPGranularity ( PMPGranularity ), - .PMPNumRegions ( PMPNumRegions ), - .MHPMCounterNum ( MHPMCounterNum ), - .MHPMCounterWidth ( MHPMCounterWidth ), - .RV32E ( RV32E ), - .RV32M ( RV32M ), - .RV32B ( RV32B ), - .BranchTargetALU ( BranchTargetALU ), - .ICache ( ICache ), - .ICacheECC ( ICacheECC ), - .BusSizeECC ( BusSizeECC ), - .TagSizeECC ( TagSizeECC ), - .LineSizeECC ( LineSizeECC ), - .BranchPredictor ( BranchPredictor ), - .DbgTriggerEn ( DbgTriggerEn ), - .DbgHwBreakNum ( DbgHwBreakNum ), - .WritebackStage ( WritebackStage ), - .ResetAll ( ResetAll ), - .RndCnstLfsrSeed ( RndCnstLfsrSeed ), - .RndCnstLfsrPerm ( RndCnstLfsrPerm ), - .SecureIbex ( SecureIbex ), - .DummyInstructions ( DummyInstructions ), - .RegFileECC ( RegFileECC ), - .RegFileDataWidth ( RegFileDataWidth ), - .DmHaltAddr ( DmHaltAddr ), - .DmExceptionAddr ( DmExceptionAddr ) - ) u_shadow_core ( - .clk_i (clk_i), - .rst_ni (rst_shadow_n), - - .hart_id_i (hart_id_i), - .boot_addr_i (boot_addr_i), - - .instr_req_o (shadow_outputs_d.instr_req), - .instr_gnt_i (shadow_inputs_q[0].instr_gnt), - .instr_rvalid_i (shadow_inputs_q[0].instr_rvalid), - .instr_addr_o (shadow_outputs_d.instr_addr), - .instr_rdata_i (shadow_inputs_q[0].instr_rdata), - .instr_err_i (shadow_inputs_q[0].instr_err), - - .data_req_o (shadow_outputs_d.data_req), - .data_gnt_i (shadow_inputs_q[0].data_gnt), - .data_rvalid_i (shadow_inputs_q[0].data_rvalid), - .data_we_o (shadow_outputs_d.data_we), - .data_be_o (shadow_outputs_d.data_be), - .data_addr_o (shadow_outputs_d.data_addr), - .data_wdata_o (shadow_outputs_d.data_wdata), - .data_rdata_i (shadow_inputs_q[0].data_rdata), - .data_err_i (shadow_inputs_q[0].data_err), - - .dummy_instr_id_o (shadow_outputs_d.dummy_instr_id), - .rf_raddr_a_o (shadow_outputs_d.rf_raddr_a), - .rf_raddr_b_o (shadow_outputs_d.rf_raddr_b), - .rf_waddr_wb_o (shadow_outputs_d.rf_waddr_wb), - .rf_we_wb_o (shadow_outputs_d.rf_we_wb), - .rf_wdata_wb_ecc_o (shadow_outputs_d.rf_wdata_wb_ecc), - .rf_rdata_a_ecc_i (shadow_inputs_q[0].rf_rdata_a_ecc), - .rf_rdata_b_ecc_i (shadow_inputs_q[0].rf_rdata_b_ecc), - - .ic_tag_req_o (shadow_outputs_d.ic_tag_req), - .ic_tag_write_o (shadow_outputs_d.ic_tag_write), - .ic_tag_addr_o (shadow_outputs_d.ic_tag_addr), - .ic_tag_wdata_o (shadow_outputs_d.ic_tag_wdata), - .ic_tag_rdata_i (shadow_tag_rdata_q[0]), - .ic_data_req_o (shadow_outputs_d.ic_data_req), - .ic_data_write_o (shadow_outputs_d.ic_data_write), - .ic_data_addr_o (shadow_outputs_d.ic_data_addr), - .ic_data_wdata_o (shadow_outputs_d.ic_data_wdata), - .ic_data_rdata_i (shadow_data_rdata_q[0]), - .ic_scr_key_valid_i (shadow_inputs_q[0].ic_scr_key_valid), - - .irq_software_i (shadow_inputs_q[0].irq_software), - .irq_timer_i (shadow_inputs_q[0].irq_timer), - .irq_external_i (shadow_inputs_q[0].irq_external), - .irq_fast_i (shadow_inputs_q[0].irq_fast), - .irq_nm_i (shadow_inputs_q[0].irq_nm), - .irq_pending_o (shadow_outputs_d.irq_pending), - - .debug_req_i (shadow_inputs_q[0].debug_req), - .crash_dump_o (shadow_outputs_d.crash_dump), - .double_fault_seen_o (shadow_outputs_d.double_fault_seen), - -`ifdef RVFI - .rvfi_valid (), - .rvfi_order (), - .rvfi_insn (), - .rvfi_trap (), - .rvfi_halt (), - .rvfi_intr (), - .rvfi_mode (), - .rvfi_ixl (), - .rvfi_rs1_addr (), - .rvfi_rs2_addr (), - .rvfi_rs3_addr (), - .rvfi_rs1_rdata (), - .rvfi_rs2_rdata (), - .rvfi_rs3_rdata (), - .rvfi_rd_addr (), - .rvfi_rd_wdata (), - .rvfi_pc_rdata (), - .rvfi_pc_wdata (), - .rvfi_mem_addr (), - .rvfi_mem_rmask (), - .rvfi_mem_wmask (), - .rvfi_mem_rdata (), - .rvfi_mem_wdata (), - .rvfi_ext_mip (), - .rvfi_ext_nmi (), - .rvfi_ext_debug_req (), - .rvfi_ext_mcycle (), -`endif - - .fetch_enable_i (shadow_inputs_q[0].fetch_enable), - .alert_minor_o (shadow_alert_minor), - .alert_major_o (shadow_alert_major), - .icache_inval_o (shadow_outputs_d.icache_inval), - .core_busy_o (shadow_outputs_d.core_busy) - ); - - // Register the shadow core outputs - always_ff @(posedge clk_i) begin - shadow_outputs_q <= shadow_outputs_d; - end - - ///////////////////////// - // Compare the outputs // - ///////////////////////// - - logic outputs_mismatch; - - assign outputs_mismatch = enable_cmp_q & (shadow_outputs_q != core_outputs_q[0]); - assign alert_major_internal_o = outputs_mismatch | shadow_alert_major; - assign alert_major_bus_o = bus_intg_err; - assign alert_minor_o = shadow_alert_minor; - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_fpga.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_fpga.sv deleted file mode 100644 index 678549ab..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_fpga.sv +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * RISC-V register file - * - * Register file with 31 or 15x 32 bit wide registers. Register 0 is fixed to 0. - * - * This register file is designed to make FPGA synthesis tools infer RAM primitives. For Xilinx - * FPGA architectures, it will produce RAM32M primitives. Other vendors have not yet been tested. - */ -module ibex_register_file_fpga #( - parameter bit RV32E = 0, - parameter int unsigned DataWidth = 32, - parameter bit DummyInstructions = 0, - parameter logic [DataWidth-1:0] WordZeroVal = '0 -) ( - // Clock and Reset - input logic clk_i, - input logic rst_ni, - - input logic test_en_i, - input logic dummy_instr_id_i, - - //Read port R1 - input logic [ 4:0] raddr_a_i, - output logic [DataWidth-1:0] rdata_a_o, - //Read port R2 - input logic [ 4:0] raddr_b_i, - output logic [DataWidth-1:0] rdata_b_o, - // Write port W1 - input logic [ 4:0] waddr_a_i, - input logic [DataWidth-1:0] wdata_a_i, - input logic we_a_i -); - - localparam int ADDR_WIDTH = RV32E ? 4 : 5; - localparam int NUM_WORDS = 2 ** ADDR_WIDTH; - - logic [DataWidth-1:0] mem[NUM_WORDS]; - logic we; // write enable if writing to any register other than R0 - - // async_read a - assign rdata_a_o = (raddr_a_i == '0) ? '0 : mem[raddr_a_i]; - - // async_read b - assign rdata_b_o = (raddr_b_i == '0) ? '0 : mem[raddr_b_i]; - - // we select - assign we = (waddr_a_i == '0) ? 1'b0 : we_a_i; - - // Note that the SystemVerilog LRM requires variables on the LHS of assignments within - // "always_ff" to not be written to by any other process. However, to enable the initialization - // of the inferred RAM32M primitives with non-zero values, below "initial" procedure is needed. - // Therefore, we use "always" instead of the generally preferred "always_ff" for the synchronous - // write procedure. - always @(posedge clk_i) begin : sync_write - if (we == 1'b1) begin - mem[waddr_a_i] <= wdata_a_i; - end - end : sync_write - - // Make sure we initialize the BRAM with the correct register reset value. - initial begin - for (int k = 0; k < NUM_WORDS; k++) begin - mem[k] = WordZeroVal; - end - end - - // Reset not used in this register file version - logic unused_rst_ni; - assign unused_rst_ni = rst_ni; - - // Dummy instruction changes not relevant for FPGA implementation - logic unused_dummy_instr; - assign unused_dummy_instr = dummy_instr_id_i; - // Test enable signal not used in FPGA implementation - logic unused_test_en; - assign unused_test_en = test_en_i; - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_latch.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_latch.sv deleted file mode 100644 index f1e4df75..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_register_file_latch.sv +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * RISC-V register file - * - * Register file with 31 or 15x 32 bit wide registers. Register 0 is fixed to 0. - * This register file is based on latches and is thus smaller than the flip-flop - * based RF. It requires a target technology-specific clock gating cell. Use this - * register file when targeting ASIC synthesis or event-based simulators. - */ -module ibex_register_file_latch #( - parameter bit RV32E = 0, - parameter int unsigned DataWidth = 32, - parameter bit DummyInstructions = 0, - parameter logic [DataWidth-1:0] WordZeroVal = '0 -) ( - // Clock and Reset - input logic clk_i, - input logic rst_ni, - - input logic test_en_i, - input logic dummy_instr_id_i, - - //Read port R1 - input logic [4:0] raddr_a_i, - output logic [DataWidth-1:0] rdata_a_o, - - //Read port R2 - input logic [4:0] raddr_b_i, - output logic [DataWidth-1:0] rdata_b_o, - - // Write port W1 - input logic [4:0] waddr_a_i, - input logic [DataWidth-1:0] wdata_a_i, - input logic we_a_i - -); - - localparam int unsigned ADDR_WIDTH = RV32E ? 4 : 5; - localparam int unsigned NUM_WORDS = 2**ADDR_WIDTH; - - logic [DataWidth-1:0] mem[NUM_WORDS]; - - logic [NUM_WORDS-1:1] waddr_onehot_a; - - logic [NUM_WORDS-1:1] mem_clocks; - logic [DataWidth-1:0] wdata_a_q; - - // internal addresses - logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int; - - assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0]; - assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0]; - assign waddr_a_int = waddr_a_i[ADDR_WIDTH-1:0]; - - logic clk_int; - - ////////// - // READ // - ////////// - assign rdata_a_o = mem[raddr_a_int]; - assign rdata_b_o = mem[raddr_b_int]; - - /////////// - // WRITE // - /////////// - // Global clock gating - prim_clock_gating cg_we_global ( - .clk_i ( clk_i ), - .en_i ( we_a_i ), - .test_en_i ( test_en_i ), - .clk_o ( clk_int ) - ); - - // Sample input data - // Use clk_int here, since otherwise we don't want to write anything anyway. - always_ff @(posedge clk_int or negedge rst_ni) begin : sample_wdata - if (!rst_ni) begin - wdata_a_q <= WordZeroVal; - end else begin - if (we_a_i) begin - wdata_a_q <= wdata_a_i; - end - end - end - - // Write address decoding - always_comb begin : wad - for (int i = 1; i < NUM_WORDS; i++) begin : wad_word_iter - if (we_a_i && (waddr_a_int == 5'(i))) begin - waddr_onehot_a[i] = 1'b1; - end else begin - waddr_onehot_a[i] = 1'b0; - end - end - end - - // Individual clock gating (if integrated clock-gating cells are available) - for (genvar x = 1; x < NUM_WORDS; x++) begin : gen_cg_word_iter - prim_clock_gating cg_i ( - .clk_i ( clk_int ), - .en_i ( waddr_onehot_a[x] ), - .test_en_i ( test_en_i ), - .clk_o ( mem_clocks[x] ) - ); - end - - // Actual write operation: - // Generate the sequential process for the NUM_WORDS words of the memory. - // The process is synchronized with the clocks mem_clocks[i], i = 1, ..., NUM_WORDS-1. - for (genvar i = 1; i < NUM_WORDS; i++) begin : g_rf_latches - always_latch begin - if (mem_clocks[i]) begin - mem[i] = wdata_a_q; - end - end - end - - // With dummy instructions enabled, R0 behaves as a real register but will always return 0 for - // real instructions. - if (DummyInstructions) begin : g_dummy_r0 - // SEC_CM: CTRL_FLOW.UNPREDICTABLE - logic we_r0_dummy; - logic r0_clock; - logic [DataWidth-1:0] mem_r0; - - // Write enable for dummy R0 register (waddr_a_i will always be 0 for dummy instructions) - assign we_r0_dummy = we_a_i & dummy_instr_id_i; - - // R0 clock gate - prim_clock_gating cg_i ( - .clk_i ( clk_int ), - .en_i ( we_r0_dummy ), - .test_en_i ( test_en_i ), - .clk_o ( r0_clock ) - ); - - always_latch begin : latch_wdata - if (r0_clock) begin - mem_r0 = wdata_a_q; - end - end - - // Output the dummy data for dummy instructions, otherwise R0 reads as zero - assign mem[0] = dummy_instr_id_i ? mem_r0 : WordZeroVal; - - end else begin : g_normal_r0 - logic unused_dummy_instr_id; - assign unused_dummy_instr_id = dummy_instr_id_i; - - assign mem[0] = WordZeroVal; - end - -`ifdef VERILATOR - initial begin - $display("Latch-based register file not supported for Verilator simulation"); - $fatal; - end -`endif - -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top.sv deleted file mode 100644 index b566bb17..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_top.sv +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -`ifdef RISCV_FORMAL - `define RVFI -`endif - -`include "prim_assert.sv" - -/** - * Top level module of the ibex RISC-V core - */ -module ibex_top import ibex_pkg::*; #( - parameter bit PMPEnable = 1'b0, - parameter int unsigned PMPGranularity = 0, - parameter int unsigned PMPNumRegions = 4, - parameter int unsigned MHPMCounterNum = 0, - parameter int unsigned MHPMCounterWidth = 40, - parameter bit RV32E = 1'b0, - parameter rv32m_e RV32M = RV32MFast, - parameter rv32b_e RV32B = RV32BNone, - parameter regfile_e RegFile = RegFileFF, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter bit BranchPredictor = 1'b0, - parameter bit DbgTriggerEn = 1'b0, - parameter int unsigned DbgHwBreakNum = 1, - parameter bit SecureIbex = 1'b0, - parameter bit ICacheScramble = 1'b0, - parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, - parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, - parameter int unsigned DmHaltAddr = 32'h1A110800, - parameter int unsigned DmExceptionAddr = 32'h1A110808, - // Default seed and nonce for scrambling - parameter logic [SCRAMBLE_KEY_W-1:0] RndCnstIbexKey = RndCnstIbexKeyDefault, - parameter logic [SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonce = RndCnstIbexNonceDefault -) ( - // Clock and Reset - input logic clk_i, - input logic rst_ni, - - input logic test_en_i, // enable all clock gates for testing - input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i, - - input logic [31:0] hart_id_i, - input logic [31:0] boot_addr_i, - - // Instruction memory interface - output logic instr_req_o, - input logic instr_gnt_i, - input logic instr_rvalid_i, - output logic [31:0] instr_addr_o, - input logic [31:0] instr_rdata_i, - input logic [6:0] instr_rdata_intg_i, - input logic instr_err_i, - - // Data memory interface - output logic data_req_o, - input logic data_gnt_i, - input logic data_rvalid_i, - output logic data_we_o, - output logic [3:0] data_be_o, - output logic [31:0] data_addr_o, - output logic [31:0] data_wdata_o, - output logic [6:0] data_wdata_intg_o, - input logic [31:0] data_rdata_i, - input logic [6:0] data_rdata_intg_i, - input logic data_err_i, - - // Interrupt inputs - input logic irq_software_i, - input logic irq_timer_i, - input logic irq_external_i, - input logic [14:0] irq_fast_i, - input logic irq_nm_i, // non-maskeable interrupt - - // Scrambling Interface - input logic scramble_key_valid_i, - input logic [SCRAMBLE_KEY_W-1:0] scramble_key_i, - input logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_i, - output logic scramble_req_o, - - // Debug Interface - input logic debug_req_i, - output crash_dump_t crash_dump_o, - output logic double_fault_seen_o, - - // RISC-V Formal Interface - // Does not comply with the coding standards of _i/_o suffixes, but follows - // the convention of RISC-V Formal Interface Specification. -`ifdef RVFI - output logic rvfi_valid, - output logic [63:0] rvfi_order, - output logic [31:0] rvfi_insn, - output logic rvfi_trap, - output logic rvfi_halt, - output logic rvfi_intr, - output logic [ 1:0] rvfi_mode, - output logic [ 1:0] rvfi_ixl, - output logic [ 4:0] rvfi_rs1_addr, - output logic [ 4:0] rvfi_rs2_addr, - output logic [ 4:0] rvfi_rs3_addr, - output logic [31:0] rvfi_rs1_rdata, - output logic [31:0] rvfi_rs2_rdata, - output logic [31:0] rvfi_rs3_rdata, - output logic [ 4:0] rvfi_rd_addr, - output logic [31:0] rvfi_rd_wdata, - output logic [31:0] rvfi_pc_rdata, - output logic [31:0] rvfi_pc_wdata, - output logic [31:0] rvfi_mem_addr, - output logic [ 3:0] rvfi_mem_rmask, - output logic [ 3:0] rvfi_mem_wmask, - output logic [31:0] rvfi_mem_rdata, - output logic [31:0] rvfi_mem_wdata, - output logic [31:0] rvfi_ext_mip, - output logic rvfi_ext_nmi, - output logic rvfi_ext_debug_req, - output logic [63:0] rvfi_ext_mcycle, -`endif - - // CPU Control Signals - input fetch_enable_t fetch_enable_i, - output logic alert_minor_o, - output logic alert_major_internal_o, - output logic alert_major_bus_o, - output logic core_sleep_o, - - // DFT bypass controls - input logic scan_rst_ni -); - - localparam bit Lockstep = SecureIbex; - localparam bit ResetAll = Lockstep; - localparam bit DummyInstructions = SecureIbex; - localparam bit RegFileECC = SecureIbex; - localparam int unsigned RegFileDataWidth = RegFileECC ? 32 + 7 : 32; - // Icache parameters - localparam int unsigned BusSizeECC = ICacheECC ? (BUS_SIZE + 7) : BUS_SIZE; - localparam int unsigned LineSizeECC = BusSizeECC * IC_LINE_BEATS; - localparam int unsigned TagSizeECC = ICacheECC ? (IC_TAG_SIZE + 6) : IC_TAG_SIZE; - // Scrambling Parameter - localparam int unsigned NumAddrScrRounds = ICacheScramble ? 2 : 0; - localparam int unsigned NumDiffRounds = NumAddrScrRounds; - - // Clock signals - logic clk; - logic core_busy_d, core_busy_q; - logic clock_en; - logic irq_pending; - // Core <-> Register file signals - logic dummy_instr_id; - logic [4:0] rf_raddr_a; - logic [4:0] rf_raddr_b; - logic [4:0] rf_waddr_wb; - logic rf_we_wb; - logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc; - logic [RegFileDataWidth-1:0] rf_rdata_a_ecc, rf_rdata_a_ecc_buf; - logic [RegFileDataWidth-1:0] rf_rdata_b_ecc, rf_rdata_b_ecc_buf; - // Core <-> RAMs signals - logic [IC_NUM_WAYS-1:0] ic_tag_req; - logic ic_tag_write; - logic [IC_INDEX_W-1:0] ic_tag_addr; - logic [TagSizeECC-1:0] ic_tag_wdata; - logic [TagSizeECC-1:0] ic_tag_rdata [IC_NUM_WAYS]; - logic [IC_NUM_WAYS-1:0] ic_data_req; - logic ic_data_write; - logic [IC_INDEX_W-1:0] ic_data_addr; - logic [LineSizeECC-1:0] ic_data_wdata; - logic [LineSizeECC-1:0] ic_data_rdata [IC_NUM_WAYS]; - // Alert signals - logic core_alert_major, core_alert_minor; - logic lockstep_alert_major_internal, lockstep_alert_major_bus; - logic lockstep_alert_minor; - // Scramble signals - logic icache_inval; - logic [SCRAMBLE_KEY_W-1:0] scramble_key_q; - logic [SCRAMBLE_NONCE_W-1:0] scramble_nonce_q; - logic scramble_key_valid_d, scramble_key_valid_q; - logic scramble_req_d, scramble_req_q; - - fetch_enable_t fetch_enable_buf; - - ///////////////////// - // Main clock gate // - ///////////////////// - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - core_busy_q <= 1'b0; - end else begin - core_busy_q <= core_busy_d; - end - end - - assign clock_en = core_busy_q | debug_req_i | irq_pending | irq_nm_i; - assign core_sleep_o = ~clock_en; - - prim_clock_gating core_clock_gate_i ( - .clk_i (clk_i), - .en_i (clock_en), - .test_en_i(test_en_i), - .clk_o (clk) - ); - - //////////////////////// - // Core instantiation // - //////////////////////// - - // Buffer security critical signals to prevent synthesis optimisation removing them - prim_buf #(.Width($bits(fetch_enable_t))) u_fetch_enable_buf ( - .in_i (fetch_enable_i), - .out_o(fetch_enable_buf) - ); - - prim_buf #(.Width(RegFileDataWidth)) u_rf_rdata_a_ecc_buf ( - .in_i (rf_rdata_a_ecc), - .out_o(rf_rdata_a_ecc_buf) - ); - - prim_buf #(.Width(RegFileDataWidth)) u_rf_rdata_b_ecc_buf ( - .in_i (rf_rdata_b_ecc), - .out_o(rf_rdata_b_ecc_buf) - ); - - ibex_core #( - .PMPEnable (PMPEnable), - .PMPGranularity (PMPGranularity), - .PMPNumRegions (PMPNumRegions), - .MHPMCounterNum (MHPMCounterNum), - .MHPMCounterWidth (MHPMCounterWidth), - .RV32E (RV32E), - .RV32M (RV32M), - .RV32B (RV32B), - .BranchTargetALU (BranchTargetALU), - .ICache (ICache), - .ICacheECC (ICacheECC), - .BusSizeECC (BusSizeECC), - .TagSizeECC (TagSizeECC), - .LineSizeECC (LineSizeECC), - .BranchPredictor (BranchPredictor), - .DbgTriggerEn (DbgTriggerEn), - .DbgHwBreakNum (DbgHwBreakNum), - .WritebackStage (WritebackStage), - .ResetAll (ResetAll), - .RndCnstLfsrSeed (RndCnstLfsrSeed), - .RndCnstLfsrPerm (RndCnstLfsrPerm), - .SecureIbex (SecureIbex), - .DummyInstructions(DummyInstructions), - .RegFileECC (RegFileECC), - .RegFileDataWidth (RegFileDataWidth), - .DmHaltAddr (DmHaltAddr), - .DmExceptionAddr (DmExceptionAddr) - ) u_ibex_core ( - .clk_i(clk), - .rst_ni, - - .hart_id_i, - .boot_addr_i, - - .instr_req_o, - .instr_gnt_i, - .instr_rvalid_i, - .instr_addr_o, - .instr_rdata_i, - .instr_err_i, - - .data_req_o, - .data_gnt_i, - .data_rvalid_i, - .data_we_o, - .data_be_o, - .data_addr_o, - .data_wdata_o, - .data_rdata_i, - .data_err_i, - - .dummy_instr_id_o (dummy_instr_id), - .rf_raddr_a_o (rf_raddr_a), - .rf_raddr_b_o (rf_raddr_b), - .rf_waddr_wb_o (rf_waddr_wb), - .rf_we_wb_o (rf_we_wb), - .rf_wdata_wb_ecc_o(rf_wdata_wb_ecc), - .rf_rdata_a_ecc_i (rf_rdata_a_ecc_buf), - .rf_rdata_b_ecc_i (rf_rdata_b_ecc_buf), - - .ic_tag_req_o (ic_tag_req), - .ic_tag_write_o (ic_tag_write), - .ic_tag_addr_o (ic_tag_addr), - .ic_tag_wdata_o (ic_tag_wdata), - .ic_tag_rdata_i (ic_tag_rdata), - .ic_data_req_o (ic_data_req), - .ic_data_write_o (ic_data_write), - .ic_data_addr_o (ic_data_addr), - .ic_data_wdata_o (ic_data_wdata), - .ic_data_rdata_i (ic_data_rdata), - .ic_scr_key_valid_i(scramble_key_valid_q), - - .irq_software_i, - .irq_timer_i, - .irq_external_i, - .irq_fast_i, - .irq_nm_i, - .irq_pending_o(irq_pending), - - .debug_req_i, - .crash_dump_o, - .double_fault_seen_o, - -`ifdef RVFI - .rvfi_valid, - .rvfi_order, - .rvfi_insn, - .rvfi_trap, - .rvfi_halt, - .rvfi_intr, - .rvfi_mode, - .rvfi_ixl, - .rvfi_rs1_addr, - .rvfi_rs2_addr, - .rvfi_rs3_addr, - .rvfi_rs1_rdata, - .rvfi_rs2_rdata, - .rvfi_rs3_rdata, - .rvfi_rd_addr, - .rvfi_rd_wdata, - .rvfi_pc_rdata, - .rvfi_pc_wdata, - .rvfi_mem_addr, - .rvfi_mem_rmask, - .rvfi_mem_wmask, - .rvfi_mem_rdata, - .rvfi_mem_wdata, - .rvfi_ext_mip, - .rvfi_ext_nmi, - .rvfi_ext_debug_req, - .rvfi_ext_mcycle, -`endif - - .fetch_enable_i(fetch_enable_buf), - .alert_minor_o (core_alert_minor), - .alert_major_o (core_alert_major), - .icache_inval_o(icache_inval), - .core_busy_o (core_busy_d) - ); - - ///////////////////////////////// - // Register file Instantiation // - ///////////////////////////////// - - if (RegFile == RegFileFF) begin : gen_regfile_ff - ibex_register_file_ff #( - .RV32E (RV32E), - .DataWidth (RegFileDataWidth), - .DummyInstructions(DummyInstructions), - .WordZeroVal (RegFileDataWidth'(prim_secded_pkg::SecdedInv3932ZeroWord)) - ) register_file_i ( - .clk_i (clk), - .rst_ni(rst_ni), - - .test_en_i (test_en_i), - .dummy_instr_id_i(dummy_instr_id), - - .raddr_a_i(rf_raddr_a), - .rdata_a_o(rf_rdata_a_ecc), - .raddr_b_i(rf_raddr_b), - .rdata_b_o(rf_rdata_b_ecc), - .waddr_a_i(rf_waddr_wb), - .wdata_a_i(rf_wdata_wb_ecc), - .we_a_i (rf_we_wb) - ); - end else if (RegFile == RegFileFPGA) begin : gen_regfile_fpga - ibex_register_file_fpga #( - .RV32E (RV32E), - .DataWidth (RegFileDataWidth), - .DummyInstructions(DummyInstructions), - .WordZeroVal (RegFileDataWidth'(prim_secded_pkg::SecdedInv3932ZeroWord)) - ) register_file_i ( - .clk_i (clk), - .rst_ni(rst_ni), - - .test_en_i (test_en_i), - .dummy_instr_id_i(dummy_instr_id), - - .raddr_a_i(rf_raddr_a), - .rdata_a_o(rf_rdata_a_ecc), - .raddr_b_i(rf_raddr_b), - .rdata_b_o(rf_rdata_b_ecc), - .waddr_a_i(rf_waddr_wb), - .wdata_a_i(rf_wdata_wb_ecc), - .we_a_i (rf_we_wb) - ); - end else if (RegFile == RegFileLatch) begin : gen_regfile_latch - ibex_register_file_latch #( - .RV32E (RV32E), - .DataWidth (RegFileDataWidth), - .DummyInstructions(DummyInstructions), - .WordZeroVal (RegFileDataWidth'(prim_secded_pkg::SecdedInv3932ZeroWord)) - ) register_file_i ( - .clk_i (clk), - .rst_ni(rst_ni), - - .test_en_i (test_en_i), - .dummy_instr_id_i(dummy_instr_id), - - .raddr_a_i(rf_raddr_a), - .rdata_a_o(rf_rdata_a_ecc), - .raddr_b_i(rf_raddr_b), - .rdata_b_o(rf_rdata_b_ecc), - .waddr_a_i(rf_waddr_wb), - .wdata_a_i(rf_wdata_wb_ecc), - .we_a_i (rf_we_wb) - ); - end - - /////////////////////////////// - // Scrambling Infrastructure // - /////////////////////////////// - - if (ICacheScramble) begin : gen_scramble - - // SEC_CM: ICACHE.MEM.SCRAMBLE - // Scramble key valid starts with OTP returning new valid key and stays high - // until we request a new valid key. - assign scramble_key_valid_d = scramble_req_q ? scramble_key_valid_i : - icache_inval ? 1'b0 : - scramble_key_valid_q; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - scramble_key_q <= RndCnstIbexKey; - scramble_nonce_q <= RndCnstIbexNonce; - end else if (scramble_key_valid_i) begin - scramble_key_q <= scramble_key_i; - scramble_nonce_q <= scramble_nonce_i; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - scramble_key_valid_q <= 1'b1; - scramble_req_q <= '0; - end else begin - scramble_key_valid_q <= scramble_key_valid_d; - scramble_req_q <= scramble_req_d; - end - end - - // Scramble key request starts with invalidate signal from ICache and stays high - // until we got a valid key. - assign scramble_req_d = scramble_req_q ? ~scramble_key_valid_i : icache_inval; - assign scramble_req_o = scramble_req_q; - - end else begin : gen_noscramble - - logic unused_scramble_inputs = scramble_key_valid_i & (|scramble_key_i) & (|RndCnstIbexKey) & - (|scramble_nonce_i) & (|RndCnstIbexNonce) & scramble_req_q & - icache_inval & scramble_key_valid_d & scramble_req_d; - - assign scramble_req_d = 1'b0; - assign scramble_req_q = 1'b0; - assign scramble_req_o = 1'b0; - assign scramble_key_q = '0; - assign scramble_nonce_q = '0; - assign scramble_key_valid_q = 1'b1; - assign scramble_key_valid_d = 1'b1; - end - - //////////////////////// - // Rams Instantiation // - //////////////////////// - - if (ICache) begin : gen_rams - - for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams_inner - - // SEC_CM: ICACHE.MEM.SCRAMBLE - // Tag RAM instantiation - prim_ram_1p_scr #( - .Width (TagSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask (TagSizeECC), - .EnableParity (0), - .DiffWidth (TagSizeECC), - .NumAddrScrRounds (NumAddrScrRounds), - .NumDiffRounds (NumDiffRounds) - ) tag_bank ( - .clk_i, - .rst_ni, - - .key_valid_i (scramble_key_valid_q), - .key_i (scramble_key_q), - .nonce_i (scramble_nonce_q), - - .req_i (ic_tag_req[way]), - - .gnt_o (), - .write_i (ic_tag_write), - .addr_i (ic_tag_addr), - .wdata_i (ic_tag_wdata), - .wmask_i ({TagSizeECC{1'b1}}), - .intg_error_i(1'b0), - - .rdata_o (ic_tag_rdata[way]), - .rvalid_o (), - .raddr_o (), - .rerror_o (), - .cfg_i (ram_cfg_i) - ); - - // Data RAM instantiation - prim_ram_1p_scr #( - .Width (LineSizeECC), - .Depth (IC_NUM_LINES), - .DataBitsPerMask (LineSizeECC), - .ReplicateKeyStream (1), - .EnableParity (0), - .DiffWidth (LineSizeECC), - .NumAddrScrRounds (NumAddrScrRounds), - .NumDiffRounds (NumDiffRounds) - ) data_bank ( - .clk_i, - .rst_ni, - - .key_valid_i (scramble_key_valid_q), - .key_i (scramble_key_q), - .nonce_i (scramble_nonce_q), - - .req_i (ic_data_req[way]), - - .gnt_o (), - .write_i (ic_data_write), - .addr_i (ic_data_addr), - .wdata_i (ic_data_wdata), - .wmask_i ({LineSizeECC{1'b1}}), - .intg_error_i(1'b0), - - .rdata_o (ic_data_rdata[way]), - .rvalid_o (), - .raddr_o (), - .rerror_o (), - .cfg_i (ram_cfg_i) - ); - end - - end else begin : gen_norams - - prim_ram_1p_pkg::ram_1p_cfg_t unused_ram_cfg; - logic unused_ram_inputs; - - assign unused_ram_cfg = ram_cfg_i; - assign unused_ram_inputs = (|ic_tag_req) & ic_tag_write & (|ic_tag_addr) & (|ic_tag_wdata) & - (|ic_data_req) & ic_data_write & (|ic_data_addr) & (|ic_data_wdata) & - (|scramble_key_q) & (|scramble_nonce_q) & scramble_key_valid_q & - scramble_key_valid_d & (|scramble_nonce_q) & - (|NumAddrScrRounds); - - assign ic_tag_rdata = '{default:'b0}; - assign ic_data_rdata = '{default:'b0}; - - end - - // Redundant lockstep core implementation - if (Lockstep) begin : gen_lockstep - // SEC_CM: LOGIC.SHADOW - // Note: certain synthesis tools like DC are very smart at optimizing away redundant logic. - // Hence, we have to insert an optimization barrier at the IOs of the lockstep Ibex. - // This is achieved by manually buffering each bit using prim_buf. - // Our Xilinx and DC synthesis flows make sure that these buffers cannot be optimized away - // using keep attributes (Vivado) and size_only constraints (DC). - - localparam int NumBufferBits = $bits({ - hart_id_i, - boot_addr_i, - instr_req_o, - instr_gnt_i, - instr_rvalid_i, - instr_addr_o, - instr_rdata_i, - instr_rdata_intg_i, - instr_err_i, - data_req_o, - data_gnt_i, - data_rvalid_i, - data_we_o, - data_be_o, - data_addr_o, - data_wdata_o, - data_rdata_i, - data_rdata_intg_i, - data_err_i, - dummy_instr_id, - rf_raddr_a, - rf_raddr_b, - rf_waddr_wb, - rf_we_wb, - rf_wdata_wb_ecc, - rf_rdata_a_ecc, - rf_rdata_b_ecc, - ic_tag_req, - ic_tag_write, - ic_tag_addr, - ic_tag_wdata, - ic_data_req, - ic_data_write, - ic_data_addr, - ic_data_wdata, - scramble_key_valid_i, - irq_software_i, - irq_timer_i, - irq_external_i, - irq_fast_i, - irq_nm_i, - irq_pending, - debug_req_i, - crash_dump_o, - double_fault_seen_o, - fetch_enable_i, - icache_inval, - core_busy_d - }); - - logic [NumBufferBits-1:0] buf_in, buf_out; - - logic [31:0] hart_id_local; - logic [31:0] boot_addr_local; - - logic instr_req_local; - logic instr_gnt_local; - logic instr_rvalid_local; - logic [31:0] instr_addr_local; - logic [31:0] instr_rdata_local; - logic [6:0] instr_rdata_intg_local; - logic instr_err_local; - - logic data_req_local; - logic data_gnt_local; - logic data_rvalid_local; - logic data_we_local; - logic [3:0] data_be_local; - logic [31:0] data_addr_local; - logic [31:0] data_wdata_local; - logic [6:0] data_wdata_intg_local; - logic [31:0] data_rdata_local; - logic [6:0] data_rdata_intg_local; - logic data_err_local; - - logic dummy_instr_id_local; - logic [4:0] rf_raddr_a_local; - logic [4:0] rf_raddr_b_local; - logic [4:0] rf_waddr_wb_local; - logic rf_we_wb_local; - logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_local; - logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_local; - logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_local; - - logic [IC_NUM_WAYS-1:0] ic_tag_req_local; - logic ic_tag_write_local; - logic [IC_INDEX_W-1:0] ic_tag_addr_local; - logic [TagSizeECC-1:0] ic_tag_wdata_local; - logic [IC_NUM_WAYS-1:0] ic_data_req_local; - logic ic_data_write_local; - logic [IC_INDEX_W-1:0] ic_data_addr_local; - logic [LineSizeECC-1:0] ic_data_wdata_local; - logic scramble_key_valid_local; - - logic irq_software_local; - logic irq_timer_local; - logic irq_external_local; - logic [14:0] irq_fast_local; - logic irq_nm_local; - logic irq_pending_local; - - logic debug_req_local; - crash_dump_t crash_dump_local; - logic double_fault_seen_local; - fetch_enable_t fetch_enable_local; - - logic icache_inval_local; - logic core_busy_local; - - assign buf_in = { - hart_id_i, - boot_addr_i, - instr_req_o, - instr_gnt_i, - instr_rvalid_i, - instr_addr_o, - instr_rdata_i, - instr_rdata_intg_i, - instr_err_i, - data_req_o, - data_gnt_i, - data_rvalid_i, - data_we_o, - data_be_o, - data_addr_o, - data_wdata_o, - data_rdata_i, - data_rdata_intg_i, - data_err_i, - dummy_instr_id, - rf_raddr_a, - rf_raddr_b, - rf_waddr_wb, - rf_we_wb, - rf_wdata_wb_ecc, - rf_rdata_a_ecc, - rf_rdata_b_ecc, - ic_tag_req, - ic_tag_write, - ic_tag_addr, - ic_tag_wdata, - ic_data_req, - ic_data_write, - ic_data_addr, - ic_data_wdata, - scramble_key_valid_q, - irq_software_i, - irq_timer_i, - irq_external_i, - irq_fast_i, - irq_nm_i, - irq_pending, - debug_req_i, - crash_dump_o, - double_fault_seen_o, - fetch_enable_i, - icache_inval, - core_busy_d - }; - - assign { - hart_id_local, - boot_addr_local, - instr_req_local, - instr_gnt_local, - instr_rvalid_local, - instr_addr_local, - instr_rdata_local, - instr_rdata_intg_local, - instr_err_local, - data_req_local, - data_gnt_local, - data_rvalid_local, - data_we_local, - data_be_local, - data_addr_local, - data_wdata_local, - data_rdata_local, - data_rdata_intg_local, - data_err_local, - dummy_instr_id_local, - rf_raddr_a_local, - rf_raddr_b_local, - rf_waddr_wb_local, - rf_we_wb_local, - rf_wdata_wb_ecc_local, - rf_rdata_a_ecc_local, - rf_rdata_b_ecc_local, - ic_tag_req_local, - ic_tag_write_local, - ic_tag_addr_local, - ic_tag_wdata_local, - ic_data_req_local, - ic_data_write_local, - ic_data_addr_local, - ic_data_wdata_local, - scramble_key_valid_local, - irq_software_local, - irq_timer_local, - irq_external_local, - irq_fast_local, - irq_nm_local, - irq_pending_local, - debug_req_local, - crash_dump_local, - double_fault_seen_local, - fetch_enable_local, - icache_inval_local, - core_busy_local - } = buf_out; - - // Manually buffer all input signals. - prim_buf #(.Width(NumBufferBits)) u_signals_prim_buf ( - .in_i(buf_in), - .out_o(buf_out) - ); - - logic [TagSizeECC-1:0] ic_tag_rdata_local [IC_NUM_WAYS]; - logic [LineSizeECC-1:0] ic_data_rdata_local [IC_NUM_WAYS]; - for (genvar k = 0; k < IC_NUM_WAYS; k++) begin : gen_ways - prim_buf #(.Width(TagSizeECC)) u_tag_prim_buf ( - .in_i(ic_tag_rdata[k]), - .out_o(ic_tag_rdata_local[k]) - ); - prim_buf #(.Width(LineSizeECC)) u_data_prim_buf ( - .in_i(ic_data_rdata[k]), - .out_o(ic_data_rdata_local[k]) - ); - end - - logic lockstep_alert_minor_local, lockstep_alert_major_internal_local; - logic lockstep_alert_major_bus_local; - - ibex_lockstep #( - .PMPEnable (PMPEnable), - .PMPGranularity (PMPGranularity), - .PMPNumRegions (PMPNumRegions), - .MHPMCounterNum (MHPMCounterNum), - .MHPMCounterWidth (MHPMCounterWidth), - .RV32E (RV32E), - .RV32M (RV32M), - .RV32B (RV32B), - .BranchTargetALU (BranchTargetALU), - .ICache (ICache), - .ICacheECC (ICacheECC), - .BusSizeECC (BusSizeECC), - .TagSizeECC (TagSizeECC), - .LineSizeECC (LineSizeECC), - .BranchPredictor (BranchPredictor), - .DbgTriggerEn (DbgTriggerEn), - .DbgHwBreakNum (DbgHwBreakNum), - .WritebackStage (WritebackStage), - .ResetAll (ResetAll), - .RndCnstLfsrSeed (RndCnstLfsrSeed), - .RndCnstLfsrPerm (RndCnstLfsrPerm), - .SecureIbex (SecureIbex), - .DummyInstructions(DummyInstructions), - .RegFileECC (RegFileECC), - .RegFileDataWidth (RegFileDataWidth), - .DmHaltAddr (DmHaltAddr), - .DmExceptionAddr (DmExceptionAddr) - ) u_ibex_lockstep ( - .clk_i (clk), - .rst_ni (rst_ni), - - .hart_id_i (hart_id_local), - .boot_addr_i (boot_addr_local), - - .instr_req_i (instr_req_local), - .instr_gnt_i (instr_gnt_local), - .instr_rvalid_i (instr_rvalid_local), - .instr_addr_i (instr_addr_local), - .instr_rdata_i (instr_rdata_local), - .instr_rdata_intg_i (instr_rdata_intg_local), - .instr_err_i (instr_err_local), - - .data_req_i (data_req_local), - .data_gnt_i (data_gnt_local), - .data_rvalid_i (data_rvalid_local), - .data_we_i (data_we_local), - .data_be_i (data_be_local), - .data_addr_i (data_addr_local), - .data_wdata_i (data_wdata_local), - .data_wdata_intg_o (data_wdata_intg_local), - .data_rdata_i (data_rdata_local), - .data_rdata_intg_i (data_rdata_intg_local), - .data_err_i (data_err_local), - - .dummy_instr_id_i (dummy_instr_id_local), - .rf_raddr_a_i (rf_raddr_a_local), - .rf_raddr_b_i (rf_raddr_b_local), - .rf_waddr_wb_i (rf_waddr_wb_local), - .rf_we_wb_i (rf_we_wb_local), - .rf_wdata_wb_ecc_i (rf_wdata_wb_ecc_local), - .rf_rdata_a_ecc_i (rf_rdata_a_ecc_local), - .rf_rdata_b_ecc_i (rf_rdata_b_ecc_local), - - .ic_tag_req_i (ic_tag_req_local), - .ic_tag_write_i (ic_tag_write_local), - .ic_tag_addr_i (ic_tag_addr_local), - .ic_tag_wdata_i (ic_tag_wdata_local), - .ic_tag_rdata_i (ic_tag_rdata_local), - .ic_data_req_i (ic_data_req_local), - .ic_data_write_i (ic_data_write_local), - .ic_data_addr_i (ic_data_addr_local), - .ic_data_wdata_i (ic_data_wdata_local), - .ic_data_rdata_i (ic_data_rdata_local), - .ic_scr_key_valid_i (scramble_key_valid_local), - - .irq_software_i (irq_software_local), - .irq_timer_i (irq_timer_local), - .irq_external_i (irq_external_local), - .irq_fast_i (irq_fast_local), - .irq_nm_i (irq_nm_local), - .irq_pending_i (irq_pending_local), - - .debug_req_i (debug_req_local), - .crash_dump_i (crash_dump_local), - .double_fault_seen_i (double_fault_seen_local), - - .fetch_enable_i (fetch_enable_local), - .alert_minor_o (lockstep_alert_minor_local), - .alert_major_internal_o (lockstep_alert_major_internal_local), - .alert_major_bus_o (lockstep_alert_major_bus_local), - .icache_inval_i (icache_inval_local), - .core_busy_i (core_busy_local), - .test_en_i (test_en_i), - .scan_rst_ni (scan_rst_ni) - ); - - // Manually buffer the output signals. - prim_buf #(.Width (7)) u_prim_buf_wdata_intg ( - .in_i(data_wdata_intg_local), - .out_o(data_wdata_intg_o) - ); - - prim_buf u_prim_buf_alert_minor ( - .in_i (lockstep_alert_minor_local), - .out_o(lockstep_alert_minor) - ); - - prim_buf u_prim_buf_alert_major_internal ( - .in_i (lockstep_alert_major_internal_local), - .out_o(lockstep_alert_major_internal) - ); - - prim_buf u_prim_buf_alert_major_bus ( - .in_i (lockstep_alert_major_bus_local), - .out_o(lockstep_alert_major_bus) - ); - - end else begin : gen_no_lockstep - assign lockstep_alert_major_internal = 1'b0; - assign lockstep_alert_major_bus = 1'b0; - assign lockstep_alert_minor = 1'b0; - assign data_wdata_intg_o = 'b0; - logic unused_scan, unused_intg; - assign unused_scan = scan_rst_ni; - assign unused_intg = |{instr_rdata_intg_i, data_rdata_intg_i}; - end - - assign alert_major_internal_o = core_alert_major | lockstep_alert_major_internal; - assign alert_major_bus_o = lockstep_alert_major_bus; - assign alert_minor_o = core_alert_minor | lockstep_alert_minor; - - // X checks for top-level outputs - `ASSERT_KNOWN(IbexInstrReqX, instr_req_o) - `ASSERT_KNOWN_IF(IbexInstrReqPayloadX, instr_addr_o, instr_req_o) - - `ASSERT_KNOWN(IbexDataReqX, data_req_o) - `ASSERT_KNOWN_IF(IbexDataReqPayloadX, - {data_we_o, data_be_o, data_addr_o, data_wdata_o, data_wdata_intg_o}, data_req_o) - - `ASSERT_KNOWN(IbexScrambleReqX, scramble_req_o) - `ASSERT_KNOWN(IbexDoubleFaultSeenX, double_fault_seen_o) - `ASSERT_KNOWN(IbexAlertMinorX, alert_minor_o) - `ASSERT_KNOWN(IbexAlertMajorInternalX, alert_major_internal_o) - `ASSERT_KNOWN(IbexAlertMajorBusX, alert_major_bus_o) - `ASSERT_KNOWN(IbexCoreSleepX, core_sleep_o) - - // X check for top-level inputs - `ASSERT_KNOWN(IbexTestEnX, test_en_i) - `ASSERT_KNOWN(IbexRamCfgX, ram_cfg_i) - `ASSERT_KNOWN(IbexHartIdX, hart_id_i) - `ASSERT_KNOWN(IbexBootAddrX, boot_addr_i) - - `ASSERT_KNOWN(IbexInstrGntX, instr_gnt_i) - `ASSERT_KNOWN(IbexInstrRValidX, instr_rvalid_i) - `ASSERT_KNOWN_IF(IbexInstrRPayloadX, - {instr_rdata_i, instr_rdata_intg_i, instr_err_i}, instr_rvalid_i) - - `ASSERT_KNOWN(IbexDataGntX, data_gnt_i) - `ASSERT_KNOWN(IbexDataRValidX, data_rvalid_i) - `ASSERT_KNOWN_IF(IbexDataRPayloadX, {data_rdata_i, data_rdata_intg_i, data_err_i}, data_rvalid_i) - - `ASSERT_KNOWN(IbexIrqX, {irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i}) - - `ASSERT_KNOWN(IbexScrambleKeyValidX, scramble_key_valid_i) - `ASSERT_KNOWN_IF(IbexScramblePayloadX, {scramble_key_i, scramble_nonce_i}, scramble_key_valid_i) - - `ASSERT_KNOWN(IbexDebugReqX, debug_req_i) - `ASSERT_KNOWN(IbexFetchEnableX, fetch_enable_i) -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_wb_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_wb_stage.sv deleted file mode 100644 index 14364c57..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/ibex_wb_stage.sv +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -/** - * Writeback Stage - * - * Writeback is an optional third pipeline stage. It writes data back to the register file that was - * produced in the ID/EX stage or awaits a response to a load/store (LSU writes direct to register - * file for load data). If the writeback stage is not present (WritebackStage == 0) this acts as - * a simple passthrough to write data direct to the register file. - */ - -`include "prim_assert.sv" -//`include "dv_fcov_macros.svh" - -module ibex_wb_stage #( - parameter bit ResetAll = 1'b0, - parameter bit WritebackStage = 1'b0 -) ( - input logic clk_i, - input logic rst_ni, - - input logic en_wb_i, - input ibex_pkg::wb_instr_type_e instr_type_wb_i, - input logic [31:0] pc_id_i, - input logic instr_is_compressed_id_i, - input logic instr_perf_count_id_i, - - output logic ready_wb_o, - output logic rf_write_wb_o, - output logic outstanding_load_wb_o, - output logic outstanding_store_wb_o, - output logic [31:0] pc_wb_o, - output logic perf_instr_ret_wb_o, - output logic perf_instr_ret_compressed_wb_o, - output logic perf_instr_ret_wb_spec_o, - output logic perf_instr_ret_compressed_wb_spec_o, - - input logic [4:0] rf_waddr_id_i, - input logic [31:0] rf_wdata_id_i, - input logic rf_we_id_i, - - input logic [31:0] rf_wdata_lsu_i, - input logic rf_we_lsu_i, - - output logic [31:0] rf_wdata_fwd_wb_o, - - output logic [4:0] rf_waddr_wb_o, - output logic [31:0] rf_wdata_wb_o, - output logic rf_we_wb_o, - - input logic lsu_resp_valid_i, - input logic lsu_resp_err_i, - - output logic instr_done_wb_o -); - - import ibex_pkg::*; - - // 0 == RF write from ID - // 1 == RF write from LSU - logic [31:0] rf_wdata_wb_mux [2]; - logic [1:0] rf_wdata_wb_mux_we; - - if (WritebackStage) begin : g_writeback_stage - logic [31:0] rf_wdata_wb_q; - logic rf_we_wb_q; - logic [4:0] rf_waddr_wb_q; - - logic wb_done; - - logic wb_valid_q; - logic [31:0] wb_pc_q; - logic wb_compressed_q; - logic wb_count_q; - wb_instr_type_e wb_instr_type_q; - - logic wb_valid_d; - - // Stage becomes valid if an instruction enters for ID/EX and valid is cleared when instruction - // is done - assign wb_valid_d = (en_wb_i & ready_wb_o) | (wb_valid_q & ~wb_done); - - // Writeback for non load/store instructions always completes in a cycle (so instantly done) - // Writeback for load/store must wait for response to be received by the LSU - // Signal only relevant if wb_valid_q set - assign wb_done = (wb_instr_type_q == WB_INSTR_OTHER) | lsu_resp_valid_i; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - wb_valid_q <= 1'b0; - end else begin - wb_valid_q <= wb_valid_d; - end - end - - if (ResetAll) begin : g_wb_regs_ra - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rf_we_wb_q <= '0; - rf_waddr_wb_q <= '0; - rf_wdata_wb_q <= '0; - wb_instr_type_q <= wb_instr_type_e'(0); - wb_pc_q <= '0; - wb_compressed_q <= '0; - wb_count_q <= '0; - end else if (en_wb_i) begin - rf_we_wb_q <= rf_we_id_i; - rf_waddr_wb_q <= rf_waddr_id_i; - rf_wdata_wb_q <= rf_wdata_id_i; - wb_instr_type_q <= instr_type_wb_i; - wb_pc_q <= pc_id_i; - wb_compressed_q <= instr_is_compressed_id_i; - wb_count_q <= instr_perf_count_id_i; - end - end - end else begin : g_wb_regs_nr - always_ff @(posedge clk_i) begin - if (en_wb_i) begin - rf_we_wb_q <= rf_we_id_i; - rf_waddr_wb_q <= rf_waddr_id_i; - rf_wdata_wb_q <= rf_wdata_id_i; - wb_instr_type_q <= instr_type_wb_i; - wb_pc_q <= pc_id_i; - wb_compressed_q <= instr_is_compressed_id_i; - wb_count_q <= instr_perf_count_id_i; - end - end - end - - assign rf_waddr_wb_o = rf_waddr_wb_q; - assign rf_wdata_wb_mux[0] = rf_wdata_wb_q; - assign rf_wdata_wb_mux_we[0] = rf_we_wb_q & wb_valid_q; - - assign ready_wb_o = ~wb_valid_q | wb_done; - - // Instruction in writeback will be writing to register file if either rf_we is set or writeback - // is awaiting load data. This is used for determining RF read hazards in ID/EX - assign rf_write_wb_o = wb_valid_q & (rf_we_wb_q | (wb_instr_type_q == WB_INSTR_LOAD)); - - assign outstanding_load_wb_o = wb_valid_q & (wb_instr_type_q == WB_INSTR_LOAD); - assign outstanding_store_wb_o = wb_valid_q & (wb_instr_type_q == WB_INSTR_STORE); - - assign pc_wb_o = wb_pc_q; - - assign instr_done_wb_o = wb_valid_q & wb_done; - - // Increment instruction retire counters for valid instructions which are not lsu errors. - // Speculative versions of the signals do not factor in exceptions and whether the instruction - // is done yet. These are used to get correct values for instructions reading the relevant - // performance counters in the ID stage. - assign perf_instr_ret_wb_spec_o = wb_count_q; - assign perf_instr_ret_compressed_wb_spec_o = perf_instr_ret_wb_spec_o & wb_compressed_q; - assign perf_instr_ret_wb_o = instr_done_wb_o & wb_count_q & - ~(lsu_resp_valid_i & lsu_resp_err_i); - assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & wb_compressed_q; - - // Forward data that will be written to the RF back to ID to resolve data hazards. The flopped - // rf_wdata_wb_q is used rather than rf_wdata_wb_o as the latter includes read data from memory - // that returns too late to be used on the forwarding path. - assign rf_wdata_fwd_wb_o = rf_wdata_wb_q; - end else begin : g_bypass_wb - // without writeback stage just pass through register write signals - assign rf_waddr_wb_o = rf_waddr_id_i; - assign rf_wdata_wb_mux[0] = rf_wdata_id_i; - assign rf_wdata_wb_mux_we[0] = rf_we_id_i; - - // Increment instruction retire counters for valid instructions which are not lsu errors. - // The speculative signals are always 0 when no writeback stage is present as the raw counter - // values will be correct. - assign perf_instr_ret_wb_spec_o = 1'b0; - assign perf_instr_ret_compressed_wb_spec_o = 1'b0; - assign perf_instr_ret_wb_o = instr_perf_count_id_i & en_wb_i & - ~(lsu_resp_valid_i & lsu_resp_err_i); - assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & instr_is_compressed_id_i; - - // ready needs to be constant 1 without writeback stage (otherwise ID/EX stage will stall) - assign ready_wb_o = 1'b1; - - // Unused Writeback stage only IO & wiring - // Assign inputs and internal wiring to unused signals to satisfy lint checks - // Tie-off outputs to constant values - logic unused_clk; - logic unused_rst; - wb_instr_type_e unused_instr_type_wb; - logic [31:0] unused_pc_id; - - assign unused_clk = clk_i; - assign unused_rst = rst_ni; - assign unused_instr_type_wb = instr_type_wb_i; - assign unused_pc_id = pc_id_i; - - assign outstanding_load_wb_o = 1'b0; - assign outstanding_store_wb_o = 1'b0; - assign pc_wb_o = '0; - assign rf_write_wb_o = 1'b0; - assign rf_wdata_fwd_wb_o = 32'b0; - assign instr_done_wb_o = 1'b0; - end - - assign rf_wdata_wb_mux[1] = rf_wdata_lsu_i; - assign rf_wdata_wb_mux_we[1] = rf_we_lsu_i; - - // RF write data can come from ID results (all RF writes that aren't because of loads will come - // from here) or the LSU (RF writes for load data) - assign rf_wdata_wb_o = ({32{rf_wdata_wb_mux_we[0]}} & rf_wdata_wb_mux[0]) | - ({32{rf_wdata_wb_mux_we[1]}} & rf_wdata_wb_mux[1]); - assign rf_we_wb_o = |rf_wdata_wb_mux_we; - - //`DV_FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, WritebackStage) - - `ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we)) -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/README.md b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/README.md new file mode 100644 index 00000000..e69de29b diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core new file mode 100644 index 00000000..02c03356 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.core @@ -0,0 +1,17 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_fcov_macros" +description: "DV FCOV macros" + +filesets: + files_fcov: + files: + - dv_fcov_macros.svh: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_fcov diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh new file mode 100644 index 00000000..8ca12cdc --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_fcov_macros.svh @@ -0,0 +1,112 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Include FCOV RTL by default. Disable it for synthesis and where explicitly requested (by defining +// DV_FCOV_DISABLE). +`ifdef SYNTHESIS + `define DV_FCOV_DISABLE +`elsif YOSYS + `define DV_FCOV_DISABLE +`endif + +// Disable instantiations of FCOV coverpoints or covergroups. +`ifdef VERILATOR + `define DV_FCOV_DISABLE_CP +`elsif DV_FCOV_DISABLE + `define DV_FCOV_DISABLE_CP +`endif + +// Instantiates a covergroup in an interface or module. +// +// This macro assumes that a covergroup of the same name as the NAME_ arg is defined in the +// interface or module. It just adds some extra signals and logic to control the creation of the +// covergroup instance with ~bit en_~. This defaults to 0. It is ORed with the external +// COND_ signal. The testbench can modify it at t = 0 based on the test being run. +// NOTE: This is not meant to be invoked inside a class. +// +// NAME_ : Name of the covergroup. +// COND_ : External condition / expr that controls the creation of the covergroup. +// ARGS_ : Arguments to covergroup instance, if any. Args MUST BE wrapped in (..). +`ifndef DV_FCOV_INSTANTIATE_CG +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) +`else + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) \ + bit en_``NAME_ = 1'b0; \ + NAME_ NAME_``_inst; \ + initial begin \ + /* The #1 delay below allows any part of the tb to control the conditions first at t = 0. */ \ + #1; \ + if ((en_``NAME_) || (COND_)) begin \ + $display("%0t: (%0s:%0d) [%m] %0s", $time, `__FILE__, `__LINE__, \ + {"Creating covergroup ", `"NAME_`"}); \ + NAME_``_inst = new``ARGS_; \ + end \ + end +`endif +`endif + +// Creates a coverpoint for an expression where only the expression true case is of interest for +// coverage (e.g. where the expression indicates an event has occured). +`ifndef DV_FCOV_EXPR_SEEN +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) +`else + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) cp_``NAME_: coverpoint EXPR_ { bins seen = {1}; } +`endif +`endif + +// Creates a SVA cover that can be used in a covergroup. +// +// This macro creates an unnamed SVA cover from the property (or an expression) `PROP_` and an event +// with the name `EV_NAME_`. When the SVA cover is hit, the event is triggered. A coverpoint can +// cover the `triggered` property of the event. +`ifndef DV_FCOV_SVA +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) +`else + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) \ + event EV_NAME_; \ + cover property (@(posedge CLK_) disable iff (RST_ == 0) (PROP_)) begin \ + -> EV_NAME_; \ + end +`endif +`endif + +// Coverage support is not always available but it's useful to include extra fcov signals for +// linting purposes. They need to be marked as unused to avoid warnings. +`ifndef DV_FCOV_MARK_UNUSED + `define DV_FCOV_MARK_UNUSED(TYPE_, NAME_) \ + TYPE_ unused_fcov_``NAME_; \ + assign unused_fcov_``NAME_ = fcov_``NAME_; +`endif + +// Define a signal and expression in the design for capture in functional coverage +`ifndef DV_FCOV_SIGNAL +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) +`else + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) \ + TYPE_ fcov_``NAME_; \ + assign fcov_``NAME_ = EXPR_; \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif + +// Define a signal and expression in the design for capture in functional coverage depending on +// design configuration. The input GEN_COND_ must be a constant or parameter. +`ifndef DV_FCOV_SIGNAL_GEN_IF +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) +`else + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) \ + TYPE_ fcov_``NAME_; \ + if (GEN_COND_) begin : g_fcov_``NAME_ \ + assign fcov_``NAME_ = EXPR_; \ + end else begin : g_no_fcov_``NAME_ \ + assign fcov_``NAME_ = DEFAULT_; \ + end \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core new file mode 100644 index 00000000..5f2fb800 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.core @@ -0,0 +1,17 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_macros" +description: "A collection of macros used in DV." + +filesets: + files_dv: + files: + - dv_macros.svh: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - files_dv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh new file mode 100644 index 00000000..2e5e1375 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -0,0 +1,536 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifdef UVM + `include "uvm_macros.svh" +`endif + +// UVM speficic macros +`ifndef gfn +`ifdef UVM + // verilog_lint: waive macro-name-style + `define gfn get_full_name() +`else + // verilog_lint: waive macro-name-style + `define gfn $sformatf("%m") +`endif +`endif + +`ifndef gtn + // verilog_lint: waive macro-name-style + `define gtn get_type_name() +`endif + +`ifndef gn + // verilog_lint: waive macro-name-style + `define gn get_name() +`endif + +`ifndef gmv + // verilog_lint: waive macro-name-style + `define gmv(csr) csr.get_mirrored_value() +`endif + +// cast base class obj holding extended class handle to extended class handle; +// throw error if cast fails +`ifndef downcast + // verilog_lint: waive macro-name-style + `define downcast(EXT_, BASE_, MSG_="", SEV_=fatal, ID_=`gfn) \ + begin \ + if (!$cast(EXT_, BASE_)) begin \ + `dv_``SEV_($sformatf({"Cast failed: base class variable %0s ", \ + "does not hold extended class %0s handle %s"}, \ + `"BASE_`", `"EXT_`", MSG_), ID_) \ + end \ + end +`endif + +// Note, UVM provides a macro `uvm_new_func -- which only applies to uvm_components +`ifndef uvm_object_new + `define uvm_object_new \ + function new (string name=""); \ + super.new(name); \ + endfunction : new +`endif + +`ifndef uvm_create_obj + `define uvm_create_obj(_type_name_, _inst_name_) \ + _inst_name_ = _type_name_::type_id::create(`"_inst_name_`"); +`endif + +`ifndef uvm_component_new + `define uvm_component_new \ + function new (string name="", uvm_component parent=null); \ + super.new(name, parent); \ + endfunction : new +`endif + +`ifndef uvm_create_comp + `define uvm_create_comp(_type_name_, _inst_name_) \ + _inst_name_ = _type_name_::type_id::create(`"_inst_name_`", this); +`endif + +// Convert arbitrary text / expression to string. +`ifndef DV_STRINGIFY + `define DV_STRINGIFY(I_) `"I_`" +`endif + +`ifndef DUT_HIER_STR + `define DUT_HIER_STR `DV_STRINGIFY(`DUT_HIER) +`endif + +// Common check macros used by DV_CHECK error and fatal macros. +// Note: Should not be called by user code +`ifndef DV_CHECK + `define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!(T_)) begin \ + `dv_``SEV_($sformatf("Check failed (%s) %s ", `"T_`", MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_EQ + `define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) == (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_NE + `define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) != (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_CASE_EQ + `define DV_CHECK_CASE_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) === (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s === %s (0x%0h [%0b] vs 0x%0h [%0b]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_CASE_NE + `define DV_CHECK_CASE_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) !== (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s !== %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_LT + `define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) < (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_GT + `define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) > (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_LE + `define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) <= (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_GE + `define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + begin \ + if (!((ACT_) >= (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ + `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \ + end \ + end +`endif + +`ifndef DV_CHECK_STREQ + `define DV_CHECK_STREQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + if (!((ACT_) == (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed \"%s\" == \"%s\" %s", ACT_, EXP_, MSG_), ID_) \ + end +`endif + +`ifndef DV_CHECK_STRNE + `define DV_CHECK_STRNE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ + if (!((ACT_) != (EXP_))) begin \ + `dv_``SEV_($sformatf("Check failed \"%s\" != \"%s\" %s", ACT_, EXP_, MSG_), ID_) \ + end +`endif + +// Fatal version of the checks +`ifndef DV_CHECK_FATAL + `define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn) \ + `DV_CHECK(T_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_EQ_FATAL + `define DV_CHECK_EQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_EQ(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_NE_FATAL + `define DV_CHECK_NE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_NE(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_LT_FATAL + `define DV_CHECK_LT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_LT(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_GT_FATAL + `define DV_CHECK_GT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_GT(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_LE_FATAL + `define DV_CHECK_LE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_LE(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_GE_FATAL + `define DV_CHECK_GE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_GE(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_STREQ_FATAL + `define DV_CHECK_STREQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_STREQ(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +`ifndef DV_CHECK_STRNE_FATAL + `define DV_CHECK_STRNE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \ + `DV_CHECK_STRNE(ACT_, EXP_, MSG_, fatal, ID_) +`endif + +// Shorthand for common foo.randomize() + fatal check +`ifndef DV_CHECK_RANDOMIZE_FATAL + `define DV_CHECK_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(VAR_.randomize(), MSG_, ID_) +`endif + +// Shorthand for common foo.randomize() with { } + fatal check +`ifndef DV_CHECK_RANDOMIZE_WITH_FATAL + `define DV_CHECK_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(VAR_.randomize() with {WITH_C_}, MSG_, ID_) +`endif + +// Shorthand for common std::randomize(foo) + fatal check +`ifndef DV_CHECK_STD_RANDOMIZE_FATAL + `define DV_CHECK_STD_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_) +`endif + +// Shorthand for common std::randomize(foo) with { } + fatal check +`ifndef DV_CHECK_STD_RANDOMIZE_WITH_FATAL + `define DV_CHECK_STD_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!",ID_=`gfn) \ + `DV_CHECK_FATAL(std::randomize(VAR_) with {WITH_C_}, MSG_, ID_) +`endif + +// Shorthand for common cls_inst.randomize(member) + fatal check +// Randomizes a specific member of a class instance. +`ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL + `define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(CLS_INST_.randomize(VAR_), MSG_, ID_) +`endif + +// Shorthand for common cls_inst.randomize(member) with { } + fatal check +// Randomizes a specific member of a class instance with inline constraints. +`ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL + `define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \ + `DV_CHECK_FATAL(CLS_INST_.randomize(VAR_) with {C_}, MSG_, ID_) +`endif + +// print static/dynamic 1d array or queue +`ifndef DV_PRINT_ARR_CONTENTS +`define DV_PRINT_ARR_CONTENTS(ARR_, V_=uvm_pkg::UVM_MEDIUM, ID_=`gfn) \ + begin \ + foreach (ARR_[i]) begin \ + `dv_info($sformatf("%s[%0d] = %0d (0x%0h)", `"ARR_`", i, ARR_[i], ARR_[i]), V_, ID_) \ + end \ + end +`endif + +// print non-empty tlm fifos that were uncompared at end of test +`ifndef DV_EOT_PRINT_TLM_FIFO_CONTENTS +`define DV_EOT_PRINT_TLM_FIFO_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \ + begin \ + while (!FIFO_.is_empty()) begin \ + TYP_ item; \ + void'(FIFO_.try_get(item)); \ + `dv_``SEV_($sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint()), ID_) \ + end \ + end +`endif + +// print non-empty tlm fifos that were uncompared at end of test +`ifndef DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS +`define DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \ + begin \ + foreach (FIFO_[i]) begin \ + while (!FIFO_[i].is_empty()) begin \ + TYP_ item; \ + void'(FIFO_[i].try_get(item)); \ + `dv_``SEV_($sformatf("%s[%0d] item uncompared:\n%s", `"FIFO_`", i, item.sprint()), ID_) \ + end \ + end \ + end +`endif + +// print non-empty tlm fifos that were uncompared at end of test +`ifndef DV_EOT_PRINT_Q_CONTENTS +`define DV_EOT_PRINT_Q_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \ + begin \ + while (Q_.size() != 0) begin \ + TYP_ item = Q_.pop_front(); \ + `dv_``SEV_($sformatf("%s item uncompared:\n%s", `"Q_`", item.sprint()), ID_) \ + end \ + end +`endif + +// print non-empty tlm fifos that were uncompared at end of test +`ifndef DV_EOT_PRINT_Q_ARR_CONTENTS +`define DV_EOT_PRINT_Q_ARR_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \ + begin \ + foreach (Q_[i]) begin \ + while (Q_[i].size() != 0) begin \ + TYP_ item = Q_[i].pop_front(); \ + `dv_``SEV_($sformatf("%s[%0d] item uncompared:\n%s", `"Q_`", i, item.sprint()), ID_) \ + end \ + end \ + end +`endif + +// check for non-empty mailbox and print items that were uncompared at end of test +`ifndef DV_EOT_PRINT_MAILBOX_CONTENTS +`define DV_EOT_PRINT_MAILBOX_CONTENTS(TYP_, MAILBOX_, SEV_=error, ID_=`gfn) \ + begin \ + while (MAILBOX_.num() != 0) begin \ + TYP_ item; \ + void'(MAILBOX_.try_get(item)); \ + `dv_``SEV_($sformatf("%s item uncompared:\n%s", `"MAILBOX_`", item.sprint()), ID_) \ + end \ + end +`endif + +// get parity - implemented as a macro so that it can be invoked in constraints as well +`ifndef GET_PARITY + `define GET_PARITY(val, odd=0) (^val ^ odd) +`endif + +// Wait a task or statement with exit condition +// Kill the thread when either the wait statement is completed or exit condition occurs +// input WAIT_ need to be a statement. Here are some examples +// `DV_SPINWAIT(wait(...);, "Wait for ...") +// `DV_SPINWAIT( +// while (1) begin +// ... +// end) +`ifndef DV_SPINWAIT_EXIT +`define DV_SPINWAIT_EXIT(WAIT_, EXIT_, MSG_ = "exit condition occurred!", ID_ =`gfn) \ + begin \ + fork begin \ + fork \ + begin \ + WAIT_ \ + end \ + begin \ + EXIT_ \ + if (MSG_ != "") begin \ + `dv_info(MSG_, uvm_pkg::UVM_HIGH, ID_) \ + end \ + end \ + join_any \ + disable fork; \ + end join \ + end +`endif + +// wait a task or statement with timer watchdog +`ifndef DV_SPINWAIT +`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \ + `DV_SPINWAIT_EXIT(WAIT_, wait_timeout(TIMEOUT_NS_, ID_, MSG_);, "", ID_) +`endif + +// Control assertions in the DUT. +// +// This macro is invoked in top level testbench that instantiates the DUT. It spawns off an initial +// block that forever waits for a resource of type bit named by the string arg ~LABEL_~ that +// can be set by any entity in the testbench. Based on the value set, it enables or disables the +// assertions at the hierarchy of the provided path. The entity setting the resource value invokes +// uvm_config_db#(bit)::set(...) and this macro calls the corresponding get. +// +// LABEL_ : Name of the assertion control resource bit (string). +// HIER_ : Path to the module within which the assertion is controlled. +// LEVELS_: Number of levels within the module to control the assertions. +// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m. +// ID_ : Identifier string used for UVM logs. +`ifndef DV_ASSERT_CTRL +`define DV_ASSERT_CTRL(LABEL_, HIER_, LEVELS_ = 0, SCOPE_ = "", ID_ = $sformatf("%m")) \ + initial begin \ + bit assert_en; \ + forever begin \ + uvm_config_db#(bit)::wait_modified(null, SCOPE_, LABEL_); \ + if (!uvm_config_db#(bit)::get(null, SCOPE_, LABEL_, assert_en)) begin \ + `uvm_fatal(ID_, $sformatf("Failed to get \"%0s\" from uvm_config_db", LABEL_)) \ + end \ + if (assert_en) begin \ + `uvm_info(ID_, $sformatf("Enabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \ + $asserton(LEVELS_, HIER_); \ + end else begin \ + `uvm_info(ID_, $sformatf("Disabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \ + $assertoff(LEVELS_, HIER_); \ + end \ + end \ + end +`endif + +// Retrieves a plusarg value representing an enum literal. +// +// The plusarg is parsed as a string, which needs to be converted into the enum literal whose name +// matches the string. This functionality is provided by the UVM helper function below. +// +// ENUM_: The enum type. +// VAR_: The enum variable to which the plusarg value will be set (must be declared already). +// PLUSARG_: the name of the plusarg (as raw text). This is typically the same as the enum variable. +// CHECK_EXISTS_: Throws a fatal error if the plusarg is not set. +`ifndef DV_GET_ENUM_PLUSARG +`define DV_GET_ENUM_PLUSARG(ENUM_, VAR_, PLUSARG_ = VAR_, CHECK_EXISTS_ = 0, ID_ = `gfn) \ + begin \ + string str; \ + if ($value$plusargs("``PLUSARG_``=%0s", str)) begin \ + if (!uvm_enum_wrapper#(ENUM_)::from_name(str, VAR_)) begin \ + `uvm_fatal(ID_, $sformatf("Cannot find %s from enum ``ENUM_``", VAR_.name())) \ + end \ + end else if (CHECK_EXISTS_) begin \ + `uvm_fatal(ID_, "Please pass the plusarg +``PLUSARG_``=<``ENUM_``-literal>") \ + end \ + end +`endif + +// Enable / disable assertions at a module hierarchy identified by LABEL_. +// +// This goes in conjunction with `DV_ASSERT_CTRL() macro above, but is invoked in the entity that is +// sending the req to turn on / off the assertions. Note that that piece of code invoking this macro +// does not have the information on the actual hierarchical path to the module or the levels - this +// is 'wrapped' into the LABEL_ instead. DV user needs to uniquify the label sufficienly enough to +// reflect it. +// +// LABEL_ : Name of the assertion control resource bit (string). +// VALUE_ : Value of the control bit - 1 - enable assertions, 0 - disable assertions. +// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m. +`ifndef DV_ASSERT_CTRL_REQ +`define DV_ASSERT_CTRL_REQ(LABEL_, VALUE_, SCOPE_="") \ + begin \ + uvm_config_db#(bit)::set(null, SCOPE_, LABEL_, VALUE_); \ + end +`endif + +// Macros for logging (info, warning, error and fatal severities). +// +// These are meant to be invoked in modules and interfaces that are shared between DV and Verilator +// testbenches. We waive the lint requirement for these to be in uppercase, since they are +// UVM-adjacent. +`ifdef UVM +`ifndef dv_info + // verilog_lint: waive macro-name-style + `define dv_info(MSG_, VERBOSITY_ = uvm_pkg::UVM_LOW, ID_ = $sformatf("%m")) \ + if (uvm_pkg::uvm_report_enabled(VERBOSITY_, uvm_pkg::UVM_INFO, ID_)) begin \ + uvm_pkg::uvm_report_info(ID_, MSG_, VERBOSITY_, `uvm_file, `uvm_line, "", 1); \ + end +`endif + +`ifndef dv_warning + // verilog_lint: waive macro-name-style + `define dv_warning(MSG_, ID_ = $sformatf("%m")) \ + if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_WARNING, ID_)) begin \ + uvm_pkg::uvm_report_warning(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end +`endif + +`ifndef dv_error + // verilog_lint: waive macro-name-style + `define dv_error(MSG_, ID_ = $sformatf("%m")) \ + if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_ERROR, ID_)) begin \ + uvm_pkg::uvm_report_error(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end +`endif + +`ifndef dv_fatal + // verilog_lint: waive macro-name-style + `define dv_fatal(MSG_, ID_ = $sformatf("%m")) \ + if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_FATAL, ID_)) begin \ + uvm_pkg::uvm_report_fatal(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end +`endif + +`else // UVM + +`ifndef dv_info + // verilog_lint: waive macro-name-style + `define dv_info(MSG_, VERBOSITY = DUMMY_, ID_ = $sformatf("%m")) \ + $display("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef dv_warning + // verilog_lint: waive macro-name-style + `define dv_warning(MSG_, ID_ = $sformatf("%m")) \ + $warning("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef dv_error + // verilog_lint: waive macro-name-style + `define dv_error(MSG_, ID_ = $sformatf("%m")) \ + $error("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`ifndef dv_fatal + // verilog_lint: waive macro-name-style + `define dv_fatal(MSG_, ID_ = $sformatf("%m")) \ + $fatal("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_); +`endif + +`endif // UVM + +// Macros for constrain clk with common frequencies +// constrain clock to run at 24Mhz - 100Mhz and use higher weights on 24, 25, 48, 50, 100 +`ifndef DV_COMMON_CLK_CONSTRAINT +`define DV_COMMON_CLK_CONSTRAINT(FREQ_) \ + FREQ_ dist { \ + [24:25] :/ 2, \ + [26:47] :/ 1, \ + [48:50] :/ 2, \ + [51:95] :/ 1, \ + 96 :/ 1, \ + [97:99] :/ 1, \ + 100 :/ 1 \ + }; +`endif diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv new file mode 100644 index 00000000..91e3337e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_catcher.sv @@ -0,0 +1,46 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// Report catcher/demoter +class dv_report_catcher extends uvm_report_catcher; + + // Stores a new severity indexed by the ID and + // the regular expression to match the message + protected uvm_severity m_changed_sev[string][string]; + + `uvm_object_utils(dv_report_catcher) + `uvm_object_new + + // Called for all report messages - defined in uvm_report_catcher + virtual function action_e catch(); + string id = get_id(); + if (m_changed_sev.exists(id)) begin + string report_msg = get_message(); + foreach (m_changed_sev[id][msg]) begin + if (uvm_re_match(msg, report_msg)) begin + set_severity(m_changed_sev[id][msg]); + end + end + end + return THROW; + endfunction + + // Change severity of a message with ID == id and message text + // matching msg which is treated as a regular expression + virtual function void add_change_sev(string id, string msg, uvm_severity sev); + m_changed_sev[id][msg] = sev; + endfunction + + // Remove a change entry + // If msg == "" then remove all changes for a given id + virtual function void remove_change_sev(string id, string msg = ""); + if (m_changed_sev.exists(id)) + if (msg == "") begin + // Delete all with id if message is blank + m_changed_sev.delete(id); + end else if (m_changed_sev[id].exists(msg)) begin + m_changed_sev[id].delete(msg); + end + endfunction + +endclass diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv new file mode 100644 index 00000000..a5d7440e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_report_server.sv @@ -0,0 +1,65 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Standardize look & feel of report phase and uvm logging messages. +class dv_report_server extends uvm_default_report_server; + + bit show_file_line = 1'b1; + // if enabled, show the relative path of the file. By default only show file name + bit show_file_path = 1'b0; + bit use_default_uvm_report_message_format = 1'b0; + + function new (string name = ""); + super.new(name); + // provide ability to override these knobs over cli + void'($value$plusargs("show_file_line=%0b", show_file_line)); + void'($value$plusargs("show_file_path=%0b", show_file_path)); + void'($value$plusargs("use_default_uvm_report_message_format=%0b", + use_default_uvm_report_message_format)); + endfunction + + function void report_summarize(UVM_FILE file = 0); + int num_uvm_warning; + int num_uvm_error; + int num_uvm_fatal; + + num_uvm_warning = get_severity_count(UVM_WARNING); + num_uvm_error = get_severity_count(UVM_ERROR); + num_uvm_fatal = get_severity_count(UVM_FATAL); + + // Print default summary report + super.report_summarize(file); + + // Print final test pass-fail - external tool can use this signature for test status + // Treat UVM_WARNINGs as a sign of test failure since it could silently result in false pass + dv_test_status_pkg::dv_test_status((num_uvm_warning + num_uvm_error + num_uvm_fatal) == 0); + endfunction + + // Override default messaging format to standard "pretty" format for all testbenches + virtual function string compose_report_message(uvm_report_message report_message, + string report_object_name = ""); + + if (use_default_uvm_report_message_format) begin + return (super.compose_report_message(report_message, report_object_name)); + end else begin + uvm_severity severity = report_message.get_severity(); + string filename = report_message.get_filename(); + int line = report_message.get_line(); + string obj_name = report_message.get_report_object().get_full_name(); + string id = report_message.get_id(); + string message = report_message.get_message(); + string file_line; + + if (show_file_line && filename != "") begin + if (!show_file_path) filename = str_utils_pkg::str_path_basename(filename); + file_line = $sformatf("(%0s:%0d) ", filename, line); + end + obj_name = {obj_name, ((obj_name != "") ? " " : "")}; + compose_report_message = $sformatf({"%0s @ %t: ", file_line, obj_name, "[%0s] %0s"}, + severity.name(), $realtime, id, message); + return compose_report_message; + end + endfunction + +endclass diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core new file mode 100644 index 00000000..bbec1b05 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status.core @@ -0,0 +1,17 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_test_status" +description: "DV test status reporting utilities" + +filesets: + files_dv: + files: + - dv_test_status_pkg.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv new file mode 100644 index 00000000..3a81ddfc --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_test_status_pkg.sv @@ -0,0 +1,31 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package dv_test_status_pkg; + + // Prints the test status signature & banner. + // + // This function takes a boolean arg indicating whether the test passed or failed and prints the + // signature along with a banner. The signature can be used by external scripts to determine if + // the test passed or failed. + function automatic void dv_test_status(bit passed); + if (passed) begin + $display("\nTEST PASSED CHECKS"); + $display(" _____ _ _ _ "); + $display("|_ _|__ ___| |_ _ __ __ _ ___ ___ ___ __| | |"); + $display(" | |/ _ \\/ __| __| | '_ \\ / _` / __/ __|/ _ \\/ _` | |"); + $display(" | | __/\\__ \\ |_ | |_) | (_| \\__ \\__ \\ __/ (_| |_|"); + $display(" |_|\\___||___/\\__| | .__/ \\__,_|___/___/\\___|\\__,_(_)"); + $display(" |_| \n"); + end else begin + $display("\nTEST FAILED CHECKS"); + $display(" _____ _ __ _ _ _ _ "); + $display("|_ _|__ ___| |_ / _| __ _(_) | ___ __| | |"); + $display(" | |/ _ \\/ __| __| | |_ / _` | | |/ _ \\/ _` | |"); + $display(" | | __/\\__ \\ |_ | _| (_| | | | __/ (_| |_|"); + $display(" |_|\\___||___/\\__| |_| \\__,_|_|_|\\___|\\__,_(_)\n"); + end + endfunction + +endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core new file mode 100644 index 00000000..1e405236 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils.core @@ -0,0 +1,28 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dv_utils" +description: "DV utilities" + +filesets: + files_dv: + depend: + - lowrisc:dv:dv_macros + - lowrisc:dv:dv_fcov_macros + - lowrisc:dv:common_ifs + - lowrisc:prim:assert:0.1 + - lowrisc:cve2:bus_params_pkg + - lowrisc:dv:str_utils + - lowrisc:dv:dv_test_status + files: + - dv_utils_pkg.sv + - dv_report_catcher.sv: {is_include_file: true} + - dv_report_server.sv: {is_include_file: true} + - dv_vif_wrap.sv: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv new file mode 100644 index 00000000..62f3b765 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_utils_pkg.sv @@ -0,0 +1,223 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package dv_utils_pkg; + // dep packages + import uvm_pkg::*; + import bus_params_pkg::*; + + // macro includes + `include "dv_macros.svh" +`ifdef UVM + `include "uvm_macros.svh" +`endif + + // common parameters used across all benches + parameter int NUM_MAX_INTERRUPTS = 32; + typedef logic [NUM_MAX_INTERRUPTS-1:0] interrupt_t; + + parameter int NUM_MAX_ALERTS = 32; + typedef logic [NUM_MAX_ALERTS-1:0] alert_t; + + // types & variables + typedef bit [31:0] uint; + typedef bit [7:0] uint8; + typedef bit [15:0] uint16; + typedef bit [31:0] uint32; + typedef bit [63:0] uint64; + + // TODO: The above typedefs violate the name rule, which is fixed below. Cleanup the codebase to + // use the typedefs below and remove the ones above. + typedef bit [7:0] uint8_t; + typedef bit [15:0] uint16_t; + typedef bit [31:0] uint32_t; + typedef bit [63:0] uint64_t; + + // typedef parameterized pins_if for ease of implementation for interrupts and alerts + typedef virtual pins_if #(NUM_MAX_INTERRUPTS) intr_vif; + typedef virtual pins_if #(1) devmode_vif; + + // interface direction / mode - Host or Device + typedef enum bit { + Host, + Device + } if_mode_e; + + // compare operator types + typedef enum { + CompareOpEq, + CompareOpCaseEq, + CompareOpNe, + CompareOpCaseNe, + CompareOpGt, + CompareOpGe, + CompareOpLt, + CompareOpLe + } compare_op_e; + + // mem address struct + typedef struct { + uvm_reg_addr_t start_addr; + uvm_reg_addr_t end_addr; + } addr_range_t; + + // Enum representing a bus operation type - read or write. + typedef enum bit { + BusOpWrite = 1'b0, + BusOpRead = 1'b1 + } bus_op_e; + + // Enum representing a type of host requests - read only, write only or random read & write + typedef enum int { + HostReqNone = 0, + HostReqReadOnly = 1, + HostReqWriteOnly = 2, + HostReqReadWrite = 3 + } host_req_type_e; + + // Enum representing clock frequency difference on 2 clocks + typedef enum bit [1:0] { + ClkFreqDiffNone, + ClkFreqDiffSmall, + ClkFreqDiffBig, + ClkFreqDiffAny + } clk_freq_diff_e; + + string msg_id = "dv_utils_pkg"; + + // return the smaller value of 2 inputs + function automatic int min2(int a, int b); + return (a < b) ? a : b; + endfunction + + // return the bigger value of 2 inputs + function automatic int max2(int a, int b); + return (a > b) ? a : b; + endfunction + + // return the biggest value within the given queue of integers. + function automatic int max(const ref int int_q[$]); + `DV_CHECK_GT_FATAL(int_q.size(), 0, "max function cannot accept an empty queue of integers!", + msg_id) + // Assign the first value from the queue in case of negative integers. + max = int_q[0]; + foreach (int_q[i]) max = max2(max, int_q[i]); + return max; + endfunction + + // get absolute value of the input. Usage: absolute(val) or absolute(a - b) + function automatic uint absolute(int val); + return val >= 0 ? val : -val; + endfunction + + // endian swaps a 32-bit data word + function automatic logic [31:0] endian_swap(logic [31:0] data); + return {<<8{data}}; + endfunction + + // endian swaps bytes at a word granularity, while preserving overall word ordering. + // + // e.g. if `arr[] = '{'h0, 'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7}`, this function will produce: + // `'{'h3, 'h2, 'h1, 'h0, 'h7, 'h6, 'h5, 'h4}` + function automatic void endian_swap_byte_arr(ref bit [7:0] arr[]); + arr = {<< byte {arr}}; + arr = {<< 32 {arr}}; + endfunction + +`ifdef UVM + // Simple function to set max errors before quitting sim + function automatic void set_max_quit_count(int n); + uvm_report_server report_server = uvm_report_server::get_server(); + report_server.set_max_quit_count(n); + endfunction + + // return if uvm_fatal occurred + function automatic bit has_uvm_fatal_occurred(); + uvm_report_server report_server = uvm_report_server::get_server(); + return report_server.get_severity_count(UVM_FATAL) > 0; + endfunction + + // task that waits for the specfied timeout + task automatic wait_timeout(input uint timeout_ns, + input string error_msg_id = msg_id, + input string error_msg = "timeout occurred!", + input bit report_fatal = 1); + #(timeout_ns * 1ns); + if (report_fatal) `uvm_fatal(error_msg_id, error_msg) + else `uvm_error(error_msg_id, error_msg) + endtask : wait_timeout + + // get masked data based on provided byte mask; if csr reg handle is provided (optional) then + // masked bytes from csr's mirrored value are returned, else masked bytes are 0's + function automatic bit [bus_params_pkg::BUS_DW-1:0] + get_masked_data(bit [bus_params_pkg::BUS_DW-1:0] data, + bit [bus_params_pkg::BUS_DBW-1:0] mask, + uvm_reg csr = null); + bit [bus_params_pkg::BUS_DW-1:0] csr_data; + csr_data = (csr != null) ? csr.get_mirrored_value() : '0; + get_masked_data = data; + foreach (mask[i]) begin + if (~mask[i]) get_masked_data[i * 8 +: 8] = csr_data[i * 8 +: 8]; + end + endfunction + + // create a sequence by name and return the handle of uvm_sequence + function automatic uvm_sequence create_seq_by_name(string seq_name); + uvm_object obj; + uvm_factory factory; + uvm_sequence seq; + + factory = uvm_factory::get(); + obj = factory.create_object_by_name(seq_name, "", seq_name); + if (obj == null) begin + // print factory overrides to help debug + factory.print(1); + `uvm_fatal(msg_id, $sformatf("could not create %0s seq", seq_name)) + end + if (!$cast(seq, obj)) begin + `uvm_fatal(msg_id, $sformatf("cast failed - %0s is not a uvm_sequence", seq_name)) + end + return seq; + endfunction +`endif + + // Returns the hierarchical path to the interface / module N levels up. + // + // Meant to be invoked inside a module or interface. + // hier: String input of the interface / module, typically $sformatf("%m"). + // n_levels_up: Integer number of levels up the hierarchy to omit. + // Example: if (hier = tb.dut.foo.bar, n_levels_up = 2), then return tb.dut + function automatic string get_parent_hier(string hier, int n_levels_up = 1); + int idx; + int level; + if (n_levels_up <= 0) return hier; + for (idx = hier.len() - 1; idx >= 0; idx--) begin + if (hier[idx] == ".") level++; + if (level == n_levels_up) break; + end + return (hier.substr(0, idx - 1)); + endfunction + + // Periodically check for the existence of a magic file (dv.stop). Exit if it exists. This + // provides a mechanism to gracefully kill a simulation without direct access to the process. + task automatic poll_for_stop(uint interval_ns = 10_000, string filename = "dv.stop"); + fork + while (1) begin + #(interval_ns * 1ns); + if (!$system($sformatf("test -f %0s", filename))) begin + $system($sformatf("rm %0s", filename)); + `dv_fatal($sformatf("Found %0s file. Exiting!", filename), "poll_for_stop") + end + end + join_none + endtask : poll_for_stop + + // sources +`ifdef UVM + `include "dv_report_catcher.sv" + `include "dv_report_server.sv" + `include "dv_vif_wrap.sv" +`endif + +endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv new file mode 100644 index 00000000..61d99479 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/vendor/lowrisc_ip/dv/sv/dv_utils/dv_vif_wrap.sv @@ -0,0 +1,96 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Abstract class meant to hold arbitrary virtual interface handles. +// +// Written primarily for an interface which implements functional coverage, this could be used +// for other purposes as well. This abstract class provides utilities & macros to retrieve +// virtual interface handles that are bound to a DUT's sub-modules. These sub-module interfaces must +// self-register using the `DV_VIF_WRAP_SET_VIF()` macro (see details below). The extended class +// then implements the `get_vifs()` method using the `DV_VIF_WRAP_GET_VIF*` macros below to retrieve +// the sub-module interface handles it maintains. +virtual class dv_vif_wrap; + string hier; // Represents the hierarchy of the parent module or interface. + string name; // Name of the class instance. + + function new(string hier, string name = ""); + this.hier = hier; + this.name = name; + endfunction + + // Abstract method implemented by the extended class. It is recommended to invoke the helper + // macros below rather than manually define it. + pure virtual task get_vifs(); + +endclass + +// Helper macros. +// +// These are defined in the file itself since they are tightly coupled to the class definition +// above. These are scoped globally so that extended classes can invoke them. + +// Enable an interface to register itself (set its handle into the config db). +// +// Meant to be invoked from an interface. The macros invocation causes the interface to register +// itself into the uvm_resource_db pool. The derived class of dv_vif_wrap retrieves the handle to +// that interface handle from the uvm_resource db pool. +// +// SV LRM does not yet allow referencing the instance of an interface within itself as one +// would in case of a class using the ~this~ keyword. However, most major simulators actually +// support this in their own custom way. On VCS, a reference to self within the interface can be set +// using `interface::self()` construct. On Xcelium, this is achieved by simply referencing the +// interface name. +// +// _IF: The SV interface +// _VIF: The corresponding virtual interface handle name +// _LEVEL: # of hierarchical levels the module to which the SV interface is bound, starting at the +// top level DUT instance. +`define DV_VIF_WRAP_SET_VIF(_IF, _VIF, _LEVEL = 0) \ + import uvm_pkg::*; \ + function automatic void self_register(); \ + string path; \ + virtual _IF vif; \ + /* Initial block adds another level in the path hierarchy which needs to be split out. */ \ + /* Add one more to go one level up the interface instance. */ \ + /* Example: tb.dut.core.u_foo_if.self_register -> tb.dut.core. */ \ + path = dv_utils_pkg::get_parent_hier(.hier($sformatf("%m")), .n_levels_up(2 + _LEVEL)); \ +`ifdef VCS \ + vif = interface::self(); \ +`elsif XCELIUM \ + vif = _IF; \ +`else \ + vif = _IF; \ +`endif \ + uvm_pkg::uvm_resource_db#(virtual _IF)::set(path, `"_VIF`", vif); \ + endfunction \ + initial self_register(); + +// Enables the retrieval of individual vifs. +// +// The three macros below go together to define the _get_vifs() task in the extended class. +`define DV_VIF_WRAP_GET_VIFS_BEGIN \ + task get_vifs(); \ + fork \ + +// To avoid race condition between the instant when an interface handle is set into the config db +// and the instant when it is retrieved (in the same time step, at t = 0), the macro below invokes +// uvm_config_db#(..)::wait_modified() to ensure that the retrieval is done only after the set. +`define DV_VIF_WRAP_GET_VIF(_IF, _VIF) \ + begin \ + bit vif_found; \ + /* At most 2 retries. */ \ + repeat (2) begin \ + /* Force the evaluation at the end of the time step. */ \ + #0; \ + if (uvm_pkg::uvm_resource_db#(virtual _IF)::read_by_name(hier, `"_VIF`", _VIF)) begin \ + vif_found = 1'b1; \ + break; \ + end \ + end \ + `DV_CHECK_FATAL(vif_found, {`"_VIF`", " not found in the resource db"}, hier) \ + end + +`define DV_VIF_WRAP_GET_VIFS_END \ + join \ + endtask diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.core index f11d35c1..1d8a39f7 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.core @@ -64,3 +64,4 @@ targets: - files_rtl - ff_regfile - target_sim? (files_clk_gate) + - target_sim_sc? (files_clk_gate) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson index 00ea518e..b122083e 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/openhwgroup/cv32e40p.git - rev: c8d65849ec060c6f7bc62325b46ba0ab7eae8805 + rev: 370cf19b3b60cbdc847ff102551392dd501029a2 } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson index 462a2848..5b2ce889 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/openhwgroup/cv32e40p.git", - rev: "c8d65849ec060c6f7bc62325b46ba0ab7eae8805", + rev: "370cf19b3b60cbdc847ff102551392dd501029a2", }, patch_dir: "patches/openhwgroup_cv32e40p", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore index ef351b19..66eb251a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore @@ -18,3 +18,9 @@ TAGS /build /Bender.lock /Bender.local +golden_reference_design +golden.src +revised.src +cadence_conformal +synopsys_formality +questa_autocheck diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh index 8c4ae99f..a89ed4e4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh @@ -679,22 +679,22 @@ class instr_trace_t; // decode and print instruction case (instr[11:8]) // cv.starti, cv.endi - 4'b0000, 4'b0010: str = $sformatf("%-16s %d, 0x%0x", mnemonic, rd[0], imm_iz_type); + 4'b0000, 4'b0010: str = $sformatf("%-16s %d, 0x%0x", mnemonic, instr[7], imm_iz_type); // cv.counti - 4'b0100: str = $sformatf("%-16s %d, %d", mnemonic, rd[0], imm_iz_type); + 4'b0100: str = $sformatf("%-16s %d, %d", mnemonic, instr[7], imm_iz_type); // cv.start, cv.end, cv.count 4'b0001, 4'b0011, 4'b0101: begin regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %d, %s", mnemonic, rd[0], regAddrToStr(rs1)); + str = $sformatf("%-16s %d, %s", mnemonic, instr[7], regAddrToStr(rs1)); end // cv.setupi 4'b0110: begin - str = $sformatf("%-16s %d, %d, 0x%0x", mnemonic, rd[0], imm_iz_type, rs1); + str = $sformatf("%-16s %d, %d, 0x%0x", mnemonic, instr[7], imm_iz_type, rs1); end // cv.setup 4'b0111: begin regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %d, %s, 0x%0x", mnemonic, rd[0], regAddrToStr(rs1), imm_iz_type); + str = $sformatf("%-16s %d, %s, 0x%0x", mnemonic, instr[7], regAddrToStr(rs1), imm_iz_type); end endcase end @@ -861,7 +861,7 @@ class instr_trace_t; endcase str_sci = ""; end - + // shuffle/pack 6'b110000: begin if (instr[14:12] == 3'b111) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv index ca158f96..13a5beb0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv @@ -73,6 +73,10 @@ module cv32e40p_rvfi input logic is_compressed_id_i, input logic ebrk_insn_dec_i, + input logic ecall_insn_dec_i, + + input logic mret_insn_dec_i, + input logic mret_dec_i, input logic [5:0] csr_cause_i, @@ -126,6 +130,9 @@ module cv32e40p_rvfi input logic [31:0] data_wdata_ex_i, input logic lsu_split_q_ex_i, + input logic mult_ready_i, + input logic alu_ready_i, + //// WB probes //// input logic [31:0] pc_wb_i, input logic wb_ready_i, @@ -202,6 +209,7 @@ module cv32e40p_rvfi input logic csr_we_i, input logic [31:0] csr_wdata_int_i, + input logic csr_fregs_we_i, input logic csr_jvt_we_i, input Status_t csr_mstatus_n_i, input Status_t csr_mstatus_q_i, @@ -617,6 +625,8 @@ module cv32e40p_rvfi logic pc_mux_interrupt; logic pc_mux_nmi; + localparam logic [31:0] MSTATUS_WRITE_MASK = 32'h0000_6088; + `include "pipe_freeze_trace.sv" `include "insn_trace.sv" @@ -633,6 +643,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; logic [2:0] saved_debug_cause; integer next_send; + event e_empty_queue; function void empty_fifo(); integer i, trace_q_size; trace_q_size = wb_bypass_trace_q.size(); @@ -648,6 +659,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; new_rvfi_trace.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; rvfi_trace_q.push_back(new_rvfi_trace); next_send = next_send + 1; + ->e_empty_queue; end else begin wb_bypass_trace_q.push_back(new_rvfi_trace); end @@ -658,6 +670,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; /* * Function used to alocate a new insn and send it to the rvfi driver */ + event e_add_to_bypass; function void send_rvfi(insn_trace_t m_wb_insn); insn_trace_t new_rvfi_trace; new_rvfi_trace = new(); @@ -667,6 +680,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; next_send = next_send + 1; end else begin wb_bypass_trace_q.push_back(new_rvfi_trace); + ->e_add_to_bypass; end empty_fifo(); endfunction @@ -837,7 +851,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; //CSR rvfi_csr_mstatus_rmask = new_rvfi_trace.m_csr.mstatus_rmask | new_rvfi_trace.m_csr.mstatus_fs_rmask; - rvfi_csr_mstatus_wmask = new_rvfi_trace.m_csr.mstatus_wmask; + rvfi_csr_mstatus_wmask = new_rvfi_trace.m_csr.mstatus_wmask & MSTATUS_WRITE_MASK; rvfi_csr_mstatus_wmask[31] = new_rvfi_trace.m_csr.mstatus_fs_wmask[31]; rvfi_csr_mstatus_wmask[14:13] = new_rvfi_trace.m_csr.mstatus_fs_wmask[14:13]; @@ -870,7 +884,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end rvfi_csr_mstatus_wdata[30:18] = '0; // MPRV is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[17] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.mprv; + rvfi_csr_mstatus_wdata[17] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.mprv; rvfi_csr_mstatus_wdata[16:15] = '0; if (FPU == 1 && ZFINX == 0) begin rvfi_csr_mstatus_wdata[14:13] = new_rvfi_trace.m_csr.mstatus_fs_wdata; @@ -882,11 +896,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; rvfi_csr_mstatus_wdata[7] = new_rvfi_trace.m_csr.mstatus_wdata.mpie; rvfi_csr_mstatus_wdata[6:5] = '0; // UPIE is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[4] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.upie; + rvfi_csr_mstatus_wdata[4] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.upie; rvfi_csr_mstatus_wdata[3] = new_rvfi_trace.m_csr.mstatus_wdata.mie; rvfi_csr_mstatus_wdata[2:1] = '0; // UIE is not implemented in the target configuration, writes to it are ignored - rvfi_csr_mstatus_wdata[0] = 1'b0;//new_rvfi_trace.m_csr.mstatus_wdata.uie; + rvfi_csr_mstatus_wdata[0] = 1'b0; //new_rvfi_trace.m_csr.mstatus_wdata.uie; `SET_RVFI_CSR_FROM_INSN(misa) `SET_RVFI_CSR_FROM_INSN(mie) @@ -1111,6 +1125,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; * The third updates the rvfi interface */ `define CSR_FROM_PIPE(TRACE_NAME, CSR_NAME) \ + if(!trace_``TRACE_NAME``.m_csr.``CSR_NAME``_we) begin \ + trace_``TRACE_NAME``.m_csr.``CSR_NAME``_wdata = r_pipe_freeze_trace.csr.``CSR_NAME``_n; \ + end\ if (r_pipe_freeze_trace.csr.``CSR_NAME``_we) begin \ trace_``TRACE_NAME``.m_csr.``CSR_NAME``_we = r_pipe_freeze_trace.csr.``CSR_NAME``_we; \ trace_``TRACE_NAME``.m_csr.``CSR_NAME``_wdata = r_pipe_freeze_trace.csr.``CSR_NAME``_n; \ @@ -1120,9 +1137,14 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_``TRACE_NAME``.m_csr.``CSR_NAME``_rmask = '1; event e_mstatus_to_id; + event e_fregs_dirty_1, e_fregs_dirty_2, e_fregs_dirty_3; function void mstatus_to_id(); `CSR_FROM_PIPE(id, mstatus) `CSR_FROM_PIPE(id, mstatus_fs) + if(r_pipe_freeze_trace.csr.fregs_we && !r_pipe_freeze_trace.csr.mstatus_fs_we && !(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we)) begin //writes happening in ex that needs to be reported to id + trace_id.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + ->e_fregs_dirty_2; + end ->e_mstatus_to_id; endfunction //those event are for debug purpose @@ -1133,10 +1155,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; e_dev_commit_rf_to_ex_3, e_dev_commit_rf_to_ex_4, e_dev_commit_rf_to_ex_5; - event e_if_2_id_1, e_if_2_id_2; + event e_if_2_id_1, e_if_2_id_2, e_if_2_id_3, e_if_2_id_4; event e_ex_to_wb_1, e_ex_to_wb_2; event e_id_to_ex_1, e_id_to_ex_2; event e_commit_dpc; + event e_csr_in_ex, e_csr_irq; event e_send_rvfi_trace_apu_resp; event @@ -1160,12 +1183,17 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(apu_resp, fcsr) `CSR_FROM_PIPE(apu_resp, fflags) - // `CSR_FROM_PIPE(apu_resp, mstatus) `CSR_FROM_PIPE(apu_resp, mstatus_fs) - if (r_pipe_freeze_trace.csr.mstatus_we) begin + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_id.m_order > trace_apu_resp.m_order)) begin + trace_id.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + end + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_ex.m_order > trace_apu_resp.m_order)) begin trace_ex.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; end + if (r_pipe_freeze_trace.csr.mstatus_fs_we && (trace_wb.m_order > trace_apu_resp.m_order)) begin + trace_wb.m_csr.mstatus_fs_rdata = r_pipe_freeze_trace.csr.mstatus_fs_n; + end endfunction function void csr_to_apu_req(); @@ -1243,14 +1271,22 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_is_irq_start; bit s_id_done; function void if_to_id(); + if (trace_id.m_valid) begin + `CSR_FROM_PIPE(id, misa) + `CSR_FROM_PIPE(id, tdata1) + `CSR_FROM_PIPE(id, tdata2) + tinfo_to_id(); + `CSR_FROM_PIPE(id, mip) + send_rvfi(trace_id); + end trace_id.init(trace_if); trace_id.m_trap = ~r_pipe_freeze_trace.minstret; - trace_id.m_is_illegal = r_pipe_freeze_trace.is_illegal; + trace_id.m_is_illegal = trace_id.m_is_illegal | r_pipe_freeze_trace.is_illegal; + `CSR_FROM_PIPE(id, dpc) s_is_pc_set = 1'b0; s_is_irq_start = 1'b0; trace_if.m_valid = 1'b0; s_id_done = 1'b0; - `CSR_FROM_PIPE(id, dpc) endfunction function logic [31:0] be_to_mask(logic [3:0] be); @@ -1280,34 +1316,44 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_core_is_decoding; // For readability, ctrl_fsm is DECODE or DECODE_HWLOOP - trace_if = new(); - trace_id = new(); - trace_ex = new(); - trace_wb = new(); - s_new_valid_insn = 1'b0; - s_ex_valid_adjusted = 1'b0; + bit s_ex_reg_we_adjusted; //ex_reg_we + bit s_rf_we_wb_adjusted; // + + bit s_dont_override_mstatus_fs_id; + + trace_if = new(); + trace_id = new(); + trace_ex = new(); + trace_wb = new(); + s_new_valid_insn = 1'b0; + s_ex_valid_adjusted = 1'b0; + + s_id_done = 1'b0; + s_apu_wb_ok = 1'b0; + s_apu_0_cycle_reps = 1'b0; + + next_send = 1; + cnt_data_req = 0; + cnt_data_resp = 0; + cnt_apu_req = 0; + cnt_apu_resp = 0; + csr_is_irq = '0; + is_dbg_taken = '0; + s_was_flush = 1'b0; - s_id_done = 1'b0; - s_apu_wb_ok = 1'b0; - s_apu_0_cycle_reps = 1'b0; + s_is_pc_set = 1'b0; + s_is_irq_start = 1'b0; - next_send = 1; - cnt_data_req = 0; - cnt_data_resp = 0; - cnt_apu_req = 0; - cnt_apu_resp = 0; - csr_is_irq = '0; - is_dbg_taken = '0; - s_was_flush = 1'b0; + s_is_pc_set = 1'b0; + s_is_irq_start = 1'b0; + s_skip_wb = 1'b0; - s_is_pc_set = 1'b0; - s_is_irq_start = 1'b0; + s_core_is_decoding = 1'b0; - s_is_pc_set = 1'b0; - s_is_irq_start = 1'b0; - s_skip_wb = 1'b0; + s_ex_reg_we_adjusted = 1'b0; + s_rf_we_wb_adjusted = 1'b0; - s_core_is_decoding = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; forever begin wait(e_pipe_monitor_ok.triggered); // event triggered @@ -1325,19 +1371,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end if (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID && r_pipe_freeze_trace.ebrk_insn_dec) begin - if (trace_wb.m_valid) begin - send_rvfi(trace_wb); - trace_wb.m_valid = 1'b0; - ->e_send_rvfi_trace_wb_1; - end - if (trace_ex.m_valid) begin - send_rvfi(trace_ex); - trace_ex.m_valid = 1'b0; - ->e_send_rvfi_trace_ex_1; - end if (trace_id.m_valid) begin - - minstret_to_id(); `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) @@ -1387,7 +1421,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; s_new_valid_insn = r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.is_decoding;// && !r_pipe_freeze_trace.apu_rvalid; - s_wb_valid_adjusted = r_pipe_freeze_trace.wb_valid && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX));// && !r_pipe_freeze_trace.apu_rvalid;; + s_wb_valid_adjusted = r_pipe_freeze_trace.wb_valid && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) || (r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_WB) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF));// && !r_pipe_freeze_trace.apu_rvalid;; + s_ex_reg_we_adjusted = r_pipe_freeze_trace.ex_reg_we && r_pipe_freeze_trace.mult_ready && r_pipe_freeze_trace.alu_ready && r_pipe_freeze_trace.lsu_ready_ex && !s_apu_to_alu_port; + s_rf_we_wb_adjusted = r_pipe_freeze_trace.rf_we_wb && (~r_pipe_freeze_trace.data_misaligned_ex && r_pipe_freeze_trace.wb_ready) && (!s_apu_to_lsu_port || r_pipe_freeze_trace.wb_contention_lsu); s_fflags_we_non_apu = 1'b0; if (r_pipe_freeze_trace.csr.fflags_we) begin @@ -1418,60 +1454,55 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; s_skip_wb = 1'b1; end end - if (trace_wb.m_valid && !s_skip_wb) begin - if (r_pipe_freeze_trace.rf_we_wb) begin - if((trace_wb.m_rd_addr[0] == r_pipe_freeze_trace.rf_addr_wb) && (cnt_data_resp == trace_wb.m_mem_req_id[0]) && trace_wb.m_mem_req_id_valid[0]) begin - trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_wb.m_mem_req_id_valid[0] = 1'b0; - end else if (trace_wb.m_2_rd_insn && (trace_wb.m_rd_addr[1] == r_pipe_freeze_trace.rf_addr_wb) && (cnt_data_resp == trace_wb.m_mem_req_id[1]) && trace_wb.m_mem_req_id_valid[1]) begin - trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_wb.m_mem_req_id_valid[1] = 1'b0; - end - end - if (!trace_wb.m_data_missaligned) begin - send_rvfi(trace_wb); - ->e_dev_send_wb_1; ->e_send_rvfi_trace_wb_2; - trace_wb.m_valid = 1'b0; + if (trace_wb.m_valid && !s_skip_wb && s_rf_we_wb_adjusted) begin + if (trace_wb.m_2_rd_insn) begin + trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + end else if (trace_wb.m_ex_fw) begin + trace_wb.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + trace_wb.m_2_rd_insn = 1'b1; end else begin - if (s_wb_valid_adjusted) begin - if (r_pipe_freeze_trace.rf_we_wb) begin - if (!trace_wb.m_ex_fw) begin - trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - end - if (trace_wb.m_data_missaligned && !trace_wb.m_got_first_data) begin - trace_wb.m_got_first_data = 1'b1; - end else begin - send_rvfi(trace_wb); - ->e_dev_send_wb_2; ->e_send_rvfi_trace_wb_3; - trace_wb.m_valid = 1'b0; - end - end // rf_we_wb + trace_wb.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; + trace_wb.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; + end + + if (r_pipe_freeze_trace.csr.fregs_we) begin + `CSR_FROM_PIPE(wb, mstatus_fs) + trace_wb.m_csr.mstatus_fs_we = 1'b1; + trace_wb.m_csr.mstatus_fs_wmask = '1; + if(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we) begin //In this specific case, two writes to mstatus_fs happen at the same time. We need to recreate the writes caused by fregs_we + trace_wb.m_csr.mstatus_fs_wdata = FS_DIRTY; end + ->e_fregs_dirty_1; end + + send_rvfi(trace_wb); + ->e_dev_send_wb_1; ->e_send_rvfi_trace_wb_2; + trace_wb.m_valid = 1'b0; + end if (trace_ex.m_valid) begin - - if (!trace_ex.m_csr.got_minstret) begin + if(trace_ex.m_instret_smaple_trigger == 1) begin //time to sample instret minstret_to_ex(); end + trace_ex.m_instret_smaple_trigger = trace_ex.m_instret_smaple_trigger + 1; + `CSR_FROM_PIPE(ex, misa) `CSR_FROM_PIPE(ex, tdata1) `CSR_FROM_PIPE(ex, tdata2) tinfo_to_ex(); - if (r_pipe_freeze_trace.regfile_we_lsu) begin + if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_4; - if ((cnt_data_resp == trace_ex.m_mem_req_id[0]) && !(trace_ex.m_got_ex_reg) && trace_ex.m_mem_req_id_valid[0]) begin + if (!(trace_ex.m_got_ex_reg) && trace_ex.m_mem_req_id_valid[0]) begin trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; trace_ex.m_mem_req_id_valid[0] = 1'b0; - end else if ((cnt_data_resp == trace_ex.m_mem_req_id[1]) && trace_ex.m_mem_req_id_valid[1]) begin + end else if (trace_ex.m_mem_req_id_valid[1]) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; @@ -1485,7 +1516,8 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_valid = 1'b0; ->e_send_rvfi_trace_ex_2; end else begin - if (r_pipe_freeze_trace.rf_we_wb && !s_apu_to_lsu_port) begin + + if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_1; if (trace_ex.m_got_ex_reg) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; @@ -1497,24 +1529,35 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; trace_ex.m_got_first_data = 1'b1; end - end - if (!s_ex_valid_adjusted & !trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end - if (trace_ex.m_is_load) begin // only move relevant instr in wb stage - ->e_ex_to_wb_1; - trace_wb.move_down_pipe(trace_ex); - end else begin - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); + if (r_pipe_freeze_trace.csr.fregs_we && !r_pipe_freeze_trace.apu_rvalid) begin //Catching mstatus_fs updates caused by flw + `CSR_FROM_PIPE(ex, mstatus_fs) + trace_ex.m_csr.mstatus_fs_we = 1'b1; + trace_ex.m_csr.mstatus_fs_wmask = '1; + if(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we) begin //In this specific case, two writes to mstatus_fs happen at the same time. We need to recreate the writes caused by fregs_we + trace_ex.m_csr.mstatus_fs_wdata = FS_DIRTY; + end else begin + trace_id.m_csr.mstatus_fs_rdata = trace_ex.m_csr.mstatus_fs_wdata; + s_dont_override_mstatus_fs_id = 1'b1; + end + ->e_fregs_dirty_3; end + send_rvfi(trace_ex); - ->e_send_rvfi_trace_ex_6; + trace_ex.m_valid = 1'b0; + + end else begin + if (trace_ex.m_is_load) begin // only move relevant instr in wb stage + ->e_ex_to_wb_1; + trace_wb.move_down_pipe(trace_ex); + end else begin + send_rvfi(trace_ex); + ->e_send_rvfi_trace_ex_6; + end + trace_ex.m_valid = 1'b0; end - trace_ex.m_valid = 1'b0; end - end else if (r_pipe_freeze_trace.rf_we_wb && !s_apu_to_lsu_port && !s_was_flush) begin + end else if (s_rf_we_wb_adjusted && !s_was_flush) begin ->e_dev_commit_rf_to_ex_2; if (trace_ex.m_got_ex_reg) begin trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; @@ -1529,21 +1572,38 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end - s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF)) && (!r_pipe_freeze_trace.apu_rvalid || r_pipe_freeze_trace.data_req_ex); + // If mret, we need to keep the instruction in Id during flush_ex because mstatus update happens at that time + s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || ((r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) && !r_pipe_freeze_trace.mret_insn_dec)); //EX_STAGE - if (trace_id.m_valid) begin - mtvec_to_id(); - `CSR_FROM_PIPE(id, mip) - `CSR_FROM_PIPE(id, misa) + if (trace_id.m_valid) begin + if(trace_id.m_instret_smaple_trigger == 1) begin //time to sample instret + minstret_to_id(); + end + trace_id.m_instret_smaple_trigger = trace_id.m_instret_smaple_trigger + 1; - if (!csr_is_irq && !s_is_irq_start) begin - mstatus_to_id(); + if(trace_id.m_sample_csr_write_in_ex && !csr_is_irq && !s_is_irq_start) begin //First cycle after id_ready, csr write is asserted in this cycle + `CSR_FROM_PIPE(id, mstatus) + if(!s_dont_override_mstatus_fs_id) begin + `CSR_FROM_PIPE(id, mstatus_fs) + end `CSR_FROM_PIPE(id, mepc) - if (trace_id.m_csr.mcause_we == '0) begin //for debug purpose - `CSR_FROM_PIPE(id, mcause) + `CSR_FROM_PIPE(id, mcause) + `CSR_FROM_PIPE(id, dscratch0) + `CSR_FROM_PIPE(id, dscratch1) + if(r_pipe_freeze_trace.csr.we && (r_pipe_freeze_trace.csr.addr == CSR_DPC)) begin + `CSR_FROM_PIPE(id, dpc) end + ->e_csr_in_ex; + end + + if(r_pipe_freeze_trace.is_decoding) begin + trace_id.m_sample_csr_write_in_ex = 1'b0; end + mtvec_to_id(); + + `CSR_FROM_PIPE(id, mip) + `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, mcountinhibit) `CSR_FROM_PIPE(id, mscratch) @@ -1553,10 +1613,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(id, frm) `CSR_FROM_PIPE(id, fcsr) - if (r_pipe_freeze_trace.csr.we) begin - `CSR_FROM_PIPE(id, dpc) - end - if (r_pipe_freeze_trace.csr.dcsr_we) begin dcsr_to_id(); end @@ -1577,6 +1633,15 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_csr.frm_wmask = '0; trace_ex.m_csr.fcsr_wmask = '0; + if(r_pipe_freeze_trace.ctrl_fsm_cs == XRET_JUMP) begin //xret exit pipeline + tinfo_to_id(); + `CSR_FROM_PIPE(id, tdata1) + `CSR_FROM_PIPE(id, tdata2) + send_rvfi(trace_id); + trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; + end + if (r_pipe_freeze_trace.apu_req && r_pipe_freeze_trace.apu_gnt) begin trace_id.m_is_apu = 1'b1; trace_id.m_apu_req_id = cnt_apu_req; @@ -1586,6 +1651,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_apu_req.set_to_apu(); apu_trace_q.push_back(trace_apu_req); trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; if(r_pipe_freeze_trace.apu_rvalid && (cnt_apu_req == cnt_apu_resp)) begin//APU return in the same cycle apu_resp(); @@ -1603,10 +1669,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_rd_addr[0] = r_pipe_freeze_trace.ex_reg_addr; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.ex_reg_wdata; trace_id.m_got_ex_reg = 1'b1; - end else if (!trace_ex.m_valid & r_pipe_freeze_trace.rf_we_wb & !trace_id.m_ex_fw) begin + end else if (!trace_ex.m_valid & s_rf_we_wb_adjusted & !trace_id.m_ex_fw) begin trace_id.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - end else if (r_pipe_freeze_trace.rf_we_wb) begin + end else if (s_rf_we_wb_adjusted) begin trace_id.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; trace_id.m_2_rd_insn = 1'b1; @@ -1621,19 +1687,16 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem.addr = r_pipe_freeze_trace.data_addr_pmp; if (r_pipe_freeze_trace.data_misaligned) begin cnt_data_req = cnt_data_req + 1; + trace_id.m_mem_req_id[0] = cnt_data_req; end + if (!r_pipe_freeze_trace.data_we_ex) begin trace_id.m_is_load = 1'b1; trace_id.m_mem.wmask = be_to_mask(r_pipe_freeze_trace.lsu_data_be); //'1; - if (r_pipe_freeze_trace.data_misaligned) begin - trace_id.m_data_missaligned = 1'b1; - trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; - trace_id.m_mem_req_id[0] = cnt_data_req; - trace_id.m_mem_req_id_valid[1] = 1'b1; - end end else begin trace_id.m_mem.rmask = be_to_mask(r_pipe_freeze_trace.lsu_data_be); //'1; end + if (trace_id.m_got_ex_reg) begin // Shift index 0 to 1 trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; trace_id.m_mem_req_id[0] = 0; @@ -1644,6 +1707,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; hwloop_to_id(); trace_ex.move_down_pipe(trace_id); // The instruction moves forward from ID to EX trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; ->e_id_to_ex_1; end else if (r_pipe_freeze_trace.ex_reg_we && r_pipe_freeze_trace.rf_alu_we_ex) begin @@ -1667,9 +1731,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (s_new_valid_insn) begin // There is a new valid instruction if (trace_id.m_valid) begin if (trace_ex.m_valid) begin - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end if (trace_wb.m_valid) begin send_rvfi(trace_ex); ->e_send_rvfi_trace_ex_4; @@ -1692,15 +1753,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem.addr = r_pipe_freeze_trace.data_addr_pmp; if (r_pipe_freeze_trace.data_misaligned) begin cnt_data_req = cnt_data_req + 1; + trace_id.m_mem_req_id[0] = cnt_data_req; end if (!r_pipe_freeze_trace.data_we_ex) begin trace_id.m_is_load = 1'b1; - if (r_pipe_freeze_trace.data_misaligned) begin - trace_id.m_data_missaligned = 1'b1; - trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; - trace_id.m_mem_req_id[0] = cnt_data_req; - trace_id.m_mem_req_id_valid[1] = 1'b1; - end end if (trace_id.m_got_ex_reg) begin // Shift index 0 to 1 trace_id.m_mem_req_id[1] = trace_id.m_mem_req_id[0]; @@ -1708,7 +1764,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_id.m_mem_req_id_valid[0] = 1'b0; trace_id.m_mem_req_id_valid[1] = 1'b1; end - end else if (r_pipe_freeze_trace.rf_we_wb && !r_pipe_freeze_trace.ex_reg_we) begin + end else if (s_rf_we_wb_adjusted && !r_pipe_freeze_trace.ex_reg_we) begin trace_id.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; trace_id.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; end @@ -1716,6 +1772,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; hwloop_to_id(); trace_ex.move_down_pipe(trace_id); trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; ->e_id_to_ex_2; end if_to_id(); @@ -1733,12 +1790,27 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end //IF_STAGE - if (r_pipe_freeze_trace.if_valid && r_pipe_freeze_trace.if_ready) begin - if(trace_if.m_valid && r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.id_ready && !trace_id.m_valid && r_pipe_freeze_trace.ebrk_insn_dec) begin - if_to_id(); - trace_id.m_is_ebreak = '1; //trace_if.m_is_ebreak; - ->e_if_2_id_2; + if(trace_if.m_valid) begin + if(r_pipe_freeze_trace.is_illegal && r_pipe_freeze_trace.is_decoding) begin + trace_if.m_is_illegal = 1'b1; end + end + + if (r_pipe_freeze_trace.if_valid && r_pipe_freeze_trace.if_ready && r_pipe_freeze_trace.instr_valid_if) begin + if (trace_if.m_valid) begin + if (r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.id_ready && !trace_id.m_valid && r_pipe_freeze_trace.ebrk_insn_dec) begin + if_to_id(); + trace_id.m_is_ebreak = '1; //trace_if.m_is_ebreak; + ->e_if_2_id_2; + end else if (trace_if.m_is_illegal) begin + if_to_id(); + ->e_if_2_id_3; + end else if (r_pipe_freeze_trace.ecall_insn_dec) begin + if_to_id(); + ->e_if_2_id_4; + end + end + trace_if.m_insn = r_pipe_freeze_trace.instr_if; //Instr comes from if, buffer for one cycle trace_if.m_pc_rdata = r_pipe_freeze_trace.pc_if; @@ -1754,6 +1826,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; mstatus_to_id(); `CSR_FROM_PIPE(id, mepc) `CSR_FROM_PIPE(id, mcause) + ->e_csr_irq; end if (!s_id_done && r_pipe_freeze_trace.is_decoding) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv index 725ed4f0..ca703682 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv @@ -279,8 +279,12 @@ module cv32e40p_tb_wrapper // .instr (cv32e40p_top_i.core_i.id_stage_i.instr ), .is_compressed_id_i(cv32e40p_top_i.core_i.id_stage_i.is_compressed_i), .ebrk_insn_dec_i (cv32e40p_top_i.core_i.id_stage_i.ebrk_insn_dec), - .csr_cause_i (cv32e40p_top_i.core_i.csr_cause), - .debug_csr_save_i (cv32e40p_top_i.core_i.debug_csr_save), + .ecall_insn_dec_i (cv32e40p_top_i.core_i.id_stage_i.ecall_insn_dec), + .mret_insn_dec_i (cv32e40p_top_i.core_i.id_stage_i.mret_insn_dec), + .mret_dec_i (cv32e40p_top_i.core_i.id_stage_i.mret_dec), + + .csr_cause_i (cv32e40p_top_i.core_i.csr_cause), + .debug_csr_save_i(cv32e40p_top_i.core_i.debug_csr_save), // HWLOOP regs .hwlp_start_q_i (hwlp_start_q), @@ -305,9 +309,11 @@ module cv32e40p_tb_wrapper // .rf_addr_alu_i (cv32e40p_top_i.core_i.id_stage_i.regfile_alu_waddr_fw_i), // .rf_wdata_alu_i (cv32e40p_top_i.core_i.id_stage_i.regfile_alu_wdata_fw_i), + .mult_ready_i (cv32e40p_top_i.core_i.ex_stage_i.mult_ready), + .alu_ready_i (cv32e40p_top_i.core_i.ex_stage_i.alu_ready), //// WB probes //// - .wb_valid_i(cv32e40p_top_i.core_i.wb_valid), - + .wb_valid_i (cv32e40p_top_i.core_i.wb_valid), + .wb_ready_i (cv32e40p_top_i.core_i.lsu_ready_wb), //// LSU probes //// .data_we_ex_i (cv32e40p_top_i.core_i.data_we_ex), .data_atop_ex_i (cv32e40p_top_i.core_i.data_atop_ex), @@ -360,6 +366,8 @@ module cv32e40p_tb_wrapper .csr_we_i (cv32e40p_top_i.core_i.cs_registers_i.csr_we_int), .csr_wdata_int_i(cv32e40p_top_i.core_i.cs_registers_i.csr_wdata_int), + .csr_fregs_we_i(cv32e40p_top_i.core_i.cs_registers_i.fregs_we_i), + .csr_mstatus_n_i (cv32e40p_top_i.core_i.cs_registers_i.mstatus_n), .csr_mstatus_q_i (cv32e40p_top_i.core_i.cs_registers_i.mstatus_q), .csr_mstatus_fs_n_i(cv32e40p_top_i.core_i.cs_registers_i.mstatus_fs_n), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv index c099ff4f..d026c4aa 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv @@ -196,8 +196,8 @@ package cv32e40p_tracer_pkg; parameter INSTR_CVEND0 = {12'b000000000000, 5'b?, 3'b100, 4'b0011, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNTI0 = {12'b?, 5'b00000, 3'b100, 4'b0100, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNT0 = {12'b000000000000, 5'b?, 3'b100, 4'b0101, 1'b0, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUPI0 = {12'b?, 5'b00000, 3'b100, 4'b0110, 1'b0, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUP0 = {12'b?, 5'b00000, 3'b100, 4'b0111, 1'b0, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUPI0 = {17'b?, 3'b100, 4'b0110, 1'b0, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUP0 = {12'b?, 5'b?, 3'b100, 4'b0111, 1'b0, OPCODE_CUSTOM_1}; parameter INSTR_CVSTARTI1 = {12'b?, 5'b00000, 3'b100, 4'b0000, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVSTART1 = {12'b000000000000, 5'b?, 3'b100, 4'b0001, 1'b1, OPCODE_CUSTOM_1}; @@ -205,8 +205,8 @@ package cv32e40p_tracer_pkg; parameter INSTR_CVEND1 = {12'b000000000000, 5'b?, 3'b100, 4'b0011, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNTI1 = {12'b?, 5'b00000, 3'b100, 4'b0100, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_CVCOUNT1 = {12'b000000000000, 5'b?, 3'b100, 4'b0101, 1'b1, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUPI1 = {12'b?, 5'b00000, 3'b100, 4'b0110, 1'b1, OPCODE_CUSTOM_1}; - parameter INSTR_CVSETUP1 = {12'b?, 5'b00000, 3'b100, 4'b0111, 1'b1, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUPI1 = {17'b?, 3'b100, 4'b0110, 1'b1, OPCODE_CUSTOM_1}; + parameter INSTR_CVSETUP1 = {12'b?, 5'b?, 3'b100, 4'b0111, 1'b1, OPCODE_CUSTOM_1}; parameter INSTR_FF1 = {7'b0100001, 5'b0, 5'b?, 3'b011, 5'b?, OPCODE_CUSTOM_1}; @@ -449,8 +449,8 @@ package cv32e40p_tracer_pkg; parameter INSTR_CVSHUFFLE2H = {5'b11100, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVSHUFFLE2B = {5'b11100, 1'b0, 1'b0, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; - parameter INSTR_CVPACK = {5'b11101, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; - parameter INSTR_CVPACKH = {5'b11101, 1'b0, 1'b1, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; + parameter INSTR_CVPACK = {5'b11110, 1'b0, 1'b0, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; + parameter INSTR_CVPACKH = {5'b11110, 1'b0, 1'b1, 5'b?, 5'b?, 3'b000, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVPACKHIB = {5'b11111, 1'b0, 1'b1, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; parameter INSTR_CVPACKLOB = {5'b11111, 1'b0, 1'b0, 5'b?, 5'b?, 3'b001, 5'b?, OPCODE_CUSTOM_3}; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv index 3db2a7ee..71cbaaff 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv @@ -65,6 +65,9 @@ bit m_move_down_pipe; int m_instret_cnt; + int m_instret_smaple_trigger; //We need to sample minstret from csr 2 cycle after id is doen + + bit m_sample_csr_write_in_ex; struct { logic [31:0] addr ; @@ -145,32 +148,34 @@ function new(); - this.m_order = 0; - this.m_skip_order = 1'b0; - this.m_valid = 1'b0; - this.m_move_down_pipe = 1'b0; - this.m_data_missaligned = 1'b0; - this.m_got_first_data = 1'b0; - this.m_got_ex_reg = 1'b0; - this.m_intr = '0; - this.m_dbg_taken = 1'b0; - this.m_dbg_cause = '0; - this.m_is_ebreak = '0; - this.m_is_illegal = '0; - this.m_is_irq = '0; - this.m_is_memory = 1'b0; - this.m_is_load = 1'b0; - this.m_is_apu = 1'b0; - this.m_is_apu_ok = 1'b0; - this.m_apu_req_id = 0; - this.m_mem_req_id[0] = 0; - this.m_mem_req_id[1] = 0; - this.m_mem_req_id_valid = '0; - this.m_trap = 1'b0; - this.m_fflags_we_non_apu = 1'b0; - this.m_frm_we_non_apu = 1'b0; - this.m_fcsr_we_non_apu = 1'b0; - this.m_instret_cnt = 0; + this.m_order = 0; + this.m_skip_order = 1'b0; + this.m_valid = 1'b0; + this.m_move_down_pipe = 1'b0; + this.m_data_missaligned = 1'b0; + this.m_got_first_data = 1'b0; + this.m_got_ex_reg = 1'b0; + this.m_intr = '0; + this.m_dbg_taken = 1'b0; + this.m_dbg_cause = '0; + this.m_is_ebreak = '0; + this.m_is_illegal = '0; + this.m_is_irq = '0; + this.m_is_memory = 1'b0; + this.m_is_load = 1'b0; + this.m_is_apu = 1'b0; + this.m_is_apu_ok = 1'b0; + this.m_apu_req_id = 0; + this.m_mem_req_id[0] = 0; + this.m_mem_req_id[1] = 0; + this.m_mem_req_id_valid = '0; + this.m_trap = 1'b0; + this.m_fflags_we_non_apu = 1'b0; + this.m_frm_we_non_apu = 1'b0; + this.m_fcsr_we_non_apu = 1'b0; + this.m_instret_cnt = 0; + this.m_instret_smaple_trigger = 0; + this.m_sample_csr_write_in_ex = 1'b1; endfunction function void get_mnemonic(); @@ -875,37 +880,39 @@ if(this.m_skip_order) begin this.m_order = this.m_order + 64'h1; end - this.m_skip_order = 1'b0; - this.m_pc_rdata = r_pipe_freeze_trace.pc_id; - this.m_is_illegal = 1'b0; - this.m_is_irq = 1'b0; - this.m_is_memory = 1'b0; - this.m_is_load = 1'b0; - this.m_is_apu = 1'b0; - this.m_is_apu_ok = 1'b0; - this.m_apu_req_id = 0; - this.m_mem_req_id[0] = 0; - this.m_mem_req_id[1] = 0; - this.m_mem_req_id_valid = '0; - this.m_data_missaligned = 1'b0; - this.m_got_first_data = 1'b0; - this.m_got_ex_reg = 1'b0; - this.m_got_regs_write = 1'b0; - this.m_move_down_pipe = 1'b0; - this.m_instret_cnt = 0; - this.m_rd_addr[0] = '0; - this.m_rd_addr[1] = '0; - this.m_2_rd_insn = 1'b0; - this.m_rs1_addr = '0; - this.m_rs2_addr = '0; - this.m_rs3_addr = '0; - this.m_ex_fw = '0; - this.m_csr.got_minstret = '0; - this.m_dbg_taken = '0; - this.m_trap = 1'b0; - this.m_fflags_we_non_apu = 1'b0; - this.m_frm_we_non_apu = 1'b0; - this.m_fcsr_we_non_apu = 1'b0; + this.m_skip_order = 1'b0; + this.m_pc_rdata = r_pipe_freeze_trace.pc_id; + this.m_is_illegal = 1'b0; + this.m_is_irq = 1'b0; + this.m_is_memory = 1'b0; + this.m_is_load = 1'b0; + this.m_is_apu = 1'b0; + this.m_is_apu_ok = 1'b0; + this.m_apu_req_id = 0; + this.m_mem_req_id[0] = 0; + this.m_mem_req_id[1] = 0; + this.m_mem_req_id_valid = '0; + this.m_data_missaligned = 1'b0; + this.m_got_first_data = 1'b0; + this.m_got_ex_reg = 1'b0; + this.m_got_regs_write = 1'b0; + this.m_move_down_pipe = 1'b0; + this.m_instret_cnt = 0; + this.m_instret_smaple_trigger = 0; + this.m_sample_csr_write_in_ex = 1'b1; + this.m_rd_addr[0] = '0; + this.m_rd_addr[1] = '0; + this.m_2_rd_insn = 1'b0; + this.m_rs1_addr = '0; + this.m_rs2_addr = '0; + this.m_rs3_addr = '0; + this.m_ex_fw = '0; + this.m_csr.got_minstret = '0; + this.m_dbg_taken = '0; + this.m_trap = 1'b0; + this.m_fflags_we_non_apu = 1'b0; + this.m_frm_we_non_apu = 1'b0; + this.m_fcsr_we_non_apu = 1'b0; this.m_csr.mcause_we = '0; if (is_compressed_id_i) begin this.m_insn[31:16] = '0; @@ -944,47 +951,49 @@ endfunction function void copy_full(insn_trace_t m_source); - this.m_valid = m_source.m_valid; - this.m_stage = m_source.m_stage; - this.m_order = m_source.m_order; - this.m_pc_rdata = m_source.m_pc_rdata; - this.m_insn = m_source.m_insn; - this.m_mnemonic = m_source.m_mnemonic; - this.m_is_memory = m_source.m_is_memory; - this.m_is_load = m_source.m_is_load; - this.m_is_apu = m_source.m_is_apu; - this.m_is_apu_ok = m_source.m_is_apu_ok; - this.m_apu_req_id = m_source.m_apu_req_id; - this.m_mem_req_id = m_source.m_mem_req_id; - this.m_mem_req_id_valid = m_source.m_mem_req_id_valid; - this.m_data_missaligned = m_source.m_data_missaligned; - this.m_got_first_data = m_source.m_got_first_data; - this.m_got_ex_reg = m_source.m_got_ex_reg; - this.m_dbg_taken = m_source.m_dbg_taken; - this.m_dbg_cause = m_source.m_dbg_cause; - this.m_is_ebreak = m_source.m_is_ebreak; - this.m_is_illegal = m_source.m_is_illegal; - this.m_is_irq = m_source.m_is_irq; - this.m_instret_cnt = m_source.m_instret_cnt; - this.m_rs1_addr = m_source.m_rs1_addr; - this.m_rs2_addr = m_source.m_rs2_addr; - this.m_rs3_addr = m_source.m_rs3_addr; - this.m_rs1_rdata = m_source.m_rs1_rdata; - this.m_rs2_rdata = m_source.m_rs2_rdata; - this.m_rs3_rdata = m_source.m_rs3_rdata; - - this.m_ex_fw = m_source.m_ex_fw; - this.m_rd_addr = m_source.m_rd_addr; - this.m_2_rd_insn = m_source.m_2_rd_insn; - this.m_rd_wdata = m_source.m_rd_wdata; - - this.m_intr = m_source.m_intr; - this.m_trap = m_source.m_trap; - this.m_fflags_we_non_apu = m_source.m_fflags_we_non_apu; - this.m_frm_we_non_apu = m_source.m_frm_we_non_apu ; - this.m_fcsr_we_non_apu = m_source.m_fcsr_we_non_apu; - - this.m_mem = m_source.m_mem; + this.m_valid = m_source.m_valid; + this.m_stage = m_source.m_stage; + this.m_order = m_source.m_order; + this.m_pc_rdata = m_source.m_pc_rdata; + this.m_insn = m_source.m_insn; + this.m_mnemonic = m_source.m_mnemonic; + this.m_is_memory = m_source.m_is_memory; + this.m_is_load = m_source.m_is_load; + this.m_is_apu = m_source.m_is_apu; + this.m_is_apu_ok = m_source.m_is_apu_ok; + this.m_apu_req_id = m_source.m_apu_req_id; + this.m_mem_req_id = m_source.m_mem_req_id; + this.m_mem_req_id_valid = m_source.m_mem_req_id_valid; + this.m_data_missaligned = m_source.m_data_missaligned; + this.m_got_first_data = m_source.m_got_first_data; + this.m_got_ex_reg = m_source.m_got_ex_reg; + this.m_dbg_taken = m_source.m_dbg_taken; + this.m_dbg_cause = m_source.m_dbg_cause; + this.m_is_ebreak = m_source.m_is_ebreak; + this.m_is_illegal = m_source.m_is_illegal; + this.m_is_irq = m_source.m_is_irq; + this.m_instret_cnt = m_source.m_instret_cnt; + this.m_instret_smaple_trigger = m_source.m_instret_smaple_trigger; + this.m_sample_csr_write_in_ex = m_source.m_sample_csr_write_in_ex; + this.m_rs1_addr = m_source.m_rs1_addr; + this.m_rs2_addr = m_source.m_rs2_addr; + this.m_rs3_addr = m_source.m_rs3_addr; + this.m_rs1_rdata = m_source.m_rs1_rdata; + this.m_rs2_rdata = m_source.m_rs2_rdata; + this.m_rs3_rdata = m_source.m_rs3_rdata; + + this.m_ex_fw = m_source.m_ex_fw; + this.m_rd_addr = m_source.m_rd_addr; + this.m_2_rd_insn = m_source.m_2_rd_insn; + this.m_rd_wdata = m_source.m_rd_wdata; + + this.m_intr = m_source.m_intr; + this.m_trap = m_source.m_trap; + this.m_fflags_we_non_apu = m_source.m_fflags_we_non_apu; + this.m_frm_we_non_apu = m_source.m_frm_we_non_apu ; + this.m_fcsr_we_non_apu = m_source.m_fcsr_we_non_apu; + + this.m_mem = m_source.m_mem; //CRS `ASSIGN_CSR(mstatus) `ASSIGN_CSR(mstatus_fs) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv index 58051ab8..88d65d0b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv @@ -64,6 +64,9 @@ typedef struct { logic is_compressed_id; logic ebrk_insn_dec; + logic ecall_insn_dec; + logic mret_insn_dec; + logic mret_dec; logic [5:0] csr_cause; @@ -112,6 +115,9 @@ typedef struct { logic [31:0] data_wdata_ex; logic lsu_split_q_ex; + logic mult_ready; + logic alu_ready; + //// WB probes //// logic [31:0] pc_wb; logic wb_ready; @@ -198,6 +204,8 @@ typedef struct { logic mcause_we; logic dcsr_we; + logic fregs_we; + logic jvt_we; Status_t mstatus_n; Status_t mstatus_q; @@ -348,16 +356,24 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.mstatus_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; end - CSR_MISA: r_pipe_freeze_trace.csr.misa_we = 1'b1; - CSR_MTVEC: r_pipe_freeze_trace.csr.mtvec_we = 1'b1; - CSR_MSCRATCH: r_pipe_freeze_trace.csr.mscratch_we = 1'b1; - CSR_MEPC: r_pipe_freeze_trace.csr.mepc_we = 1'b1; - CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = 1'b1; - CSR_DCSR: r_pipe_freeze_trace.csr.dcsr_we = 1'b1; - CSR_FFLAGS: r_pipe_freeze_trace.csr.fflags_we = 1'b1; - CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; - CSR_FCSR: r_pipe_freeze_trace.csr.fcsr_we = 1'b1; - CSR_DPC: r_pipe_freeze_trace.csr.dpc_we = 1'b1; + CSR_MISA: r_pipe_freeze_trace.csr.misa_we = 1'b1; + CSR_MTVEC: r_pipe_freeze_trace.csr.mtvec_we = 1'b1; + CSR_MSCRATCH: r_pipe_freeze_trace.csr.mscratch_we = 1'b1; + CSR_MEPC: r_pipe_freeze_trace.csr.mepc_we = 1'b1; + CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = 1'b1; + CSR_DCSR: r_pipe_freeze_trace.csr.dcsr_we = 1'b1; + CSR_FFLAGS: begin + r_pipe_freeze_trace.csr.fflags_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end + CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; + CSR_FCSR: begin + r_pipe_freeze_trace.csr.fcsr_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end + CSR_DPC: r_pipe_freeze_trace.csr.dpc_we = 1'b1; + CSR_DSCRATCH0: r_pipe_freeze_trace.csr.dscratch0_we = 1'b1; + CSR_DSCRATCH1: r_pipe_freeze_trace.csr.dscratch1_we = 1'b1; endcase end // CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = r_pipe_freeze_trace.csr.mcause_n != r_pipe_freeze_trace.csr.mcause_q; //for debug purpose @@ -416,6 +432,9 @@ task monitor_pipeline(); r_pipe_freeze_trace.jump_target_id = jump_target_id_i; r_pipe_freeze_trace.is_compressed_id = is_compressed_id_i; r_pipe_freeze_trace.ebrk_insn_dec = ebrk_insn_dec_i; + r_pipe_freeze_trace.ecall_insn_dec = ecall_insn_dec_i; + r_pipe_freeze_trace.mret_insn_dec = mret_insn_dec_i; + r_pipe_freeze_trace.mret_dec = mret_dec_i; r_pipe_freeze_trace.csr_cause = csr_cause_i; r_pipe_freeze_trace.debug_csr_save = debug_csr_save_i; r_pipe_freeze_trace.minstret = minstret_i; @@ -462,6 +481,8 @@ task monitor_pipeline(); r_pipe_freeze_trace.data_wdata_ex = data_wdata_ex_i; r_pipe_freeze_trace.lsu_split_q_ex = lsu_split_q_ex_i; + r_pipe_freeze_trace.mult_ready = mult_ready_i; + r_pipe_freeze_trace.alu_ready = alu_ready_i; //// WB probes //// r_pipe_freeze_trace.pc_wb = pc_wb_i; r_pipe_freeze_trace.wb_ready = wb_ready_i; @@ -526,6 +547,8 @@ task monitor_pipeline(); r_pipe_freeze_trace.csr.we = csr_we_i; r_pipe_freeze_trace.csr.wdata_int = csr_wdata_int_i; + r_pipe_freeze_trace.csr.fregs_we = csr_fregs_we_i; + r_pipe_freeze_trace.csr.jvt_we = csr_jvt_we_i; r_pipe_freeze_trace.csr.mstatus_n = csr_mstatus_n_i; r_pipe_freeze_trace.csr.mstatus_q = csr_mstatus_q_i; @@ -650,10 +673,6 @@ task monitor_pipeline(); if (r_pipe_freeze_trace.csr.fcsr_we) begin r_pipe_freeze_trace.csr.fflags_we = 1'b1; r_pipe_freeze_trace.csr.frm_we = 1'b1; - end else begin - if (r_pipe_freeze_trace.csr.fflags_we || r_pipe_freeze_trace.csr.frm_we) begin - r_pipe_freeze_trace.csr.fcsr_we = 1'b1; - end end if (csr_fcsr_fflags_we_i) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv index 54980269..a41e345d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv @@ -491,6 +491,7 @@ module cv32e40p_controller import cv32e40p_pkg::*; if ( (debug_req_pending || trigger_match_i) & ~debug_mode_q ) begin //Serving the debug + is_decoding_o = COREV_PULP ? 1'b0 : 1'b1; halt_if_o = 1'b1; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; @@ -712,6 +713,7 @@ module cv32e40p_controller import cv32e40p_pkg::*; if ( (debug_req_pending || trigger_match_i) & ~debug_mode_q ) begin //Serving the debug + is_decoding_o = COREV_PULP ? 1'b0 : 1'b1; halt_if_o = 1'b1; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; @@ -764,7 +766,7 @@ module cv32e40p_controller import cv32e40p_pkg::*; ebrk_insn_i: begin halt_if_o = 1'b1; - halt_id_o = 1'b1; + halt_id_o = 1'b0; if (debug_mode_q) // we got back to the park loop in the debug rom @@ -776,15 +778,15 @@ module cv32e40p_controller import cv32e40p_pkg::*; else begin // otherwise just a normal ebreak exception - ctrl_fsm_ns = FLUSH_EX; + ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; end end ecall_insn_i: begin halt_if_o = 1'b1; - halt_id_o = 1'b1; - ctrl_fsm_ns = FLUSH_EX; + halt_id_o = 1'b0; + ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; end csr_status_i: begin @@ -1559,7 +1561,7 @@ endgenerate // HWLoop 0 and 1 having target address constraints property p_hwlp_same_target_address; - @(posedge clk) (hwlp_counter_i[1] > 1 && hwlp_counter_i[0] > 1) |-> ( hwlp_end_addr_i[1] - 4 >= hwlp_end_addr_i[0] - 4 + 8 ); + @(posedge clk) (hwlp_counter_i[1] > 1 && hwlp_counter_i[0] > 1 && pc_id_i >= hwlp_start_addr_i[0] && pc_id_i <= hwlp_end_addr_i[0] - 4) |-> ( hwlp_end_addr_i[1] - 4 >= hwlp_end_addr_i[0] - 4 + 8 ); endproperty a_hwlp_same_target_address : assert property(p_hwlp_same_target_address) else $warning("%t, HWLoops target address do not respect constraints", $time); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv index e6f9f709..d72fae9e 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv @@ -158,6 +158,7 @@ module cv32e40p_core logic [31:0] jump_target_id, jump_target_ex; logic branch_in_ex; logic branch_decision; + logic [ 1:0] ctrl_transfer_insn_in_dec; logic ctrl_busy; logic if_busy; @@ -201,6 +202,7 @@ module cv32e40p_core logic [ C_RM-1:0] frm_csr; logic [ C_FFLAG-1:0] fflags_csr; logic fflags_we; + logic fregs_we; // APU logic apu_en_ex; @@ -228,6 +230,7 @@ module cv32e40p_core logic regfile_we_ex; logic [ 5:0] regfile_waddr_fw_wb_o; // From WB to ID logic regfile_we_wb; + logic regfile_we_wb_power; logic [ 31:0] regfile_wdata; logic [ 5:0] regfile_alu_waddr_ex; @@ -235,6 +238,7 @@ module cv32e40p_core logic [ 5:0] regfile_alu_waddr_fw; logic regfile_alu_we_fw; + logic regfile_alu_we_fw_power; logic [ 31:0] regfile_alu_wdata_fw; // CSR control @@ -540,9 +544,10 @@ module cv32e40p_core .instr_req_o (instr_req_int), // Jumps and branches - .branch_in_ex_o (branch_in_ex), - .branch_decision_i(branch_decision), - .jump_target_o (jump_target_id), + .branch_in_ex_o (branch_in_ex), + .branch_decision_i (branch_decision), + .jump_target_o (jump_target_id), + .ctrl_transfer_insn_in_dec_o(ctrl_transfer_insn_in_dec), // IF and ID control signals .clear_instr_valid_o(clear_instr_valid), @@ -699,13 +704,15 @@ module cv32e40p_core .wake_from_sleep_o(wake_from_sleep), // Forward Signals - .regfile_waddr_wb_i(regfile_waddr_fw_wb_o), // Write address ex-wb pipeline - .regfile_we_wb_i (regfile_we_wb), // write enable for the register file - .regfile_wdata_wb_i(regfile_wdata), // write data to commit in the register file + .regfile_waddr_wb_i (regfile_waddr_fw_wb_o), // Write address ex-wb pipeline + .regfile_we_wb_i (regfile_we_wb), // write enable for the register file + .regfile_we_wb_power_i(regfile_we_wb_power), + .regfile_wdata_wb_i (regfile_wdata), // write data to commit in the register file - .regfile_alu_waddr_fw_i(regfile_alu_waddr_fw), - .regfile_alu_we_fw_i (regfile_alu_we_fw), - .regfile_alu_wdata_fw_i(regfile_alu_wdata_fw), + .regfile_alu_waddr_fw_i (regfile_alu_waddr_fw), + .regfile_alu_we_fw_i (regfile_alu_we_fw), + .regfile_alu_we_fw_power_i(regfile_alu_we_fw_power), + .regfile_alu_wdata_fw_i (regfile_alu_wdata_fw), // from ALU .mult_multicycle_i(mult_multicycle), @@ -737,6 +744,7 @@ module cv32e40p_core // // ///////////////////////////////////////////////////// cv32e40p_ex_stage #( + .COREV_PULP (COREV_PULP), .FPU (FPU), .APU_NARGS_CPU (APU_NARGS_CPU), .APU_WOP_CPU (APU_WOP_CPU), @@ -785,6 +793,8 @@ module cv32e40p_core .data_misaligned_ex_i(data_misaligned_ex), // from ID/EX pipeline .data_misaligned_i (data_misaligned), + .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec), + // FPU .fpu_fflags_we_o(fflags_we), .fpu_fflags_o (fflags_csr), @@ -838,18 +848,20 @@ module cv32e40p_core .regfile_we_i (regfile_we_ex), // Output of ex stage pipeline - .regfile_waddr_wb_o(regfile_waddr_fw_wb_o), - .regfile_we_wb_o (regfile_we_wb), - .regfile_wdata_wb_o(regfile_wdata), + .regfile_waddr_wb_o (regfile_waddr_fw_wb_o), + .regfile_we_wb_o (regfile_we_wb), + .regfile_we_wb_power_o(regfile_we_wb_power), + .regfile_wdata_wb_o (regfile_wdata), // To IF: Jump and branch target and decision .jump_target_o (jump_target_ex), .branch_decision_o(branch_decision), // To ID stage: Forwarding signals - .regfile_alu_waddr_fw_o(regfile_alu_waddr_fw), - .regfile_alu_we_fw_o (regfile_alu_we_fw), - .regfile_alu_wdata_fw_o(regfile_alu_wdata_fw), + .regfile_alu_waddr_fw_o (regfile_alu_waddr_fw), + .regfile_alu_we_fw_o (regfile_alu_we_fw), + .regfile_alu_we_fw_power_o(regfile_alu_we_fw_power), + .regfile_alu_wdata_fw_o (regfile_alu_wdata_fw), // stall control .is_decoding_i (is_decoding), @@ -969,6 +981,7 @@ module cv32e40p_core .frm_o (frm_csr), .fflags_i (fflags_csr), .fflags_we_i(fflags_we), + .fregs_we_i (fregs_we), // Interrupt related control signals .mie_bypass_o (mie_bypass), @@ -1037,13 +1050,16 @@ module cv32e40p_core ); // CSR access - assign csr_addr = csr_addr_int; - assign csr_wdata = alu_operand_a_ex; - assign csr_op = csr_op_ex; + assign csr_addr = csr_addr_int; + assign csr_wdata = alu_operand_a_ex; + assign csr_op = csr_op_ex; assign csr_addr_int = csr_num_e'(csr_access_ex ? alu_operand_b_ex[11:0] : '0); - + // Floating-Point registers write + assign fregs_we = (FPU == 1 & ZFINX == 0) ? ((regfile_alu_we_fw && regfile_alu_waddr_fw[5]) || + (regfile_we_wb && regfile_waddr_fw_wb_o[5])) + : 1'b0; /////////////////////////// // ____ __ __ ____ // diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_cs_registers.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_cs_registers.sv index 25c777e2..920305c8 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_cs_registers.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_cs_registers.sv @@ -68,6 +68,7 @@ module cv32e40p_cs_registers output logic [ 2:0] frm_o, input logic [C_FFLAG-1:0] fflags_i, input logic fflags_we_i, + input logic fregs_we_i, // Interrupts output logic [31:0] mie_bypass_o, @@ -212,6 +213,7 @@ module cv32e40p_cs_registers logic [31:0] exception_pc; Status_t mstatus_q, mstatus_n; + logic mstatus_we_int; FS_t mstatus_fs_q, mstatus_fs_n; logic [5:0] mcause_q, mcause_n; logic [5:0] ucause_q, ucause_n; @@ -507,7 +509,7 @@ module cv32e40p_cs_registers // mimpid, Machine Implementation ID CSR_MIMPID: begin - csr_rdata_int = (FPU || COREV_PULP || COREV_CLUSTER) ? 32'h1 : 'b0; + csr_rdata_int = (FPU == 1 || COREV_PULP == 1 || COREV_CLUSTER == 1) ? 32'h1 : 'b0; end // unimplemented, read 0 CSRs @@ -897,6 +899,7 @@ module cv32e40p_cs_registers dscratch0_n = dscratch0_q; dscratch1_n = dscratch1_q; + mstatus_we_int = 1'b0; mstatus_n = mstatus_q; mcause_n = mcause_q; ucause_n = '0; // Not used if PULP_SECURE == 0 @@ -957,7 +960,8 @@ module cv32e40p_cs_registers mprv: csr_wdata_int[MSTATUS_MPRV_BIT] }; if (FPU == 1 && ZFINX == 0) begin - mstatus_fs_n = FS_t'(csr_wdata_int[MSTATUS_FS_BIT_HIGH:MSTATUS_FS_BIT_LOW]); + mstatus_we_int = 1'b1; + mstatus_fs_n = FS_t'(csr_wdata_int[MSTATUS_FS_BIT_HIGH:MSTATUS_FS_BIT_LOW]); end end // mie: machine interrupt enable @@ -1027,7 +1031,7 @@ module cv32e40p_cs_registers if (ZFINX == 0) begin // FPU Register File/Flags implicit update or modified by CSR instructions - if (fflags_we_i || fcsr_update) begin + if ((fregs_we_i && !(mstatus_we_int && mstatus_fs_n != FS_DIRTY)) || fflags_we_i || fcsr_update) begin mstatus_fs_n = FS_DIRTY; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_ex_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_ex_stage.sv index c51ef7f8..488a83dc 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_ex_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_ex_stage.sv @@ -33,6 +33,7 @@ module cv32e40p_ex_stage import cv32e40p_pkg::*; import cv32e40p_apu_core_pkg::*; #( + parameter COREV_PULP = 0, parameter FPU = 0, parameter APU_NARGS_CPU = 3, parameter APU_WOP_CPU = 6, @@ -81,6 +82,8 @@ module cv32e40p_ex_stage input logic data_misaligned_ex_i, input logic data_misaligned_i, + input logic [1:0] ctrl_transfer_insn_in_dec_i, + // FPU signals output logic fpu_fflags_we_o, output logic [APU_NUSFLAGS_CPU-1:0] fpu_fflags_o, @@ -138,11 +141,13 @@ module cv32e40p_ex_stage // Output of EX stage pipeline output logic [ 5:0] regfile_waddr_wb_o, output logic regfile_we_wb_o, + output logic regfile_we_wb_power_o, output logic [31:0] regfile_wdata_wb_o, // Forwarding ports : to ID stage output logic [ 5:0] regfile_alu_waddr_fw_o, output logic regfile_alu_we_fw_o, + output logic regfile_alu_we_fw_power_o, output logic [31:0] regfile_alu_wdata_fw_o, // forward to RF and ID/EX pipe, ALU & MUL // To IF: Jump and branch target and decision @@ -190,22 +195,27 @@ module cv32e40p_ex_stage // ALU write port mux always_comb begin - regfile_alu_wdata_fw_o = '0; - regfile_alu_waddr_fw_o = '0; - regfile_alu_we_fw_o = '0; - wb_contention = 1'b0; + regfile_alu_wdata_fw_o = '0; + regfile_alu_waddr_fw_o = '0; + regfile_alu_we_fw_o = 1'b0; + regfile_alu_we_fw_power_o = 1'b0; + wb_contention = 1'b0; - // APU single cycle operations, and multicycle operations (>2cycles) are written back on ALU port + // APU single cycle operations, and multicycle operations (> 2cycles) are written back on ALU port if (apu_valid & (apu_singlecycle | apu_multicycle)) begin - regfile_alu_we_fw_o = 1'b1; - regfile_alu_waddr_fw_o = apu_waddr; - regfile_alu_wdata_fw_o = apu_result; + regfile_alu_we_fw_o = 1'b1; + regfile_alu_we_fw_power_o = 1'b1; + regfile_alu_waddr_fw_o = apu_waddr; + regfile_alu_wdata_fw_o = apu_result; if (regfile_alu_we_i & ~apu_en_i) begin wb_contention = 1'b1; end end else begin - regfile_alu_we_fw_o = regfile_alu_we_i & ~apu_en_i; // private fpu incomplete? + regfile_alu_we_fw_o = regfile_alu_we_i & ~apu_en_i; + regfile_alu_we_fw_power_o = (COREV_PULP == 0) ? regfile_alu_we_i & ~apu_en_i : + regfile_alu_we_i & ~apu_en_i & + mult_ready & alu_ready & lsu_ready_ex_i; regfile_alu_waddr_fw_o = regfile_alu_waddr_i; if (alu_en_i) regfile_alu_wdata_fw_o = alu_result; if (mult_en_i) regfile_alu_wdata_fw_o = mult_result; @@ -215,21 +225,24 @@ module cv32e40p_ex_stage // LSU write port mux always_comb begin - regfile_we_wb_o = 1'b0; - regfile_waddr_wb_o = regfile_waddr_lsu; - regfile_wdata_wb_o = lsu_rdata_i; - wb_contention_lsu = 1'b0; + regfile_we_wb_o = 1'b0; + regfile_we_wb_power_o = 1'b0; + regfile_waddr_wb_o = regfile_waddr_lsu; + regfile_wdata_wb_o = lsu_rdata_i; + wb_contention_lsu = 1'b0; if (regfile_we_lsu) begin - regfile_we_wb_o = 1'b1; + regfile_we_wb_o = 1'b1; + regfile_we_wb_power_o = (COREV_PULP == 0) ? 1'b1 : ~data_misaligned_ex_i & wb_ready_i; if (apu_valid & (!apu_singlecycle & !apu_multicycle)) begin wb_contention_lsu = 1'b1; end // APU two-cycle operations are written back on LSU port end else if (apu_valid & (!apu_singlecycle & !apu_multicycle)) begin - regfile_we_wb_o = 1'b1; - regfile_waddr_wb_o = apu_waddr; - regfile_wdata_wb_o = apu_result; + regfile_we_wb_o = 1'b1; + regfile_we_wb_power_o = 1'b1; + regfile_waddr_wb_o = apu_waddr; + regfile_wdata_wb_o = apu_result; end end @@ -371,11 +384,20 @@ module cv32e40p_ex_stage apu_result_q <= 'b0; apu_flags_q <= 'b0; end else begin - if (apu_rvalid_i && apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || (data_req_i && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) begin + if (apu_rvalid_i && apu_multicycle && + (data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) begin apu_rvalid_q <= 1'b1; apu_result_q <= apu_result_i; apu_flags_q <= apu_flags_i; - end else if (apu_rvalid_q && !(data_misaligned_i || data_misaligned_ex_i || ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) begin + end else if (apu_rvalid_q && !(data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) begin apu_rvalid_q <= 1'b0; end end @@ -383,7 +405,12 @@ module cv32e40p_ex_stage assign apu_req_o = apu_req; assign apu_gnt = apu_gnt_i; - assign apu_valid = (apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || (mulh_active && (mult_operator_i == MUL_H)))) ? 1'b0 : (apu_rvalid_i || apu_rvalid_q); + assign apu_valid = (apu_multicycle && (data_misaligned_i || data_misaligned_ex_i || + ((data_req_i || data_rvalid_i) && regfile_alu_we_i) || + (mulh_active && (mult_operator_i == MUL_H)) || + ((ctrl_transfer_insn_in_dec_i == BRANCH_JALR) && + regfile_alu_we_i && ~apu_read_dep_for_jalr_o))) + ? 1'b0 : (apu_rvalid_i || apu_rvalid_q); assign apu_operands_o = apu_operands_i; assign apu_op_o = apu_op_i; assign apu_result = apu_rvalid_q ? apu_result_q : apu_result_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv index 042fa0f2..62ec46c2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv @@ -111,7 +111,7 @@ module cv32e40p_fp_wrapper .int_fmt_i (fpnew_pkg::int_format_e'(fpu_int_fmt)), .vectorial_op_i(fpu_vec_op), .tag_i (1'b0), - .simd_mask_i ('b0), + .simd_mask_i (1'b0), .in_valid_i (apu_req_i), .in_ready_o (apu_gnt_o), .flush_i (1'b0), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv index 7811eabf..93bb1380 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv @@ -70,6 +70,7 @@ module cv32e40p_id_stage output logic branch_in_ex_o, input logic branch_decision_i, output logic [31:0] jump_target_o, + output logic [ 1:0] ctrl_transfer_insn_in_dec_o, // IF and ID stage signals output logic clear_instr_valid_o, @@ -225,10 +226,12 @@ module cv32e40p_id_stage // Forward Signals input logic [5:0] regfile_waddr_wb_i, input logic regfile_we_wb_i, + input logic regfile_we_wb_power_i, input logic [31:0] regfile_wdata_wb_i, // From wb_stage: selects data from data memory, ex_stage result and sp rdata input logic [ 5:0] regfile_alu_waddr_fw_i, input logic regfile_alu_we_fw_i, + input logic regfile_alu_we_fw_power_i, input logic [31:0] regfile_alu_wdata_fw_i, // from ALU @@ -809,6 +812,9 @@ module cv32e40p_id_stage if (ctrl_transfer_target_mux_sel == JT_JALR) begin apu_read_regs[0] = regfile_addr_ra_id; apu_read_regs_valid[0] = 1'b1; + end else begin + apu_read_regs[0] = regfile_addr_ra_id; + apu_read_regs_valid[0] = 1'b0; end end // OP_A_CURRPC: OP_A_REGA_OR_FWD: begin @@ -948,12 +954,12 @@ module cv32e40p_id_stage // Write port a .waddr_a_i(regfile_waddr_wb_i), .wdata_a_i(regfile_wdata_wb_i), - .we_a_i (regfile_we_wb_i), + .we_a_i (regfile_we_wb_power_i), // Write port b .waddr_b_i(regfile_alu_waddr_fw_i), .wdata_b_i(regfile_alu_wdata_fw_i), - .we_b_i (regfile_alu_we_fw_i) + .we_b_i (regfile_alu_we_fw_power_i) ); @@ -1087,7 +1093,7 @@ module cv32e40p_id_stage .debug_wfi_no_sleep_i(debug_wfi_no_sleep), // jump/branches - .ctrl_transfer_insn_in_dec_o (ctrl_transfer_insn_in_dec), + .ctrl_transfer_insn_in_dec_o (ctrl_transfer_insn_in_dec_o), .ctrl_transfer_insn_in_id_o (ctrl_transfer_insn_in_id), .ctrl_transfer_target_mux_sel_o(ctrl_transfer_target_mux_sel), @@ -1187,7 +1193,7 @@ module cv32e40p_id_stage // jump/branch control .branch_taken_ex_i (branch_taken_ex), .ctrl_transfer_insn_in_id_i (ctrl_transfer_insn_in_id), - .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec), + .ctrl_transfer_insn_in_dec_i(ctrl_transfer_insn_in_dec_o), // Interrupt signals .irq_wu_ctrl_i (irq_wu_ctrl), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40x.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40x.core index 70a248de..7a12b181 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40x.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40x.core @@ -67,3 +67,4 @@ targets: filesets: - files_rtl - target_sim? (files_clk_gate) + - target_sim_sc? (files_clk_gate) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson index d1cc1ce7..a9251111 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson @@ -8,7 +8,7 @@ { upstream: { - url: https://github.com/davideschiavone/cve2.git - rev: 5039e60cdea6a76282576ca7e93a35ee9a3ff2e9 + url: https://github.com/openhwgroup/cve2.git + rev: f5b21e71c9b511477b04ef81d1292858c51ac20c } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson index 8c860069..d398c1eb 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson @@ -6,22 +6,43 @@ target_dir: "openhwgroup_cv32e20", upstream: { - url: "https://github.com/davideschiavone/cve2.git", - rev: "5039e60cdea6a76282576ca7e93a35ee9a3ff2e9", + url: "https://github.com/openhwgroup/cve2.git", + rev: "f5b21e71c9b511477b04ef81d1292858c51ac20c", }, + patch_dir: "patches/openhwgroup_cv32e20", + exclude_from_upstream: [ "ci", "dv", "examples", "formal", ".dir-locals.el", - "cv32e40p_manifest.flist", "doc", "shared", "syn", "util", - "vendor", + "scripts", + "vendor/eembc_coremark", + "vendor/eembc_coremark.lock.hjson", + "vendor/google_riscv-dv", + "vendor/google_riscv-dv.lock.hjson", + "vendor/google_riscv-dv.vendor.hjson", + "vendor/lowrisc_ip.lock.hjson", + "vendor/lowrisc_ip.vendor.hjson", + "vendor/patches", + "vendor/lowrisc_ip/ip" + "vendor/lowrisc_ip/lint" + "vendor/lowrisc_ip/util" + "vendor/lowrisc_ip/dv/tools", + "vendor/lowrisc_ip/dv/verilator", + "vendor/lowrisc_ip/dv/sv/common_ifs", + "vendor/lowrisc_ip/dv/sv/csr_utils", + "vendor/lowrisc_ip/dv/sv/dv_base_reg", + "vendor/lowrisc_ip/dv/sv/dv_lib", + "vendor/lowrisc_ip/dv/sv/mem_bkdr_util", + "vendor/lowrisc_ip/dv/sv/mem_model", + "vendor/lowrisc_ip/dv/sv/str_utils", ".github", "azure-pipelines.yml", "check_tool_requirements.core", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/esl_epfl_cv32e40px/0001-vendor-cv32e40px-Re-vendor.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/esl_epfl_cv32e40px/0001-vendor-cv32e40px-Re-vendor.patch deleted file mode 100644 index 28ab47b1..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/esl_epfl_cv32e40px/0001-vendor-cv32e40px-Re-vendor.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/rtl/cv32e40px_cs_registers.sv b/rtl/cv32e40px_cs_registers.sv -index 1f1d56b..cdc6433 100644 ---- a/rtl/cv32e40px_cs_registers.sv -+++ b/rtl/cv32e40px_cs_registers.sv -@@ -1450,7 +1450,7 @@ module cv32e40px_cs_registers - // minstret is located at index 2 - // Programable HPM counters start at index 3 - if ((cnt_gidx == 1) || (cnt_gidx >= (NUM_MHPMCOUNTERS + 3))) begin : gen_non_implemented -- assign mhpmcounter_q[cnt_gidx] = 'b0; -+ always_ff @(posedge clk) mhpmcounter_q[cnt_gidx] <= 'b0; - end else begin : gen_implemented - always_ff @(posedge clk, negedge rst_n) - if (!rst_n) begin -@@ -1478,10 +1478,10 @@ module cv32e40px_cs_registers - for (evt_gidx = 0; evt_gidx < 32; evt_gidx++) begin : gen_mhpmevent - // programable HPM events start at index3 - if ((evt_gidx < 3) || (evt_gidx >= (NUM_MHPMCOUNTERS + 3))) begin : gen_non_implemented -- assign mhpmevent_q[evt_gidx] = 'b0; -+ always_ff @(posedge clk) mhpmevent_q[evt_gidx] <= 'b0; - end else begin : gen_implemented - if (NUM_HPM_EVENTS < 32) begin : gen_tie_off -- assign mhpmevent_q[evt_gidx][31:NUM_HPM_EVENTS] = 'b0; -+ always_ff @(posedge clk) mhpmevent_q[evt_gidx][31:NUM_HPM_EVENTS] <= 'b0; - end - always_ff @(posedge clk, negedge rst_n) - if (!rst_n) mhpmevent_q[evt_gidx][NUM_HPM_EVENTS-1:0] <= 'b0; -@@ -1499,7 +1499,7 @@ module cv32e40px_cs_registers - (en_gidx == 1) || - (en_gidx >= (NUM_MHPMCOUNTERS+3) ) ) - begin : gen_non_implemented -- assign mcounteren_q[en_gidx] = 'b0; -+ always_ff @(posedge clk) mcounteren_q[en_gidx] <= 'b0; - end else begin : gen_implemented - always_ff @(posedge clk, negedge rst_n) - if (!rst_n) mcounteren_q[en_gidx] <= 'b0; // default disable -@@ -1514,7 +1514,7 @@ module cv32e40px_cs_registers - generate - for (inh_gidx = 0; inh_gidx < 32; inh_gidx++) begin : gen_mcountinhibit - if ((inh_gidx == 1) || (inh_gidx >= (NUM_MHPMCOUNTERS + 3))) begin : gen_non_implemented -- assign mcountinhibit_q[inh_gidx] = 'b0; -+ always_ff @(posedge clk) mcountinhibit_q[inh_gidx] <= 'b0; - end else begin : gen_implemented - always_ff @(posedge clk, negedge rst_n) - if (!rst_n) mcountinhibit_q[inh_gidx] <= 'b1; // default disable diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/lowrisc_opentitan/uartdpi.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/lowrisc_opentitan/uartdpi.patch index 94b7d2b8..54c13229 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/lowrisc_opentitan/uartdpi.patch +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/lowrisc_opentitan/uartdpi.patch @@ -1,5 +1,5 @@ diff --git a/hw/dv/dpi/uartdpi/uartdpi.h b/hw/dv/dpi/uartdpi/uartdpi.h -index 29d50a5a2..2149fb115 100644 +index 29d50a5a28..2149fb1155 100644 --- a/hw/dv/dpi/uartdpi/uartdpi.h +++ b/hw/dv/dpi/uartdpi/uartdpi.h @@ -5,7 +5,9 @@ @@ -21,21 +21,23 @@ index 29d50a5a2..2149fb115 100644 +#endif #endif // OPENTITAN_HW_DV_DPI_UARTDPI_UARTDPI_H_ diff --git a/hw/dv/dpi/uartdpi/uartdpi.sv b/hw/dv/dpi/uartdpi/uartdpi.sv -index 97fae4767..07c75cf8e 100644 +index 97fae47674..2be4df54ff 100644 --- a/hw/dv/dpi/uartdpi/uartdpi.sv +++ b/hw/dv/dpi/uartdpi/uartdpi.sv -@@ -82,11 +82,14 @@ module uartdpi #( +@@ -82,11 +82,16 @@ module uartdpi #( end end - +`ifndef VCS +`ifndef MODELSIM ++`ifndef XCELIUM initial begin // Prevent falling edges of rx_i before reset causing spurious characters seen_reset = 0; end +`endif ++`endif +`endif // RX diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_assert.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_assert.patch new file mode 100644 index 00000000..4ac84c15 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_assert.patch @@ -0,0 +1,12 @@ +diff --git a/rtl/cve2_top.sv b/rtl/cve2_top.sv +index 34af60b7..00c38a4a 100644 +--- a/rtl/cve2_top.sv ++++ b/rtl/cve2_top.sv +@@ -265,7 +265,6 @@ module cve2_top import cve2_pkg::*; #( + + `ASSERT_KNOWN(IbexDataGntX, data_gnt_i) + `ASSERT_KNOWN(IbexDataRValidX, data_rvalid_i) +- `ASSERT_KNOWN_IF(IbexDataRPayloadX, {data_rdata_i, data_err_i}, data_rvalid_i) + + `ASSERT_KNOWN(IbexIrqX, {irq_software_i, irq_timer_i, irq_external_i, irq_fast_i, irq_nm_i}) + diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_core.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_core.patch new file mode 100644 index 00000000..9727dec1 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/openhwgroup_cv32e20/cv32e20_core.patch @@ -0,0 +1,12 @@ +diff --git a/cve2_top.core b/cve2_top.core +index cb4e23b4..0d9d2c5c 100644 +--- a/cve2_top.core ++++ b/cve2_top.core +@@ -75,6 +75,7 @@ targets: + - tool_veriblelint ? (files_lint_verible) + - files_rtl + - target_sim ? (files_clk_gate) ++ - target_sim_sc ? (files_clk_gate) + toplevel: cve2_top + parameters: + - tool_vivado ? (FPGA_XILINX=true) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_common_cells/clk_mux_glitch_free.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_common_cells/clk_mux_glitch_free.patch new file mode 100644 index 00000000..3e5ccb84 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_common_cells/clk_mux_glitch_free.patch @@ -0,0 +1,13 @@ +diff --git a/src/clk_mux_glitch_free.sv b/src/clk_mux_glitch_free.sv +index e0eb5cd..5193742 100644 +--- a/src/clk_mux_glitch_free.sv ++++ b/src/clk_mux_glitch_free.sv +@@ -191,7 +191,7 @@ endmodule + + // Helper Module to generate an N-input clock OR-gate from a tree of tc_clk_or2 cells. + module clk_or_tree #( +- parameter int unsigned NUM_INPUTS ++ parameter int unsigned NUM_INPUTS = 1 + ) ( + input logic [NUM_INPUTS-1:0] clks_i, + output logic clk_o diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch deleted file mode 100644 index 5b525705..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0002-spiflash_valueargs.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v -index 22b337b..e0eef9f 100644 ---- a/picosoc/spiflash.v -+++ b/picosoc/spiflash.v -@@ -102,8 +102,14 @@ module spiflash ( - reg [7:0] memory [0:16*1024*1024-1]; - - reg [1023:0] firmware_file; -+ reg result; -+ integer i; -+ - initial begin -- if (!$value$plusargs("firmware=%s", firmware_file)) -+ for (i=0;i<=16*1024*1024;i=i+1) -+ memory[i] = '0; -+ result = $value$plusargs("firmware=%s", firmware_file); -+ if (!result) - firmware_file = "firmware.hex"; - $readmemh(firmware_file, memory); - end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spiflash.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spiflash.patch new file mode 100644 index 00000000..3583151d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spiflash.patch @@ -0,0 +1,113 @@ +diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v +index 22b337b..55342b5 100644 +--- a/picosoc/spiflash.v ++++ b/picosoc/spiflash.v +@@ -26,7 +26,7 @@ + // updates output signals 1ns after the SPI clock edge. + // + // Supported commands: +-// AB, B9, FF, 03, BB, EB, ED ++// AB, B9, FF, 03, BB, EB, ED, 06, 02, 32 + // + // Well written SPI flash data sheets: + // Cypress S25FL064L http://www.cypress.com/file/316661/download +@@ -61,6 +61,8 @@ module spiflash ( + reg spi_io_vld; + + reg powered_up = 0; ++ reg write_enable = 0; ++ reg write_enable_reset = 0; + + localparam [3:0] mode_spi = 1; + localparam [3:0] mode_dspi_rd = 2; +@@ -102,8 +104,14 @@ module spiflash ( + reg [7:0] memory [0:16*1024*1024-1]; + + reg [1023:0] firmware_file; ++ reg result; ++ integer i; ++ + initial begin +- if (!$value$plusargs("firmware=%s", firmware_file)) ++ for (i=0;i<=16*1024*1024;i=i+1) ++ memory[i] = 8'h00; ++ result = $value$plusargs("firmware=%s", firmware_file); ++ if (!result) + firmware_file = "firmware.hex"; + $readmemh(firmware_file, memory); + end +@@ -123,6 +131,9 @@ module spiflash ( + + if (spi_cmd == 8'h ff) + xip_cmd = 0; ++ ++ if (spi_cmd == 8'h 06) ++ write_enable = 1; + end + + if (powered_up && spi_cmd == 'h 03) begin +@@ -141,6 +152,25 @@ module spiflash ( + end + end + ++ if (powered_up && write_enable && spi_cmd == 'h 02) begin ++ if (bytecount == 1) ++ write_enable_reset = 1; ++ ++ if (bytecount == 2) ++ spi_addr[23:16] = buffer; ++ ++ if (bytecount == 3) ++ spi_addr[15:8] = buffer; ++ ++ if (bytecount == 4) ++ spi_addr[7:0] = buffer; ++ ++ if (bytecount >= 5 && bytecount <= 260) begin ++ memory[spi_addr] = buffer; ++ spi_addr = spi_addr + 1; ++ end ++ end ++ + if (powered_up && spi_cmd == 'h bb) begin + if (bytecount == 1) + mode = mode_dspi_rd; +@@ -191,6 +221,27 @@ module spiflash ( + end + end + ++ if (powered_up && write_enable && spi_cmd == 'h 32) begin ++ if (bytecount == 1) ++ write_enable_reset = 1; ++ ++ if (bytecount == 2) ++ spi_addr[23:16] = buffer; ++ ++ if (bytecount == 3) ++ spi_addr[15:8] = buffer; ++ ++ if (bytecount == 4) begin ++ spi_addr[7:0] = buffer; ++ mode = mode_qspi_rd; ++ end ++ ++ if (bytecount >= 5 && bytecount <= 260) begin ++ memory[spi_addr] = buffer; ++ spi_addr = spi_addr + 1; ++ end ++ end ++ + if (powered_up && spi_cmd == 'h ed) begin + if (bytecount == 1) + next_mode = mode_qspi_ddr_rd; +@@ -268,6 +319,10 @@ module spiflash ( + $display(""); + $fflush; + end ++ if (write_enable_reset) begin ++ write_enable = 0; ++ write_enable_reset = 0; ++ end + buffer = 0; + bitcount = 0; + bytecount = 0; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0001-async.-lowactive-reset.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spimemio.patch similarity index 100% rename from hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/0001-async.-lowactive-reset.patch rename to hw/vendor/esl_epfl_x_heep/hw/vendor/patches/yosyshq_picorv32/spimemio.patch diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_common_cells/src/clk_mux_glitch_free.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_common_cells/src/clk_mux_glitch_free.sv index e0eb5cdc..51937424 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_common_cells/src/clk_mux_glitch_free.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_common_cells/src/clk_mux_glitch_free.sv @@ -191,7 +191,7 @@ endmodule // Helper Module to generate an N-input clock OR-gate from a tree of tc_clk_or2 cells. module clk_or_tree #( - parameter int unsigned NUM_INPUTS + parameter int unsigned NUM_INPUTS = 1 ) ( input logic [NUM_INPUTS-1:0] clks_i, output logic clk_o diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.lock.hjson index bc1ec555..de40549d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/pulp-platform/fpnew.git - rev: d6e581628f3517a1fb1257507d3214e599f7859d + rev: 79e453139072df42c9ec8f697132ba485d74e23d } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.vendor.hjson index 7ae0d55c..1fe09cca 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_fpnew.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/pulp-platform/fpnew.git", - rev: "d6e581628f3517a1fb1257507d3214e599f7859d", + rev: "79e453139072df42c9ec8f697132ba485d74e23d", }, exclude_from_upstream: [ diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_gpio.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_gpio.core index 630f318a..2d79c611 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_gpio.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_gpio.core @@ -39,8 +39,10 @@ targets: - rtl - "gpio-test? (testbench)" - target_sim? (clock-gate) + - target_sim_sc? (clock-gate) - target_asic_synthesis? (clock-gate) - target_asic_yosys_synthesis? (clock-gate) - target_nexys-a7-100t? (no-clock-gate) - target_pynq-z2? (no-clock-gate) - target_pynq-z2-arm-emulation? (no-clock-gate) + - target_zcu104? (no-clock-gate) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.lock.hjson index 3f13125e..f74356a1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/pulp-platform/riscv-dbg.git - rev: 69be5ddc03ea1688c0eab47d6ed9d0e8725beda1 + rev: 358f90110220adf7a083f8b65d157e836d706236 } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson index 2ec8e7e9..1c13cb43 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/pulp-platform/riscv-dbg.git", - rev: "69be5ddc03ea1688c0eab47d6ed9d0e8725beda1", + rev: "358f90110220adf7a083f8b65d157e836d706236", }, exclude_from_upstream: [ diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/CHANGELOG.md b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/CHANGELOG.md index 35db8983..99dab605 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/CHANGELOG.md +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/CHANGELOG.md @@ -4,7 +4,40 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## Unreleased + +## [0.8.1] - 2023-10-01 +### Changed +- debug_rom: Add rst + +## [0.8.0] - 2023-04-05 +### Fixed +- dm_csrs: Fix W1C behavior of `sberror` (#155) [@andreaskurth](https://github.com/andreaskurth) +- gen_rom.py: Port to python3 (#152) [@andreaskurth](https://github.com/andreaskurth) + +### Added +- `xprop_off` to Xprop-incompatible processes (#151) [@andreaskurth](https://github.com/andreaskurth) + +## [0.7.0] - 2022-11-02 +### Fixed +- 64-bit unaligned accesses (#145) [@creinwar](https://github.com/creinwar) +- Various minor testbench fixes (#146) + +### Changed +- Halted, Resume and Exception addresses are now aligned to 8 bytes + +## [0.6.0] - 2022-10-11 +### Fixed +- Testbench build (#141, #142) +- remote_bitbang tb build for newer GCC versions (#133) [@epsilon537](https://github.com/noytzach) +- 32-bit access to abstract data (#27) [@Silabs-ArjanB](https://github.com/Silabs-ArjanB) +- `dm_mem`: Clear state of hart upon ndmreset (#140) [@andreaskurth](https://github.com/andreaskurth) +- `dmi_jtag_tap`: Bring all state to initial value in test-logic-reset (#139) [@andreaskurth](https://github.com/andreaskurth) +- Fix DMI response when command or SBA are busy (#138) [@andreaskurth](https://github.com/andreaskurth) + +### Changed +- Add expontential backoff to read_dmi in tb (#134) [@colluca](https://github.com/colluca) + ## [0.5.1] - 2022-04-12 ### Fixed - Fixed dmi_bscane_tap top-level signals diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/Makefile b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/Makefile index b23370aa..931e2532 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/Makefile +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/Makefile @@ -5,7 +5,7 @@ debug_rom = debug_rom.sv debug_rom_one_scratch.sv GCC?=riscv64-unknown-elf-gcc OBJCOPY?=riscv64-unknown-elf-objcopy OBJDUMP?=riscv64-unknown-elf-objdump -PYTHON?=python +PYTHON?=python3 all: $(debug_rom) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.S b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.S index 2989c7e8..7126ae46 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.S +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.S @@ -6,9 +6,9 @@ // # define SND_SCRATCH 1 // These are implementation-specific addresses in the Debug Module #define HALTED 0x100 -#define GOING 0x104 -#define RESUMING 0x108 -#define EXCEPTION 0x10C +#define GOING 0x108 +#define RESUMING 0x110 +#define EXCEPTION 0x118 // Region of memory where each hart has 1 // byte to read. @@ -26,10 +26,13 @@ entry: jal zero, _entry + nop resume: jal zero, _resume + nop exception: jal zero, _exception + nop diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.h b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.h index b4f2d35a..9e1d73d2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.h +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.h @@ -1,11 +1,14 @@ // Auto-generated code -const int reset_vec_size = 38; +const int reset_vec_size = 40; uint32_t reset_vec[reset_vec_size] = { - 0x00c0006f, - 0x07c0006f, - 0x04c0006f, + 0x0180006f, + 0x00000013, + 0x0840006f, + 0x00000013, + 0x0500006f, + 0x00000013, 0x0ff0000f, 0x7b241073, 0x7b351073, @@ -22,23 +25,22 @@ uint32_t reset_vec[reset_vec_size] = { 0x00a40433, 0x40044403, 0x00247413, - 0xfa041ce3, + 0xfa0418e3, 0xfd5ff06f, 0x00000517, 0x00c55513, 0x00c51513, - 0x10052623, + 0x10052c23, 0x7b302573, 0x7b202473, 0x00100073, - 0x10052223, + 0x10052423, 0x7b302573, 0x7b202473, - 0xa85ff06f, + 0xa79ff06f, 0xf1402473, - 0x10852423, + 0x10852823, 0x7b302573, 0x7b202473, - 0x7b200073, - 0x00000000 + 0x7b200073 }; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.sv index 0299db6b..ac10eeea 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom.sv @@ -16,41 +16,47 @@ // Auto-generated code module debug_rom ( input logic clk_i, + input logic rst_ni, input logic req_i, input logic [63:0] addr_i, output logic [63:0] rdata_o ); - localparam int unsigned RomSize = 19; + localparam int unsigned RomSize = 20; logic [RomSize-1:0][63:0] mem; assign mem = { - 64'h00000000_7b200073, + 64'h7b200073_7b202473, + 64'h7b302573_10852823, + 64'hf1402473_a79ff06f, 64'h7b202473_7b302573, - 64'h10852423_f1402473, - 64'ha85ff06f_7b202473, - 64'h7b302573_10052223, - 64'h00100073_7b202473, - 64'h7b302573_10052623, - 64'h00c51513_00c55513, - 64'h00000517_fd5ff06f, - 64'hfa041ce3_00247413, - 64'h40044403_00a40433, - 64'hf1402473_02041c63, - 64'h00147413_40044403, - 64'h00a40433_10852023, - 64'hf1402473_00c51513, + 64'h10052423_00100073, + 64'h7b202473_7b302573, + 64'h10052c23_00c51513, 64'h00c55513_00000517, - 64'h7b351073_7b241073, - 64'h0ff0000f_04c0006f, - 64'h07c0006f_00c0006f + 64'hfd5ff06f_fa0418e3, + 64'h00247413_40044403, + 64'h00a40433_f1402473, + 64'h02041c63_00147413, + 64'h40044403_00a40433, + 64'h10852023_f1402473, + 64'h00c51513_00c55513, + 64'h00000517_7b351073, + 64'h7b241073_0ff0000f, + 64'h00000013_0500006f, + 64'h00000013_0840006f, + 64'h00000013_0180006f }; - logic [$clog2(RomSize)-1:0] addr_q; + logic [$clog2(RomSize)-1:0] addr_d, addr_q; + + assign addr_d = req_i ? addr_i[$clog2(RomSize)-1+3:3] : addr_q; - always_ff @(posedge clk_i) begin - if (req_i) begin - addr_q <= addr_i[$clog2(RomSize)-1+3:3]; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + addr_q <= '0; + end else begin + addr_q <= addr_d; end end @@ -59,7 +65,7 @@ module debug_rom ( always_comb begin : p_outmux rdata_o = '0; if (addr_q < $clog2(RomSize)'(RomSize)) begin - rdata_o = mem[addr_q]; + rdata_o = mem[addr_q]; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.h b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.h index 625d66a0..d4539714 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.h +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.h @@ -1,11 +1,14 @@ // Auto-generated code -const int reset_vec_size = 26; +const int reset_vec_size = 28; uint32_t reset_vec[reset_vec_size] = { - 0x00c0006f, - 0x0500006f, - 0x0340006f, + 0x0180006f, + 0x00000013, + 0x0580006f, + 0x00000013, + 0x0380006f, + 0x00000013, 0x0ff0000f, 0x7b241073, 0xf1402473, @@ -16,17 +19,16 @@ uint32_t reset_vec[reset_vec_size] = { 0xf1402473, 0x40044403, 0x00247413, - 0xfc0418e3, + 0xfc0414e3, 0xfddff06f, - 0x10002623, + 0x10002c23, 0x7b202473, 0x00100073, - 0x10002223, + 0x10002423, 0x7b202473, - 0xab1ff06f, + 0xaa5ff06f, 0xf1402473, - 0x10802423, + 0x10802823, 0x7b202473, - 0x7b200073, - 0x00000000 + 0x7b200073 }; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.sv index af7e67c7..3cd2d9e2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/debug_rom_one_scratch.sv @@ -16,35 +16,41 @@ // Auto-generated code module debug_rom_one_scratch ( input logic clk_i, + input logic rst_ni, input logic req_i, input logic [63:0] addr_i, output logic [63:0] rdata_o ); - localparam int unsigned RomSize = 13; + localparam int unsigned RomSize = 14; logic [RomSize-1:0][63:0] mem; assign mem = { - 64'h00000000_7b200073, - 64'h7b202473_10802423, - 64'hf1402473_ab1ff06f, - 64'h7b202473_10002223, - 64'h00100073_7b202473, - 64'h10002623_fddff06f, - 64'hfc0418e3_00247413, - 64'h40044403_f1402473, - 64'h02041263_00147413, - 64'h40044403_10802023, - 64'hf1402473_7b241073, - 64'h0ff0000f_0340006f, - 64'h0500006f_00c0006f + 64'h7b200073_7b202473, + 64'h10802823_f1402473, + 64'haa5ff06f_7b202473, + 64'h10002423_00100073, + 64'h7b202473_10002c23, + 64'hfddff06f_fc0414e3, + 64'h00247413_40044403, + 64'hf1402473_02041263, + 64'h00147413_40044403, + 64'h10802023_f1402473, + 64'h7b241073_0ff0000f, + 64'h00000013_0380006f, + 64'h00000013_0580006f, + 64'h00000013_0180006f }; - logic [$clog2(RomSize)-1:0] addr_q; + logic [$clog2(RomSize)-1:0] addr_d, addr_q; - always_ff @(posedge clk_i) begin - if (req_i) begin - addr_q <= addr_i[$clog2(RomSize)-1+3:3]; + assign addr_d = req_i ? addr_i[$clog2(RomSize)-1+3:3] : addr_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + addr_q <= '0; + end else begin + addr_q <= addr_d; end end @@ -53,7 +59,7 @@ module debug_rom_one_scratch ( always_comb begin : p_outmux rdata_o = '0; if (addr_q < $clog2(RomSize)'(RomSize)) begin - rdata_o = mem[addr_q]; + rdata_o = mem[addr_q]; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/gen_rom.py b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/gen_rom.py index b8cb60bc..a34efc5d 100755 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/gen_rom.py +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/debug_rom/gen_rom.py @@ -43,6 +43,7 @@ module = """\ module $filename ( input logic clk_i, + input logic rst_ni, input logic req_i, input logic [63:0] addr_i, output logic [63:0] rdata_o @@ -55,11 +56,15 @@ $content }; - logic [$$clog2(RomSize)-1:0] addr_q; + logic [$$clog2(RomSize)-1:0] addr_d, addr_q; - always_ff @(posedge clk_i) begin - if (req_i) begin - addr_q <= addr_i[$$clog2(RomSize)-1+3:3]; + assign addr_d = req_i ? addr_i[$$clog2(RomSize)-1+3:3] : addr_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + addr_q <= '0; + end else begin + addr_q <= addr_d; end end @@ -68,7 +73,7 @@ always_comb begin : p_outmux rdata_o = '0; if (addr_q < $$clog2(RomSize)'(RomSize)) begin - rdata_o = mem[addr_q]; + rdata_o = mem[addr_q]; end end @@ -88,9 +93,8 @@ def read_bin(): with open(filename + ".img", 'rb') as f: - rom = binascii.hexlify(f.read()) - rom = map(''.join, zip(rom[::2], rom[1::2])) - + rom = bytes.hex(f.read()) + rom = list(map(''.join, zip(rom[::2], rom[1::2]))) # align to 64 bit align = (int((len(rom) + 7) / 8 )) * 8; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/doc/debug-system.md b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/doc/debug-system.md index 1beca7df..5fbfbe18 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/doc/debug-system.md +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/doc/debug-system.md @@ -439,9 +439,9 @@ Address | Description --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ 0x0 to 0x0ff | _unused_ 0x100 | Halted. Write to this address to acknowledge that the core is halted. -0x104 | Going. Write to this address to acknowledge that the core is executing. -0x108 | Resuming. Write to this address to acknowledge that the core is resuming non-debug operation. -0x10c | Exception. An exception was triggered while the core was in debug mode. +0x108 | Going. Write to this address to acknowledge that the core is executing. +0x110 | Resuming. Write to this address to acknowledge that the core is resuming non-debug operation. +0x118 | Exception. An exception was triggered while the core was in debug mode. 0x300 | WhereTo 0x338 to 0x35f | AbstractCmd 0x360 to 0x37f | Program Buffer (8 words) @@ -449,8 +449,8 @@ Address | Description 0x400 to 0x7ff | Flags 0x800 to 0x1000 | Debug ROM 0x800 | HaltAddress. Entry point into the Debug Module. The core must jump to this address when it was requested to halt. -0x804 | ResumeAddress. Entry point into the Debug Module. Jumping to this address instructs the debug module to bring the core out of debug mode and back into normal operation mode. -0x808 | ExceptionAddress. Entry point into the Debug Module. The core must jump to this address when it receives an exception while being in debug mode. +0x808 | ResumeAddress. Entry point into the Debug Module. Jumping to this address instructs the debug module to bring the core out of debug mode and back into normal operation mode. +0x810 | ExceptionAddress. Entry point into the Debug Module. The core must jump to this address when it receives an exception while being in debug mode. (Note: The debug memory addressing scheme is adopted from the Rocket Chip Generator.) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv index 350c6c5f..59d1c90a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv @@ -90,7 +90,6 @@ module dm_csrs #( logic resp_queue_empty; logic resp_queue_push; logic resp_queue_pop; - logic [31:0] resp_queue_data; localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'h0, dm::DataCount} - 8'h1); localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'h0, dm::ProgBufSize} - 8'h1); @@ -179,8 +178,8 @@ module dm_csrs #( logic [HartSelLen-1:0] selected_hart; - // a successful response returns zero - assign dmi_resp_o.resp = dm::DTM_SUCCESS; + dm::dmi_resp_t resp_queue_inp; + assign dmi_resp_valid_o = ~resp_queue_empty; assign dmi_req_ready_o = ~resp_queue_full; assign resp_queue_push = dmi_req_valid_i & dmi_req_ready_o; @@ -223,7 +222,7 @@ module dm_csrs #( // types instead. assign autoexecdata_idx = 4'({dm_csr_addr} - {dm::Data0}); - always_comb begin : csr_read_write + always_comb (*xprop_off *) begin : csr_read_write // -------------------- // Static Values (R/O) // -------------------- @@ -279,7 +278,8 @@ module dm_csrs #( sbaddr_d = 64'(sbaddress_i); sbdata_d = sbdata_q; - resp_queue_data = 32'h0; + resp_queue_inp.data = 32'h0; + resp_queue_inp.resp = dm::DTM_SUCCESS; cmd_valid_d = 1'b0; sbaddress_write_valid_o = 1'b0; sbdata_read_valid_o = 1'b0; @@ -294,62 +294,70 @@ module dm_csrs #( if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) begin unique case (dm_csr_addr) inside [(dm::Data0):DataEnd]: begin - resp_queue_data = data_q[$clog2(dm::DataCount)'(autoexecdata_idx)]; + resp_queue_inp.data = data_q[$clog2(dm::DataCount)'(autoexecdata_idx)]; if (!cmdbusy_i) begin // check whether we need to re-execute the command (just give a cmd_valid) cmd_valid_d = abstractauto_q.autoexecdata[autoexecdata_idx]; // An abstract command was executing while one of the data registers was read - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end - dm::DMControl: resp_queue_data = dmcontrol_q; - dm::DMStatus: resp_queue_data = dmstatus; - dm::Hartinfo: resp_queue_data = hartinfo_aligned[selected_hart]; - dm::AbstractCS: resp_queue_data = abstractcs; - dm::AbstractAuto: resp_queue_data = abstractauto_q; + dm::DMControl: resp_queue_inp.data = dmcontrol_q; + dm::DMStatus: resp_queue_inp.data = dmstatus; + dm::Hartinfo: resp_queue_inp.data = hartinfo_aligned[selected_hart]; + dm::AbstractCS: resp_queue_inp.data = abstractcs; + dm::AbstractAuto: resp_queue_inp.data = abstractauto_q; // command is read-only - dm::Command: resp_queue_data = '0; + dm::Command: resp_queue_inp.data = '0; [(dm::ProgBuf0):ProgBufEnd]: begin - resp_queue_data = progbuf_q[dmi_req_i.addr[$clog2(dm::ProgBufSize)-1:0]]; + resp_queue_inp.data = progbuf_q[dmi_req_i.addr[$clog2(dm::ProgBufSize)-1:0]]; if (!cmdbusy_i) begin // check whether we need to re-execute the command (just give a cmd_valid) // range of autoexecprogbuf is 31:16 cmd_valid_d = abstractauto_q.autoexecprogbuf[{1'b1, dmi_req_i.addr[3:0]}]; // An abstract command was executing while one of the progbuf registers was read - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end - dm::HaltSum0: resp_queue_data = haltsum0; - dm::HaltSum1: resp_queue_data = haltsum1; - dm::HaltSum2: resp_queue_data = haltsum2; - dm::HaltSum3: resp_queue_data = haltsum3; + dm::HaltSum0: resp_queue_inp.data = haltsum0; + dm::HaltSum1: resp_queue_inp.data = haltsum1; + dm::HaltSum2: resp_queue_inp.data = haltsum2; + dm::HaltSum3: resp_queue_inp.data = haltsum3; dm::SBCS: begin - resp_queue_data = sbcs_q; + resp_queue_inp.data = sbcs_q; end dm::SBAddress0: begin - resp_queue_data = sbaddr_q[31:0]; + resp_queue_inp.data = sbaddr_q[31:0]; end dm::SBAddress1: begin - resp_queue_data = sbaddr_q[63:32]; + resp_queue_inp.data = sbaddr_q[63:32]; end dm::SBData0: begin // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbdata_read_valid_o = (sbcs_q.sberror == '0); - resp_queue_data = sbdata_q[31:0]; + resp_queue_inp.data = sbdata_q[31:0]; end end dm::SBData1: begin // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin - resp_queue_data = sbdata_q[63:32]; + resp_queue_inp.data = sbdata_q[63:32]; end end default:; @@ -367,8 +375,11 @@ module dm_csrs #( // check whether we need to re-execute the command (just give a cmd_valid) cmd_valid_d = abstractauto_q.autoexecdata[autoexecdata_idx]; //An abstract command was executing while one of the data registers was written - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end end @@ -391,8 +402,11 @@ module dm_csrs #( // reads during abstract command execution are not allowed if (!cmdbusy_i) begin cmderr_d = dm::cmderr_e'(~a_abstractcs.cmderr & cmderr_q); - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end dm::Command: begin @@ -402,8 +416,11 @@ module dm_csrs #( command_d = dm::command_t'(dmi_req_i.data); // if there was an attempted to write during a busy execution // and the cmderror field is zero set the busy error - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end dm::AbstractAuto: begin @@ -412,8 +429,11 @@ module dm_csrs #( abstractauto_d = 32'h0; abstractauto_d.autoexecdata = 12'(dmi_req_i.data[dm::DataCount-1:0]); abstractauto_d.autoexecprogbuf = 16'(dmi_req_i.data[dm::ProgBufSize-1+16:16]); - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end [(dm::ProgBuf0):ProgBufEnd]: begin @@ -426,26 +446,31 @@ module dm_csrs #( // range of autoexecprogbuf is 31:16 cmd_valid_d = abstractauto_q.autoexecprogbuf[{1'b1, dmi_req_i.addr[3:0]}]; //An abstract command was executing while one of the progbuf registers was written - end else if (cmderr_q == dm::CmdErrNone) begin - cmderr_d = dm::CmdErrBusy; + end else begin + resp_queue_inp.resp = dm::DTM_BUSY; + if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end end end dm::SBCS: begin // access while the SBA was busy if (sbbusy_i) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbcs = dm::sbcs_t'(dmi_req_i.data); sbcs_d = sbcs; // R/W1C sbcs_d.sbbusyerror = sbcs_q.sbbusyerror & (~sbcs.sbbusyerror); - sbcs_d.sberror = sbcs_q.sberror & {3{~(sbcs.sberror == 3'd1)}}; + sbcs_d.sberror = (|sbcs.sberror) ? 3'b0 : sbcs_q.sberror; end end dm::SBAddress0: begin // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbaddr_d[31:0] = dmi_req_i.data; sbaddress_write_valid_o = (sbcs_q.sberror == '0); @@ -455,6 +480,7 @@ module dm_csrs #( // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbaddr_d[63:32] = dmi_req_i.data; end @@ -463,6 +489,7 @@ module dm_csrs #( // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbdata_d[31:0] = dmi_req_i.data; sbdata_write_valid_o = (sbcs_q.sberror == '0); @@ -472,6 +499,7 @@ module dm_csrs #( // access while the SBA was busy if (sbbusy_i || sbcs_q.sbbusyerror) begin sbcs_d.sbbusyerror = 1'b1; + resp_queue_inp.resp = dm::DTM_BUSY; end else begin sbdata_d[63:32] = dmi_req_i.data; end @@ -557,8 +585,8 @@ module dm_csrs #( // response FIFO fifo_v2 #( - .dtype ( logic [31:0] ), - .DEPTH ( 2 ) + .dtype ( logic [$bits(dmi_resp_o)-1:0] ), + .DEPTH ( 2 ) ) i_fifo ( .clk_i, .rst_ni, @@ -569,9 +597,9 @@ module dm_csrs #( .empty_o ( resp_queue_empty ), .alm_full_o ( ), .alm_empty_o ( ), - .data_i ( resp_queue_data ), + .data_i ( resp_queue_inp ), .push_i ( resp_queue_push ), - .data_o ( dmi_resp_o.data ), + .data_o ( dmi_resp_o ), .pop_i ( resp_queue_pop ) ); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv index 178259f6..9ff3c86a 100755 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv @@ -26,6 +26,7 @@ module dm_mem #( input logic rst_ni, // debug module reset output logic [NrHarts-1:0] debug_req_o, + input logic ndmreset_i, input logic [19:0] hartsel_i, // from Ctrl and Status register input logic [NrHarts-1:0] haltreq_i, @@ -77,9 +78,9 @@ module dm_mem #( localparam logic [DbgAddressBits-1:0] FlagsEndAddr = 'h7FF; localparam logic [DbgAddressBits-1:0] HaltedAddr = 'h100; - localparam logic [DbgAddressBits-1:0] GoingAddr = 'h104; - localparam logic [DbgAddressBits-1:0] ResumingAddr = 'h108; - localparam logic [DbgAddressBits-1:0] ExceptionAddr = 'h10C; + localparam logic [DbgAddressBits-1:0] GoingAddr = 'h108; + localparam logic [DbgAddressBits-1:0] ResumingAddr = 'h110; + localparam logic [DbgAddressBits-1:0] ExceptionAddr = 'h118; logic [dm::ProgBufSize/2-1:0][63:0] progbuf; logic [7:0][63:0] abstract_cmd; @@ -201,6 +202,13 @@ module dm_mem #( cmderror_valid_o = 1'b1; cmderror_o = dm::CmdErrorException; end + + if (ndmreset_i) begin + // Clear state of hart and its control signals when it is being reset. + state_d = Idle; + go = 1'b0; + resume = 1'b0; + end end // word mux for 32bit and 64bit buses @@ -214,14 +222,13 @@ module dm_mem #( end // read/write logic - logic [63:0] data_bits; + logic [dm::DataCount-1:0][31:0] data_bits; logic [7:0][7:0] rdata; - always_comb begin : p_rw_logic + always_comb (* xprop_off *) begin : p_rw_logic halted_d_aligned = NrHartsAligned'(halted_q); resuming_d_aligned = NrHartsAligned'(resuming_q); rdata_d = rdata_q; - // convert the data in bits representation data_bits = data_i; rdata = '0; @@ -258,9 +265,19 @@ module dm_mem #( // core can write data registers [DataBaseAddr:DataEndAddr]: begin data_valid_o = 1'b1; - for (int i = 0; i < $bits(be_i); i++) begin - if (be_i[i]) begin - data_bits[i*8+:8] = wdata_i[i*8+:8]; + for (int dc = 0; dc < dm::DataCount; dc++) begin + if ((addr_i[DbgAddressBits-1:2] - DataBaseAddr[DbgAddressBits-1:2]) == dc) begin + for (int i = 0; i < $bits(be_i); i++) begin + if (be_i[i]) begin + if (i>3) begin // for upper 32bit data write (only used for BusWidth == 64) + if ((dc+1) < dm::DataCount) begin // ensure we write to an implemented data register + data_bits[dc+1][(i-4)*8+:8] = wdata_i[i*8+:8]; + end + end else begin // for lower 32bit data write + data_bits[dc][i*8+:8] = wdata_i[i*8+:8]; + end + end + end end end end @@ -293,10 +310,8 @@ module dm_mem #( [DataBaseAddr:DataEndAddr]: begin rdata_d = { - data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] - - DataBaseAddr[DbgAddressBits-1:3] + 1'b1)], - data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] - - DataBaseAddr[DbgAddressBits-1:3])] + data_i[$clog2(dm::DataCount)'(((addr_i[DbgAddressBits-1:3] - DataBaseAddr[DbgAddressBits-1:3]) << 1) + 1'b1)], + data_i[$clog2(dm::DataCount)'(((addr_i[DbgAddressBits-1:3] - DataBaseAddr[DbgAddressBits-1:3]) << 1))] }; end @@ -325,6 +340,12 @@ module dm_mem #( end end + if (ndmreset_i) begin + // When harts are reset, they are neither halted nor resuming. + halted_d_aligned = '0; + resuming_d_aligned = '0; + end + data_o = data_bits; end @@ -476,6 +497,7 @@ module dm_mem #( if (HasSndScratch) begin : gen_rom_snd_scratch debug_rom i_debug_rom ( .clk_i, + .rst_ni, .req_i, .addr_i ( rom_addr ), .rdata_o ( rom_rdata ) @@ -486,6 +508,7 @@ module dm_mem #( // be saved. debug_rom_one_scratch i_debug_rom ( .clk_i, + .rst_ni, .req_i, .addr_i ( rom_addr ), .rdata_o ( rom_rdata ) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_pkg.sv index 1c2b6195..cc2e1ebc 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_pkg.sv @@ -26,8 +26,8 @@ package dm; // address to which a hart should jump when it was requested to halt localparam logic [63:0] HaltAddress = 64'h800; - localparam logic [63:0] ResumeAddress = HaltAddress + 4; - localparam logic [63:0] ExceptionAddress = HaltAddress + 8; + localparam logic [63:0] ResumeAddress = HaltAddress + 8; + localparam logic [63:0] ExceptionAddress = HaltAddress + 16; // address where data0-15 is shadowed or if shadowed in a CSR // address of the first CSR used for shadowing the data @@ -197,6 +197,12 @@ package dm; DTM_WRITE = 2'h2 } dtm_op_e; + typedef enum logic [1:0] { + DTM_SUCCESS = 2'h0, + DTM_ERR = 2'h2, + DTM_BUSY = 2'h3 + } dtm_op_status_e; + typedef struct packed { logic [31:29] sbversion; logic [28:23] zero0; @@ -215,8 +221,6 @@ package dm; logic sbaccess8; } sbcs_t; - localparam logic [1:0] DTM_SUCCESS = 2'h0; - typedef struct packed { logic [6:0] addr; dtm_op_e op; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_top.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_top.sv index 3c9c4451..c21e58d9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_top.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_top.sv @@ -86,6 +86,7 @@ module dm_top #( logic [dm::DataCount-1:0][31:0] data_csrs_mem; logic [dm::DataCount-1:0][31:0] data_mem_csrs; logic data_valid; + logic ndmreset; logic [19:0] hartsel; // System Bus Access Module logic [BusWidth-1:0] sbaddress_csrs_sba; @@ -104,6 +105,7 @@ module dm_top #( logic sberror_valid; logic [2:0] sberror; + assign ndmreset_o = ndmreset; dm_csrs #( .NrHarts(NrHarts), @@ -120,7 +122,7 @@ module dm_top #( .dmi_resp_valid_o, .dmi_resp_ready_i, .dmi_resp_o, - .ndmreset_o, + .ndmreset_o ( ndmreset ), .dmactive_o, .hartsel_o ( hartsel ), .hartinfo_i, @@ -201,6 +203,7 @@ module dm_top #( .clk_i, .rst_ni, .debug_req_o, + .ndmreset_i ( ndmreset ), .hartsel_i ( hartsel ), .haltreq_i ( haltreq ), .resumereq_i ( resumereq ), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag.sv index 0712f8c6..577c3fd0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag.sv @@ -17,7 +17,7 @@ */ module dmi_jtag #( - parameter logic [31:0] IdcodeValue = 32'h00000001 + parameter logic [31:0] IdcodeValue = 32'h00000DB3 ) ( input logic clk_i, // DMI Clock input logic rst_ni, // Asynchronous reset active low @@ -134,9 +134,11 @@ module dmi_jtag #( assign dmi_resp_ready = 1'b1; logic error_dmi_busy; + logic error_dmi_op_failed; always_comb begin : p_fsm error_dmi_busy = 1'b0; + error_dmi_op_failed = 1'b0; // default assignments state_d = state_q; address_d = address_q; @@ -177,7 +179,22 @@ module dmi_jtag #( WaitReadValid: begin // load data into register and shift out if (dmi_resp_valid) begin - data_d = dmi_resp.data; + unique case (dmi_resp.resp) + dm::DTM_SUCCESS: begin + data_d = dmi_resp.data; + end + dm::DTM_ERR: begin + data_d = 32'hDEAD_BEEF; + error_dmi_op_failed = 1'b1; + end + dm::DTM_BUSY: begin + data_d = 32'hB051_B051; + error_dmi_busy = 1'b1; + end + default: begin + data_d = 32'hBAAD_C0DE; + end + endcase state_d = Idle; end end @@ -193,6 +210,11 @@ module dmi_jtag #( WaitWriteValid: begin // got a valid answer go back to idle if (dmi_resp_valid) begin + unique case (dmi_resp.resp) + dm::DTM_ERR: error_dmi_op_failed = 1'b1; + dm::DTM_BUSY: error_dmi_busy = 1'b1; + default: ; + endcase state_d = Idle; end end @@ -218,9 +240,14 @@ module dmi_jtag #( error_dmi_busy = 1'b1; end - if (error_dmi_busy) begin + if (error_dmi_busy && error_q == DMINoError) begin error_d = DMIBusy; end + + if (error_dmi_op_failed && error_q == DMINoError) begin + error_d = DMIOPFailed; + end + // clear sticky error flag if (update && dtmcs_q.dmireset && dtmcs_select) begin error_d = DMINoError; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag_tap.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag_tap.sv index 0c188c05..53f0fa9d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag_tap.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dmi_jtag_tap.sv @@ -94,8 +94,9 @@ module dmi_jtag_tap #( jtag_ir_d = ir_reg_e'(jtag_ir_shift_q); end - // According to JTAG spec we have to reset the IR to IDCODE in test_logic_reset if (test_logic_reset) begin + // Bring all TAP state to the initial value. + jtag_ir_shift_d = '0; jtag_ir_d = IDCODE; end end @@ -135,6 +136,12 @@ module dmi_jtag_tap #( if (idcode_select) idcode_d = {td_i, 31'(idcode_q >> 1)}; if (bypass_select) bypass_d = td_i; end + + if (test_logic_reset) begin + // Bring all TAP state to the initial value. + idcode_d = IdcodeValue; + bypass_d = 1'b0; + end end // ---------------- @@ -180,12 +187,12 @@ module dmi_jtag_tap #( // ---------------- logic tck_n, tck_ni; - cluster_clock_inverter i_tck_inv ( + tc_clk_inverter i_tck_inv ( .clk_i ( tck_i ), .clk_o ( tck_ni ) ); - pulp_clock_mux2 i_dft_tck_mux ( + tc_clk_mux2 i_dft_tck_mux ( .clk0_i ( tck_ni ), .clk1_i ( tck_i ), // bypass the inverted clock for testing .clk_sel_i ( testmode_i ), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_tech_cells_generic.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_tech_cells_generic.core index 6a70b8e2..02d8b12c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_tech_cells_generic.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_tech_cells_generic.core @@ -20,3 +20,4 @@ targets: default: filesets: - target_sim? (rtl_sim) + - target_sim_sc? (rtl_sim) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40p.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40p.vlt index 65542b42..4be49e61 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40p.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40p.vlt @@ -114,3 +114,4 @@ lint_off -rule WIDTH -file "*/rtl/cv32e40p_decoder.sv" -match "Logical operator lint_off -rule WIDTH -file "*/rtl/cv32e40p_controller.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" lint_off -rule WIDTH -file "*/rtl/cv32e40p_cs_registers.sv" -match "Logical operator LOGOR expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" lint_off -rule LATCH -file "*/rtl/cv32e40p_id_stage.sv" -match "Latch inferred for signal*apu_read_regs*" +lint_off -rule WIDTH -file "*/rtl/cv32e40p_cs_registers.sv" -match "Logical operator LOGOR expects 1 bit on the RHS, but RHS's VARREF 'COREV_PULP' generates 32 bits.*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cve2.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cve2.vlt index ac5b0076..7b3fc6bb 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cve2.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cve2.vlt @@ -6,3 +6,6 @@ lint_off -rule DECLFILENAME -file "*bhv/cve2_sim_clock_gate.sv" -match "*Filename 'cve2_sim_clock_gate' does not match MODULE name: 'cve2_clock_gate'*" lint_off -rule UNOPTFLAT -file "*rtl/*.sv" -match "*" +lint_off -rule UNUSED -file "*rtl/cve2_core.sv" -match "Signal is not used: 'rf_ren_a'*" +lint_off -rule UNUSED -file "*rtl/cve2_core.sv" -match "Signal is not used: 'rf_ren_b'*" +lint_off -rule UNUSED -file "*rtl/cve2_wb.sv" -match "Signal is not used:*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt index 460f3c6b..6a33f058 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt @@ -11,3 +11,4 @@ lint_off -rule DECLFILENAME -file "*/src/cdc_reset_ctrlr.sv" -match "Filename 'c lint_off -rule DECLFILENAME -file "*/src/cdc_fifo_gray_clearable.sv" -match "Filename 'cdc_fifo_gray_clearable' does not match MODULE name: 'cdc_fifo_gray_src_clearable'*" lint_off -rule WIDTH -file "*/src/cdc_2phase_clearable.sv" -match "Logical operator GENIF expects 1 bit on the If, but If's VARREF 'CLEAR_ON_ASYNC_RESET' generates 32 bits.*" lint_off -rule UNOPTFLAT -file "*/src/cdc_4phase.sv" -match "Signal unoptimizable*" +lint_off -rule WIDTH -file "*/src/dm_mem.sv" -match "*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v b/hw/vendor/esl_epfl_x_heep/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v index e0eef9f7..55342b5f 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/yosyshq_picorv32/picosoc/spiflash.v @@ -26,7 +26,7 @@ // updates output signals 1ns after the SPI clock edge. // // Supported commands: -// AB, B9, FF, 03, BB, EB, ED +// AB, B9, FF, 03, BB, EB, ED, 06, 02, 32 // // Well written SPI flash data sheets: // Cypress S25FL064L http://www.cypress.com/file/316661/download @@ -61,6 +61,8 @@ module spiflash ( reg spi_io_vld; reg powered_up = 0; + reg write_enable = 0; + reg write_enable_reset = 0; localparam [3:0] mode_spi = 1; localparam [3:0] mode_dspi_rd = 2; @@ -107,7 +109,7 @@ module spiflash ( initial begin for (i=0;i<=16*1024*1024;i=i+1) - memory[i] = '0; + memory[i] = 8'h00; result = $value$plusargs("firmware=%s", firmware_file); if (!result) firmware_file = "firmware.hex"; @@ -129,6 +131,9 @@ module spiflash ( if (spi_cmd == 8'h ff) xip_cmd = 0; + + if (spi_cmd == 8'h 06) + write_enable = 1; end if (powered_up && spi_cmd == 'h 03) begin @@ -147,6 +152,25 @@ module spiflash ( end end + if (powered_up && write_enable && spi_cmd == 'h 02) begin + if (bytecount == 1) + write_enable_reset = 1; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount >= 5 && bytecount <= 260) begin + memory[spi_addr] = buffer; + spi_addr = spi_addr + 1; + end + end + if (powered_up && spi_cmd == 'h bb) begin if (bytecount == 1) mode = mode_dspi_rd; @@ -197,6 +221,27 @@ module spiflash ( end end + if (powered_up && write_enable && spi_cmd == 'h 32) begin + if (bytecount == 1) + write_enable_reset = 1; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) begin + spi_addr[7:0] = buffer; + mode = mode_qspi_rd; + end + + if (bytecount >= 5 && bytecount <= 260) begin + memory[spi_addr] = buffer; + spi_addr = spi_addr + 1; + end + end + if (powered_up && spi_cmd == 'h ed) begin if (bytecount == 1) next_mode = mode_qspi_ddr_rd; @@ -274,6 +319,10 @@ module spiflash ( $display(""); $fflush; end + if (write_enable_reset) begin + write_enable = 0; + write_enable_reset = 0; + end buffer = 0; bitcount = 0; bytecount = 0; diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/README.md b/hw/vendor/esl_epfl_x_heep/linux_femu/README.md deleted file mode 100644 index 45764e74..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# Linux-FEMU - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Zynq 7020 chip and Linux is run on the ARM-based processing system (PS) side of the same chip. The X-HEEP JTAG signals are driven by the PS GPIO peripheral and are used to program and debug the architecture, while the X-HEEP UART is connected to the PS UART peripheral and is used to get the stdout of the program running on the architecture. Moreover, the X-HEEP flash SPI is connected to the ARM AXI bus passing through an SPI to AXI bridge: this allows virtualising the flash memory into the on-board DDR RAM memory. In this way, the program running on the architecture can read the external virtualised flash as it was a real flash memory, i.e., this virtualisation is totally transparent to the X-HEEP code. - -Go through the following steps to build and use our Linux-FEMU version. - -## Build the platform - -Start in the x-heep main folder. - -## Generate the files - -1. Activate the conda environment with: - -``` -conda activate core-v-mini-mcu -``` - -2. Generate the hdl files by calling: - -``` -make linux-femu-gen PAD_CFG=linux_femu/pad_cfg.hjson -``` - -__NOTE__: you can customize the mcu-gen process by providing the MEMORY_BANKS - CPU - BUS parameters to the above command. - -## Flash the SD card with a Linux image - -1. Download the Linux image (version v3.0.1) using the following link: - -`http://www.pynq.io/board.html` - -2. Follow the procedure explained in the following linked page to flash the downloaded image to the SD card: - -`https://pynq.readthedocs.io/en/v2.2.1/appendix.html#writing-the-sd-card` - -3. Insert the SD into the Pynq-Z2 board and make sure the booting bridge is on the SD position. - -4. Power-on the board and wait for Linux to boot (a row of 4 leds should turn on). - -## Create the Vivado project and generate the bitstream - -1. Starting in the x-heep main folder, run the following command to create the Vivado project and generate the bitstream: - -``` -make vivado-fpga FPGA_BOARD=pynq-z2-arm-emulation -``` - -2. Open the project x-heep/build/openhwgroup.org_systems_core-v-mini-mcu_0/pynq-z2-arm-emulation-vivado/openhwgroup.org_systems_core-v-mini-mcu_0.xpr with Vivado and use the Hardware Manager to program the bitstream to the Zynq 7020 of the Pynq-Z2 board. - -## Connect to Linux running on the Pynq-Z2 board - -Connect your Linux-based PC to the Pynq-Z2 board through Ethernet and run the following command: - -``` -ssh -X xilinx@board_ip -``` - -The default password is: xilinx - -If you need additional documentation on how to connect your PC to the Pynq-Z2 board, use the following link: - -`https://pynq.readthedocs.io/en/v2.6.1/getting_started/pynq_z2_setup.html` - -## Install OpenOCD on the Pynq-Z2 board - -1. Clone the OpenOCD repository usign the following link: - -`https://github.com/openocd-org/openocd` - -2. Run the following commands from the OpneOCD main folder to install it: - -``` -sudo ./bootstrap -sudo ./configure --enable-sysfsgpio -sudo make -sudo make install -``` - -## Copy the x-heep folder to the Pynq-Z2 baord - -Copy the x-heep/linux_femu/arm/ folder from your PC to the home directory of the Pynq-Z2 board with the following command: - -``` -sudo scp -r x-heep/linux_femu/arm/ xilinx@board_ip:~ -``` - -## Enable UART1 on Linux on the Pynq-Z2 baord - -Enter the arm/uart_enable/ folder and run the following commands: - -``` -sudo su -mkdir -p /configfs -./uart_enable.sh -exit -``` - -These commands enable the UART1 on the ARM system side of the Zynq 7020 on the Pynq-Z2 board. UART1 is used to receive the stdout of the code running on the HEEP architecture implemented on the PL side of the chip. - -## Prepare the needed shells - -You need to use 5 shells (the first, second and third shells will run on the Pynq-Z2 board, while the fourth and fifth shells will run on your PC): - -1. First shell - run virtual flash app on the Pynq-Z2 board - browse to the arm/virtual_flash/ folder and execute the following commands to compile and run the required application: - -``` -sudo make clean -sudo make -sudo ./virtual_flash -``` - -This app allocates a buffer into the off-chip DDR memory of the Pynq-Z2 board and stores its physical base address to the hijacker PL peripheral. - -2. Second shell - run the following commands on the Pynq-Z2 board to get the stdout from the app running on x-heep: - -``` -sudo apt-get install screen -sudo screen /dev/ttyPS1 115200 -``` - -3. Third shell - run openocd on the Pynq-Z2 board - browse to the arm/openocd_cfg/ folder and run the following command: - -``` -sudo openocd -f ./gpio_bitbang.cfg -``` - -4. Fourth shell - compile HEEP app on your PC - browse to the x-heep/sw/ folder and run the following command: - -``` -make clean applications/example_virtual_flash/example_virtual_flash.hex TARGET=pynq-z2 -``` - -With this command you compile a sample RISC-V based application that uses the allocated DDR-based virtual memory. You may want to change this command with the name of your own application. - -5. Fifth shell - run GDB on your PC - browse to the x-heep/sw/applications/example_virtual_flash/ folder and run the following command to connect GDB: - -``` -sudo /path_to_your_riscv_toolchain/bin/riscv32-unknown-elf-gdb -``` - -Use the following GDB commands to connect to OpenOCD running on the Pynq-Z2 board and run your application: - -``` -(gdb) target remote board_ip:3333 -(gdb) load example_virtual_flash.elf -(gdb) cont -``` - -Go back to the first shell and press ENTER to end the application and dump the content of the virtual flash to a file. Then, run the following commands: - -``` -xxd dump.txt dump -nano dump -``` - -Check if your result corresponds to the following lines: - -``` -00000000: 0000 0000 0000 0001 0000 0002 0000 0003 ................ -00000010: 0000 0004 0000 0005 0000 0006 0000 0007 ................ -00000020: 0000 0008 0000 0009 0000 000a 0000 000b ................ -00000030: 0000 000c 0000 000d 0000 000e 0000 000f ................ -00000040: 0000 0010 0000 0011 0000 0012 0000 0013 ................ -00000050: 0000 0014 0000 0015 0000 0016 0000 0017 ................ -00000060: 0000 0018 0000 0019 0000 001a 0000 001b ................ -00000070: 0000 001c 0000 001d 0000 001e 0000 001f ................ -00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ -``` - -__NOTE__: to run other applications, press the hard reset button on the Pynq-Z2 board (BTN3) and re-connect OpneOCD and GDB. diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/README.md b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/README.md deleted file mode 100644 index 38dfdbce..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/README.md +++ /dev/null @@ -1,80 +0,0 @@ -### Hardware Configurations - -On the hardware side, we must configure the ZYNQ processing system to use the EMIO and export them externally so that they can be attached to x-heep. They are then routed outwards from the wrapper to x-heep JTAG signals. - -### Software Configurations - -## Target adapter configuration __gpio_bitbang.cfg__: - -``` -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# Config for using RaspberryPi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V -# -# Do not forget the GND connection, pin 6 of the expansion header. -# - -adapter driver sysfsgpio -transport select jtag - -bindto 0.0.0.0 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10001c05 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x000 -echo "Target created" - -riscv set_reset_timeout_sec 2000 -riscv set_command_timeout_sec 2000 -# riscv set_prefer_sba off - -echo "Setting preferences" - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -sysfsgpio jtag_nums 964 961 963 962 - -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -# sysfsgpio swd_nums 11 25 - -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 - -sysfsgpio trst_num 960 -reset_config trst_only - -# sysfsgpio srst_num 24 -# reset_config srst_only srst_push_pull - -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull - -scan_chain - -init - -echo "Init routine started" - -halt -echo "Ready for connections" -``` - -This instructs openocd to use the riscv HART and jtag module but instead of transmitting the commands over the usual FTDI usb adapter, it bitbangs the GPIOs by using the SYSFS framework. - -In order to understand the pin numbering used in the script we have to know how the JTAG has been ported to the PYNQ without using external adapters. The ZYNQ 7000 offers several banks of GPIO lines used for different purposes. The first 54 are MIO (multiplexed I/O) and are configured for different purposes but are PS-side only. After those, we have 64 EMIO (extended MIO) which are lines that can be routed to the PL). The idea is therefore to expose 5 EMIO GPIOS (5 jtag signals) and route them to the PL and to x-heep directly. Those can be controlled as normal GPIO lines and allow interfacing directly from ARM. - -Therefore, the pin numbers used in the configuration file are derived as follows: - -1. Find the GPIO starting numbers that linux uses by running ``` sudo cat /sys/kernel/debug/gpio ``` -> in this case it was __906__ - -2. Add 54 (the first 54 GPIOS are the MIOs). - -3. Add the gpio_n assigned to the specific signal (depends on the HDL connections). diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/gpio_bitbang.cfg b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/gpio_bitbang.cfg deleted file mode 100755 index 11c5519d..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/openocd_cfg/gpio_bitbang.cfg +++ /dev/null @@ -1,58 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# Config for using RaspberryPi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V -# -# Do not forget the GND connection, pin 6 of the expansion header. -# - -adapter driver sysfsgpio -transport select jtag - -bindto 0.0.0.0 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10001c05 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x000 -echo "Target created" - -riscv set_reset_timeout_sec 2000 -riscv set_command_timeout_sec 2000 -# riscv set_prefer_sba off - -echo "Setting preferences" - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -sysfsgpio jtag_nums 964 961 963 962 - -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -# sysfsgpio swd_nums 11 25 - -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 - -sysfsgpio trst_num 960 -reset_config trst_only - -# sysfsgpio srst_num 24 -# reset_config srst_only srst_push_pull - -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull - -scan_chain - -init - -echo "Init routine started" - -halt -echo "Ready for connections" diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/README.md b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/README.md deleted file mode 100644 index 15f4fac9..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/README.md +++ /dev/null @@ -1,57 +0,0 @@ -### Hardware Configurations - -On the hardware side, we must configure the ZYNQ processing system to enable UART1 and route tx and rx to the EMIO pins so that they can be attached to x-heep. They are then routed outwards from the wrapper to x-heep UART signals. - -__NOTE__: remembed to connect tx to rx and viceversa. - -### Software Configurations - -## Enable UART1 - -In order to ask Linux to use that as a normal serial port, we need to modify the DEVICE TREE to expose this new hardware piece. In theory, the UART1 peripheral is already defined in the tree but is disabled. Instead of rebuilding the device tree, we can add an overlay at runtime to add and change configuration properties of the tree. In particular, we need to extend the device tree with the following: - -``` -/dts-v1/; -/plugin/; - -/{ - fragment@0{ - target-path = "/aliases"; - __overlay__ { - serial1 = "/axi/serial@e0001000"; - }; - }; - - fragment@1{ - target = <&uart1>; - __overlay__ { - status = "okay"; - }; - }; -}; - -``` - -This first makes an alias to make sure that the uart1 (/axi/serial@e0001000) is called serial1, and then enables it by setting the status as "okay". Aliasing is important to avoid a problem that could arise if the kernel decides to swap the ttyPS1 and ttyPS0 (uart0 and the one used to connect to ARM through serial), because we'd have no access to the board over serial. - -1. DTSI file must be compiled into binary format as follows: - -``` -dtc -O dtb -o uart_enable.dtbo -b 0 -@ uart_enable.dtsi -``` -2. We mount the configfs, which is a RAM-based configuration file-system exposed to add overlays. - -``` -sudo mount configfs configfs /configfs -sudo mkdir configfs/device-tree/overlays/uart_enable -``` - -3. Concatenate the dtbo binary file to insert into the kernel device tree. - -``` -sudo su -cat uart_enable.dtbo >/configfs/device-tree/overlays/uart_enable/dtbo -exit -``` - -4. Make sure with dmesg that no errors were thrown and that /dev/ttySP1 has appeared -> that is x-heep's serial. diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtbo b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtbo deleted file mode 100755 index 896a0f34f64bdb7390b4dc181001e74076428956..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmZusJqyAx5WV;@2nq^1xjDH=n@u|PXSjtM(ps#xB&oFj(m&$vq~0~9qWIwD-97G- zm)q=l2M`AU*pr5&TjGK^Co;HywAJ?^x>h6x)3d&~n709j#0eJx<{4UTxh4puimNs` zHcD~Nb1ULBz&Z=8HW}uz4#Q9qd4MqJ_<2LNKJSi*%NK$4-`!*K*To4NQbvE5Qb|@< orS&oT9Gjs3h>RSXRJ-Um$He=)65SDeWC`8_>(EseDl|^Q8(n`scK`qY diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtsi b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtsi deleted file mode 100755 index 21804e30..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.dtsi +++ /dev/null @@ -1,18 +0,0 @@ -/dts-v1/; -/plugin/; - -/{ - fragment@0{ - target-path = "/aliases"; - __overlay__ { - serial1 = "/axi/serial@e0001000"; - }; - }; - - fragment@1{ - target = <&uart1>; - __overlay__ { - status = "okay"; - }; - }; -}; diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.sh b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.sh deleted file mode 100755 index ec02611c..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/uart_enable/uart_enable.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -mount -t configfs configfs /configfs -mkdir /configfs/device-tree/overlays/uart_enable -cat ./uart_enable.dtbo >/configfs/device-tree/overlays/uart_enable/dtbo diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/Makefile b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/Makefile deleted file mode 100755 index e9c11b69..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: virtual_flash - -virtual_flash: virtual_flash.cpp OverlayControl.c OverlayControl.h - g++ -O0 -g -Wall virtual_flash.cpp OverlayControl.c -o virtual_flash -lpthread -lm -lcma - -clean: - rm -f virtual_flash diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.c b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.c deleted file mode 100755 index 68f2a857..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.c +++ /dev/null @@ -1,103 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -// 1 --> Basic logging, 2 --> Debugging -#define LOGGING 2 - -#include "OverlayControl.h" -extern "C" { -#include -} - -static volatile uint32_t * memMapAddr = NULL; -static int memMapFileDesc = -1; -static uint32_t memMapSize = 0; - -volatile uint32_t * MapMemIO(uint32_t baseAddr, uint32_t mapSize) -{ - bool res = true; - - res = ( (memMapFileDesc = open("/dev/mem", O_RDWR | O_SYNC )) != -1); - - if (!res) { - #ifdef LOGGING - printf("Error opening file.\n"); - #endif - } - else { - #if LOGGING == 2 - printf("File opened.\n"); - #endif - memMapAddr = (volatile unsigned int *)mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, memMapFileDesc, baseAddr); - res = (memMapAddr != MAP_FAILED); - if (!res) { - #ifdef LOGGING - printf("Memory mapping failed.\n"); - #endif - close(memMapFileDesc); - memMapFileDesc = -1; - memMapAddr = NULL; - } - } - - if (res) { - #ifdef LOGGING - printf("Memory mapped.\n"); - #endif - memMapSize = mapSize; - } - - return memMapAddr; -} - -bool UnmapMemIO() -{ - bool res = true; - - if ((memMapAddr != NULL) && (memMapAddr != MAP_FAILED)) { - if ( munmap((void*)memMapAddr, memMapSize) ) { - #ifdef LOGGING - printf("Memory unmapping failed.\n"); - #endif - res = false; - } - else { - #ifdef LOGGING - printf("Memory unmapped.\n"); - #endif - } - } - - if (memMapFileDesc != -1) { - close(memMapFileDesc); - memMapFileDesc = -1; - } - - return res; -} - -// Reference of functions to (de)allocate DMA memory. -// extern "C" { -// #include -// } -/* * Allocate a physically contiguos chunk of CMA memory and map it into - * virtual memory space. Return this Virtual pointer. Returns -1 on failure. -void *cma_alloc(uint32_t len, uint32_t cacheable); - * Return a physical memory address corresponding to a given Virtual address - * pointer. Returns NULL on failure. -unsigned long cma_get_phy_addr(void *buf); - * Free a previously allocated CMA memory chunk. -void cma_free(void *buf); - * Returns the number of available CMA memiry pages which can be allocated. -uint32_t cma_pages_available(); - * Extra functions in case user needs to flush or invalidate Cache. -void cma_flush_cache(void *buf, unsigned int phys_addr, int size); -void cma_invalidate_cache(void *buf, unsigned int phys_addr, int size); -*/ diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.h b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.h deleted file mode 100755 index 92807321..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/OverlayControl.h +++ /dev/null @@ -1,27 +0,0 @@ - -#ifndef OVERLAYCONTROL_H -#define OVERLAYCONTROL_H - -volatile uint32_t * MapMemIO(uint32_t baseAddr, uint32_t mapSize); -bool UnmapMemIO(); - -// Reference of functions to (de)allocate DMA memory. -// extern "C" { -// #include -// } -/* * Allocate a physically contiguos chunk of CMA memory and map it into - * virtual memory space. Return this Virtual pointer. Returns -1 on failure. -void *cma_alloc(uint32_t len, uint32_t cacheable); - * Return a physical memory address corresponding to a given Virtual address - * pointer. Returns NULL on failure. -unsigned long cma_get_phy_addr(void *buf); - * Free a previously allocated CMA memory chunk. -void cma_free(void *buf); - * Returns the number of available CMA memiry pages which can be allocated. -uint32_t cma_pages_available(); - * Extra functions in case user needs to flush or invalidate Cache. -void cma_flush_cache(void *buf, unsigned int phys_addr, int size); -void cma_invalidate_cache(void *buf, unsigned int phys_addr, int size); -*/ - -#endif // OVERLAYCONTROL_H diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/virtual_flash.cpp b/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/virtual_flash.cpp deleted file mode 100755 index 8de7bc7c..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/arm/virtual_flash/virtual_flash.cpp +++ /dev/null @@ -1,100 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include "OverlayControl.h" - -extern "C" { -#include -} - -const uint32_t MEM_IS_CACHEABLE = 0; -const uint32_t MAP_SIZE = 64*1024; -const uint32_t BASE_ADDR = 0x43C00000; -const uint32_t ALLOC_SIZE_BYTE = 64*1024*128; -const uint32_t FIXED_VALUE = 0x1c; - -uint32_t *virtual_flash_buffer, *virtual_flash_buffer_phy; - -static void stop(int) -{ - signal(SIGTERM, SIG_DFL); - signal(SIGINT, SIG_DFL); - - if(virtual_flash_buffer != NULL){ - FILE* dump = fopen("./dump.txt", "wb"); - fwrite(virtual_flash_buffer, ALLOC_SIZE_BYTE, 1, dump); - fclose(dump); - } -} - -int main(int argc, char **argv) -{ - signal(SIGTERM, stop); - signal(SIGINT, stop); - volatile uint8_t *pl_peripherals = NULL; - volatile uint32_t* hijacker = NULL; - - printf("Press ENTER to confirm that the bitstream is loaded (proceeding without it can crash the board).\n"); - getchar(); - - // Get the virtual address corresponding to the physical base address of the PL peripherals - if ((pl_peripherals = (uint8_t *) MapMemIO(BASE_ADDR, MAP_SIZE)) == NULL) { - printf("Error getting address!\n"); - return -1; - } - printf("PL peripherals mapped at 0x%08X.\n", (uint32_t)pl_peripherals); - fflush(stdout); - - // Map hijacker PL peripheral - hijacker = (uint32_t *)pl_peripherals; - printf("hijacker mapped at 0x%08X.\n", (uint32_t)hijacker); - - // Allocate DDR memory buffer to virtualize a Flash memory and get its physical address - fflush(stdout); - virtual_flash_buffer = (uint32_t *)cma_alloc(ALLOC_SIZE_BYTE, MEM_IS_CACHEABLE); - virtual_flash_buffer_phy = (uint32_t *)((uint32_t)cma_get_phy_addr(virtual_flash_buffer)); - printf("DDR memory buffer allocated.\n"); - fflush(stdout); - printf("Virtual address: 0x%.8X.\n", (uint32_t)virtual_flash_buffer); - fflush(stdout); - printf("Physical address: Phys: 0x%.8X.\n\n", (uint32_t)virtual_flash_buffer_phy); - fflush(stdout); - if (virtual_flash_buffer == NULL) { - printf("Error allocating DDR memory for %u bytes!\n", ALLOC_SIZE_BYTE); - return -1; - } - - // Initialize DDR memory buffer - for (uint32_t i = 0; i < ALLOC_SIZE_BYTE / sizeof(uint32_t); i++) - virtual_flash_buffer[0] = i; - - // Copy the physical address of the DDR memory buffer to hijacker PL peripheral - *hijacker = (uint32_t)virtual_flash_buffer_phy; - - // Press ENTER to end the application - printf("Press ENTER to end the application.\n"); - getchar(); - - printf("Virtual flash read and content stored in file dump.txt.\n\n"); - - // Read content of the DDR memory buffer and store it to a file - FILE *dump = fopen("./dump.txt", "wb"); - fwrite(virtual_flash_buffer, ALLOC_SIZE_BYTE, 1, dump); - fclose(dump); - - /////////////////////////////////////////////////////////////////////////////////////// - // DDR memory is a global variable. In this Linux version, it is allocated - // by a pl_peripherals driver provided by Xilinx. This means that it is not freed - // automatically when our process exits. We MUST free it or the board will - // run out of DMA memory!!! - /////////////////////////////////////////////////////////////////////////////////////// - if (virtual_flash_buffer != NULL) - cma_free(virtual_flash_buffer); - UnmapMemIO(); - - return 0; -} diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/constraints.xdc b/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/constraints.xdc deleted file mode 100644 index ca9babe2..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/constraints.xdc +++ /dev/null @@ -1 +0,0 @@ -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets linux_femu/pad_ring_i/pad_clk_i/xilinx_iobuf_i/O] diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/pin_assign.xdc deleted file mode 100644 index d6be7e83..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/constraints/pin_assign.xdc +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2022 EPFL -# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports clk_in] -set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports rst_i] -set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports rst_led] -set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports clk_led] -set_property -dict {PACKAGE_PIN W9 IOSTANDARD LVCMOS33} [get_ports clk_out] -set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] -set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports exit_value_o] -set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] -set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports boot_select_i] - -## Pmoda -## RPi GPIO 7-0 are shared with pmoda_rpi_gpio_tri_io[7:0] - -# QSPI - -set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports spi_csb_io] -set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports spi_sck_io] -set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports {spi_sd_0_io}] -set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {spi_sd_1_io}] -set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {spi_sd_2_io}] -set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {spi_sd_3_io}] - -## Pmodb - -set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[0]}] -set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[1]}] -set_property -dict {PACKAGE_PIN W8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]}] -set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}] -set_property -dict {PACKAGE_PIN Y6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}] -set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {gpio_io[5]}] -set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}] -set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}] -set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[8]}] -set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[9]}] -set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[10]}] -set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[11]}] -set_property -dict {PACKAGE_PIN V6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[12]}] -set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[13]}] -set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[14]}] -set_property -dict {PACKAGE_PIN Y9 IOSTANDARD LVCMOS33} [get_ports {gpio_io[15]}] -set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[16]}] -set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {gpio_io[17]}] -set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[18]}] -set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[19]}] -set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[20]}] -set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports {gpio_io[21]}] -set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {gpio_io[22]}] -set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_io[0]}] -set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_io[1]}] -set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {spi2_sck_io}] -set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_0_io}] -set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_1_io}] -set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_2_io}] -set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_3_io}] -#set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[24]}] -#set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[25]}] -#set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[26]}] -#set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[27]}] -#set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {gpio_io[28]}] -#set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[29]}] -#set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[30]}] -#set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {gpio_io[31]}] - -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] - -set_property PACKAGE_PIN W13 [get_ports i2c_scl_io] -set_property PACKAGE_PIN T10 [get_ports i2c_sda_io] -set_property IOSTANDARD LVCMOS33 [get_ports i2c_scl_io] -set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda_io] diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/pad_cfg.hjson b/hw/vendor/esl_epfl_x_heep/linux_femu/pad_cfg.hjson deleted file mode 100644 index 235ee13f..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/pad_cfg.hjson +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 -// Derived from Occamy: https://github.com/pulp-platform/snitch/blob/master/hw/system/occamy/src/occamy_cfg.hjson -// Peripherals configuration for core-v-mini-mcu. -{ - pads: { - - clk: { - num: 1, - type: input - }, - rst: { - num: 1, - active: low, - driven_manually: True - type: input - }, - boot_select: { - num: 1, - type: input - }, - execute_from_flash: { - num: 1, - type: input - }, - jtag_tck: { - num: 1, - keep_internal: True - type: input - }, - jtag_tms: { - num: 1, - keep_internal: True - type: input - }, - jtag_trst: { - num: 1, - keep_internal: True - active: low, - type: input - }, - jtag_tdi: { - num: 1, - keep_internal: True - type: input - }, - jtag_tdo: { - num: 1, - keep_internal: True - type: output - }, - uart_rx: { - num: 1, - keep_internal: True - type: input - }, - uart_tx: { - num: 1, - keep_internal: True - type: output - }, - exit_valid: { - num: 1, - type: output - }, - gpio: { - num: 23, - num_offset: 0, #first gpio is gpio0 - type: inout - }, - spi_flash_sck: { - num: 1, - keep_internal: True - type: inout - }, - spi_flash_cs: { - num: 2, #carefull, the x-heep uses the CS from the spi pkg, change it - keep_internal: True - type: inout - }, - spi_flash_sd: { - num: 4, - keep_internal: True - type: inout - }, - spi_sck: { - num: 1, - type: inout - }, - spi_cs: { - num: 2, - type: inout - }, - spi_sd: { - num: 4, - type: inout - }, - spi2_cs_0: { - num: 1, - type: inout - mux: { - spi2_cs_0: { - type: inout - }, - gpio_23: { - type: inout - }, - } - }, - spi2_cs_1: { - num: 1, - type: inout - mux: { - spi2_cs_1: { - type: inout - }, - gpio_24: { - type: inout - }, - }, - }, - spi2_sck: { - num: 1, - type: inout - mux: { - spi2_sck: { - type: inout - }, - gpio_25: { - type: inout - }, - } - }, - spi2_sd_0: { - num: 1, - type: inout - mux: { - spi2_sd_0: { - type: inout - }, - gpio_26: { - type: inout - }, - } - }, - spi2_sd_1: { - num: 1, - type: inout - mux: { - spi2_sd_1: { - type: inout - }, - gpio_27: { - type: inout - }, - } - }, - spi2_sd_2: { - num: 1, - type: inout - mux: { - spi2_sd_2: { - type: inout - }, - gpio_28: { - type: inout - }, - } - }, - spi2_sd_3: { - num: 1, - type: inout - mux: { - spi2_sd_3: { - type: inout - }, - gpio_29: { - type: inout - }, - } - }, - i2c_scl: { - num: 1, - type: inout - mux: { - i2c_scl: { - type: inout - }, - gpio_31: { - type: inout - }, - } - }, - i2c_sda: { - num: 1, - type: inout - mux: { - i2c_sda: { - type: inout - }, - gpio_30: { - type: inout - }, - } - } - } -} diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/axi_address_hijacker.v b/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/axi_address_hijacker.v deleted file mode 100644 index e99c60e8..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/axi_address_hijacker.v +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2022 EPFL -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -module axi_address_hijacker # -( - parameter integer AXI_ADDR_WIDTH = 32, - parameter integer C_S_AXI_DATA_WIDTH = 32, - parameter integer C_S_AXI_ADDR_WIDTH = 4 -)( - input wire [AXI_ADDR_WIDTH-1:0] axi_master_awaddr_in, - input wire [AXI_ADDR_WIDTH-1:0] axi_master_araddr_in, - - output wire [AXI_ADDR_WIDTH-1:0] axi_master_araddr_out, - output wire [AXI_ADDR_WIDTH-1:0] axi_master_awaddr_out, - - ///////////////////////////////////////// - // AXI-Lite slave interface - ///////////////////////////////////////// - - // clock and reset - input wire S_AXI_ACLK, - input wire S_AXI_ARESETN, - - // write address - input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, - input wire [2 : 0] S_AXI_AWPROT, - input wire S_AXI_AWVALID, - output wire S_AXI_AWREADY, - - // write data - input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, - input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, - input wire S_AXI_WVALID, - output wire S_AXI_WREADY, - - // write response - output wire [1 : 0] S_AXI_BRESP, - output wire S_AXI_BVALID, - input wire S_AXI_BREADY, - - // read address - input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, - input wire [2 : 0] S_AXI_ARPROT, - input wire S_AXI_ARVALID, - output wire S_AXI_ARREADY, - - // read data - output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, - output wire [1 : 0] S_AXI_RRESP, - output wire S_AXI_RVALID, - input wire S_AXI_RREADY -); - - reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; - reg axi_awready; - reg axi_wready; - reg [1 : 0] axi_bresp; - reg axi_bvalid; - reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; - reg axi_arready; - reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; - reg [1 : 0] axi_rresp; - reg axi_rvalid; - - localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; - localparam integer OPT_MEM_ADDR_BITS = 1; - - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; - wire slv_reg_rden; - wire slv_reg_wren; - reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; - integer byte_index; - reg aw_en; - - assign S_AXI_AWREADY = axi_awready; - assign S_AXI_WREADY = axi_wready; - assign S_AXI_BRESP = axi_bresp; - assign S_AXI_BVALID = axi_bvalid; - assign S_AXI_ARREADY = axi_arready; - assign S_AXI_RDATA = axi_rdata; - assign S_AXI_RRESP = axi_rresp; - assign S_AXI_RVALID = axi_rvalid; - - // Implement axi_awready generation - // axi_awready is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is - // de-asserted when reset is low. - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_awready <= 1'b0; - aw_en <= 1'b1; - end - else - begin - if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) - begin - axi_awready <= 1'b1; - aw_en <= 1'b0; - end - else if (S_AXI_BREADY && axi_bvalid) - begin - aw_en <= 1'b1; - axi_awready <= 1'b0; - end - else - begin - axi_awready <= 1'b0; - end - end - end - - // Implement axi_awaddr latching - // This process is used to latch the address when both - // S_AXI_AWVALID and S_AXI_WVALID are valid. - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_awaddr <= 0; - end - else - begin - if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) - begin - axi_awaddr <= S_AXI_AWADDR; - end - end - end - - // Implement axi_wready generation - // axi_wready is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is - // de-asserted when reset is low. - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_wready <= 1'b0; - end - else - begin - if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en ) - begin - axi_wready <= 1'b1; - end - else - begin - axi_wready <= 1'b0; - end - end - end - - // Implement memory mapped register select and write logic generation - // The write data is accepted and written to memory mapped registers when - // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to - // select byte enables of slave registers while writing. - // These registers are cleared when reset (active low) is applied. - // Slave register write enable is asserted when valid address and data are available - // and the slave is ready to accept the write address and write data. - assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - slv_reg0 <= 0; - slv_reg1 <= 0; - slv_reg2 <= 0; - slv_reg3 <= 0; - end - else begin - if (slv_reg_wren) - begin - case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) - 2'h0: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 2'h1: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 2'h2: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 2'h3: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - default : begin - slv_reg0 <= slv_reg0; - slv_reg1 <= slv_reg1; - slv_reg2 <= slv_reg2; - slv_reg3 <= slv_reg3; - end - endcase - end - end - end - - // Implement write response logic generation - // The write response and response valid signals are asserted by the slave - // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. - // This marks the acceptance of address and indicates the status of - // write transaction. - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_bvalid <= 0; - axi_bresp <= 2'b0; - end - else - begin - if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) - begin - axi_bvalid <= 1'b1; - axi_bresp <= 2'b0; - end - else - begin - if (S_AXI_BREADY && axi_bvalid) - begin - axi_bvalid <= 1'b0; - end - end - end - end - - // Implement axi_arready generation - // axi_arready is asserted for one S_AXI_ACLK clock cycle when - // S_AXI_ARVALID is asserted. axi_awready is - // de-asserted when reset (active low) is asserted. - // The read address is also latched when S_AXI_ARVALID is - // asserted. axi_araddr is reset to zero on reset assertion. - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_arready <= 1'b0; - axi_araddr <= 32'b0; - end - else - begin - if (~axi_arready && S_AXI_ARVALID) - begin - axi_arready <= 1'b1; - axi_araddr <= S_AXI_ARADDR; - end - else - begin - axi_arready <= 1'b0; - end - end - end - - // Implement axi_arvalid generation - // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_ARVALID and axi_arready are asserted. The slave registers - // data are available on the axi_rdata bus at this instance. The - // assertion of axi_rvalid marks the validity of read data on the - // bus and axi_rresp indicates the status of read transaction.axi_rvalid - // is deasserted on reset (active low). axi_rresp and axi_rdata are - // cleared to zero on reset (active low). - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_rvalid <= 0; - axi_rresp <= 0; - end - else - begin - if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) - begin - axi_rvalid <= 1'b1; - axi_rresp <= 2'b0; - end - else if (axi_rvalid && S_AXI_RREADY) - begin - axi_rvalid <= 1'b0; - end - end - end - - // Implement memory mapped register select and read logic generation - // Slave register read enable is asserted when valid address is available - // and the slave is ready to accept the read address. - assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; - always @(*) - begin - case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) - 2'h0 : reg_data_out <= slv_reg0; - 2'h1 : reg_data_out <= slv_reg1; - 2'h2 : reg_data_out <= slv_reg2; - 2'h3 : reg_data_out <= slv_reg3; - default : reg_data_out <= 0; - endcase - end - - // Output register or memory read data - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_rdata <= 0; - end - else - begin - if (slv_reg_rden) - begin - axi_rdata <= reg_data_out; - end - end - end - - assign axi_master_araddr_out = axi_master_araddr_in + slv_reg0; - assign axi_master_awaddr_out = axi_master_awaddr_in + slv_reg0; - - endmodule diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/linux_femu.sv.tpl b/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/linux_femu.sv.tpl deleted file mode 100644 index ef5dad9b..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/rtl/linux_femu.sv.tpl +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2022 EPFL -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -module linux_femu - import obi_pkg::*; - import reg_pkg::*; -#( - parameter COREV_PULP = 0, - parameter FPU = 0, - parameter ZFINX = 0, - parameter EXT_XBAR_NMASTER = 0, - parameter CLK_LED_COUNT_LENGTH = 27 -) ( - inout logic clk_in, - inout logic rst_i, - - output logic rst_led, - output logic clk_led, - output logic clk_out, - - inout logic boot_select_i, - inout logic execute_from_flash_i, - - inout logic [29:0] gpio_io, - - output logic exit_value_o, - inout logic exit_valid_o, - - inout logic spi_sd_0_io, - inout logic spi_sd_1_io, - inout logic spi_sd_2_io, - inout logic spi_sd_3_io, - inout logic spi_csb_io, - inout logic spi_sck_io, - - inout logic spi2_sd_0_io, - inout logic spi2_sd_1_io, - inout logic spi2_sd_2_io, - inout logic spi2_sd_3_io, - inout logic [1:0] spi2_csb_io, - inout logic spi2_sck_io, - - inout logic i2c_scl_io, - inout logic i2c_sda_io, - - inout wire [14:0] DDR_addr, - inout wire [2:0] DDR_ba, - inout wire DDR_cas_n, - inout wire DDR_ck_n, - inout wire DDR_ck_p, - inout wire DDR_cke, - inout wire DDR_cs_n, - inout wire [3:0] DDR_dm, - inout wire [31:0] DDR_dq, - inout wire [3:0] DDR_dqs_n, - inout wire [3:0] DDR_dqs_p, - inout wire DDR_odt, - inout wire DDR_ras_n, - inout wire DDR_reset_n, - inout wire DDR_we_n, - inout wire FIXED_IO_ddr_vrn, - inout wire FIXED_IO_ddr_vrp, - inout wire [53:0] FIXED_IO_mio, - inout wire FIXED_IO_ps_clk, - inout wire FIXED_IO_ps_porb, - inout wire FIXED_IO_ps_srstb -); - - import core_v_mini_mcu_pkg::*; - - parameter AXI_ADDR_WIDTH = 32; - parameter AXI_ADDR_WIDTH_SLAVE = 4; - parameter AXI_DATA_WIDTH = 32; - - // PM signals - logic cpu_subsystem_powergate_switch; - logic cpu_subsystem_powergate_switch_ack; - logic cpu_subsystem_powergate_iso; - logic cpu_subsystem_rst_n; - logic peripheral_subsystem_powergate_switch; - logic peripheral_subsystem_powergate_switch_ack; - logic peripheral_subsystem_powergate_iso; - logic peripheral_subsystem_rst_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_ack; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_iso; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_set_retentive; - - // PS SIDE PORTS - logic AXI_HP_ACLK; - logic AXI_HP_ARESETN; - logic [AXI_ADDR_WIDTH - 1:0] AXI_HP_araddr_sig; - logic [1:0] AXI_HP_arburst_sig; - logic [3:0] AXI_HP_arcache_sig; - logic [5:0] AXI_HP_arid_sig; - logic [3:0] AXI_HP_arlen_sig; - logic [1:0] AXI_HP_arlock_sig; - logic [2:0] AXI_HP_arprot_sig; - logic [3:0] AXI_HP_arqos_sig; - logic AXI_HP_arready_sig; - logic [2:0] AXI_HP_arsize_sig; - logic AXI_HP_arvalid_sig; - logic [AXI_ADDR_WIDTH - 1:0] AXI_HP_awaddr_sig; - logic [1:0] AXI_HP_awburst_sig; - logic [3:0] AXI_HP_awcache_sig; - logic [5:0] AXI_HP_awid_sig; - logic [3:0] AXI_HP_awlen_sig; - logic [1:0] AXI_HP_awlock_sig; - logic [2:0] AXI_HP_awprot_sig; - logic [3:0] AXI_HP_awqos_sig; - logic AXI_HP_awready_sig; - logic [2:0] AXI_HP_awsize_sig; - logic AXI_HP_awvalid_sig; - logic [5:0] AXI_HP_bid_sig; - logic AXI_HP_bready_sig; - logic [1:0] AXI_HP_bresp_sig; - logic AXI_HP_bvalid_sig; - logic [AXI_DATA_WIDTH - 1:0] AXI_HP_rdata_sig; - logic [5:0] AXI_HP_rid_sig; - logic AXI_HP_rlast_sig; - logic AXI_HP_rready_sig; - logic [1:0] AXI_HP_rresp_sig; - logic AXI_HP_rvalid_sig; - logic [AXI_DATA_WIDTH - 1:0] AXI_HP_wdata_sig; - logic [5:0] AXI_HP_wid_sig; - logic AXI_HP_wlast_sig; - logic AXI_HP_wready_sig; - logic [3:0] AXI_HP_wstrb_sig; - logic AXI_HP_wvalid_sig; - - logic spi_test_clk_sig; - logic spi_test_cs_sig; - logic [3:0] spi_test_data_sig; - - // ADDRESS HIJACKER PORTS - logic [AXI_ADDR_WIDTH-1:0] axi_master_awaddr_in_sig; - logic [AXI_ADDR_WIDTH-1:0] axi_master_araddr_in_sig; - - logic [AXI_ADDR_WIDTH_SLAVE - 1 : 0] s00_axi_awaddr_sig; - logic s00_axi_awvalid_sig; - logic s00_axi_awready_sig; - logic [AXI_DATA_WIDTH - 1 : 0] s00_axi_wdata_sig; - logic s00_axi_wvalid_sig; - logic s00_axi_wready_sig; - logic s00_axi_bvalid_sig; - logic s00_axi_bready_sig; - logic [(AXI_DATA_WIDTH / 8)-1 : 0] s00_axi_wstrb_sig; - logic [2 : 0] s00_axi_arprot_sig; - logic [2 : 0] s00_axi_awprot_sig; - logic [AXI_ADDR_WIDTH_SLAVE - 1 : 0] s00_axi_araddr_sig; - logic s00_axi_arvalid_sig; - logic s00_axi_arready_sig; - logic [AXI_DATA_WIDTH - 1 : 0] s00_axi_rdata_sig; - logic s00_axi_rvalid_sig; - logic s00_axi_rready_sig; - logic [1:0] s00_axi_rresp_sig; - logic [1:0] s00_axi_bresp_sig; - - // PAD controller - reg_req_t pad_req; - reg_rsp_t pad_resp; - logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][7:0] pad_attributes; - logic [core_v_mini_mcu_pkg::NUM_PAD-1:0][3:0] pad_muxes; - - logic rst_ngen; - - // input, output pins from core_v_mini_mcu -% for pad in total_pad_list: -${pad.internal_signals} -% endfor - - wire clk_gen; - logic [ 31:0] exit_value; - wire rst_n; - logic [CLK_LED_COUNT_LENGTH - 1:0] clk_count; - - // low active reset - assign rst_n = !rst_i; - - // reset LED for debugging - assign rst_led = rst_n; - - // counter to blink an LED - assign clk_led = clk_count[CLK_LED_COUNT_LENGTH-1]; - - always_ff @(posedge clk_gen or negedge rst_n) begin : clk_count_process - if (!rst_n) begin - clk_count <= '0; - end else begin - clk_count <= clk_count + 1; - end - end - - // clock output for debugging - assign clk_out = clk_gen; - - xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( - .clk_125MHz(clk_in), - .clk_out1_0(clk_gen) - ); - - // eXtension Interface - if_xif #() ext_if (); - - logic clk_i; - assign clk_i = clk_gen; - - core_v_mini_mcu #( - .COREV_PULP(COREV_PULP), - .FPU(FPU), - .ZFINX(ZFINX), - .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER) - ) core_v_mini_mcu_i ( - - .rst_ni(rst_ngen), -% for pad in pad_list: -${pad.core_v_mini_mcu_bonding} -% endfor - .intr_vector_ext_i('0), - .xif_compressed_if(ext_if), - .xif_issue_if(ext_if), - .xif_commit_if(ext_if), - .xif_mem_if(ext_if), - .xif_mem_result_if(ext_if), - .xif_result_if(ext_if), - .ext_xbar_master_req_i('0), - .ext_xbar_master_resp_o(), - .ext_core_instr_req_o(), - .ext_core_instr_resp_i('0), - .ext_core_data_req_o(), - .ext_core_data_resp_i('0), - .ext_debug_master_req_o(), - .ext_debug_master_resp_i('0), - .ext_dma_read_ch0_req_o(), - .ext_dma_read_ch0_resp_i('0), - .ext_dma_write_ch0_req_o(), - .ext_dma_write_ch0_resp_i('0), - .ext_dma_addr_ch0_req_o(), - .ext_dma_addr_ch0_resp_i('0), - .ext_peripheral_slave_req_o(), - .ext_peripheral_slave_resp_i('0), - .external_subsystem_powergate_switch_o(), - .external_subsystem_powergate_switch_ack_i(), - .external_subsystem_powergate_iso_o(), - .external_subsystem_rst_no(), - .external_ram_banks_set_retentive_o(), - .exit_value_o(exit_value), - .pad_req_o(pad_req), - .pad_resp_i(pad_resp), - .cpu_subsystem_powergate_switch_o(cpu_subsystem_powergate_switch), - .cpu_subsystem_powergate_switch_ack_i(cpu_subsystem_powergate_switch_ack), - .peripheral_subsystem_powergate_switch_o(peripheral_subsystem_powergate_switch), - .peripheral_subsystem_powergate_switch_ack_i(peripheral_subsystem_powergate_switch_ack), - .memory_subsystem_banks_powergate_switch_o(memory_subsystem_banks_powergate_switch), - .memory_subsystem_banks_powergate_switch_ack_i(memory_subsystem_banks_powergate_switch_ack) - ); - - logic gpio_0_io; - logic gpio_1_io; - logic gpio_2_io; - logic gpio_3_io; - logic gpio_4_io; - logic gpio_5_io; - logic gpio_6_io; - logic gpio_7_io; - logic gpio_8_io; - logic gpio_9_io; - logic gpio_10_io; - logic gpio_11_io; - logic gpio_12_io; - logic gpio_13_io; - logic gpio_14_io; - logic gpio_15_io; - logic gpio_16_io; - logic gpio_17_io; - logic gpio_18_io; - logic gpio_19_io; - logic gpio_20_io; - logic gpio_21_io; - logic gpio_22_io; - - assign spi_flash_sck_o_sig = spi_flash_sck_out_x; - assign spi_flash_csb_o_sig = spi_flash_cs_0_out_x; - assign spi_sdi1_sig = spi_flash_sd_1_in_x; - assign spi_sdo0_sig = spi_flash_sd_0_out_x; - assign spi_sdo2_sig = spi_sd_2_out_x; - assign spi_sdo3_sig = spi_sd_3_out_x; - - assign spi2_csb_io[0] = spi2_cs_0_io; - assign spi2_csb_io[1] = spi2_cs_1_io; - - assign gpio_io[0] = gpio_0_io; - assign gpio_io[1] = gpio_1_io; - assign gpio_io[2] = gpio_2_io; - assign gpio_io[3] = gpio_3_io; - assign gpio_io[4] = gpio_4_io; - assign gpio_io[5] = gpio_5_io; - assign gpio_io[6] = gpio_6_io; - assign gpio_io[7] = gpio_7_io; - assign gpio_io[8] = gpio_8_io; - assign gpio_io[9] = gpio_9_io; - assign gpio_io[10] = gpio_10_io; - assign gpio_io[11] = gpio_11_io; - assign gpio_io[12] = gpio_12_io; - assign gpio_io[13] = gpio_13_io; - assign gpio_io[14] = gpio_14_io; - assign gpio_io[15] = gpio_15_io; - assign gpio_io[16] = gpio_16_io; - assign gpio_io[17] = gpio_17_io; - assign gpio_io[18] = gpio_18_io; - assign gpio_io[19] = gpio_19_io; - assign gpio_io[20] = gpio_20_io; - assign gpio_io[21] = gpio_21_io; - assign gpio_io[22] = gpio_22_io; - - processing_system_wrapper processing_system_wrapper_i ( - .DDR_addr(DDR_addr), - .DDR_ba(DDR_ba), - .DDR_cas_n(DDR_cas_n), - .DDR_ck_n(DDR_ck_n), - .DDR_ck_p(DDR_ck_p), - .DDR_cke(DDR_cke), - .DDR_cs_n(DDR_cs_n), - .DDR_dm(DDR_dm), - .DDR_dq(DDR_dq), - .DDR_dqs_n(DDR_dqs_n), - .DDR_dqs_p(DDR_dqs_p), - .DDR_odt(DDR_odt), - .DDR_ras_n(DDR_ras_n), - .DDR_reset_n(DDR_reset_n), - .DDR_we_n(DDR_we_n), - .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn), - .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp), - .FIXED_IO_mio(FIXED_IO_mio), - .FIXED_IO_ps_clk(FIXED_IO_ps_clk), - .FIXED_IO_ps_porb(FIXED_IO_ps_porb), - .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb), - .UART_rxd(uart_tx_out_x), - .UART_txd(uart_rx_in_x), - .gpio_jtag_tck_i(jtag_tck_in_x), - .gpio_jtag_tms_i(jtag_tms_in_x), - .gpio_jtag_trst_ni(jtag_trst_nin_x), - .gpio_jtag_tdi_i(jtag_tdi_in_x), - .gpio_jtag_tdo_o(jtag_tdo_out_x), - .AXI_HP_ACLK(AXI_HP_ACLK), - .AXI_HP_ARESETN(AXI_HP_ARESETN), - .AXI_HP_araddr(AXI_HP_araddr_sig), - .AXI_HP_arburst(AXI_HP_arburst_sig), - .AXI_HP_arcache(AXI_HP_arcache_sig), - .AXI_HP_arlen(AXI_HP_arlen_sig), - .AXI_HP_arlock(AXI_HP_arlock_sig), - .AXI_HP_arprot(AXI_HP_arprot_sig), - .AXI_HP_arqos(AXI_HP_arqos_sig), - .AXI_HP_arready(AXI_HP_arready_sig), - .AXI_HP_arsize(AXI_HP_arsize_sig), - .AXI_HP_arvalid(AXI_HP_arvalid_sig), - .AXI_HP_awaddr(AXI_HP_awaddr_sig), - .AXI_HP_awburst(AXI_HP_awburst_sig), - .AXI_HP_awcache(AXI_HP_awcache_sig), - .AXI_HP_awlen(AXI_HP_awlen_sig), - .AXI_HP_awlock(AXI_HP_awlock_sig), - .AXI_HP_awprot(AXI_HP_awprot_sig), - .AXI_HP_awqos(AXI_HP_awqos_sig), - .AXI_HP_awready(AXI_HP_awready_sig), - .AXI_HP_awsize(AXI_HP_awsize_sig), - .AXI_HP_awvalid(AXI_HP_awvalid_sig), - .AXI_HP_bready(AXI_HP_bready_sig), - .AXI_HP_bresp(AXI_HP_bresp_sig), - .AXI_HP_bvalid(AXI_HP_bvalid_sig), - .AXI_HP_rdata(AXI_HP_rdata_sig), - .AXI_HP_rlast(AXI_HP_rlast_sig), - .AXI_HP_rready(AXI_HP_rready_sig), - .AXI_HP_rresp(AXI_HP_rresp_sig), - .AXI_HP_rvalid(AXI_HP_rvalid_sig), - .AXI_HP_wdata(AXI_HP_wdata_sig), - .AXI_HP_wlast(AXI_HP_wlast_sig), - .AXI_HP_wready(AXI_HP_wready_sig), - .AXI_HP_wstrb(AXI_HP_wstrb_sig), - .AXI_HP_wvalid(AXI_HP_wvalid_sig), - .M_AXI_araddr(s00_axi_araddr_sig), - .M_AXI_arready(s00_axi_arready_sig), - .M_AXI_arvalid(s00_axi_arvalid_sig), - .M_AXI_awaddr(s00_axi_awaddr_sig), - .M_AXI_awready(s00_axi_awready_sig), - .M_AXI_awvalid(s00_axi_awvalid_sig), - .M_AXI_bready(s00_axi_bready_sig), - .M_AXI_bresp(s00_axi_bresp_sig), - .M_AXI_bvalid(s00_axi_bvalid_sig), - .M_AXI_rdata(s00_axi_rdata_sig), - .M_AXI_rready(s00_axi_rready_sig), - .M_AXI_rresp(s00_axi_rresp_sig), - .M_AXI_rvalid(s00_axi_rvalid_sig), - .M_AXI_wdata(s00_axi_wdata_sig), - .M_AXI_wready(s00_axi_wready_sig), - .M_AXI_wvalid(s00_axi_wvalid_sig), - .M_AXI_awprot(s00_axi_awprot_sig), - .M_AXI_arprot(s00_axi_arprot_sig), - .M_AXI_wstrb(s00_axi_wstrb_sig) - ); - - axi_address_hijacker #( - .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH), - .C_S_AXI_DATA_WIDTH(AXI_DATA_WIDTH) - ) add_hij ( - .axi_master_awaddr_in(axi_master_awaddr_in_sig), - .axi_master_araddr_in(axi_master_araddr_in_sig), - - // output write and read address by adding fixed offset - .axi_master_araddr_out(AXI_HP_araddr_sig), - .axi_master_awaddr_out(AXI_HP_awaddr_sig), - - .S_AXI_ACLK(AXI_HP_ACLK), - .S_AXI_ARESETN(AXI_HP_ARESETN), - - .S_AXI_AWADDR (s00_axi_awaddr_sig), - .S_AXI_AWPROT (s00_axi_awprot_sig), - .S_AXI_AWVALID(s00_axi_awvalid_sig), - .S_AXI_AWREADY(s00_axi_awready_sig), - .S_AXI_WDATA (s00_axi_wdata_sig), - .S_AXI_WSTRB (s00_axi_wstrb_sig), - .S_AXI_WVALID (s00_axi_wvalid_sig), - .S_AXI_WREADY (s00_axi_wready_sig), - .S_AXI_BRESP (s00_axi_bresp_sig), - .S_AXI_BVALID (s00_axi_bvalid_sig), - .S_AXI_BREADY (s00_axi_bready_sig), - .S_AXI_ARADDR (s00_axi_araddr_sig), - .S_AXI_ARPROT (s00_axi_arprot_sig), - .S_AXI_ARVALID(s00_axi_arvalid_sig), - .S_AXI_ARREADY(s00_axi_arready_sig), - .S_AXI_RDATA (s00_axi_rdata_sig), - .S_AXI_RRESP (s00_axi_rresp_sig), - .S_AXI_RVALID (s00_axi_rvalid_sig), - .S_AXI_RREADY (s00_axi_rready_sig) - ); - - axi_spi_slave #( - .AXI_DATA_WIDTH(AXI_DATA_WIDTH) - ) fake_flash ( - .axi_aclk(AXI_HP_ACLK), - .axi_aresetn(AXI_HP_ARESETN), - - .test_mode('0), - - .axi_master_aw_valid(AXI_HP_awvalid_sig), - .axi_master_aw_id(AXI_HP_awid_sig), - .axi_master_aw_prot(AXI_HP_awprot_sig), - .axi_master_aw_qos(AXI_HP_awqos_sig), - .axi_master_aw_cache(AXI_HP_awcache_sig), - .axi_master_aw_lock(AXI_HP_awlock_sig), - .axi_master_aw_burst(AXI_HP_awburst_sig), - .axi_master_aw_size(AXI_HP_awsize_sig), - .axi_master_aw_len(AXI_HP_awlen_sig), - .axi_master_aw_addr(axi_master_awaddr_in_sig), - .axi_master_aw_ready(AXI_HP_awready_sig), - - .axi_master_w_valid(AXI_HP_wvalid_sig), - .axi_master_w_data (AXI_HP_wdata_sig), - .axi_master_w_strb (AXI_HP_wstrb_sig), - .axi_master_w_last (AXI_HP_wlast_sig), - .axi_master_w_ready(AXI_HP_wready_sig), - - .axi_master_b_valid(AXI_HP_bvalid_sig), - .axi_master_b_id(AXI_HP_bid_sig), - .axi_master_b_resp(AXI_HP_bresp_sig), - .axi_master_b_ready(AXI_HP_bready_sig), - - .axi_master_ar_valid(AXI_HP_arvalid_sig), - .axi_master_ar_id(AXI_HP_arid_sig), - .axi_master_ar_prot(AXI_HP_arprot_sig), - .axi_master_ar_qos(AXI_HP_arqos_sig), - .axi_master_ar_cache(AXI_HP_arcache_sig), - .axi_master_ar_lock(AXI_HP_arlock_sig), - .axi_master_ar_burst(AXI_HP_arburst_sig), - .axi_master_ar_size(AXI_HP_arsize_sig), - .axi_master_ar_len(AXI_HP_arlen_sig), - .axi_master_ar_addr(axi_master_araddr_in_sig), - .axi_master_ar_ready(AXI_HP_arready_sig), - - .axi_master_r_valid(AXI_HP_rvalid_sig), - .axi_master_r_id(AXI_HP_rid_sig), - .axi_master_r_data(AXI_HP_rdata_sig), - .axi_master_r_resp(AXI_HP_rresp_sig), - .axi_master_r_last(AXI_HP_rlast_sig), - .axi_master_r_ready(AXI_HP_rready_sig), - - .spi_sclk(spi_flash_sck_o_sig), - .spi_cs (spi_flash_csb_o_sig), - .spi_sdo1(spi_sdi1_sig), - .spi_sdi0(spi_sdo0_sig), - .spi_sdi2(spi_sdo2_sig), - .spi_sdi3(spi_sdo3_sig) - ); - - // TESTING PURPOSES -> THEY WILL BE INPUT TO PS AND READ BY SYSTEM ILA - assign spi_test_clk_sig = spi_flash_sck_o_sig; - assign spi_test_cs_sig = spi_flash_csb_o_sig; - assign spi_test_data_sig = {spi_sdo0_sig, spi_sdi1_sig, spi_sdo2_sig, spi_sdo3_sig}; - - pad_ring pad_ring_i ( -% for pad in total_pad_list: -${pad.pad_ring_bonding_bonding} -% endfor - .pad_attributes_i(pad_attributes) - ); - -${pad_constant_driver_assign} - -${pad_mux_process} - - pad_control #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t), - .NUM_PAD (core_v_mini_mcu_pkg::NUM_PAD) - ) pad_control_i ( - .clk_i(clk_in_x), - .rst_ni(rst_ngen), - .reg_req_i(pad_req), - .reg_rsp_o(pad_resp), - .pad_attributes_o(pad_attributes), - .pad_muxes_o(pad_muxes) - ); - - rstgen rstgen_i ( - .clk_i(clk_in_x), - .rst_ni(rst_n), - .test_mode_i(1'b0), - .rst_no(rst_ngen), - .init_no() - ); - - assign exit_value_o = exit_value[0]; -endmodule diff --git a/hw/vendor/esl_epfl_x_heep/linux_femu/scripts/xilinx_generate_processing_system.tcl b/hw/vendor/esl_epfl_x_heep/linux_femu/scripts/xilinx_generate_processing_system.tcl deleted file mode 100644 index a4628c5b..00000000 --- a/hw/vendor/esl_epfl_x_heep/linux_femu/scripts/xilinx_generate_processing_system.tcl +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright 2022 EPFL -# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 -# Define design macros - -# Select board -set_property board_part tul.com.tw:pynq-z2:part0:1.0 [current_project] - -# Create block design -create_bd_design "processing_system" - -# Add Zynq Processing System -create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 -apply_bd_automation -rule xilinx.com:bd_rule:processing_system7 -config {make_external "FIXED_IO, DDR" apply_board_preset "1" Master "Disable" Slave "Disable" } [get_bd_cells processing_system7_0] -set_property -dict [list CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {20} CONFIG.PCW_USE_S_AXI_HP0 {1} CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {0} CONFIG.PCW_SD0_PERIPHERAL_ENABLE {0} CONFIG.PCW_UART0_PERIPHERAL_ENABLE {0} CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} CONFIG.PCW_UART1_UART1_IO {EMIO} CONFIG.PCW_USB0_PERIPHERAL_ENABLE {0} CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {0} CONFIG.PCW_GPIO_EMIO_GPIO_ENABLE {1} CONFIG.PCW_GPIO_EMIO_GPIO_IO {5}] [get_bd_cells processing_system7_0] - -# Add AXI Interconnect -create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 axi_interconnect_0 -set_property -dict [list CONFIG.NUM_SI {2} CONFIG.NUM_MI {2}] [get_bd_cells axi_interconnect_0] - -# Add Constant -create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 xlconstant_0 -set_property -dict [list CONFIG.CONST_WIDTH {2} CONFIG.CONST_VAL {0b11}] [get_bd_cells xlconstant_0] - -# Add Concatenation -create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 xlconcat_0 -set_property -dict [list CONFIG.IN0_WIDTH.VALUE_SRC USER CONFIG.IN1_WIDTH.VALUE_SRC USER CONFIG.IN2_WIDTH.VALUE_SRC USER] [get_bd_cells xlconcat_0] -set_property -dict [list CONFIG.NUM_PORTS {3} CONFIG.IN0_WIDTH {2} CONFIG.IN2_WIDTH {2}] [get_bd_cells xlconcat_0] - -# Add Slices -create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_0 -create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_1 -create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_2 -create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_3 -set_property -dict [list CONFIG.DIN_TO {3} CONFIG.DIN_FROM {3} CONFIG.DIN_WIDTH {5} CONFIG.DOUT_WIDTH {1}] [get_bd_cells xlslice_0] -set_property -dict [list CONFIG.DIN_TO {4} CONFIG.DIN_FROM {4} CONFIG.DIN_WIDTH {5} CONFIG.DOUT_WIDTH {1}] [get_bd_cells xlslice_1] -set_property -dict [list CONFIG.DIN_TO {1} CONFIG.DIN_FROM {1} CONFIG.DIN_WIDTH {5} CONFIG.DOUT_WIDTH {1}] [get_bd_cells xlslice_2] -set_property -dict [list CONFIG.DIN_TO {0} CONFIG.DIN_FROM {0} CONFIG.DIN_WIDTH {5} CONFIG.DOUT_WIDTH {1}] [get_bd_cells xlslice_3] - -# Create port AXI_HP -make_bd_intf_pins_external [get_bd_intf_pins axi_interconnect_0/S00_AXI] -set_property name AXI_HP [get_bd_intf_ports S00_AXI_0] -set_property -dict [list CONFIG.FREQ_HZ {20000000}] [get_bd_intf_ports AXI_HP] - -# Create port M_AXI -make_bd_intf_pins_external [get_bd_intf_pins axi_interconnect_0/M01_AXI] -set_property name M_AXI [get_bd_intf_ports M01_AXI_0] -set_property -dict [list CONFIG.FREQ_HZ {20000000}] [get_bd_intf_ports M_AXI] - -# Connect AXI Interconnect and Zynq Processing System -connect_bd_intf_net -boundary_type upper [get_bd_intf_pins axi_interconnect_0/M00_AXI] [get_bd_intf_pins processing_system7_0/S_AXI_HP0] -connect_bd_intf_net [get_bd_intf_pins processing_system7_0/M_AXI_GP0] -boundary_type upper [get_bd_intf_pins axi_interconnect_0/S01_AXI] -apply_bd_automation -rule xilinx.com:bd_rule:clkrst -config { Clk {/processing_system7_0/FCLK_CLK0 (20 MHz)} Freq {100} Ref_Clk0 {} Ref_Clk1 {} Ref_Clk2 {}} [get_bd_pins axi_interconnect_0/ACLK] -apply_bd_automation -rule xilinx.com:bd_rule:clkrst -config { Clk {/processing_system7_0/FCLK_CLK0 (20 MHz)} Freq {100} Ref_Clk0 {} Ref_Clk1 {} Ref_Clk2 {}} [get_bd_pins axi_interconnect_0/M00_ACLK] -apply_bd_automation -rule xilinx.com:bd_rule:clkrst -config { Clk {/processing_system7_0/FCLK_CLK0 (20 MHz)} Freq {100} Ref_Clk0 {} Ref_Clk1 {} Ref_Clk2 {}} [get_bd_pins axi_interconnect_0/M01_ACLK] -apply_bd_automation -rule xilinx.com:bd_rule:clkrst -config { Clk {/processing_system7_0/FCLK_CLK0 (20 MHz)} Freq {100} Ref_Clk0 {} Ref_Clk1 {} Ref_Clk2 {}} [get_bd_pins axi_interconnect_0/S00_ACLK] -apply_bd_automation -rule xilinx.com:bd_rule:clkrst -config { Clk {/processing_system7_0/FCLK_CLK0 (20 MHz)} Freq {100} Ref_Clk0 {} Ref_Clk1 {} Ref_Clk2 {}} [get_bd_pins axi_interconnect_0/S01_ACLK] - -# Create port AXI_HP_ACLK -create_bd_port -dir O -type clk AXI_HP_ACLK - -# Create port AXI_HP_ARESETN -create_bd_port -dir O -type rst AXI_HP_ARESETN - -# Connect AXI_HP_ACLK and AXI_HP_ARESETN -connect_bd_net [get_bd_ports AXI_HP_ACLK] [get_bd_pins processing_system7_0/FCLK_CLK0] -connect_bd_net [get_bd_ports AXI_HP_ARESETN] [get_bd_pins rst_ps7_0_20M/peripheral_aresetn] - -# Create port gpio_jtag_tdo_o -make_bd_pins_external [get_bd_pins xlconcat_0/In1] -set_property name gpio_jtag_tdo_o [get_bd_ports In1_0] - -# Connect Constant and Concatenation -connect_bd_net [get_bd_pins xlconstant_0/dout] [get_bd_pins xlconcat_0/In0] -connect_bd_net [get_bd_pins xlconcat_0/In2] [get_bd_pins xlconstant_0/dout] -connect_bd_net [get_bd_pins xlconcat_0/dout] [get_bd_pins processing_system7_0/GPIO_I] - -# Create port gpio_jtag_tdi_i -make_bd_pins_external [get_bd_pins xlslice_0/Dout] -set_property name gpio_jtag_tdi_i [get_bd_ports Dout_0] - -# Create port gpio_jtag_tck_i -make_bd_pins_external [get_bd_pins xlslice_1/Dout] -set_property name gpio_jtag_tck_i [get_bd_ports Dout_0] - -# Create port gpio_jtag_tms_i -make_bd_pins_external [get_bd_pins xlslice_2/Dout] -set_property name gpio_jtag_tms_i [get_bd_ports Dout_0] - -# Create port gpio_jtag_trst_ni -make_bd_pins_external [get_bd_pins xlslice_3/Dout] -set_property name gpio_jtag_trst_ni [get_bd_ports Dout_0] - -# Connect Slices -connect_bd_net [get_bd_pins xlslice_0/Din] [get_bd_pins processing_system7_0/GPIO_O] -connect_bd_net [get_bd_pins xlslice_1/Din] [get_bd_pins processing_system7_0/GPIO_O] -connect_bd_net [get_bd_pins xlslice_2/Din] [get_bd_pins processing_system7_0/GPIO_O] -connect_bd_net [get_bd_pins xlslice_3/Din] [get_bd_pins processing_system7_0/GPIO_O] - -# Create port UART -make_bd_intf_pins_external [get_bd_intf_pins processing_system7_0/UART_1] -set_property name UART [get_bd_intf_ports UART_1_0] - -# Assign addresses -assign_bd_address - -# Validate design -validate_bd_design - -# Save design -save_bd_design - -# Close design -close_bd_design [get_bd_designs processing_system] - -# Make wrapper -set wrapper_path [ make_wrapper -fileset sources_1 -files [ get_files -norecurse processing_system.bd ] -top ] -add_files -norecurse -fileset sources_1 $wrapper_path diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson index 4bc1e1df..f1d435df 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson @@ -27,6 +27,8 @@ lenght: whatisleft, #keyword used to calculate the size as: ram.length - code.lenght } }, + stack_size: 0x800, + heap_size: 0x800, } debug: { diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson index 98440522..ed74849a 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson @@ -27,6 +27,8 @@ lenght: whatisleft, #keyword used to calculate the size as: ram.length - code.lenght } }, + stack_size: 0x800, + heap_size: 0x800, } debug: { diff --git a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt index d857d792..9639d6cf 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt +++ b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt @@ -63,9 +63,9 @@ FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS ${SOURCE_PATH}*.h) SET(dir_list_str "") FOREACH(file_path ${new_list}) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list - if(${file_path} MATCHES "/device/") - if(${file_path} MATCHES "/target/") # Add it if its not in target, or if its in target/${TARGET} - if(${file_path} MATCHES ${TARGET}) + if(${file_path} MATCHES "${ROOT_PROJECT}device/") + if(${file_path} MATCHES "${ROOT_PROJECT}device/target/") # Add it if its not in target, or if its in target/${TARGET} + if(${file_path} MATCHES "${ROOT_PROJECT}device/target/${TARGET}") SET(add 1) endif() else() @@ -73,9 +73,9 @@ FOREACH(file_path ${new_list}) endif() elseif(${file_path} MATCHES ${PROJECT}) SET(add 1) - elseif( ( ${file_path} MATCHES "/freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) ) + elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) ) SET(add 1) - elseif( ${file_path} MATCHES "/external/" ) + elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" ) SET(add 1) endif() @@ -124,9 +124,9 @@ SET( c_dir_list "" ) SET( app_found 0 ) FOREACH(file_path IN LISTS new_list) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list - if(${file_path} MATCHES "/device/") + if(${file_path} MATCHES "${ROOT_PROJECT}device/") SET(add 1) - elseif( ${file_path} MATCHES "/external/" ) + elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" ) SET(add 1) elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) ) SET(add 1) @@ -153,7 +153,7 @@ if( app_found EQUAL 0 ) SET(c_dir_list "") FOREACH(file_path IN LISTS new_list) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list - if(${file_path} MATCHES "/device/") + if(${file_path} MATCHES "${ROOT_PROJECT}device/") SET(add 1) elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) ) SET(add 1) @@ -303,14 +303,27 @@ endif() # Set CMAKE flags # specify the C standard -set(COMPILER_LINKER_FLAGS "\ - -march=${CMAKE_SYSTEM_PROCESSOR} \ - -w -Os -g -nostdlib \ - -DHOST_BUILD \ - -D${CRT_TYPE} \ - -D${CRTO} \ - -DportasmHANDLE_INTERRUPT=vSystemIrqHandler\ -") +if(NOT ${PROJECT} MATCHES "coremark") + set(COMPILER_LINKER_FLAGS "\ + -march=${CMAKE_SYSTEM_PROCESSOR} \ + -w -O2 -g -nostdlib \ + -ffunction-sections \ + -DHOST_BUILD \ + -D${CRT_TYPE} \ + -D${CRTO} \ + -DportasmHANDLE_INTERRUPT=vSystemIrqHandler\ + ") +else() + set(COMPILER_LINKER_FLAGS "\ + -march=${CMAKE_SYSTEM_PROCESSOR} \ + -w -O3 -g -nostdlib -falign-functions=16 -funroll-all-loops -falign-jumps=4 -finline-functions -Wall -static -pedantic -DPERFORMANCE_RUN=1 -DITERATIONS=1 -DHAS_STDIO=1 -DHAS_PRINTF=1 \ + -ffunction-sections \ + -DHOST_BUILD \ + -D${CRT_TYPE} \ + -D${CRTO} \ + -DportasmHANDLE_INTERRUPT=vSystemIrqHandler\ + ") +endif() set(CMAKE_C_FLAGS ${COMPILER_LINKER_FLAGS}) if (${COMPILER} MATCHES "clang") @@ -401,7 +414,7 @@ endif() # Post processing command to create a disassembly file add_custom_command(TARGET ${MAINFILE}.elf POST_BUILD - COMMAND ${CMAKE_OBJDUMP} -S ${MAINFILE}.elf > ${MAINFILE}.disasm + COMMAND ${CMAKE_OBJDUMP} -S ${MAINFILE}.elf > ${MAINFILE}.S COMMENT "Invoking: Disassemble") # Post processing command to create a hex file @@ -434,4 +447,4 @@ endforeach() SET(DCMAKE_EXPORT_COMPILE_COMMANDS ON) -#message( FATAL_ERROR "You can not do this at all, CMake will exit." ) \ No newline at end of file +#message( FATAL_ERROR "You can not do this at all, CMake will exit." ) diff --git a/hw/vendor/esl_epfl_x_heep/sw/Makefile b/hw/vendor/esl_epfl_x_heep/sw/Makefile index 3582fb25..a36f5ead 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/Makefile +++ b/hw/vendor/esl_epfl_x_heep/sw/Makefile @@ -25,7 +25,7 @@ PROJECT ?= hello_world # Linker options are 'on_chip' (default),'flash_load','flash_exec' LINKER ?= on_chip -# Target options are 'sim' (default) and 'pynq-z2' +# Target options are 'sim' (default), 'pynq-z2', and 'nexys-a7-100t' TARGET ?= sim # Compiler options are 'gcc' (default) and 'clang' @@ -38,7 +38,7 @@ COMPILER_PREFIX ?= riscv32-unknown- ARCH ?= rv32imc # Path relative from the location of sw/Makefile from which to fetch source files. The directory of that file is the default value. -SOURCE ?= "." +SOURCE ?= $(".") # riscv toolchain install path RISCV ?= ~/.riscv @@ -56,7 +56,7 @@ source_path := $(realpath $(mkfile_path)/$(SOURCE)) $(info $$You are fetching sources from $(source_path) ) -SOURCE_PATH = $(source_path)/ +SOURCE_PATH = $(source_path)/ ROOT_PROJECT = $(mkfile_path)/ INC_FOLDERS = $(mkfile_path)/device/target/$(TARGET)/ LINK_FOLDER = $(mkfile_path)/linker @@ -70,6 +70,9 @@ else CMAKE=cmake3 endif +# Export variables to sub-makefiles +export + # Let's CMake! include cmake/targets.mak diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_list_join.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_list_join.c new file mode 100644 index 00000000..64527aa5 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_list_join.c @@ -0,0 +1,612 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include "coremark.h" +/* +Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this +library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accomodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b +are divided as follows: o Upper 8b are backup of original data. o Bit 7 +indicates if the lower 7 bits are to be used as is or calculated. o Bits 0-2 +indicate type of operation to perform to get a 7b value. o Bits 3-6 provide +input for the operation. + +*/ + +/* local functions */ + +list_head *core_list_find(list_head *list, list_data *info); +list_head *core_list_reverse(list_head *list); +list_head *core_list_remove(list_head *item); +list_head *core_list_undo_remove(list_head *item_removed, + list_head *item_modified); +list_head *core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end); +typedef ee_s32 (*list_cmp)(list_data *a, list_data *b, core_results *res); +list_head *core_list_mergesort(list_head * list, + list_cmp cmp, + core_results *res); + +ee_s16 +calc_func(ee_s16 *pdata, core_results *res) +{ + ee_s16 data = *pdata; + ee_s16 retval; + ee_u8 optype + = (data >> 7) + & 1; /* bit 7 indicates if the function result has been cached */ + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else + { /* otherwise calculate and cache the result */ + ee_s16 flag = data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype + = ((data >> 3) + & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + switch (flag) + { + case 0: + if (dtype < 0x22) /* set min period for bit corruption */ + dtype = 0x22; + retval = core_bench_state(res->size, + res->memblock[3], + res->seed1, + res->seed2, + dtype, + res->crc); + if (res->crcstate == 0) + res->crcstate = retval; + break; + case 1: + retval = core_bench_matrix(&(res->mat), dtype, res->crc); + if (res->crcmatrix == 0) + res->crcmatrix = retval; + break; + default: + retval = data; + break; + } + res->crc = crcu16(retval, res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 +cmp_complex(list_data *a, list_data *b, core_results *res) +{ + ee_s16 val1 = calc_func(&(a->data16), res); + ee_s16 val2 = calc_func(&(b->data16), res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 +cmp_idx(list_data *a, list_data *b, core_results *res) +{ + if (res == NULL) + { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16 >> 8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16 >> 8)); + } + return a->idx - b->idx; +} + +void +copy_info(list_data *to, list_data *from) +{ + to->data16 = from->data16; + to->idx = from->idx; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + * At the end of this function, the list is back to original state +*/ +ee_u16 +core_bench_list(core_results *res, ee_s16 finder_idx) +{ + ee_u16 retval = 0; + ee_u16 found = 0, missed = 0; + list_head *list = res->list; + ee_s16 find_num = res->seed3; + list_head *this_find; + list_head *finder, *remover; + list_data info; + ee_s16 i; + + info.idx = finder_idx; + /* find values in the list, and change the list each time + * (reverse and cache if value found) */ + for (i = 0; i < find_num; i++) + { + info.data16 = (i & 0xff); + this_find = core_list_find(list, &info); + list = core_list_reverse(list); + if (this_find == NULL) + { + missed++; + retval += (list->next->info->data16 >> 8) & 1; + } + else + { + found++; + if (this_find->info->data16 & 0x1) /* use found value */ + retval += (this_find->info->data16 >> 9) & 1; + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next = list->next; + list->next = finder; + } + } + if (info.idx >= 0) + info.idx++; +#if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n", i, retval, missed, found); +#endif + } + retval += found * 4 - missed; + /* sort the list by data content and remove one item*/ + if (finder_idx > 0) + list = core_list_mergesort(list, cmp_complex, res); + remover = core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo + * remove */ + finder = core_list_find(list, &info); + if (!finder) + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 1: %04x\n", retval); +#endif + remover = core_list_undo_remove(remover, list->next); + /* sort the list by index, in effect returning the list to original state */ + list = core_list_mergesort(list, cmp_idx, NULL); + /* CRC data content of list */ + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 2: %04x\n", retval); +#endif + return retval; +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be + determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head * +core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) +{ + /* calculated pointers for the list */ + ee_u32 per_item = 16 + sizeof(struct list_data_s); + ee_u32 size = (blksize / per_item) + - 2; /* to accomodate systems with 64b pointers, and make sure + same code is executed, set max list elements */ + list_head *memblock_end = memblock + size; + list_data *datablock = (list_data *)(memblock_end); + list_data *datablock_end = datablock + size; + /* some useful variables */ + ee_u32 i; + list_head *finder, *list = memblock; + list_data info; + + /* create a fake items for the list head and tail */ + list->next = NULL; + list->info = datablock; + list->info->idx = 0x0000; + list->info->data16 = (ee_s16)0x8080; + memblock++; + datablock++; + info.idx = 0x7fff; + info.data16 = (ee_s16)0xffff; + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + + /* then insert size items */ + for (i = 0; i < size; i++) + { + ee_u16 datpat = ((ee_u16)(seed ^ i) & 0xf); + ee_u16 dat + = (datpat << 3) | (i & 0x7); /* alternate between algorithms */ + info.data16 = (dat << 8) | dat; /* fill the data with actual data and + upper bits with rebuild value */ + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + } + /* and now index the list so we know initial seed order of the list */ + finder = list->next; + i = 1; + while (finder->next != NULL) + { + if (i < size / 5) /* first 20% of the list in order */ + finder->info->idx = i++; + else + { + ee_u16 pat = (ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx = 0x3fff + & (((i & 0x07) << 8) + | pat); /* make sure the mixed items end up + after the ones in sequence */ + } + finder = finder->next; + } + list = core_list_mergesort(list, cmp_idx, NULL); +#if CORE_DEBUG + ee_printf("Initialized list:\n"); + finder = list; + while (finder) + { + ee_printf( + "[%04x,%04x]", finder->info->idx, (ee_u16)finder->info->data16); + finder = finder->next; + } + ee_printf("\n"); +#endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head * +core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end) +{ + list_head *newitem; + + if ((*memblock + 1) >= memblock_end) + return NULL; + if ((*datablock + 1) >= datablock_end) + return NULL; + + newitem = *memblock; + (*memblock)++; + newitem->next = insert_point->next; + insert_point->next = newitem; + + newitem->info = *datablock; + (*datablock)++; + copy_info(newitem->info, info); + + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to + check for NULL. + + Returns: + Removed item. +*/ +list_head * +core_list_remove(list_head *item) +{ + list_data *tmp; + list_head *ret = item->next; + /* swap data pointers */ + tmp = item->info; + item->info = ret->info; + ret->info = tmp; + /* and eliminate item */ + item->next = item->next->next; + ret->next = NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the + item_modified - List item that was modified during + + Returns: + The item that was linked back to the list. + +*/ +list_head * +core_list_undo_remove(list_head *item_removed, list_head *item_modified) +{ + list_data *tmp; + /* swap data pointers */ + tmp = item_removed->info; + item_removed->info = item_modified->info; + item_modified->info = tmp; + /* and insert item */ + item_removed->next = item_modified->next; + item_modified->next = item_removed; + return item_removed; +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head * +core_list_reverse(list_head *list) +{ + list_head *next = NULL, *tmp; + while (list) + { + tmp = list->next; + list->next = next; + next = list; + list = tmp; + } + return next; +} +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative + rather then recursive algorithm. The sort can either return the list to + original order (by idx) , or use the data item to invoke other other + algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + + */ +list_head * +core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) +{ + list_head *p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + if (!q) + break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info, q->info, res) <= 0) + { + /* First element of p is lower (or same); e must come from + * p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } +#if COMPILER_REQUIRES_SORT_RETURN + return list; +#endif +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_matrix.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_matrix.c new file mode 100644 index 00000000..9c7901c3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_matrix.c @@ -0,0 +1,376 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include "coremark.h" +/* +Topic: Description + Matrix manipulation benchmark + + This very simple algorithm forms the basis of many more complex +algorithms. + + The tight inner loop is the focus of many optimizations (compiler as +well as hardware based) and is thus relevant for embedded processing. + + The total available data space will be divided to 3 parts: + NxN Matrix A - initialized with small values (upper 3/4 of the bits all +zero). NxN Matrix B - initialized with medium values (upper half of the bits all +zero). NxN Matrix C - used for the result. + + The actual values for A and B must be derived based on input that is not +available at compile time. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val); +ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval); +void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val); +void matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val); + +#define matrix_test_next(x) (x + 1) +#define matrix_clip(x, y) ((y) ? (x)&0x0ff : (x)&0x0ffff) +#define matrix_big(x) (0xf000 | (x)) +#define bit_extract(x, from, to) (((x) >> (from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void +printmat(MATDAT *A, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", A[i * N + j]); + } + ee_printf("\n"); + } +} +void +printmatC(MATRES *C, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", C[i * N + j]); + } + ee_printf("\n"); + } +} +#endif +/* Function: core_bench_matrix + Benchmark function + + Iterate N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 +core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) +{ + ee_u32 N = p->N; + MATRES *C = p->C; + MATDAT *A = p->A; + MATDAT *B = p->B; + MATDAT val = (MATDAT)seed; + + crc = crc16(matrix_test(N, C, A, B, val), crc); + + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by . + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 +matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) +{ + ee_u16 crc = 0; + MATDAT clipval = matrix_big(val); + + matrix_add_const(N, A, val); /* make sure data changes */ +#if CORE_DEBUG + printmat(A, N, "matrix_add_const"); +#endif + matrix_mul_const(N, C, A, val); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_const"); +#endif + matrix_mul_vect(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_vect"); +#endif + matrix_mul_matrix(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix"); +#endif + matrix_mul_matrix_bitextract(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix_bitextract"); +#endif + + matrix_add_const(N, A, -val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +ee_u32 +core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) +{ + ee_u32 N = 0; + MATDAT *A; + MATDAT *B; + ee_s32 order = 1; + MATDAT val; + ee_u32 i = 0, j = 0; + if (seed == 0) + seed = 1; + while (j < blksize) + { + i++; + j = i * i * 2 * 4; + } + N = i - 1; + A = (MATDAT *)align_mem(memblk); + B = A + N * N; + + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + seed = ((order * seed) % 65536); + val = (seed + order); + val = matrix_clip(val, 0); + B[i * N + j] = val; + val = (val + order); + val = matrix_clip(val, 1); + A[i * N + j] = val; + order++; + } + } + + p->A = A; + p->B = B; + p->C = (MATRES *)align_mem(B + N * N); + p->N = N; +#if CORE_DEBUG + printmat(A, N, "A"); + printmat(B, N, "B"); +#endif + return N; +} + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the + matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ +ee_s16 +matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) +{ + MATRES tmp = 0, prev = 0, cur = 0; + ee_s16 ret = 0; + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + cur = C[i * N + j]; + tmp += cur; + if (tmp > clipval) + { + ret += 10; + tmp = 0; + } + else + { + ret += (cur > prev) ? 1 : 0; + } + prev = cur; + } + } + return ret; +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void +matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = (MATRES)A[i * N + j] * (MATRES)val; + } + } +} + +/* Function: matrix_add_const + Add a constant value to all elements of a matrix. +*/ +void +matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + A[i * N + j] += val; + } + } +} + +/* Function: matrix_mul_vect + Multiply a matrix by a vector. + This is common in many simple filters (e.g. fir where a vector of + coefficients is applied to the matrix.) +*/ +void +matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + C[i] = 0; + for (j = 0; j < N; j++) + { + C[i] += (MATRES)A[i * N + j] * (MATRES)B[j]; + } + } +} + +/* Function: matrix_mul_matrix + Multiply a matrix by a matrix. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + C[i * N + j] += (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + } + } + } +} + +/* Function: matrix_mul_matrix_bitextract + Multiply a matrix by a matrix, and extract some bits from the result. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + MATRES tmp = (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + C[i * N + j] += bit_extract(tmp, 2, 4) * bit_extract(tmp, 5, 7); + } + } + } +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.c new file mode 100644 index 00000000..3b40763c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.c @@ -0,0 +1,104 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include "csr.h" +#include "x-heep.h" + +#include "coremark.h" + +ee_u32 default_num_contexts = 1; + +static CORETIMETYPE start_time_val, stop_time_val; + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = ITERATIONS; +volatile ee_s32 seed5_volatile = 0; + +void +portable_init(core_portable *p, int *argc, char *argv[]) +{ + // Don't need to do anything here atm. + (void)p; + (void)argc; + (void)argv; +} + +void +portable_fini(core_portable *p) +{ + // Don't need to do anything here atm. + (void)p; +} + +void +start_time(void) +{ + // Enable mcycle counter and read value + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + + CSR_READ(CSR_REG_MCYCLE, &start_time_val); +} + +void +stop_time(void) +{ + CSR_READ(CSR_REG_MCYCLE, &stop_time_val); +} + +CORE_TICKS +get_time(void) +{ + return (stop_time_val - start_time_val); +} + +secs_ret +time_in_secs(CORE_TICKS ticks) +{ + return ticks*1E-6; // Normalized to 1 MHz clock period +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.h b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.h new file mode 100644 index 00000000..5a15066a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_portme.h @@ -0,0 +1,93 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include +#include + +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef size_t ee_size_t; + +typedef ee_u32 CORE_TICKS; + +typedef struct CORE_PORTABLE_S +{ + ee_u8 portable_id; +} core_portable; + +#ifndef MULTITHREAD +#define MULTITHREAD 1 // 1 means single-core +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Undefined non-gcc compiler used" +#endif +#endif + +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS FLAGS_STR +#endif + +#ifndef MEM_LOCATION +#define MEM_LOCATION "" +#endif + +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +#ifndef HAS_PRINTF +#define HAS_PRINTF 1 +#endif + +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x)-1) & ~3)) + +#define CORETIMETYPE ee_u32 + +extern ee_u32 default_num_contexts; + +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_state.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_state.c new file mode 100644 index 00000000..b5c3d461 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_state.c @@ -0,0 +1,347 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include "coremark.h" +/* local functions */ +enum CORE_STATE core_state_transition(ee_u8 **instr, ee_u32 *transition_count); + +/* +Topic: Description + Simple state machines like this one are used in many embedded products. + + For more complex state machines, sometimes a state transition table +implementation is used instead, trading speed of direct coding for ease of +maintenance. + + Since the main goal of using a state machine in CoreMark is to excercise +the switch/if behaviour, we are using a small moore machine. + + In particular, this machine tests type of string input, + trying to determine whether the input is a number or something else. + (see core_state.png). +*/ + +/* Function: core_bench_state + Benchmark function + + Go over the input twice, once direct, and once after introducing some + corruption. +*/ +ee_u16 +core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc) +{ + ee_u32 final_counts[NUM_CORE_STATES]; + ee_u32 track_counts[NUM_CORE_STATES]; + ee_u8 *p = memblock; + ee_u32 i; + +#if CORE_DEBUG + ee_printf("State Bench: %d,%d,%d,%04x\n", seed1, seed2, step, crc); +#endif + for (i = 0; i < NUM_CORE_STATES; i++) + { + final_counts[i] = track_counts[i] = 0; + } + /* run the state machine over the input */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* insert some corruption */ + if (*p != ',') + *p ^= (ee_u8)seed1; + p += step; + } + p = memblock; + /* run the state machine over the input again */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* undo corruption is seed1 and seed2 are equal */ + if (*p != ',') + *p ^= (ee_u8)seed2; + p += step; + } + /* end timing */ + for (i = 0; i < NUM_CORE_STATES; i++) + { + crc = crcu32(final_counts[i], crc); + crc = crcu32(track_counts[i], crc); + } + return crc; +} + +/* Default initialization patterns */ +static ee_u8 *intpat[4] + = { (ee_u8 *)"5012", (ee_u8 *)"1234", (ee_u8 *)"-874", (ee_u8 *)"+122" }; +static ee_u8 *floatpat[4] = { (ee_u8 *)"35.54400", + (ee_u8 *)".1234500", + (ee_u8 *)"-110.700", + (ee_u8 *)"+0.64400" }; +static ee_u8 *scipat[4] = { (ee_u8 *)"5.500e+3", + (ee_u8 *)"-.123e-2", + (ee_u8 *)"-87e+832", + (ee_u8 *)"+0.6e-12" }; +static ee_u8 *errpat[4] = { (ee_u8 *)"T0.3e-1F", + (ee_u8 *)"-T.T++Tq", + (ee_u8 *)"1T3.4e4z", + (ee_u8 *)"34.0e-T^" }; + +/* Function: core_init_state + Initialize the input data for the state machine. + + Populate the input with several predetermined strings, interspersed. + Actual patterns chosen depend on the seed parameter. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +void +core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p) +{ + ee_u32 total = 0, next = 0, i; + ee_u8 *buf = 0; +#if CORE_DEBUG + ee_u8 *start = p; + ee_printf("State: %d,%d\n", size, seed); +#endif + size--; + next = 0; + while ((total + next + 1) < size) + { + if (next > 0) + { + for (i = 0; i < next; i++) + *(p + total + i) = buf[i]; + *(p + total + i) = ','; + total += next + 1; + } + seed++; + switch (seed & 0x7) + { + case 0: /* int */ + case 1: /* int */ + case 2: /* int */ + buf = intpat[(seed >> 3) & 0x3]; + next = 4; + break; + case 3: /* float */ + case 4: /* float */ + buf = floatpat[(seed >> 3) & 0x3]; + next = 8; + break; + case 5: /* scientific */ + case 6: /* scientific */ + buf = scipat[(seed >> 3) & 0x3]; + next = 8; + break; + case 7: /* invalid */ + buf = errpat[(seed >> 3) & 0x3]; + next = 8; + break; + default: /* Never happen, just to make some compilers happy */ + break; + } + } + size++; + while (total < size) + { /* fill the rest with 0 */ + *(p + total) = 0; + total++; + } +#if CORE_DEBUG + ee_printf("State Input: %s\n", start); +#endif +} + +static ee_u8 +ee_isdigit(ee_u8 c) +{ + ee_u8 retval; + retval = ((c >= '0') & (c <= '9')) ? 1 : 0; + return retval; +} + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detcted. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the + end state is returned (either specific format determined or invalid). +*/ + +enum CORE_STATE +core_state_transition(ee_u8 **instr, ee_u32 *transition_count) +{ + ee_u8 * str = *instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state = CORE_START; + for (; *str && state != CORE_INVALID; str++) + { + NEXT_SYMBOL = *str; + if (NEXT_SYMBOL == ',') /* end of this input */ + { + str++; + break; + } + switch (state) + { + case CORE_START: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_S1; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + transition_count[CORE_START]++; + break; + case CORE_S1: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + break; + case CORE_INT: + if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + break; + case CORE_FLOAT: + if (NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e') + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + break; + case CORE_S2: + if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + break; + case CORE_EXPONENT: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + break; + case CORE_SCIENTIFIC: + if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + break; + default: + break; + } + } + *instr = str; + return state; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_util.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_util.c new file mode 100644 index 00000000..0544e621 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/core_util.c @@ -0,0 +1,266 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different + methods are provided: 1 - Using a volatile variable. This method is only + valid if the compiler is forced to generate code that reads the value of a + volatile variable from memory at run time. Please note, if using this method, + you would need to modify core_portme.c to generate training profile. 2 - + Command line arguments. This is the preferred method if command line + arguments are supported. 3 - System function. If none of the first 2 methods + is available on the platform, a system function which is not a stub can be + used. + + e.g. read the value on GPIO pins connected to switches, or invoke + special simulator functions. +*/ +#if (SEED_METHOD == SEED_VOLATILE) +extern volatile ee_s32 seed1_volatile; +extern volatile ee_s32 seed2_volatile; +extern volatile ee_s32 seed3_volatile; +extern volatile ee_s32 seed4_volatile; +extern volatile ee_s32 seed5_volatile; +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = seed1_volatile; + break; + case 2: + retval = seed2_volatile; + break; + case 3: + retval = seed3_volatile; + break; + case 4: + retval = seed4_volatile; + break; + case 5: + retval = seed5_volatile; + break; + default: + retval = 0; + break; + } + return retval; +} +#elif (SEED_METHOD == SEED_ARG) +ee_s32 +parseval(char *valstring) +{ + ee_s32 retval = 0; + ee_s32 neg = 1; + int hexmode = 0; + if (*valstring == '-') + { + neg = -1; + valstring++; + } + if ((valstring[0] == '0') && (valstring[1] == 'x')) + { + hexmode = 1; + valstring += 2; + } + /* first look for digits */ + if (hexmode) + { + while (((*valstring >= '0') && (*valstring <= '9')) + || ((*valstring >= 'a') && (*valstring <= 'f'))) + { + ee_s32 digit = *valstring - '0'; + if (digit > 9) + digit = 10 + *valstring - 'a'; + retval *= 16; + retval += digit; + valstring++; + } + } + else + { + while ((*valstring >= '0') && (*valstring <= '9')) + { + ee_s32 digit = *valstring - '0'; + retval *= 10; + retval += digit; + valstring++; + } + } + /* now add qualifiers */ + if (*valstring == 'K') + retval *= 1024; + if (*valstring == 'M') + retval *= 1024 * 1024; + + retval *= neg; + return retval; +} + +ee_s32 +get_seed_args(int i, int argc, char *argv[]) +{ + if (argc > i) + return parseval(argv[i]); + return 0; +} + +#elif (SEED_METHOD == SEED_FUNC) +/* If using OS based function, you must define and implement the functions below + * in core_portme.h and core_portme.c ! */ +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = portme_sys1(); + break; + case 2: + retval = portme_sys2(); + break; + case 3: + retval = portme_sys3(); + break; + case 4: + retval = portme_sys4(); + break; + case 5: + retval = portme_sys5(); + break; + default: + retval = 0; + break; + } + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ +ee_u16 +crcu8(ee_u8 data, ee_u16 crc) +{ + ee_u8 i = 0, x16 = 0, carry = 0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + crc >>= 1; + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + return crc; +} +ee_u16 +crcu16(ee_u16 newval, ee_u16 crc) +{ + crc = crcu8((ee_u8)(newval), crc); + crc = crcu8((ee_u8)((newval) >> 8), crc); + return crc; +} +ee_u16 +crcu32(ee_u32 newval, ee_u16 crc) +{ + crc = crc16((ee_s16)newval, crc); + crc = crc16((ee_s16)(newval >> 16), crc); + return crc; +} +ee_u16 +crc16(ee_s16 newval, ee_u16 crc) +{ + return crcu16((ee_u16)newval, crc); +} + +ee_u8 +check_data_types() +{ + ee_u8 retval = 0; + if (sizeof(ee_u8) != 1) + { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); + retval++; + } + if (sizeof(ee_u16) != 2) + { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s16) != 2) + { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s32) != 4) + { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_ptr_int) != sizeof(int *)) + { + ee_printf( + "ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); + retval++; + } + if (retval > 0) + { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); + } + return retval; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h new file mode 100644 index 00000000..1501da49 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h @@ -0,0 +1,211 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE +#define TOTAL_DATA_SIZE 2 * 1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" + +#if HAS_STDIO +#include +#endif +#if HAS_PRINTF +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define ee_printf(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define ee_printf(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define ee_printf printf +#endif + +#endif + +/* Actual benchmark execution in iterate */ +void *iterate(void *pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as + a double. Otherwise an unsigned int. +*/ +#if HAS_FLOAT +typedef double secs_ret; +#else +typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN +#define MAIN_RETURN_VAL +#define MAIN_RETURN_TYPE void +#else +#define MAIN_RETURN_VAL 0 +#define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void * portable_malloc(ee_size_t size); +void portable_free(void *p); +ee_s32 parseval(char *valstring); + +/* Algorithm IDS */ +#define ID_LIST (1 << 0) +#define ID_MATRIX (1 << 1) +#define ID_STATE (1 << 2) +#define ALL_ALGORITHMS_MASK (ID_LIST | ID_MATRIX | ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT +typedef ee_s16 MATDAT; +typedef ee_s32 MATRES; +#else +typedef ee_f16 MATDAT; +typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S +{ + int N; + MATDAT *A; + MATDAT *B; + MATRES *C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE +{ + CORE_START = 0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e; + +/* Helper structure to hold results */ +typedef struct RESULTS_S +{ + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void * memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s *list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD > 1) +ee_u8 core_start_parallel(core_results *res); +ee_u8 core_stop_parallel(core_results *res); +#endif + +/* list benchmark functions */ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); +ee_u16 core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, + void * memblk, + ee_s32 seed, + mat_params *p); +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/main.c new file mode 100644 index 00000000..12136ada --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/main.c @@ -0,0 +1,459 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +// Copyright 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. +// +// Licensed under the Solderpad Hardware Licence, 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 +// +// https://solderpad.org/licenses/ +// +// 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. +// +// SPDX-License-Identifier:Apache-2.0 WITH SHL-2.0 + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed + initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" + +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = { (ee_u16)0xd4b0, + (ee_u16)0x3340, + (ee_u16)0x6a79, + (ee_u16)0xe714, + (ee_u16)0xe3c1 }; +static ee_u16 matrix_known_crc[] = { (ee_u16)0xbe52, + (ee_u16)0x1199, + (ee_u16)0x5608, + (ee_u16)0x1fd7, + (ee_u16)0x0747 }; +static ee_u16 state_known_crc[] = { (ee_u16)0x5e47, + (ee_u16)0x39bf, + (ee_u16)0xe5a4, + (ee_u16)0x8e3a, + (ee_u16)0x8d84 }; +void * +iterate(void *pres) +{ + ee_u32 i; + ee_u16 crc; + core_results *res = (core_results *)pres; + ee_u32 iterations = res->iterations; + res->crc = 0; + res->crclist = 0; + res->crcmatrix = 0; + res->crcstate = 0; + + for (i = 0; i < iterations; i++) + { + crc = core_bench_list(res, 1); + res->crc = crcu16(crc, res->crc); + crc = core_bench_list(res, -1); + res->crc = crcu16(crc, res->crc); + if (i == 0) + res->crclist = res->crc; + } + return NULL; +} + +#if (SEED_METHOD == SEED_ARG) +ee_s32 get_seed_args(int i, int argc, char *argv[]); +#define get_seed(x) (ee_s16) get_seed_args(x, argc, argv) +#define get_seed_32(x) get_seed_args(x, argc, argv) +#else /* via function or volatile */ +ee_s32 get_seed_32(int i); +#define get_seed(x) (ee_s16) get_seed_32(x) +#endif + +#if (MEM_METHOD == MEM_STATIC) +ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char *mem_name[3] = { "Static", "Heap", "Stack" }; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at + compile time. 2 - Initialize memory block for use. 3 - Run and time the + benchmark. 4 - Report results, testing the validity of the output if the + seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be + identical 3 - third seed : Any value, should be at least an order of + magnitude less then the input size, but bigger then 32. 4 - Iterations : + Special, if set to 0, iterations will be automatically determined such that + the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE +main(void) +{ + int argc = 0; + char *argv[1]; +#else +MAIN_RETURN_TYPE +main(int argc, char *argv[]) +{ +#endif + ee_u16 i, j = 0, num_algorithms = 0; + ee_s16 known_id = -1, total_errors = 0; + ee_u16 seedcrc = 0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; +#if (MEM_METHOD == MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE * MULTITHREAD]; +#endif + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s) > 128) + { + ee_printf("list_head structure too big for comparable data!\n"); + return MAIN_RETURN_VAL; + } + results[0].seed1 = get_seed(1); + results[0].seed2 = get_seed(2); + results[0].seed3 = get_seed(3); + results[0].iterations = get_seed_32(4); +#if CORE_DEBUG + results[0].iterations = 1; +#endif + results[0].execs = get_seed_32(5); + if (results[0].execs == 0) + { /* if not supplied, execute all algorithms */ + results[0].execs = ALL_ALGORITHMS_MASK; + } + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1 == 0) && (results[0].seed2 == 0) + && (results[0].seed3 == 0)) + { /* perfromance run */ + results[0].seed1 = 0; + results[0].seed2 = 0; + results[0].seed3 = 0x66; + } + if ((results[0].seed1 == 1) && (results[0].seed2 == 0) + && (results[0].seed3 == 0)) + { /* validation run */ + results[0].seed1 = 0x3415; + results[0].seed2 = 0x3415; + results[0].seed3 = 0x66; + } +#if (MEM_METHOD == MEM_STATIC) + results[0].memblock[0] = (void *)static_memblk; + results[0].size = TOTAL_DATA_SIZE; + results[0].err = 0; +#if (MULTITHREAD > 1) +#error "Cannot use a static data area with multiple contexts!" +#endif +#elif (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) + { + ee_s32 malloc_override = get_seed(7); + if (malloc_override != 0) + results[i].size = malloc_override; + else + results[i].size = TOTAL_DATA_SIZE; + results[i].memblock[0] = portable_malloc(results[i].size); + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; + } +#elif (MEM_METHOD == MEM_STACK) +for (i = 0; i < MULTITHREAD; i++) +{ + results[i].memblock[0] = stack_memblock + i * TOTAL_DATA_SIZE; + results[i].size = TOTAL_DATA_SIZE; + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; +} +#else +#error "Please define a way to initialize a memory block." +#endif + /* Data init */ + /* Find out how space much we have based on number of algorithms */ + for (i = 0; i < NUM_ALGORITHMS; i++) + { + if ((1 << (ee_u32)i) & results[0].execs) + num_algorithms++; + } + for (i = 0; i < MULTITHREAD; i++) + results[i].size = results[i].size / num_algorithms; + /* Assign pointers */ + for (i = 0; i < NUM_ALGORITHMS; i++) + { + ee_u32 ctx; + if ((1 << (ee_u32)i) & results[0].execs) + { + for (ctx = 0; ctx < MULTITHREAD; ctx++) + results[ctx].memblock[i + 1] + = (char *)(results[ctx].memblock[0]) + results[0].size * j; + j++; + } + } + /* call inits */ + for (i = 0; i < MULTITHREAD; i++) + { + if (results[i].execs & ID_LIST) + { + results[i].list = core_list_init( + results[0].size, results[i].memblock[1], results[i].seed1); + } + if (results[i].execs & ID_MATRIX) + { + core_init_matrix(results[0].size, + results[i].memblock[2], + (ee_s32)results[i].seed1 + | (((ee_s32)results[i].seed2) << 16), + &(results[i].mat)); + } + if (results[i].execs & ID_STATE) + { + core_init_state( + results[0].size, results[i].seed1, results[i].memblock[3]); + } + } + + /* automatically determine number of iterations if not set */ + if (results[0].iterations == 0) + { + secs_ret secs_passed = 0; + ee_u32 divisor; + results[0].iterations = 1; + while (secs_passed < (secs_ret)1) + { + results[0].iterations *= 10; + start_time(); + iterate(&results[0]); + stop_time(); + secs_passed = time_in_secs(get_time()); + } + /* now we know it executes for at least 1 sec, set actual run time at + * about 10 secs */ + divisor = (ee_u32)secs_passed; + if (divisor == 0) /* some machines cast float to int as 0 since this + conversion is not defined by ANSI, but we know at + least one second passed */ + divisor = 1; + results[0].iterations *= 1 + 10 / divisor; + } + /* perform actual benchmark */ + start_time(); +#if (MULTITHREAD > 1) + if (default_num_contexts > MULTITHREAD) + { + default_num_contexts = MULTITHREAD; + } + for (i = 0; i < default_num_contexts; i++) + { + results[i].iterations = results[0].iterations; + results[i].execs = results[0].execs; + core_start_parallel(&results[i]); + } + for (i = 0; i < default_num_contexts; i++) + { + core_stop_parallel(&results[i]); + } +#else + iterate(&results[0]); +#endif + stop_time(); + total_time = get_time(); + /* get a function of the input to report */ + seedcrc = crc16(results[0].seed1, seedcrc); + seedcrc = crc16(results[0].seed2, seedcrc); + seedcrc = crc16(results[0].seed3, seedcrc); + seedcrc = crc16(results[0].size, seedcrc); + + switch (seedcrc) + { /* test known output for common seeds */ + case 0x8a02: /* seed1=0, seed2=0, seed3=0x66, size 2000 per algorithm */ + known_id = 0; + ee_printf("6k performance run parameters for coremark.\n"); + break; + case 0x7b05: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 2000 per + algorithm */ + known_id = 1; + ee_printf("6k validation run parameters for coremark.\n"); + break; + case 0x4eaf: /* seed1=0x8, seed2=0x8, seed3=0x8, size 400 per algorithm + */ + known_id = 2; + ee_printf("Profile generation run parameters for coremark.\n"); + break; + case 0xe9f5: /* seed1=0, seed2=0, seed3=0x66, size 666 per algorithm */ + known_id = 3; + ee_printf("2K performance run parameters for coremark.\n"); + break; + case 0x18f2: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 666 per + algorithm */ + known_id = 4; + ee_printf("2K validation run parameters for coremark.\n"); + break; + default: + total_errors = -1; + break; + } + if (known_id >= 0) + { + for (i = 0; i < default_num_contexts; i++) + { + results[i].err = 0; + if ((results[i].execs & ID_LIST) + && (results[i].crclist != list_known_crc[known_id])) + { + ee_printf("[%u]ERROR! list crc 0x%04x - should be 0x%04x\n", + i, + results[i].crclist, + list_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_MATRIX) + && (results[i].crcmatrix != matrix_known_crc[known_id])) + { + ee_printf("[%u]ERROR! matrix crc 0x%04x - should be 0x%04x\n", + i, + results[i].crcmatrix, + matrix_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_STATE) + && (results[i].crcstate != state_known_crc[known_id])) + { + ee_printf("[%u]ERROR! state crc 0x%04x - should be 0x%04x\n", + i, + results[i].crcstate, + state_known_crc[known_id]); + results[i].err++; + } + total_errors += results[i].err; + } + } + total_errors += check_data_types(); + /* and report results */ + ee_printf("CoreMark Size : %lu\n", (long unsigned)results[0].size); + ee_printf("Total ticks : %lu\n", (long unsigned)total_time); +#if HAS_FLOAT + ee_printf("Total time (secs): %f\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %f\n", + default_num_contexts * results[0].iterations + / time_in_secs(total_time)); +#else + ee_printf("Total time (secs): %d\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\n", + default_num_contexts * results[0].iterations + / time_in_secs(total_time)); +#endif +/* if (time_in_secs(total_time) < 10) + { + ee_printf( + "ERROR! Must execute for at least 10 secs for a valid result!\n"); + total_errors++; + } +*/ + + ee_printf("Iterations : %lu\n", + (long unsigned)default_num_contexts * results[0].iterations); +#if (MULTITHREAD > 1) + ee_printf("Parallel %s : %d\n", PARALLEL_METHOD, default_num_contexts); +#endif + ee_printf("Memory location : %s\n", MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\n", seedcrc); + if (results[0].execs & ID_LIST) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crclist : 0x%04x\n", i, results[i].crclist); + if (results[0].execs & ID_MATRIX) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcmatrix : 0x%04x\n", i, results[i].crcmatrix); + if (results[0].execs & ID_STATE) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcstate : 0x%04x\n", i, results[i].crcstate); + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcfinal : 0x%04x\n", i, results[i].crc); + if (total_errors == 0) + { + ee_printf( + "Correct operation validated. See README.md for run and reporting " + "rules.\n"); +#if HAS_FLOAT + if (known_id == 3) + { + ee_printf("CoreMark 1.0 : %f / %s", + default_num_contexts * results[0].iterations + / time_in_secs(total_time), + COMPILER_VERSION); +// COMPILER_VERSION, +// COMPILER_FLAGS); +#if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) + ee_printf(" / %s", MEM_LOCATION); +#else + ee_printf(" / %s", mem_name[MEM_METHOD]); +#endif + +#if (MULTITHREAD > 1) + ee_printf(" / %d:%s", default_num_contexts, PARALLEL_METHOD); +#endif + ee_printf("\n"); + } +#endif + } + if (total_errors > 0) + ee_printf("Errors detected\n"); + if (total_errors < 0) + ee_printf( + "Cannot validate operation for these seed values, please compare " + "with results on a known platform.\n"); + +#if (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) + portable_free(results[i].memblock[0]); +#endif + /* And last call any target specific code for finalizing */ + portable_fini(&(results[0].port)); + + return MAIN_RETURN_VAL; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c index bbab3698..ea842d8a 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c @@ -208,7 +208,7 @@ int main(int argc, char *argv[]) #endif // TEST_ADDRESS_MODE -#ifndef TARGET_PYNQ_Z2 +#if defined(TARGET_SIM) || defined(TARGET_SYSTEMC) #ifdef TEST_ADDRESS_MODE_EXTERNAL_DEVICE @@ -275,7 +275,7 @@ int main(int argc, char *argv[]) #endif //TEST_ADDRESS_MODE_EXTERNAL_DEVICE #else - #pragma message( "TEST_ADDRESS_MODE_EXTERNAL_DEVICE is not executed on PYNQ Z2" ) + #pragma message( "TEST_ADDRESS_MODE_EXTERNAL_DEVICE is not executed on target different than TARGET_SIM" ) #endif #ifdef TEST_PENDING_TRANSACTION diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_ext_memory/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_ext_memory/main.c new file mode 100644 index 00000000..8af03ad4 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_ext_memory/main.c @@ -0,0 +1,128 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include "core_v_mini_mcu.h" +#include "x-heep.h" + +#define BUFF_LEN 100 + +uint32_t buffer_rnd_index[BUFF_LEN]; + +#ifdef TARGET_SYSTEMC +//make app PROJECT=example_ext_memory TARGET=systemc +#define CACHE_FLUSH 1 +#define CACHE_BYPASS 2 +#define CACHE_SIZE 4*1024 +#endif + +#define MEMORY_SIZE 32*1024 +#define MEMORY_ADDR_MASK 0x7FFF +#define MEMORY_MAX_WORD_INDEX (MEMORY_SIZE/4) + +int is_in_array(uint32_t number, uint32_t* array, int N ) { + + for (int i=0;i + */ + +#include +#include + +#include "core_v_mini_mcu.h" + +#include "x-heep.h" +#include "iffifo_regs.h" + +#include "mmio.h" +#include "handler.h" +#include "csr.h" +#include "hart.h" + +#include "rv_plic.h" + +#include "dma.h" +#include "dma_regs.h" +#include "fast_intr_ctrl.h" + + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +unsigned int IFFIFO_START_ADDRESS = EXT_PERIPHERAL_START_ADDRESS + 0x2000; + +int32_t to_fifo [6] __attribute__ ((aligned (4))) = { 1, 2, 3, 4, 5, 6 }; +int32_t from_fifo[4] __attribute__ ((aligned (4))) = { 0, 0, 0, 0 }; + +int8_t dma_intr_flag = 0; +void dma_intr_handler_trans_done() +{ + dma_intr_flag = 1; +} + +void protected_wait_for_dma_interrupt(void) +{ + while(!dma_is_ready()) { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (!dma_is_ready()) { + wait_for_interrupt(); + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } +} + +iffifo_intr_flag = 0; +static void handler_irq_iffifo( uint32_t int_id ) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + mmio_region_write32(iffifo_base_addr, IFFIFO_INTERRUPTS_REG_OFFSET, 0b0); + iffifo_intr_flag = 1; + PRINTF(" ** REACH intr. fired.\n"); +} + +static dma_target_t tgt_src; +static dma_target_t tgt_dst; +static dma_trans_t trans; + +int compare_print_fifo_array(void) { + int errors = 0; + PRINTF("from_fifo = {"); + for (int i = 0; i < 4; i+=1) { + PRINTF("%d",from_fifo[i]); + if(i != 4-1) {PRINTF(", ");}; + if (to_fifo[i]+1 != from_fifo[i]) {++errors;} + } + PRINTF("}\n"); + return errors; +} + +void print_status_register(void) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + int32_t status = mmio_region_read32(iffifo_base_addr, IFFIFO_STATUS_REG_OFFSET); + PRINTF("STATUS = "); + PRINTF(status & (1 << IFFIFO_STATUS_EMPTY_BIT) ? "E" : "-"); // FIFO empty + PRINTF(status & (1 << IFFIFO_STATUS_AVAILABLE_BIT) ? "A" : "-"); // Data available in FIFO + PRINTF(status & (1 << IFFIFO_STATUS_REACHED_BIT) ? "R" : "-"); // Watermark reached + PRINTF(status & (1 << IFFIFO_STATUS_FULL_BIT) ? "F" : "-"); // FIFO full + PRINTF("\n"); +} + +int is_iffifo_full(void) +{ + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + int32_t status = mmio_region_read32(iffifo_base_addr, IFFIFO_STATUS_REG_OFFSET); + return status & (1 << IFFIFO_STATUS_FULL_BIT); +} + +int main(int argc, char *argv[]) { + + mmio_region_t iffifo_base_addr = mmio_region_from_addr((uintptr_t)IFFIFO_START_ADDRESS); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11; + CSR_SET_BITS(CSR_REG_MIE, mask); + + if(plic_Init()) {return EXIT_FAILURE;}; + if(plic_irq_set_priority(EXT_INTR_1, 1)) {return EXIT_FAILURE;}; + if(plic_irq_set_enabled(EXT_INTR_1, kPlicToggleEnabled)) {return EXIT_FAILURE;}; + + plic_assign_external_irq_handler(EXT_INTR_1, &handler_irq_iffifo); + + mmio_region_write32(iffifo_base_addr, IFFIFO_WATERMARK_REG_OFFSET, 2); + mmio_region_write32(iffifo_base_addr, IFFIFO_INTERRUPTS_REG_OFFSET, 0b1); + + dma_config_flags_t ret; + + // -- DMA CONFIGURATION -- + + dma_init(NULL); + tgt_src.ptr = to_fifo; + tgt_src.inc_du = 1; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE_WORD; + tgt_src.size_du = 6; + + tgt_dst.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_IN_REG_OFFSET; + tgt_dst.inc_du = 0; + tgt_dst.trig = DMA_TRIG_SLOT_EXT_TX; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.end = DMA_TRANS_END_INTR; + + ret = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + if (ret != 0) {return EXIT_FAILURE;} + ret = dma_load_transaction(&trans); + if (ret != 0) {return EXIT_FAILURE;} + + if (compare_print_fifo_array() != 4) {return EXIT_FAILURE;} + + print_status_register(); + + PRINTF("Launch MM -> Stream DMA\n"); + // Launch a 6-word TX DMA transaction to a 4-word FIFO. The FIFO will be full. + dma_launch( &trans ); + + // To terminate the DMA transaction, 2 words must be manually popped from the FIFO. + while(!is_iffifo_full()); + int32_t read0 = mmio_region_read32(iffifo_base_addr, IFFIFO_FIFO_OUT_REG_OFFSET); + while(!is_iffifo_full()); + int32_t read1 = mmio_region_read32(iffifo_base_addr, IFFIFO_FIFO_OUT_REG_OFFSET); + + print_status_register(); + + PRINTF("Manual readings: {%d, %d}\n", read0, read1); + + protected_wait_for_dma_interrupt(); + + dma_init(NULL); + tgt_src.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_OUT_REG_OFFSET; + tgt_src.inc_du = 0; + tgt_src.trig = DMA_TRIG_SLOT_EXT_RX; + tgt_src.type = DMA_DATA_TYPE_WORD; + tgt_src.size_du = 4; + + tgt_dst.ptr = from_fifo; + tgt_dst.inc_du = 1; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.end = DMA_TRANS_END_INTR; + + ret = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + if (ret != 0) {return EXIT_FAILURE;} + ret = dma_load_transaction(&trans); + if (ret != 0) {return EXIT_FAILURE;} + PRINTF("Launch Stream -> MM DMA\n"); + dma_launch( &trans ); + + protected_wait_for_dma_interrupt(); + + print_status_register(); + + if (compare_print_fifo_array() == 0) {return EXIT_FAILURE;}; + + if (!iffifo_intr_flag) {return EXIT_FAILURE;}; + + return EXIT_SUCCESS; + +} + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c new file mode 100644 index 00000000..86f69972 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c @@ -0,0 +1,84 @@ +// Copyright 2022 OpenHW Group +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include +#include +#include "csr.h" +#include "matrixAdd32.h" +#include "x-heep.h" +#include "core_v_mini_mcu.h" + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +void __attribute__ ((noinline)) matrixAdd(int32_t * A, int32_t * B, int32_t * C, int N, int M); +uint32_t check_results(int32_t * C, int N, int M); + +int32_t __attribute__((section(".xheep_data_interleaved"))) m_c[16*16]; + + +int main() +{ + +#ifndef HAS_MEMORY_BANKS_IL + PRINTF("This application is only meant to be tested when there are interleaved memory banks\n"); + return EXIT_SUCCESS; +#endif + + + int N = WIDTH; + int M = HEIGHT; + uint32_t errors = 0; + unsigned int instr, cycles, ldstall, jrstall, imstall; + + CSR_WRITE(CSR_REG_MCYCLE, 0); + + //execute the kernel + matrixAdd(m_a, m_b, m_c, N, M); + + CSR_READ(CSR_REG_MCYCLE, &cycles) ; + + //stop the HW counter used for monitoring + + errors = check_results(m_c, N, M); + + PRINTF("program finished with %d errors and %d cycles\n\r", errors, cycles); + return errors; +} + +void __attribute__ ((noinline)) matrixAdd(int32_t * A, int32_t * B, int32_t * C, int N, int M) +{ + for(int i = 0; i < N; i++) { + for(int j = 0; j < M; j++) { + C[i*N+j] = A[i*WIDTH+j] + B[i*WIDTH+j]; + } + } +} + +uint32_t check_results(int32_t * C, int N, int M) +{ + // check + int i, j; + uint32_t err = 0; + + for(i = 0; i < N; i++) { + for(j = 0; j < M; j++) { + if(C[i*N+j] != m_exp[i*WIDTH+j]) { + err++; + PRINTF("Error at index %d, %d, expected %d, got %d\n\r", i, j, m_exp[i*WIDTH+j], C[i*N+j]); + } + } + } + + return err; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/matrixAdd32.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/matrixAdd32.h new file mode 100644 index 00000000..8b9bace3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/matrixAdd32.h @@ -0,0 +1,64 @@ +#ifndef MatrixAdd32_H_ +#define MatrixAdd32_H_ + +int32_t __attribute__((section(".xheep_data_interleaved"))) m_a[16*16] = { +-267220638, -815694637, -357240193, 52586566, 471263969, -752743258, -54811671, -330483534, -895389047, 476606065, -261687046, -301494394, 101299356, 1064594637, 876939884, 673598893, +510087407, 21095419, -66273695, 200819447, 230905645, -522677817, 466985617, -42864608, 925345137, -985253526, 963426323, 34126990, -894741205, -944572242, -62503253, -88084923, +-40863508, 775424478, -977993934, -563294903, 240810335, -950840151, 841082377, 814816122, 1010825869, 626595210, -30466653, 32965586, -1009681585, -398274647, 209852250, -680997577, +831825297, 371554642, 209565266, -173321792, 130553499, -846489230, -837855833, -291296547, -656131005, -1008649794, -644660179, -559832327, -957317256, 414035806, 238077607, -417354312, +691270381, 167236288, -370338394, 264811381, -740211299, -502137446, -216028919, -576761164, -1005576983, -300300576, -51567714, 742968985, -713639053, 81381137, -254911471, -456085969, +-657637814, 212880558, 164912940, 975706502, -558175870, -522438623, 219649600, -149341108, -761491992, -324770181, -905679666, -1066241764, 852450941, -105770862, -706293797, 965826475, +605386582, 397282251, -510180840, 322039481, 906789344, 577829424, -244909961, -6565162, -10463653, -275962613, 1045813592, 287658995, 202626085, -913131320, -953473425, 7501200, +44568419, 631042458, -962343731, 389765403, 510986448, 615528098, 854389577, 873031590, 291656555, 717742724, 139337062, 1014134612, 37179482, 156110030, 549532436, -211305424, +146967397, -910154681, 306466943, 809719463, 990862734, -321035009, -503247368, -434011427, -184327001, -460285290, -695885128, 745541667, 549735829, 972687164, 81845219, 626415449, +-869892524, 7650305, -668932203, 612640394, -533618868, -767284692, 263874653, -505082478, -333082894, -170998598, 351985173, 539903843, 161284779, -223326011, -386924128, -894616525, +-205913216, 983230715, 184759813, 3745004, -421392253, 311771810, 809133901, 541639735, 1029270115, 390582486, 1059667793, -308077038, -345200733, 661937983, -69729012, -313649214, +-457079064, 660862401, -419895058, -352985806, 748622990, 789128492, 57857836, 123409871, 367565501, 714681971, 90478156, 401194382, -25590123, 808922190, 231668089, 365978441, +-168791957, 500701111, 966566283, -619646012, 410934777, -567381204, 405170082, -954683259, -176892010, 205925886, 1035377376, 91289957, 478111519, 220727997, -859802080, -155168848, +723982461, -833318195, -445511314, -903460885, 167471780, 423323222, -640855013, 480396600, -268314639, -850542572, 257027787, -315635254, 560711756, -717798753, -372060287, -544448897, +-103077323, -640041517, 577573751, 1039664378, -546538923, 739571966, 680289428, 412799378, 987282320, -378880850, 588647906, -965191092, -829907433, 739600408, -33720223, 56361300, +-1068334620, -399957948, -960664907, -540542510, 280786542, -752129362, -10289650, 1029788294, -636639267, 1029706817, -892387611, 191199904, -965464658, -1048403025, -734580512, 872029387, +}; + +int32_t __attribute__((section(".xheep_data_interleaved"))) m_b[16*16] = { +-451882475, -777460700, 909169980, -96074001, -300818508, 814405880, -568048006, -83472456, 402440048, 810240641, -180564453, 216877888, -140613462, 620727378, -909318526, 765805622, +-231722067, -336894715, -1073684733, -121460761, -23888211, 438175722, -904262018, 145258576, -356787314, 372900212, -358591099, 140421444, -928238022, -99914115, 968352616, -71902672, +-7354035, -831973999, 233305822, -392287490, -729923194, -828467700, -323283176, -788941348, -111739211, -199056442, -476803416, 465916744, 443852965, -376815395, 148885406, 124331090, +-998134941, -490161461, 607731285, 887008149, 683830004, -186741406, -241303958, 456378716, 536730595, 967225269, 1037796891, -802215107, 382626188, 791688228, 538691527, -19673298, +251682349, 598278365, 984763713, 698038628, 821027888, -495782484, -798473539, -424505599, 310436971, 361824506, -130460722, -847926918, 926418138, 637997507, 565305015, 901041052, +236841072, 748341019, 851219634, 437917539, 979456559, 834327011, -191800443, 415161968, -687346999, -41616108, 226338567, 671381489, -248505365, -991524242, 465050274, 673573191, +-432551530, 1057245412, 714468280, -650829182, -850172935, 408331778, 846612827, 884618062, -1025138869, 389044228, 241552082, 1038961376, -425996140, -770151901, -59811946, 433319347, +420324744, -41895865, -626338369, -617719112, -398763632, 40560785, 608712418, 270292226, 276772130, 713936878, -39616963, 852564869, 651061789, -1069752389, 942487510, -212496210, +-884568730, -614540093, 940597970, 963278316, 500604546, -89930534, -362276438, 800923761, 799305363, 67728257, -935053727, -507421158, 453168328, -270267180, 767962559, 540805, +-178905319, 755067965, -132287841, -8637376, 608185815, 427835026, 103464976, -203264205, 80225884, 539643001, -362743073, -487778248, 792077066, 697184933, 827496823, 790812604, +249285726, 359686773, 419021969, 454726313, 124358246, 47824230, -619837186, -913155286, -381944316, 783327309, 572077053, -225060553, 787746239, 671339856, 730167112, 870184696, +319311551, 932192632, -376845525, -288051918, 713264893, -102198441, -315559203, -635483087, -76253988, -427900440, -508626018, -847322511, -717023663, 649773356, -751674700, -363502823, +896873064, -967112426, -607994984, 346538028, -403535863, -456242519, -865446025, -238823125, 568667781, -1008745310, -517236588, -90482335, -769550983, -553756781, -473911347, -317302102, +308779302, 610106502, -99323447, -610238668, 176302035, 320291710, 22124485, 927846370, -961507070, 1046393978, 623269088, -385024596, -636139940, -661255126, -1024580190, -710776275, +874358552, -978379641, 484825057, -177908522, -643611415, -197553591, 406358020, 460342548, 408235584, -809119385, 1047128507, -592130753, -50891763, 786819419, 314046385, 461621105, +-328939806, 375494681, 558517164, 640788713, -419567316, -499867631, 629778826, 201608525, 1006046604, 259505742, 994398852, 338082134, -444011788, 128878595, -672831452, 18560178, +}; + +int32_t m_exp[16*16] = { +-719103113, -1593155337, 551929787, -43487435, 170445461, 61662622, -622859677, -413955990, -492948999, 1286846706, -442251499, -84616506, -39314106, 1685322015, -32378642, 1439404515, +278365340, -315799296, -1139958428, 79358686, 207017434, -84502095, -437276401, 102393968, 568557823, -612353314, 604835224, 174548434, -1822979227, -1044486357, 905849363, -159987595, +-48217543, -56549521, -744688112, -955582393, -489112859, -1779307851, 517799201, 25874774, 899086658, 427538768, -507270069, 498882330, -565828620, -775090042, 358737656, -556666487, +-166309644, -118606819, 817296551, 713686357, 814383503, -1033230636, -1079159791, 165082169, -119400410, -41424525, 393136712, -1362047434, -574691068, 1205724034, 776769134, -437027610, +942952730, 765514653, 614425319, 962850009, 80816589, -997919930, -1014502458, -1001266763, -695140012, 61523930, -182028436, -104957933, 212779085, 719378644, 310393544, 444955083, +-420796742, 961221577, 1016132574, 1413624041, 421280689, 311888388, 27849157, 265820860, -1448838991, -366386289, -679341099, -394860275, 603945576, -1097295104, -241243523, 1639399666, +172835052, 1454527663, 204287440, -328789701, 56616409, 986161202, 601702866, 878052900, -1035602522, 113081615, 1287365674, 1326620371, -223370055, -1683283221, -1013285371, 440820547, +464893163, 589146593, -1588682100, -227953709, 112222816, 656088883, 1463101995, 1143323816, 568428685, 1431679602, 99720099, 1866699481, 688241271, -913642359, 1492019946, -423801634, +-737601333, -1524694774, 1247064913, 1772997779, 1491467280, -410965543, -865523806, 366912334, 614978362, -392557033, -1630938855, 238120509, 1002904157, 702419984, 849807778, 626956254, +-1048797843, 762718270, -801220044, 604003018, 74566947, -339449666, 367339629, -708346683, -252857010, 368644403, -10757900, 52125595, 953361845, 473858922, 440572695, -103803921, +43372510, 1342917488, 603781782, 458471317, -297034007, 359596040, 189296715, -371515551, 647325799, 1173909795, 1631744846, -533137591, 442545506, 1333277839, 660438100, 556535482, +-137767513, 1593055033, -796740583, -641037724, 1461887883, 686930051, -257701367, -512073216, 291311513, 286781531, -418147862, -446128129, -742613786, 1458695546, -520006611, 2475618, +728081107, -466411315, 358571299, -273107984, 7398914, -1023623723, -460275943, -1193506384, 391775771, -802819424, 518140788, 807622, -291439464, -333028784, -1333713427, -472470950, +1032761763, -223211693, -544834761, -1513699553, 343773815, 743614932, -618730528, 1408242970, -1229821709, 195851406, 880296875, -700659850, -75428184, -1379053879, -1396640477, -1255225172, +771281229, -1618421158, 1062398808, 861755856, -1190150338, 542018375, 1086647448, 873141926, 1395517904, -1188000235, 1635776413, -1557321845, -880799196, 1526419827, 280326162, 517982405, +-1397274426, -24463267, -402147743, 100246203, -138780774, -1251996993, 619489176, 1231396819, 369407337, 1289212559, 102011241, 529282038, -1409476446, -919524430, -1407411964, 890589565, +}; + +#define WIDTH 16 +#define HEIGHT 16 + +#endif // MatrixAdd32_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/gen_stimuly.py b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/gen_stimuly.py new file mode 100644 index 00000000..cdf55503 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/gen_stimuly.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +## Copyright 2024 EPFL +## Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +import sys +import random +import numpy as np + +def write_arr(f, name, arr, ctype, size): + f.write("const " + ctype + " " + name + "[] = {\n") + + for row in arr: + for elem in row[:-1]: + f.write('%d,' % (elem)) + f.write('%d,\n' % (row[-1])) + + f.write('};\n\n') + return + + +################################################################################ +f = open('matrixMul8.h', 'w') +f.write('#ifndef _MATMUL8_\n') +f.write('#define _MATMUL8_\n') +f.write('// This file is automatically generated\n') + + +SIZE = 16 +RANGE = 4 + +m_a = [] +m_b = [] +m_exp = [] + +# Generate random 8 bit integers from -RANGE to RANGE for A and B +m_a = np.random.randint(-RANGE, RANGE, size=(SIZE, SIZE), dtype=np.int32) +m_b = np.random.randint(-RANGE, RANGE, size=(SIZE, SIZE), dtype=np.int32) +m_exp = np.zeros((SIZE, SIZE), dtype=np.int32) + +# Test the function with A and B +m_exp = np.matmul(m_a,m_b) + +write_arr(f, 'm_a', m_a, 'int8_t', SIZE) +write_arr(f, 'm_b', m_b, 'int8_t', SIZE) +write_arr(f, 'm_exp', m_exp, 'int32_t', SIZE) + +f.write('#define SIZE %d\n' % SIZE) + + +f.write('#endif') diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c new file mode 100644 index 00000000..aec6ca4e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c @@ -0,0 +1,126 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include +#include +#include "csr.h" +#include "matrixMul8.h" +#include "x-heep.h" + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +void __attribute__ ((noinline)) matrixMul8_blocksize(int8_t * A, int8_t * B, int32_t * C, int N); + +void __attribute__ ((noinline)) matrixMul8_tiled(int8_t * A, int8_t * B, int32_t * C, int N); + +uint32_t check_results(int32_t * C, int N); + +int32_t m_c[SIZE*SIZE]; + +#define BLOCK_SIZE 4 + +// Define a macro for accessing matrix elements +#define A(i,j) &A[i*SIZE+j] +#define B(i,j) &B[i*SIZE+j] +#define C(i,j) &C[i*SIZE+j] + +#define HIGHEST_PERF + +int main() +{ + + uint32_t errors = 0; + unsigned int instr, cycles; + + for(int i =0;i> 1; // Half the size + // Multiply the blocks and add them to the corresponding blocks of C + matrixMul8_tiled(A(0, 0), B(0, 0), C(0, 0), N); // C_00 += A_00 * B_00 + matrixMul8_tiled(A(0, N), B(N, 0), C(0, 0), N); // C_00 += A_01 * B_10 + matrixMul8_tiled(A(0, 0), B(0, N), C(0, N), N); // C_01 += A_00 * B_01 + matrixMul8_tiled(A(0, N), B(N, N), C(0, N), N); // C_01 += A_01 * B_11 + matrixMul8_tiled(A(N, 0), B(0, 0), C(N, 0), N); // C_10 += A_10 * B_00 + matrixMul8_tiled(A(N, N), B(N, 0), C(N, 0), N); // C_10 += A_11 * B_10 + matrixMul8_tiled(A(N, 0), B(0, N), C(N, N), N); // C_11 += A_10 * B_01 + matrixMul8_tiled(A(N, N), B(N, N), C(N, N), N); // C_11 += A_11 * B_11 + } +} + + +uint32_t check_results(int32_t * C, int N) +{ + // check + int i, j; + uint32_t err = 0; + + for(i = 0; i < N; i++) { + for(j = 0; j < N; j++) { + if(C[i*N+j] != m_exp[i*N+j]) { + err++; + PRINTF("Error at index %d, %d, expected %d, got %d\n\r", i, j, m_exp[i*N+j], C[i*N+j]); + } + } + } + + return err; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/matrixMul8.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/matrixMul8.h new file mode 100644 index 00000000..bc2be3e0 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/matrixMul8.h @@ -0,0 +1,62 @@ +#ifndef _MATMUL8_ +#define _MATMUL8_ +// This file is automatically generated +const int8_t m_a[] = { +-4,-2,-3,3,3,-1,-4,-3,1,-2,-2,2,-2,-4,-2,-1, +0,2,0,-2,-3,3,-2,3,-1,3,0,2,3,1,-3,-2, +0,2,2,3,-2,-2,-3,-2,0,-3,0,-4,2,-3,-3,1, +3,-4,1,1,-1,0,-3,0,1,3,-1,-2,2,3,-4,0, +3,-1,2,-4,-1,-2,0,-3,-3,0,-2,-4,-2,1,0,-2, +-3,0,-2,2,-1,2,2,2,3,1,0,-2,-1,-4,3,-3, +1,3,2,-3,-4,-3,-2,-1,-2,3,1,-3,2,-4,0,0, +-2,0,3,-1,3,-4,0,-2,2,3,-2,-2,-1,-4,-3,1, +-4,-2,-4,-1,-2,-4,-4,-2,-4,-4,-3,0,-2,-4,2,-4, +1,-1,-3,-2,-1,-2,-4,0,2,3,1,-3,-3,1,3,1, +-3,0,1,3,-3,1,3,2,0,-2,1,-4,-3,0,1,-4, +3,0,-1,-3,2,-1,-1,1,-1,3,2,-4,2,2,0,-2, +-4,2,2,-2,2,-4,-3,-3,-3,-3,-2,-3,3,0,3,0, +2,3,-2,0,3,1,1,-3,3,0,1,-4,-4,-1,0,1, +0,0,1,3,-3,3,3,1,-3,1,1,2,1,-2,-2,2, +-1,2,-2,1,0,-2,-3,-1,0,0,2,0,3,3,-4,-4, +}; + +const int8_t m_b[] = { +2,1,2,1,0,3,-1,-1,3,3,3,-2,0,-3,-1,3, +-3,0,-3,0,2,-2,3,0,-2,-1,2,-3,2,-2,0,-2, +-4,0,1,3,-3,-3,-2,2,3,0,-1,2,3,2,-2,-4, +3,3,-2,3,2,2,-2,-1,-3,-3,-1,-3,3,-2,2,-2, +0,1,0,-3,-1,-3,-1,0,-1,3,3,1,-1,-1,2,2, +-2,-4,-1,-1,1,1,2,-1,2,3,0,3,2,0,-4,3, +-1,-1,-3,2,-4,3,3,-1,3,1,-3,-2,1,1,2,3, +0,2,0,1,1,-3,-4,-4,2,-2,1,0,3,2,0,-1, +0,1,1,-1,2,-1,0,2,-1,-3,3,0,-2,-4,2,3, +1,-4,2,-4,0,1,3,-4,-2,-3,-2,-2,-1,3,-2,-3, +1,0,2,3,0,1,1,-1,-3,-1,3,-3,-3,-2,1,-4, +-3,2,-4,1,3,2,3,-2,1,1,3,0,-2,-2,-1,-1, +1,-3,-1,1,-2,2,-1,-4,3,0,-3,-4,-3,1,-1,2, +-1,-2,3,-4,0,1,1,1,-2,1,-4,3,0,1,2,1, +1,3,-1,-4,2,0,-1,-1,-4,-3,-2,-4,-1,-4,3,2, +0,1,0,1,3,-4,-1,2,1,-1,3,-2,-2,-2,-1,-1, +}; + +const int32_t m_exp[] = { +15,30,-21,1,25,-11,-8,24,-29,-1,32,23,-10,-15,9,-4, +-20,-44,1,-1,3,12,19,-41,25,4,-10,11,7,36,-44,-17, +13,10,3,50,-5,-17,-31,28,5,-12,9,-14,14,-3,-8,-28, +23,-31,50,-6,-12,14,-20,-5,19,6,-17,24,-4,29,-22,-1, +0,-17,35,-16,-40,5,-2,28,15,29,-28,27,10,27,-7,8, +15,8,-21,-5,6,6,0,-18,-23,-38,-11,-19,16,-8,16,14, +3,-18,14,16,-15,-9,1,-8,6,-23,-5,-36,-6,20,-27,-43, +-4,-1,9,3,-23,-39,-5,24,5,-13,15,6,-4,21,-3,-26, +20,35,-18,-6,6,3,-17,18,-28,-4,-14,16,-2,8,15,-4, +31,7,45,-49,28,-14,-8,10,-49,-31,11,-6,-24,-17,14,-3, +3,8,-5,21,-19,8,-10,8,-17,-23,-39,10,49,16,22,-9, +21,-30,44,-32,-25,5,-5,-22,-5,10,-12,-8,-15,19,1,8, +-7,8,-2,-18,-18,-38,-23,28,-20,-3,-29,-4,-9,9,17,-11, +10,4,11,-18,8,-13,16,34,-29,6,36,-5,0,-37,18,22, +-7,-13,-29,48,-2,22,13,-26,31,1,-8,-18,20,16,-30,-23, +8,-20,13,0,-5,20,10,-10,-22,2,-9,4,-12,14,6,-18, +}; + +#define SIZE 16 +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c new file mode 100644 index 00000000..71de642f --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c @@ -0,0 +1,85 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "core_v_mini_mcu.h" +#include "x-heep.h" + +#define TEST_DATA_SIZE 16 + +#define PRINTF_IN_SIM 1 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + + +int32_t errors = 0; + +//defined in the testharness_pkg.sv +#define SIMPLE_ACC_START_ADDRESS EXT_PERIPHERAL_START_ADDRESS + 0x3000; + +// Simple accelerator Decoder (address for bytes) +//0 READ ADDRESS +#define SIMPLE_ACC_READ_OFFSET 0 +//4 WRITE ADDRESS +#define SIMPLE_ACC_WRITE_OFFSET 1 +//8 THRESHOLD +#define SIMPLE_ACC_THRESHOLD_OFFSET 2 +//C READY +#define SIMPLE_ACC_READY_OFFSET 3 +//10 SIZE +#define SIMPLE_ACC_SIZE_OFFSET 4 +//14 START +#define SIMPLE_ACC_START_OFFSET 5 + + + +int main(int argc, char *argv[]) +{ + + static uint32_t source_data[TEST_DATA_SIZE] __attribute__ ((aligned (4))); + static uint32_t copied_data[TEST_DATA_SIZE] __attribute__ ((aligned (4))); + uint32_t threshold_value = 20; + volatile static uint32_t *simple_acc = SIMPLE_ACC_START_ADDRESS; + + + for(int i=0;i threshold_value ? source_data[i] : threshold_value; + if(copied_data[i] != expected_data){ + errors++; + PRINTF("copied_data[%d] is %d, expected %d\n\r",i,copied_data[i], expected_data); + } + } + + if (errors == 0) { + PRINTF("Simple Accelerator Successful\n\r"); + return EXIT_SUCCESS; + } else { + PRINTF("Simple Accelerator failure: %d errors out of %d data checked\n\r", errors, TEST_DATA_SIZE ); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_flash_write/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_flash_write/main.c deleted file mode 100644 index a3d273e7..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_flash_write/main.c +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "rv_plic.h" -#include "rv_plic_regs.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "dma.h" -#include "fast_intr_ctrl.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif -/* Test Configurations */ -#define TEST_CIRCULAR -#define TEST_MEM_2_SPI -#define TEST_SPI_2_MEM - -// These defines are used only to easily change the data types. -// If not needed, the proper way is using the dma_data_type_t enum. -#define TEST_DATA_TYPE DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD - -#if TEST_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD -#define DATA_TYPE uint8_t -#elif TEST_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD -#define DATA_TYPE uint16_t -#else -#define DATA_TYPE uint32_t -#endif - - -#ifdef TEST_CIRCULAR -// WARNING: When using circular mode the amount of WORDS of each cycle needs to be 32 <= x <= 128 - #define CIRCULAR_CYCLES 4 - #define COPY_DATA_UNITS 256 - #define COPY_DATA_PER_CYCLE ( COPY_DATA_UNITS / CIRCULAR_CYCLES )// Flash page size = 256 Bytes -#else - #define COPY_DATA_UNITS 64 - #define COPY_DATA_PER_CYCLE COPY_DATA_UNITS -#endif //TEST_CIRCULAR - -#define REVERT_24b_ADDR(addr) ((((uint32_t)addr & 0xff0000) >> 16) | ((uint32_t)addr & 0xff00) | (((uint32_t)addr & 0xff) << 16)) - -#define FLASH_ADDR 0x00008500 // 256B data alignment - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -int8_t spi_intr_flag; -spi_host_t spi_host; -int8_t cycles; - -// Reserve memory array -DATA_TYPE flash_data[COPY_DATA_UNITS] __attribute__ ((aligned (DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE)))) = { 0 }; -DATA_TYPE copy_data [COPY_DATA_UNITS] __attribute__ ((aligned (DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE)))) = { 0 }; - -DATA_TYPE *fifo_ptr_tx; -DATA_TYPE *fifo_ptr_rx; - -#ifndef USE_SPI_FLASH -void fic_irq_spi(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#else -void fic_irq_spi_flash(void) -{ - // Disable SPI interrupts - // PRINTF("&"); - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#endif //USE_SPI_FLASH - -#ifdef TEST_CIRCULAR -void dma_intr_handler_trans_done(void) -{ - PRINTF("#"); - cycles++; - if( cycles >= CIRCULAR_CYCLES -1 ) dma_stop_circular(); -} -#else -void dma_intr_handler_trans_done(void) -{ - PRINTF("#"); -} -#endif - -static inline __attribute__((always_inline)) void spi_config() -{ - -/* -* SPI CONFIGURATIONS -*/ -#ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); -#else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); -#endif //USE_SPI_FLASH - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level fast spi interrupt - - -#ifndef USE_SPI_FLASH - const uint32_t mask = 1 << 20; -#else - const uint32_t mask = 1 << 21; -#endif - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - -#ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); -#endif // USE_SPI_FLASH - - - CSR_SET_BITS(CSR_REG_MIE, mask); - - // Enable SPI host device - spi_set_enable(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // SPI and SPI_FLASH are the same IP so same register map - fifo_ptr_tx = spi_host.base_addr.base + SPI_HOST_TXDATA_REG_OFFSET; - fifo_ptr_rx = spi_host.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Reset - const uint32_t reset_cmd = 0xFFFFFFFF; - spi_write_word(&spi_host, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_reset); - spi_wait_for_ready(&spi_host); - spi_set_rx_watermark(&spi_host,1); - - // Power up flash - const uint32_t powerup_byte_cmd = 0xab; - spi_write_word(&spi_host, powerup_byte_cmd); - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - - // Write enable - const uint32_t write_enable_cmd = 0x06; - spi_write_word(&spi_host, write_enable_cmd); - const uint32_t cmd_write_en = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_write_en); - spi_wait_for_ready(&spi_host); - - // Write command - const uint32_t write_byte_cmd = ((FLASH_ADDR << 8) | 0x02); // Program Page + addr - spi_write_word(&spi_host, write_byte_cmd); - const uint32_t cmd_write = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_write); - spi_wait_for_ready(&spi_host); - -} - - -static inline __attribute__((always_inline)) void spi_wait_4_resp() -{ - // Check status register status waiting for ready - bool flash_busy = true; - uint8_t flash_resp[4] = {0xff,0xff,0xff,0xff}; - while(flash_busy){ - uint32_t flash_cmd = 0x00000005; // [CMD] Read status register - spi_write_word(&spi_host, flash_cmd); // Push TX buffer - uint32_t spi_status_cmd = spi_create_command((spi_command_t){ - .len = 0, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - uint32_t spi_status_read_cmd = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - spi_set_command(&spi_host, spi_status_cmd); - spi_wait_for_ready(&spi_host); - spi_set_command(&spi_host, spi_status_read_cmd); - spi_wait_for_ready(&spi_host); - spi_wait_for_rx_watermark(&spi_host); - spi_read_word(&spi_host, &flash_resp[0]); - if ((flash_resp[0] & 0x01) == 0) flash_busy = false; - } -} - -int main(int argc, char *argv[]) -{ - -#ifdef TARGET_SIM - #pragma message("This app does not allow Flash write operations in simulation!") - PRINTF("Flash writes are not permitted during Simulation, only on FPGA\n"); - return EXIT_SUCCESS; -#endif - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - -#ifdef USE_SPI_FLASH - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) - { - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; - } -#endif - spi_config(); - dma_init(NULL); - - dma_config_flags_t res; - - for( DATA_TYPE i = 0; i < COPY_DATA_PER_CYCLE; i ++ ) - { - ((DATA_TYPE*)flash_data)[i] = (DATA_TYPE) i; - } - -#ifdef TEST_MEM_2_SPI - - PRINTF("\n\n\r======================================\n\n\r"); - PRINTF(" MEM -> -> DMA -> -> SPI -> -> FLASH "); - PRINTF("\n\n\r======================================\n\n\r"); - -#ifndef USE_SPI_FLASH - const uint8_t slot = DMA_TRIG_SLOT_SPI_TX; // The DMA will wait for the SPI TX FIFO ready signal -#else - const uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_TX; // The DMA will wait for the SPI FLASH TX FIFO ready signal -#endif //USE_SPI_FLASH - - static dma_target_t tgt1= { - .ptr = flash_data, - .inc_du = 1, - .size_du = COPY_DATA_PER_CYCLE, - .trig = DMA_TRIG_MEMORY, - .type = TEST_DATA_TYPE, - }; - - static dma_target_t tgt2= { - .inc_du = 0, - .size_du = COPY_DATA_PER_CYCLE, - .trig = slot, - .type = TEST_DATA_TYPE, - }; - - tgt2.ptr = fifo_ptr_tx; // This is necessary because fifo_ptr_tx is not a constant, and therefore cannot be used as initializer element. - - static dma_trans_t trans = { - .src = &tgt1, - .dst = &tgt2, - .mode = DMA_TRANS_MODE_SINGLE, - .win_du = 0, - .end = DMA_TRANS_END_INTR, - }; - -#ifdef TEST_CIRCULAR - trans.mode = DMA_TRANS_MODE_CIRCULAR; - cycles = 0; -#endif // TEST_CIRCULAR - - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \n\r", res); - - res = dma_load_transaction(&trans); - PRINTF("load: %u \n\r", res); - - res = dma_launch(&trans); - - spi_intr_flag = 0; - // Wait for the first data to arrive to the TX FIFO before enabling interrupt - spi_wait_for_tx_not_empty(&spi_host); - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable TX empty interrupt - spi_enable_txempty_intr(&spi_host, true); - - const uint32_t cmd_write_tx = spi_create_command((spi_command_t){ - .len = COPY_DATA_UNITS*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE) - 1, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_write_tx); - spi_wait_for_ready(&spi_host); - - // Wait for SPI interrupt - while(spi_intr_flag == 0) { - wait_for_interrupt(); - } - PRINTF("triggered\n\r"); - - spi_wait_4_resp(); - - PRINTF("%d Bytes written in Flash at @ 0x%08x \n\r", COPY_DATA_UNITS*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE), FLASH_ADDR); - - -#endif //TEST_SPI_2_MEM - -#ifdef TEST_SPI_2_MEM - - PRINTF("\n\n\r======================================\n\n\r"); - PRINTF(" MEM <- <- DMA <- <- SPI <- <- FLASH "); - PRINTF("\n\n\r======================================\n\n\r"); - -#ifndef USE_SPI_FLASH - const uint8_t slot2 = DMA_TRIG_SLOT_SPI_RX; // The DMA will wait for the SPI TX FIFO ready signal -#else - const uint8_t slot2 = DMA_TRIG_SLOT_SPI_FLASH_RX; // The DMA will wait for the SPI FLASH TX FIFO ready signal - #endif - - static dma_target_t tgt3= { - .ptr = copy_data, - .inc_du = 1, - // Because the data type needs to be WORD the size needs to be normalized. - .size_du = COPY_DATA_PER_CYCLE*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE)/DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE_WORD), - .trig = DMA_TRIG_MEMORY, - .type = DMA_DATA_TYPE_WORD, // Only possible to read word-wise from SPI - }; - - static dma_target_t tgt4= { - .inc_du = 0, - // Because the data type needs to be WORD the size needs to be normalized. - .size_du = COPY_DATA_PER_CYCLE*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE)/DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE_WORD), - .trig = slot2, - .type = DMA_DATA_TYPE_WORD, - }; - tgt4.ptr = fifo_ptr_rx; - - static dma_trans_t trans2 = { - .src = &tgt4, - .dst = &tgt3, - .end = DMA_TRANS_END_INTR, - }; - - res = dma_validate_transaction( &trans2, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \n\r", res); - - res = dma_load_transaction(&trans2); - PRINTF("load: %u \n\r", res); - - // The address bytes sent through the SPI to the Flash are in reverse order - const int32_t read_byte_cmd = ((REVERT_24b_ADDR(FLASH_ADDR) << 8) | 0x03); - - // Fill TX FIFO with TX data (read command + 3B address) - spi_write_word(&spi_host, read_byte_cmd); - // Wait for readiness to process commands - spi_wait_for_ready(&spi_host); - - // Load command FIFO with read command (1 Byte at single speed) - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_read); - spi_wait_for_ready(&spi_host); - - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ - .len = COPY_DATA_UNITS*DMA_DATA_TYPE_2_SIZE(TEST_DATA_TYPE) - 1, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - spi_set_command(&spi_host, cmd_read_rx); - spi_wait_for_ready(&spi_host); - - res = dma_launch(&trans2); - - while( ! dma_is_ready() ){ - /* wait_for_interrupt(); For small buffer sizes the interrupt arrives before going to wfi(); */ - }; - - PRINTF("triggered!\n\r"); - - // Power down flash - const uint32_t powerdown_byte_cmd = 0xb9; - spi_write_word(&spi_host, powerdown_byte_cmd); - const uint32_t cmd_powerdown = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerdown); - spi_wait_for_ready(&spi_host); - - // The data is already in memory -- Check results - PRINTF("ram vs flash...\n\r"); - - int i; - uint32_t errors = 0; - uint32_t count = 0; - for (i = 0; i -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "fast_intr_ctrl.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -// Simple example to check the SPI host peripheral is working. It checks the ram and flash have the same content -#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - -volatile int8_t spi_intr_flag; -spi_host_t spi_host; -uint32_t flash_data[8]; -uint32_t flash_original[8] = {1}; - -#ifndef USE_SPI_FLASH -void fic_irq_spi(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#else -void fic_irq_spi_flash(void) -{ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host, false); - spi_enable_rxwm_intr(&spi_host, false); - spi_intr_flag = 1; -} -#endif - -int main(int argc, char *argv[]) -{ - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t read_byte_cmd = ((REVERT_24b_ADDR(flash_original) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) - { -#ifdef USE_SPI_FLASH - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; -#else - /* - if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different - as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH - */ - uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; - for(int i =0; i < 8 ; i++){ - flash_original[i] = ptr_flash[i]; - } - // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - -#endif - - } - - - // spi_host_t spi_host; - #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - #else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); - #endif - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level fast spi interrupt - #ifndef USE_SPI_FLASH - const uint32_t mask = 1 << 20; - #else - const uint32_t mask = 1 << 21; - #endif - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); - #endif - - // Enable SPI host device - spi_set_enable(&spi_host, true); - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Set RX watermark to 8 word - spi_set_rx_watermark(&spi_host, 8); - - uint32_t *flash_data_ptr = flash_data[0]; - - // Power up flash - const uint32_t powerup_byte_cmd = 0xab; - spi_write_word(&spi_host, powerup_byte_cmd); - // Load command FIFO with command (1 Byte at single speed) - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - - volatile uint32_t data_addr = flash_original; - - - // Fill TX FIFO with TX data (read command + 3B address) - spi_write_word(&spi_host, read_byte_cmd); - // Wait for readiness to process commands - spi_wait_for_ready(&spi_host); - - //////////////////////////////////////////////////////////////// - - // // Load command FIFO with read command (1 Byte at single speed) - // const uint32_t cmd_read = spi_create_command((spi_command_t){ - // .len = 0, - // .csaat = true, - // .speed = kSpiSpeedStandard, - // .direction = kSpiDirTxOnly - // }); - // spi_set_command(&spi_host, cmd_read); - // spi_wait_for_ready(&spi_host); - // // Load command FIFO with read address (3 Byte at single speed) - // const uint32_t cmd_addr = spi_create_command((spi_command_t){ - // .len = 2, - // .csaat = true, - // .speed = kSpiSpeedStandard, - // .direction = kSpiDirTxOnly - // }); - // spi_set_command(&spi_host, cmd_addr); - // spi_wait_for_ready(&spi_host); - - // OR - - // Load command FIFO with read command (1 Byte at single speed) - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_read); - spi_wait_for_ready(&spi_host); - - //////////////////////////////////////////////////////////////// - - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ - .len = 31, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - spi_set_command(&spi_host, cmd_read_rx); - spi_wait_for_ready(&spi_host); - - // Wait transaction is finished (polling register) - // spi_wait_for_rx_watermark(&spi_host); - // or wait for SPI interrupt - PRINTF("Waiting for SPI...\n\r"); - - while( spi_intr_flag == 0 ) { - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - - if( spi_intr_flag == 0 ) - wait_for_interrupt(); - - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } - - // Enable event interrupt - spi_enable_evt_intr(&spi_host, true); - // Enable RX watermark interrupt - spi_enable_rxwm_intr(&spi_host, true); - - // Read data from SPI RX FIFO - for (int i=0; i<8; i++) { - spi_read_word(&spi_host, &flash_data[i]); - } - - PRINTF("flash vs ram...\n\r"); - - uint32_t errors = 0; - uint32_t* ram_ptr = flash_original; - for (int i=0; i<8; i++) { - if(flash_data[i] != *ram_ptr) { - PRINTF("@%x : %x != %x\n\r", ram_ptr, flash_data[i], *ram_ptr); - errors++; - } - ram_ptr++; - } - - if (errors == 0) { - PRINTF("success!\n\r"); - } else { - PRINTF("failure, %d errors!\n\r", errors); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; - -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma/main.c deleted file mode 100644 index de6ab165..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma/main.c +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "dma.h" -#include "fast_intr_ctrl.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -// Type of data frome the SPI. For types different than words the SPI data is requested in separate transactions -// word(0), half-word(1), byte(2,3) -#define SPI_DATA_TYPE DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD - -// Number of elements to copy -#define COPY_DATA_NUM 16 - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - -#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) - -volatile int8_t dma_intr_flag; -spi_host_t spi_host; - -void dma_intr_handler_trans_done(void) -{ - PRINTF("Non-weak implementation of a DMA interrupt\n\r"); - dma_intr_flag = 1; -} - -// Reserve memory array -uint32_t flash_data[COPY_DATA_NUM] __attribute__ ((aligned (4))) = {0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98,0x89abcdef,0x679852fe,0xff8252bb,0x763b4521,0x6875adaa,0x09ac65bb,0x666ba334,0x44556677,0x0000ba98}; -uint32_t copy_data[COPY_DATA_NUM] __attribute__ ((aligned (4))) = { 0 }; - -#if SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD - #define DATA_TYPE uint32_t -#elif SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD - #define DATA_TYPE uint16_t -#else - #define DATA_TYPE uint8_t -#endif - -#define COPY_DATA_TYPE (COPY_DATA_NUM/(sizeof(uint32_t)/sizeof(DATA_TYPE))) - - -int main(int argc, char *argv[]) -{ - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t read_byte_cmd; - - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) - { -#ifdef USE_SPI_FLASH - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; -#else - /* - if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different - as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH - */ - uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; - for(int i =0; i < COPY_DATA_NUM ; i++){ - flash_data[i] = ptr_flash[i]; - } -#endif - - } - - - #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - #else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); - #endif - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); - #endif - - // Enable SPI host device - spi_set_enable(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // SPI and SPI_FLASH are the same IP so same register map - uint32_t *fifo_ptr_rx = spi_host.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; - - - // DMA CONFIGURATION - PRINTF("---- TEST ---- \n\r"); - dma_init(NULL); - - - #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_RX; // The DMA will wait for the SPI RX FIFO valid signal - #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; // The DMA will wait for the SPI FLASH RX FIFO valid signal - #endif - - static dma_target_t tgt_src = { - .inc_du = 0, - .size_du = COPY_DATA_NUM, - .type = SPI_DATA_TYPE, - }; - tgt_src.ptr = fifo_ptr_rx; // Necessary outside 'cause its not a const. - tgt_src.trig = slot;// Necessary outside 'cause its not a const. - - static dma_target_t tgt_dst = { - .ptr = copy_data, - .inc_du = 1, - .type = SPI_DATA_TYPE, - .trig = DMA_TRIG_MEMORY, - }; - static dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - .end = DMA_TRANS_END_INTR, - }; - - dma_config_flags_t res; - - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("Result - tgt trans: %u\n\r", res ); - res = dma_load_transaction(&trans); - PRINTF("Result - tgt load: %u\n\r", res ); - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Reset - const uint32_t reset_cmd = 0xFFFFFFFF; - spi_write_word(&spi_host, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_reset); - spi_wait_for_ready(&spi_host); - - // Power up flash - const uint32_t powerup_byte_cmd = 0xab; - spi_write_word(&spi_host, powerup_byte_cmd); - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - - // Load command FIFO with read command (1 Byte at single speed) - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - - dma_intr_flag = 0; - res = dma_launch(&trans); - PRINTF("launched!\n\r"); - - #if SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD - - if(get_spi_flash_mode(&soc_ctrl) != SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO) - read_byte_cmd = ((REVERT_24b_ADDR(flash_data) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - else - // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ // Single transaction - .len = COPY_DATA_NUM*sizeof(DATA_TYPE) - 1, // In bytes - 1 - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - spi_write_word(&spi_host, read_byte_cmd); // Fill TX FIFO with TX data (read command + 3B address) - spi_wait_for_ready(&spi_host); // Wait for readiness to process commands - spi_set_command(&spi_host, cmd_read); // Send read command to the external device through SPI - spi_wait_for_ready(&spi_host); - spi_set_command(&spi_host, cmd_read_rx); // Receive data in RX - spi_wait_for_ready(&spi_host); - #else - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ // Multiple transactions of the data type - .len = (sizeof(DATA_TYPE) - 1), - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - DATA_TYPE* flash_ptr = (DATA_TYPE *)flash_data; - for (int i = 0; i +#include +#include + +#include "x-heep.h" +#include "w25q128jw.h" + +/* By default, PRINTFs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef TARGET_PYNQ_Z2 + #define USE_SPI_FLASH +#endif + + +// Start buffers (the original data) +#include "buffer.h" +// End buffer (where what is read is stored) +uint32_t flash_data[256]; + +/* + * Assign the test buffer to the buffer to write to flash. + * The buffer is defined in the file buffer.h. As multiple buffers can + * be defined, this is userful to pick the right one. + * Also the length is specified, to test different length cases. In any case + * length <= test_buffer length. +*/ +#define TEST_BUFFER flash_original_1024B +#define LENGTH 1024 + +#ifndef ON_CHIP +#define FLASH_ONLY_WORDS 32 +#define FLASH_ONLY_BYTES (FLASH_ONLY_WORDS*4) + +int32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16))) flash_only_buffer[FLASH_ONLY_WORDS] = { + 0xABCDEF00, + 0xABCDEF01, + 0xABCDEF02, + 0xABCDEF03, + 0xABCDEF04, + 0xABCDEF05, + 0xABCDEF06, + 0xABCDEF07, + 0xABCDEF08, + 0xABCDEF09, + 0xABCDEF0A, + 0xABCDEF0B, + 0xABCDEF0C, + 0xABCDEF0D, + 0xABCDEF0E, + 0xABCDEF0F, + 0xABCDEF10, + 0xABCDEF11, + 0xABCDEF12, + 0xABCDEF13, + 0xABCDEF14, + 0xABCDEF15, + 0xABCDEF16, + 0xABCDEF17, + 0xABCDEF18, + 0xABCDEF19, + 0xABCDEF1A, + 0xABCDEF1B, + 0xABCDEF1C, + 0xABCDEF1D, + 0xABCDEF1E, + 0xABCDEF1F, +}; + +int32_t __attribute__ ((aligned (16))) flash_only_buffer_golden_value[FLASH_ONLY_WORDS] = { + 0xABCDEF00, + 0xABCDEF01, + 0xABCDEF02, + 0xABCDEF03, + 0xABCDEF04, + 0xABCDEF05, + 0xABCDEF06, + 0xABCDEF07, + 0xABCDEF08, + 0xABCDEF09, + 0xABCDEF0A, + 0xABCDEF0B, + 0xABCDEF0C, + 0xABCDEF0D, + 0xABCDEF0E, + 0xABCDEF0F, + 0xABCDEF10, + 0xABCDEF11, + 0xABCDEF12, + 0xABCDEF13, + 0xABCDEF14, + 0xABCDEF15, + 0xABCDEF16, + 0xABCDEF17, + 0xABCDEF18, + 0xABCDEF19, + 0xABCDEF1A, + 0xABCDEF1B, + 0xABCDEF1C, + 0xABCDEF1D, + 0xABCDEF1E, + 0xABCDEF1F, +}; +#endif + +// Test functions +uint32_t test_read(uint32_t *test_buffer, uint32_t len); +uint32_t test_read_flash_only(uint32_t *test_buffer, uint32_t len); +uint32_t test_read_dma(uint32_t *test_buffer, uint32_t len); +uint32_t test_read_quad(uint32_t *test_buffer, uint32_t len); +uint32_t test_read_quad_dma(uint32_t *test_buffer, uint32_t len); + +// Check function +uint32_t check_result(uint8_t *test_buffer, uint32_t len); + +// Define global status variable +w25q_error_codes_t global_status; + +int main(int argc, char *argv[]) { + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + PRINTF("BSP read test\n", LENGTH); + + // Pick the correct spi device based on simulation type + spi_host_t spi; + #ifndef USE_SPI_FLASH + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + #else + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + #endif + + // Define status variable + int32_t errors = 0; + + // Init SPI host and SPI<->Flash bridge parameters + if (w25q128jw_init(spi) != FLASH_OK) return EXIT_FAILURE; + + // Test simple read + PRINTF("Testing simple read...\n"); + errors += test_read(TEST_BUFFER, LENGTH); + +#ifndef ON_CHIP + PRINTF("Testing simple read on flash only data...\n"); + errors += test_read_flash_only(flash_only_buffer, FLASH_ONLY_BYTES); +#endif + + // Test simple read with DMA + PRINTF("Testing simple read with DMA...\n"); + errors += test_read_dma(TEST_BUFFER, LENGTH); + + // Test quad read + PRINTF("Testing quad read...\n"); + errors += test_read_quad(TEST_BUFFER, LENGTH); + + // Test quad read with DMA + PRINTF("Testing quad read with DMA...\n"); + errors += test_read_quad_dma(TEST_BUFFER, LENGTH); + + PRINTF("\n--------TEST FINISHED--------\n"); + if (errors == 0) { + PRINTF("All tests passed!\n"); + return EXIT_SUCCESS; + } else { + PRINTF("Some tests failed!\n"); + return EXIT_FAILURE; + } + +} + +uint32_t test_read(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = test_buffer; + + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_standard(test_buffer_flash, flash_data, len); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_data == test_buffer) + uint32_t res = check_result(test_buffer, len); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return res; +} +#ifndef ON_CHIP +uint32_t test_read_flash_only(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = heep_get_flash_address_offset(test_buffer); + + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_standard(test_buffer_flash, flash_data, len); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + printf("Checking Results \n"); + + // Check if what we read is correct (i.e. flash_data == test_buffer) + uint32_t res = check_result(flash_only_buffer_golden_value, len); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return res; +} +#endif +uint32_t test_read_dma(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = test_buffer; + + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_standard_dma(test_buffer_flash, flash_data, len); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_data == test_buffer) + uint32_t res = check_result(test_buffer, len); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return res; +} + +uint32_t test_read_quad(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = test_buffer; + + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_quad(test_buffer_flash, flash_data, len); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_data == test_buffer) + uint32_t res = check_result(test_buffer, len); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return res; +} + +uint32_t test_read_quad_dma(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = test_buffer; + + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_quad_dma(test_buffer_flash, flash_data, len); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_data == test_buffer) + uint32_t res = check_result(test_buffer, len); + + // Reset the flash data buffer + memset(flash_data, 0, len * sizeof(uint8_t)); + + return res; +} + +uint32_t check_result(uint8_t *test_buffer, uint32_t len) { + uint32_t errors = 0; + uint8_t *flash_data_char = (uint8_t *)flash_data; + + for (uint32_t i = 0; i < len; i++) { + if (test_buffer[i] != flash_data_char[i]) { + PRINTF("Error at position %d: expected %x, got %x\n", i, test_buffer[i], flash_data_char[i]); + errors++; + } + } + + if (errors == 0) { + PRINTF("success!\n"); + } else { + PRINTF("failure, %d errors!\n", errors); + } + + return errors; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_write/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_write/main.c new file mode 100644 index 00000000..2b1a362b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_write/main.c @@ -0,0 +1,351 @@ +/** + * @file main.c + * @brief Simple spi write example using BSP + * + * Simple example that writes a 1kB buffer to flash memory at a specific address + * and then read it back to check if the data was written correctly. + * For buffers bigger than 4kB (or even smaller buffers that are not aligned to 4kB), + * the erase operation must be tweeked to erase all the sectors that contain the + * buffer. + * + * @note The application assume the correct functioning of the read operation. + * +*/ + +#include +#include +#include + +#include "x-heep.h" +#include "w25q128jw.h" + +/* By default, PRINTFs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef TARGET_PYNQ_Z2 + #define USE_SPI_FLASH +#endif + + +// what to write in flash +uint32_t flash_original_1024B[256] = { + 0x76543211, 0xfedcba99, 0x579a6f91, 0x657d5bef, 0x758ee420, 0x01234568, 0xfedbca97, 0x89abde00, + 0x76543212, 0xfedcba9a, 0x579a6f92, 0x657d5bf0, 0x758ee421, 0x01234569, 0xfedbca98, 0x89abde01, + 0x76543213, 0xfedcba9b, 0x579a6f93, 0x657d5bf1, 0x758ee422, 0x0123456a, 0xfedbca99, 0x89abde02, + 0x76543214, 0xfedcba9c, 0x579a6f94, 0x657d5bf2, 0x758ee423, 0x0123456b, 0xfedbca9a, 0x89abde03, + 0x76543215, 0xfedcba9d, 0x579a6f95, 0x657d5bf3, 0x758ee424, 0x0123456c, 0xfedbca9b, 0x89abde04, + 0x76543216, 0xfedcba9e, 0x579a6f96, 0x657d5bf4, 0x758ee425, 0x0123456d, 0xfedbca9c, 0x89abde05, + 0x76543217, 0xfedcba9f, 0x579a6f97, 0x657d5bf5, 0x758ee426, 0x0123456e, 0xfedbca9d, 0x89abde06, + 0x76543218, 0xfedcbaa0, 0x579a6f98, 0x657d5bf6, 0x758ee427, 0x0123456f, 0xfedbca9e, 0x89abde07, + 0x76543219, 0xfedcbaa1, 0x579a6f99, 0x657d5bf7, 0x758ee428, 0x01234570, 0xfedbca9f, 0x89abde08, + 0x7654321a, 0xfedcbaa2, 0x579a6f9a, 0x657d5bf8, 0x758ee429, 0x01234571, 0xfedbcaa0, 0x89abde09, + 0x7654321b, 0xfedcbaa3, 0x579a6f9b, 0x657d5bf9, 0x758ee42a, 0x01234572, 0xfedbcaa1, 0x89abde0a, + 0x7654321c, 0xfedcbaa4, 0x579a6f9c, 0x657d5bfa, 0x758ee42b, 0x01234573, 0xfedbcaa2, 0x89abde0b, + 0x7654321d, 0xfedcbaa5, 0x579a6f9d, 0x657d5bfb, 0x758ee42c, 0x01234574, 0xfedbcaa3, 0x89abde0c, + 0x7654321e, 0xfedcbaa6, 0x579a6f9e, 0x657d5bfc, 0x758ee42d, 0x01234575, 0xfedbcaa4, 0x89abde0d, + 0x7654321f, 0xfedcbaa7, 0x579a6f9f, 0x657d5bfd, 0x758ee42e, 0x01234576, 0xfedbcaa5, 0x89abde0e, + 0x76543220, 0xfedcbaa8, 0x579a6fa0, 0x657d5bfe, 0x758ee42f, 0x01234577, 0xfedbcaa6, 0x89abde0f, + 0x76543221, 0xfedcbaa9, 0x579a6fa1, 0x657d5bff, 0x758ee430, 0x01234578, 0xfadbcaa7, 0x89abde10, + 0x76543222, 0xfedcbaaa, 0x579a6fa2, 0x657d5c00, 0x758ee431, 0x01234579, 0xfadbcaa8, 0x89abde11, + 0x76543223, 0xfedcbaab, 0x579a6fa3, 0x657d5c01, 0x758ee432, 0x0123457a, 0xfadbcaa9, 0x89abde12, + 0x76543224, 0xfedcbaac, 0x579a6fa4, 0x657d5c02, 0x758ee433, 0x0123457b, 0xfadbcaaa, 0x89abde13, + 0x76543225, 0xfedcbaad, 0x579a6fa5, 0x657d5c03, 0x758ee434, 0x0123457c, 0xfadbcaab, 0x89abde14, + 0x76543226, 0xfedcbaae, 0x579a6fa6, 0x657d5c04, 0x758ee435, 0x0123457d, 0xfadbcaac, 0x89abde15, + 0x76543227, 0xfedcbaaf, 0x579a6fa7, 0x657d5c05, 0x758ee436, 0x0123457e, 0xfadbcaad, 0x89abde16, + 0x76543228, 0xfedcbab0, 0x579a6fa8, 0x657d5c06, 0x758ee437, 0x0123457f, 0xfadbcaae, 0x89abde17, + 0x76543220, 0xfedcbaa8, 0x579a6fa0, 0x657d5bfe, 0x758ee42f, 0x01234577, 0xfedbcaa6, 0x89abde0f, + 0x76543221, 0xfedcbaa9, 0x579a6fa1, 0x657d5bff, 0x758ee430, 0x01234578, 0xfadbcaa7, 0x89abde10, + 0x76543222, 0xfedcbaaa, 0x579a6fa2, 0x657d5c00, 0x758ee431, 0x01234579, 0xfadbcaa8, 0x89abde11, + 0x76543223, 0xfedcbaab, 0x579a6fa3, 0x657d5c01, 0x758ee432, 0x0123457a, 0xfadbcaa9, 0x89abde12, + 0x76543224, 0xfedcbaac, 0x579a6fa4, 0x657d5c02, 0x758ee433, 0x0123457b, 0xfadbcaaa, 0x89abde13, + 0x76543225, 0xfedcbaad, 0x579a6fa5, 0x657d5c03, 0x758ee434, 0x0123457c, 0xfadbcaab, 0x89abde14, + 0x76543226, 0xfedcbaae, 0x579a6fa6, 0x657d5c04, 0x758ee435, 0x0123457d, 0xfadbcaac, 0x89abde15, + 0x76543227, 0xfedcbaaf, 0x579a6fa7, 0x657d5c05, 0x758ee436, 0x0123457e, 0xfadbcaad, 0x89abde16, + 0x76543228, 0xfedcbab0, 0x579a6fa8, 0x657d5c06, 0x758ee437, 0x0123457f, 0xfadbcaae, 0x89abde17 +}; + +// End buffer (where what is read is stored) +uint32_t flash_read_data[256]; + +#define BYTES_TO_WRITE 533 //in bytes, must be less than 256*4=1024 + +// address to which we write in FLASH, we do not initiliaze it to 0 as we do not want into the BSS +// otherwise the compilers/linker won't allocate this to the .data section, thus not written in flash +// If not written in flash, after erasing the block this array would be all '0xFF', and this would loose +// generality of the testing as without erasing, the write operation in flash can bring 1->0 but not viceversa +// by initializing to another number, we are sure it goes to .data section and written in flash +uint32_t __attribute__ ((aligned (16))) flash_write_buffer[256] = { + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, + 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA +}; + +#ifndef ON_CHIP +int32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16))) flash_only_write_buffer[256]; +#endif + +// Test functions +uint32_t test_write(uint32_t *test_buffer, uint32_t len); +uint32_t test_write_dma(uint32_t *test_buffer, uint32_t len); +uint32_t test_write_quad(uint32_t *test_buffer, uint32_t len); +uint32_t test_write_quad_dma(uint32_t *test_buffer, uint32_t len); +uint32_t test_write_flash_only(uint32_t *test_buffer, uint32_t len); + +// Check function +uint32_t check_result(uint8_t *test_buffer, uint32_t len); + +// Erase memory function +void erase_memory(uint32_t addr); + +// Define global status variable +w25q_error_codes_t global_status; + +int main(int argc, char *argv[]) { + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + PRINTF("BSP write test\n"); + + // Pick the correct spi device + spi_host_t spi; + #ifndef USE_SPI_FLASH + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); + #else + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + #endif + + // Define status variable + int32_t errors = 0; + + // Init SPI host and SPI<->Flash bridge parameters + if (w25q128jw_init(spi) != FLASH_OK) return EXIT_FAILURE; + + // Test simple write + PRINTF("Testing simple write...\n"); + errors += test_write(flash_original_1024B, BYTES_TO_WRITE); + +#ifndef ON_CHIP + // Test simple write on flash_only data + PRINTF("Testing simple write. on flash only data..\n"); + errors += test_write_flash_only(flash_original_1024B, BYTES_TO_WRITE); +#endif + + + // Test simple write with DMA + PRINTF("Testing simple write with DMA...\n"); + errors += test_write_dma(flash_original_1024B, BYTES_TO_WRITE); + + // Test quad write + PRINTF("Testing quad write...\n"); + errors += test_write_quad(flash_original_1024B, BYTES_TO_WRITE); + + // Test quad write with DMA + PRINTF("Testing quad write with DMA...\n"); + errors += test_write_quad_dma(flash_original_1024B, BYTES_TO_WRITE); + + PRINTF("\n--------TEST FINISHED--------\n"); + if (errors == 0) { + PRINTF("All tests passed!\n"); + return EXIT_SUCCESS; + } else { + PRINTF("Some tests failed!\n"); + return EXIT_FAILURE; + } +} + + +uint32_t test_write(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = flash_write_buffer; + + // Write to flash memory at specific address + global_status = w25q128jw_erase_and_write_standard(test_buffer_flash, test_buffer, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Read from flash memory at the same address + global_status = w25q128jw_read(test_buffer_flash, flash_read_data, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_original == flash_read_data) + int32_t result = check_result(test_buffer, len); + + // Clean memory for next test + erase_memory(test_buffer_flash); + + // Reset the flash data buffer + memset(flash_read_data, 0, len * sizeof(uint8_t)); + + return result; +} + +uint32_t test_write_dma(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = flash_write_buffer; + + // Write to flash memory at specific address + global_status = w25q128jw_erase_and_write_standard_dma(test_buffer_flash, test_buffer, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Read from flash memory at the same address + global_status = w25q128jw_read(test_buffer_flash, flash_read_data, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_original == flash_read_data) + int32_t result = check_result(test_buffer, len); + + // Clean memory for next test + erase_memory(test_buffer_flash); + + // Reset the flash data buffer + memset(flash_read_data, 0, len * sizeof(uint8_t)); + + return result; +} + +uint32_t test_write_quad(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = flash_write_buffer; + + // Write to flash memory at specific address + global_status = w25q128jw_erase_and_write_quad(test_buffer_flash, test_buffer, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Read from flash memory at the same address + global_status = w25q128jw_read(test_buffer_flash, flash_read_data, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_original == flash_read_data) + int32_t result = check_result(test_buffer, len); + + // Clean memory for next test + erase_memory(test_buffer_flash); + + // Reset the flash data buffer + memset(flash_read_data, 0, len * sizeof(uint8_t)); + + return result; +} + +uint32_t test_write_quad_dma(uint32_t *test_buffer, uint32_t len) { + + uint32_t *test_buffer_flash = flash_write_buffer; + + // Write to flash memory at specific address + global_status = w25q128jw_erase_and_write_quad_dma(test_buffer_flash, test_buffer, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Read from flash memory at the same address + global_status = w25q128jw_read(test_buffer_flash, flash_read_data, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_original == flash_read_data) + int32_t result = check_result(test_buffer, len); + + // Clean memory for next test + erase_memory(test_buffer_flash); + + // Reset the flash data buffer + memset(flash_read_data, 0, len * sizeof(uint8_t)); + + return result; +} +#ifndef ON_CHIP +uint32_t test_write_flash_only(uint32_t *test_buffer, uint32_t len) { + + //remove FLASH offset as required by the BSP, flash_only_write_buffer is only mapped to the LMA + uint32_t *test_buffer_flash = heep_get_flash_address_offset(flash_only_write_buffer); + + // Clean memory + erase_memory(test_buffer_flash); + + // Write to flash memory at specific address + global_status = w25q128jw_erase_and_write_standard(test_buffer_flash, test_buffer, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Read from flash memory at the same address + global_status = w25q128jw_read(test_buffer_flash, flash_read_data, len); + if (global_status != FLASH_OK) exit(EXIT_FAILURE); + + // Check if what we read is correct (i.e. flash_original == flash_read_data) + int32_t result = check_result(test_buffer, len); + + // Clean memory for next test + erase_memory(test_buffer_flash); + + // Reset the flash data buffer + memset(flash_read_data, 0, len * sizeof(uint8_t)); + + return result; +} +#endif +uint32_t check_result(uint8_t *test_buffer, uint32_t len) { + uint32_t errors = 0; + uint8_t *flash_read_data_char = (uint8_t *)flash_read_data; + + for (uint32_t i = 0; i < len; i++) { + if (test_buffer[i] != flash_read_data_char[i]) { + PRINTF("Error at position %d: expected %x, got %x\n", i, test_buffer[i], flash_read_data_char[i]); + errors++; + } + } + + if (errors == 0) { + PRINTF("success!\n"); + } else { + PRINTF("failure, %d errors!\n", errors); + } + + return errors; +} + +// Erase the memory only if FPGA is used +void erase_memory(uint32_t addr) { + #ifdef USE_SPI_FLASH + w25q128jw_4k_erase(addr); + #endif +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_virtual_flash/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_virtual_flash/main.c deleted file mode 100644 index e1e16f56..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_virtual_flash/main.c +++ /dev/null @@ -1,222 +0,0 @@ - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "rv_timer.h" -#include "rv_timer_regs.h" -#include "soc_ctrl.h" -#include "rv_plic.h" -#include "rv_plic_regs.h" -#include "spi_host.h" -#include "spi_host_regs.h" -#include "dma.h" -#include "fast_intr_ctrl.h" -#include "gpio.h" -#include "fast_intr_ctrl_regs.h" -#include "x-heep.h" - -#define REVERT_24b_ADDR(addr) ((((uint32_t)addr & 0xff0000) >> 16) | ((uint32_t)addr & 0xff00) | (((uint32_t)addr & 0xff) << 16)) -#define FLASH_ADDR 0x00000000 -#define FLASH_SIZE 64 * 1024 * 1024 -#define FLASH_CLK_MAX_HZ (133 * 1000 * 1000) - - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -// Interrupt controller variables -plic_result_t plic_res; -uint32_t intr_num; - -//volatile int8_t timer_flag; -volatile int8_t spi_intr_flag; - -spi_host_t spi_host_flash; - -void dma_intr_handler_trans_done(){ - PRINTF("#\n\r"); -} - -void fic_irq_spi_flash(){ - // Disable SPI interrupts - spi_enable_evt_intr(&spi_host_flash, false); - spi_enable_rxwm_intr(&spi_host_flash, false); - spi_intr_flag = 1; - PRINTF("@\n\r"); -} - - -void write_to_flash(spi_host_t *SPI, uint16_t *data, uint32_t byte_count, uint32_t addr) -{ - uint32_t write_to_mem = 0x02; - spi_write_word(SPI, write_to_mem); - uint32_t cmd_write_to_mem = spi_create_command((spi_command_t){ - .len = 0, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(SPI, cmd_write_to_mem); - spi_wait_for_ready(SPI); - - uint32_t addr_cmd = __builtin_bswap32(addr); - spi_write_word(SPI, addr_cmd); - uint32_t cmd_address = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(SPI, cmd_address); - spi_wait_for_ready(SPI); - - uint32_t *fifo_ptr_tx = SPI->base_addr.base + SPI_HOST_TXDATA_REG_OFFSET; - - // -- DMA CONFIGURATION -- - dma_init(NULL); - - dma_target_t tgt_src = { - .ptr = data, - .inc_du = 1, - .size_du = 64, - .type = DMA_DATA_TYPE_HALF_WORD, - .trig = DMA_TRIG_MEMORY, - }; - dma_target_t tgt_dst = { - .ptr = fifo_ptr_tx, - .inc_du = 0, - .size_du = 0, - .type = DMA_DATA_TYPE_HALF_WORD, - .trig = DMA_TRIG_SLOT_SPI_FLASH_TX, - }; - dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - .end = DMA_TRANS_END_INTR, - }; - - dma_config_flags_t res; - - spi_intr_flag = 0; - - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("trans: %u\n\r", res ); - res = dma_load_transaction(&trans); - PRINTF("load: %u\n\r", res ); - res = dma_launch(&trans); - - // Wait for the first data to arrive to the TX FIFO before enabling interrupt - spi_wait_for_tx_not_empty(SPI); - // Enable event interrupt - spi_enable_evt_intr(SPI, true); - // Enable TX empty interrupt - spi_enable_txempty_intr(SPI, true); - - const uint32_t cmd_write_tx = spi_create_command((spi_command_t){ - .len = byte_count - 1, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(SPI, cmd_write_tx); - spi_wait_for_ready(SPI); - - // Wait for SPI interrupt - while(spi_intr_flag == 0) { - wait_for_interrupt(); - } - - PRINTF("%d words written to flash.\n\n\r", byte_count/4); -} - -int main(int argc, char *argv[]) -{ - // Get current Frequency - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - soc_ctrl_select_spi_host(&soc_ctrl); - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - uint32_t mask = 1 << 21; - CSR_SET_BITS(CSR_REG_MIE, mask); - spi_intr_flag = 0; - // Set mie.MEIE bit to one to enable timer interrupt - mask = 1 << 7; - CSR_SET_BITS(CSR_REG_MIE, mask); - - spi_host_flash.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - spi_set_enable(&spi_host_flash, true); - spi_output_enable(&spi_host_flash, true); - - uint16_t clk_div = 0; - if (FLASH_CLK_MAX_HZ < core_clk / 2) - { - clk_div = (core_clk / (FLASH_CLK_MAX_HZ)-2) / 2; // The value is truncated - if (core_clk / (2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) - clk_div += 1; // Adjust if the truncation was not 0 - } - - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg_flash = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0}); - spi_set_configopts(&spi_host_flash, 0, chip_cfg_flash); - spi_set_csid(&spi_host_flash, 0); - - // To set the number of dummy cycles we have to send command 0x11 and then a 1B value - const uint32_t reset_cmd = 0x11; - spi_write_word(&spi_host_flash, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 0, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host_flash, cmd_reset); - spi_wait_for_ready(&spi_host_flash); - - const uint32_t set_dummy_cycle = 0x07; - spi_write_word(&spi_host_flash, set_dummy_cycle); - const uint32_t cmd_set_dummy = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - - spi_set_command(&spi_host_flash, cmd_set_dummy); - spi_wait_for_ready(&spi_host_flash); - - uint32_t results[32]; - for(uint32_t i = 0; i < 32; i++){ - results[i] = i; - } - - write_to_flash(&spi_host_flash, results, sizeof(*results) * 32, FLASH_ADDR); - - PRINTF("Success.\n\r"); - - return EXIT_SUCCESS; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/arch.cfg b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/arch.cfg new file mode 100644 index 00000000..0583bdfe --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/arch.cfg @@ -0,0 +1,67 @@ +############################################################################### +# +# Copyright 2020 OpenHW Group +# +# Licensed under the Solderpad Hardware Licence, 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 +# +# https://solderpad.org/licenses/ +# +# 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. +# +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +# +############################################################################### + +# This is a python setting of parameters for the architecture. The following +# parameters may be set (other keys are silently ignored). Defaults are shown +# in brackets +# - cc ('cc') +# - ld (same value as for cc) +# - cflags ([]) +# - ldflags ([]) +# - cc_define_pattern ('-D{0}') +# - cc_incdir_pattern ('-I{0}') +# - cc_input_pattern ('{0}') +# - cc_output_pattern ('-o {0}') +# - ld_input_pattern ('{0}') +# - ld_output_pattern ('-o {0}') +# - user_libs ([]) +# - dummy_libs ([]) +# - cpu_mhz (1) +# - warmup_heat (1) + +# The "flags" and "libs" parameters (cflags, ldflags, user_libs, dummy_libs) +# should be lists of arguments to be passed to the compile or link line as +# appropriate. Patterns are Python format patterns used to create arguments. +# Thus for GCC or Clang/LLVM defined constants can be passed using the prefix +# '-D', and the pattern '-D{0}' would be appropriate (which happens to be the +# default). + +# "user_libs" may be absolute file names or arguments to the linker. In the +# latter case corresponding arguments in ldflags may be needed. For example +# with GCC or Clang/LLVM is "-l" flags are used in "user_libs", the "-L" flags +# may be needed in "ldflags". + +# Dummy libs have their source in the "support" subdirectory. Thus if 'crt0' +# is specified, there should be a source file 'dummy-crt0.c' in the support +# directory. + +# There is no need to set an unused parameter, and this file may be empty to +# set no flags. + +# Parameter values which are duplicated in architecture, board, chip or +# command line are used in the following order of priority +# - default value +# - architecture specific value +# - chip specific value +# - board specific value +# - command line value + +# For flags, this priority is applied to individual flags, not the complete +# list of flags. diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.c new file mode 100644 index 00000000..5e55329f --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.c @@ -0,0 +1,177 @@ +/* BEEBS local library variants + + Copyright (C) 2019 Embecosm Limited. + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* These are very simple local versions of library routines, to ensure the + code is compiled with the flags used for the benchmark. Not all library + routines are here, just ones that cause a lot of unecessary load, or where + there is variation between platforms and architectures. */ + +#include +#include +#include "beebsc.h" + +/* Seed for the random number generator */ + +static long int seed = 0; + +/* Heap records and sane initial values */ + +static void *heap_ptr = NULL; +static void *heap_end = NULL; +static size_t heap_requested = 0; + + +/* Yield a sequence of random numbers in the range [0, 2^15-1]. + + long int is guaranteed to be at least 32 bits. The seed only ever uses 31 + bits (so is positive). + + For BEEBS this gets round different operating systems using different + multipliers and offsets and RAND_MAX variations. */ + +int +rand_beebs (void) +{ + seed = (seed * 1103515245L + 12345) & ((1UL << 31) - 1); + return (int) (seed >> 16); +} + + +/* Initialize the random number generator */ + +void +srand_beebs (unsigned int new_seed) +{ + seed = (long int) new_seed; +} + + +/* Initialize the BEEBS heap pointers. Note that the actual memory block is + in the caller code. */ + +void +init_heap_beebs (void *heap, size_t heap_size) +{ + heap_ptr = (void *) heap; + heap_end = (void *) ((char *) heap_ptr + heap_size); + heap_requested = 0; +} + + +/* Report if malloc ever failed. + + Return non-zero (TRUE) if malloc did not reqest more than was available + since the last call to init_heap_beebs, zero (FALSE) otherwise. */ + +int +check_heap_beebs (void *heap) +{ + return ((void *) ((char *) heap + heap_requested) <= heap_end); +} + + +/* BEEBS version of malloc. + + This is primarily to reduce library and OS dependencies. Malloc is + generally not used in embedded code, or if it is, only in well defined + contexts to pre-allocate a fixed amount of memory. So this simplistic + implementation is just fine. + + Note in particular the assumption that memory will never be freed! */ + +void * +malloc_beebs (size_t size) +{ + void *new_ptr = heap_ptr; + + heap_requested += size; + + if (((void *) ((char *) heap_ptr + size) > heap_end) || (0 == size)) + return NULL; + else + { + heap_ptr = (void *) ((char *) heap_ptr + size); + return new_ptr; + } +} + + +/* BEEBS version of calloc. + + Implement as wrapper for malloc */ + +void * +calloc_beebs (size_t nmemb, size_t size) +{ + void *new_ptr = malloc_beebs (nmemb * size); + + /* Calloc is defined to zero the memory. OK to use a function here, because + it will be handled specially by the compiler anyway. */ + + if (NULL != new_ptr) + memset (new_ptr, 0, nmemb * size); + + return new_ptr; +} + + +/* BEEBS version of realloc. + + This is primarily to reduce library and OS dependencies. We just have to + allocate new memory and copy stuff across. */ + +void * +realloc_beebs (void *ptr, size_t size) +{ + void *new_ptr = heap_ptr; + + heap_requested += size; + + if (((void *) ((char *) heap_ptr + size) > heap_end) || (0 == size)) + return NULL; + else + { + heap_ptr = (void *) ((char *) heap_ptr + size); + + /* This is clunky, since we don't know the size of the original + pointer. However it is a read only action and we know it must + be big enough if we right off the end, or we couldn't have + allocated here. If the size is smaller, it doesn't matter. */ + + if (NULL != ptr) + { + size_t i; + + for (i = 0; i < size; i++) + ((char *) new_ptr)[i] = ((char *) ptr)[i]; + } + + return new_ptr; + } +} + + +/* BEEBS version of free. + + For our simplified version of memory handling, free can just do nothing. */ + +void +free_beebs (void *ptr __attribute__ ((unused))) +{ +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.h b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.h new file mode 100644 index 00000000..4a108959 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/beebsc.h @@ -0,0 +1,65 @@ +/* BEEBS local library variants header + + Copyright (C) 2019 Embecosm Limited. + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef BEEBSC_H +#define BEEBSC_H + +#include + +/* BEEBS fixes RAND_MAX to its lowest permitted value, 2^15-1 */ + +#ifdef RAND_MAX +#undef RAND_MAX +#endif +#define RAND_MAX ((1U << 15) - 1) + +/* Common understanding of a "small value" (epsilon) for floating point + comparisons. */ + +#define VERIFY_DOUBLE_EPS 1.0e-13 +#define VERIFY_FLOAT_EPS 1.0e-5 + +/* Simplified assert. + + The full complexity of assert is not needed for a benchmark. See the + discussion at: + + https://lists.librecores.org/pipermail/embench/2019-August/000007.html + + This function just*/ + +#define assert_beebs(expr) { if (!(expr)) exit (1); } + +#define float_eq_beebs(exp, actual) (fabsf(exp - actual) < VERIFY_FLOAT_EPS) +#define float_neq_beebs(exp, actual) !float_eq_beebs(exp, actual) +#define double_eq_beebs(exp, actual) (fabs(exp - actual) < VERIFY_DOUBLE_EPS) +#define double_neq_beebs(exp, actual) !double_eq_beebs(exp, actual) + +/* Local simplified versions of library functions */ + +int rand_beebs (void); +void srand_beebs (unsigned int new_seed); + +void init_heap_beebs (void *heap, const size_t heap_size); +int check_heap_beebs (void *heap); +void *malloc_beebs (size_t size); +void *calloc_beebs (size_t nmemb, size_t size); +void *realloc_beebs (void *ptr, size_t size); +void free_beebs (void *ptr); +#endif /* BEEBSC_H */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/board.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/board.c new file mode 100644 index 00000000..db8fafa8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/board.c @@ -0,0 +1,22 @@ +/* Common board.c for the benchmarks + + Copyright (C) 2018-2019 Embecosm Limited + + Contributor: Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* This is just a wrapper for the board specific support file. */ + +#include "boardsupport.c" + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.c new file mode 100644 index 00000000..f2e674de --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.c @@ -0,0 +1,21 @@ +/* +** +** Copyright 2020 OpenHW Group +** +** Licensed under the Solderpad Hardware Licence, 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 +** +** https://solderpad.org/licenses/ +** +** 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 "boardsupport.h" + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.h b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.h new file mode 100644 index 00000000..6223cd68 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/boardsupport.h @@ -0,0 +1,21 @@ +/* +** +** Copyright 2020 OpenHW Group +** +** Licensed under the Solderpad Hardware Licence, 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 +** +** https://solderpad.org/licenses/ +** +** 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. +** +******************************************************************************* +*/ + + + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chip.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chip.c new file mode 100644 index 00000000..37ac28fe --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chip.c @@ -0,0 +1,32 @@ +/* Common board.c for the benchmarks + + Copyright (C) 2018-2019 Embecosm Limited + + Contributor: Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* This is just a wrapper for the chip specific support file if there is one. */ + +/*#include "config.h"*/ + +#ifdef HAVE_CHIPSUPPORT_H +#include "chipsupport.c" +#endif + +/* Standard C does not permit empty translation units, so provide one. */ + +static void +empty_func () +{ +} + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c new file mode 100644 index 00000000..3228651d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c @@ -0,0 +1,73 @@ +/* +** +** Copyright 2020 OpenHW Group +** +** Licensed under the Solderpad Hardware Licence, 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 +** +** https://solderpad.org/licenses/ +** +** 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 +#include +#include +#include "chipsupport.h" + +#include "csr.h" +#include "x-heep.h" + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#define FS_INITIAL 0x01 + +void +initialise_board () +{ + PRINTF("Initialize board corev32 \n"); + + //enable FP operations + CSR_SET_BITS(CSR_REG_MSTATUS, (FS_INITIAL << 13)); + +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +start_trigger () +{ + PRINTF("start of test \n"); + + // Enable mcycle counter and read value + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + +} + +void __attribute__ ((noinline)) __attribute__ ((externally_visible)) +stop_trigger () +{ + uint32_t cycle_cnt; + CSR_READ(CSR_REG_MCYCLE, &cycle_cnt); + PRINTF("end of test \n"); + PRINTF("Result is given in CPU cycles \n"); + PRINTF("RES: %d \n", cycle_cnt); + +} + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.h b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.h new file mode 100644 index 00000000..bd174c31 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.h @@ -0,0 +1,25 @@ +/* +** +** Copyright 2020 OpenHW Group +** +** Licensed under the Solderpad Hardware Licence, 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 +** +** https://solderpad.org/licenses/ +** +** 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 CHIPSUPPORT_H +#define CHIPSUPPORT_H + +#define CPU_MHZ 1 + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/libminver.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/libminver.c new file mode 100644 index 00000000..0cabd55b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/libminver.c @@ -0,0 +1,292 @@ +/* BEEBS minver benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor Pierre Langlois + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + ************************************************************************* + * * + * SNU-RT Benchmark Suite for Worst Case Timing Analysis * + * ===================================================== * + * Collected and Modified by S.-S. Lim * + * sslim@archi.snu.ac.kr * + * Real-Time Research Group * + * Seoul National University * + * * + * * + * < Features > - restrictions for our experimental environment * + * * + * 1. Completely structured. * + * - There are no unconditional jumps. * + * - There are no exit from loop bodies. * + * (There are no 'break' or 'return' in loop bodies) * + * 2. No 'switch' statements. * + * 3. No 'do..while' statements. * + * 4. Expressions are restricted. * + * - There are no multiple expressions joined by 'or', * + * 'and' operations. * + * 5. No library calls. * + * - All the functions needed are implemented in the * + * source file. * + * * + * * + ************************************************************************* + * * + * FILE: minver.c * + * SOURCE : Turbo C Programming for Engineering by Hyun Soo Ahn * + * * + * DESCRIPTION : * + * * + * Matrix inversion for 3x3 floating point matrix. * + * * + * REMARK : * + * * + * EXECUTION TIME : * + * * + * * + ************************************************************************* + +*/ + +#include +#include +#include "support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 555 + +int minver (int row, int col, float eps); +int mmul (int row_a, int col_a, int row_b, int col_b); + +static float a_ref[3][3] = { + {3.0, -6.0, 7.0}, + {9.0, 0.0, -5.0}, + {5.0, -8.0, 6.0}, +}; + +static float b[3][3] = { + {-3.0, 0.0, 2.0}, + {3.0, -2.0, 0.0}, + {0.0, 2.0, -3.0}, +}; + +static float a[3][3], c[3][3], d[3][3], det; + +static float +minver_fabs (float n) +{ + float f; + + if (n >= 0) + f = n; + else + f = -n; + return f; +} + +int +mmul (int row_a, int col_a, int row_b, int col_b) +{ + int i, j, k, row_c, col_c; + float w; + + row_c = row_a; + col_c = col_b; + + if (row_c < 1 || row_b < 1 || col_c < 1 || col_a != row_b) + return (999); + for (i = 0; i < row_c; i++) + { + for (j = 0; j < col_c; j++) + { + w = 0.0; + for (k = 0; k < row_b; k++) + w += a[i][k] * b[k][j]; + c[i][j] = w; + } + } + + return (0); +} + + +int +minver (int row, int col, float eps) +{ + int work[500], i, j, k, r, iw, u, v; + float w, wmax, pivot, api, w1; + + r = w = 0; + if (row < 2 || row > 500 || eps <= 0.0) + return (999); + w1 = 1.0; + for (i = 0; i < row; i++) + work[i] = i; + for (k = 0; k < row; k++) + { + wmax = 0.0; + for (i = k; i < row; i++) + { + w = minver_fabs (a[i][k]); + if (w > wmax) + { + wmax = w; + r = i; + } + } + pivot = a[r][k]; + api = minver_fabs (pivot); + if (api <= eps) + { + det = w1; + return (1); + } + w1 *= pivot; + u = k * col; + v = r * col; + if (r != k) + { + w1 = -w; + iw = work[k]; + work[k] = work[r]; + work[r] = iw; + for (j = 0; j < row; j++) + { + w = a[k][j]; + a[k][j] = a[r][j]; + a[r][j] = w; + } + } + for (i = 0; i < row; i++) + a[k][i] /= pivot; + for (i = 0; i < row; i++) + { + if (i != k) + { + v = i * col; + w = a[i][k]; + if (w != 0.0) + { + for (j = 0; j < row; j++) + if (j != k) + a[i][j] -= w * a[k][j]; + a[i][k] = -w / pivot; + } + } + } + a[k][k] = 1.0 / pivot; + } + + for (i = 0; i < row; i++) + { + while (1) + { + k = work[i]; + if (k == i) + break; + iw = work[k]; + work[k] = work[i]; + work[i] = iw; + for (j = 0; j < row; j++) + { + u = j * col; + w = a[k][i]; + a[k][i] = a[k][k]; + a[k][k] = w; + } + } + } + + det = w1; + + return (0); +} + + +int +verify_benchmark (int res __attribute ((unused))) +{ + int i, j; + float eps = 1.0e-6; + + static float c_exp[3][3] = { + {-27.0, 26.0, -15.0}, + {-27.0, -10.0, 33.0}, + {-39.0, 28.0, -8.0} + }; + + static float d_exp[3][3] = { + {0.133333325, -0.199999958, 0.2666665910}, + {-0.519999862, 0.113333330, 0.5266665220}, + {0.479999840, -0.359999895, 0.0399999917} + }; + + /* Allow small errors in floating point */ + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (float_neq_beebs(c[i][j], c_exp[i][j]) || float_neq_beebs(d[i][j], d_exp[i][j])) + return 0; + + return float_eq_beebs(det, -16.6666718); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * 1); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + float eps = 1.0e-6; + + memcpy (a, a_ref, 3 * 3 * sizeof (a[0][0])); + minver (3, 3, eps); + memcpy (d, a, 3 * 3 * sizeof (a[0][0])); + memcpy (a, a_ref, 3 * 3 * sizeof (a[0][0])); + mmul (3, 3, 3, 3); + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/main.c new file mode 100644 index 00000000..64566101 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/main.c @@ -0,0 +1,50 @@ +/* Common main.c for the benchmarks + + Copyright (C) 2014 Embecosm Limited and University of Bristol + Copyright (C) 2018-2019 Embecosm Limited + + Contributor: James Pallister + Contributor: Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "csr.h" +#include "x-heep.h" + +#include "support.h" + + +int __attribute__ ((used)) +main (int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + int i; + volatile int result; + int correct; + + initialise_board (); + initialise_benchmark (); + warm_caches (1); + + start_trigger (); + result = benchmark (); + stop_trigger (); + + /* bmarks that use arrays will check a global array rather than int result */ + + correct = verify_benchmark (result); + + return (!correct); + +} /* main () */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/support.h b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/support.h new file mode 100644 index 00000000..b68b81e6 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/support.h @@ -0,0 +1,72 @@ +/* Support header for BEEBS. + + Copyright (C) 2014 Embecosm Limited and the University of Bristol + Copyright (C) 2019 Embecosm Limited + + Contributor James Pallister + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef SUPPORT_H +#define SUPPORT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Include board support header if we have one */ + +#ifdef HAVE_BOARDSUPPORT_H +#include "boardsupport.h" +#endif + +/* Benchmarks must implement verify_benchmark, which must return -1 if no + verification is done. */ + +int verify_benchmark (int result); + +/* Standard functions implemented for each board */ + +void initialise_board (void); +void start_trigger (void); +void stop_trigger (void); + +/* Every benchmark implements this for one-off data initialization. This is + only used for initialization that is independent of how often benchmark () + is called. */ + +void initialise_benchmark (void); + +/* Every benchmark implements this for cache warm up, typically calling + benchmark several times. The argument controls how much warming up is + done, with 0 meaning no warming. */ + +void warm_caches (int temperature); + +/* Every benchmark implements this as its entry point. Don't allow it to be + inlined! */ + +int benchmark (void) __attribute__ ((noinline)); + +/* Every benchmark must implement this to validate the result of the + benchmark. */ + +int verify_benchmark (int res); + +/* Local simplified versions of library functions */ + +#include "beebsc.h" + +#endif /* SUPPORT_H */ + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c new file mode 100644 index 00000000..5c7763f5 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c @@ -0,0 +1,1449 @@ +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : w25q.c +** version : 1 +** date : 1/11/2023 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ +/** +* @file w25q.c +* @date 1/11/2023 +* @brief Source file of the W25Q-family flash memory driver. +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ +#include "string.h" + +#include "w25q128jw.h" + +/* To manage addresses. */ +#include "mmio.h" + +/* To manage interrupts. */ +#include "fast_intr_ctrl.h" +#include "csr.h" +#include "stdasm.h" + +/* To manage DMA. */ +#include "dma.h" + +/* To get TX and RX FIFO depth */ +#include "spi_host_regs.h" + +/* To get the target of the compilation (sim or pynq) */ +#include "x-heep.h" + +/* To get the soc_ctrl base address */ +#include "soc_ctrl_structs.h" + +/* For word swap operations*/ +#include "bitfield.h" + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +/** + * The flash is expecting the address in Big endian format, so a swap is needed + * in order to provide the MSB first. + * Shift is needed as the byteswap is performed on 32-bit words. +*/ +#define REVERT_24b_ADDR(addr) (bitfield_byteswap32(addr) >> 8) + +/** + * @bref If the target is the FPGA, use the SPI FLASH. +*/ +#ifdef TARGET_PYNQ_Z2 +#define USE_SPI_FLASH +#endif + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +/** + * @brief Power up the flash. +*/ +static void flash_power_up(void); + +/** + * @brief Set the QE bit in the flash status register. + * + * @return FLASH_OK if the QE bit is set, @ref error_codes otherwise. +*/ +static w25q_error_codes_t set_QE_bit(void); + +/** + * @brief Configure the SPI<->Flash connection paramethers. +*/ +static void configure_spi(void); + +/** + * @brief Wait for the flash to be ready. + * + * It pools the BUSY bit in the flash status register. + * It is not checking the SUS bit status. +*/ +static void flash_wait(void); + +/** + * @brief Reset the flash. +*/ +static void flash_reset(void); + +/** + * @brief Erase the flash and write the data. + * + * It read 4k (a sector) at a time, erase it and write the data back. + * Befor writing the data back, it modifies the buffer in order to + * add the new data without modifing the other bytes. All the bytes + * that are not going to be modified will be copied back as is. + * + * @param addr 24-bit address to write to. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +static w25q_error_codes_t erase_and_write(uint32_t addr, uint8_t *data ,uint32_t length); + +/** + * @brief Wrapper for page write. + * + * It performs the sanity checks and calls the page_write function with + * the correct speed paramether. A wrapper is necessary as it is not possible + * to program more than a page (256 bytes) at a time. So multiple calls + * to page_write can be needed. + * + * @param addr 24-bit address to write to. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @param quad if 1, the write is performed at quad speed. + * @param dma if 1, the write is performed using DMA. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +static w25q_error_codes_t page_write_wrapper(uint32_t addr, uint8_t *data, uint32_t length, uint8_t quad, uint8_t dma); + +/** + * @brief Write (up to) a page to the flash. + * + * @param addr 24-bit address to write to. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @param quad if 1, the write is performed at quad speed. + * @param dma if 1, the write is performed using DMA. +*/ +static w25q_error_codes_t page_write(uint32_t addr, uint8_t *data, uint32_t length, uint8_t quad, uint8_t dma); + +/** + * @brief Copy length bytes from data to the SPI TX FIFO, using DMA. + * + * @param data pointer to the data buffer. + * @param length number of bytes to copy. + + * @return FLASH_OK if the operation is successful, @ref error_codes otherwise. +*/ +static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length); + +/** + * @brief Enable flash write. + * + * It sets the WEL bit in the flash status register. + * Every action that require the WEL to be set is goig to automatically + * clear it. +*/ +static void flash_write_enable(void); + +/** + * @brief Performs sanity checks on the input parameters. + * + * Checks if the address is valid, the data pointer is not NULL + * and the length is not 0. + * + * @param addr 24-bit address. + * @param data pointer to the data buffer. + * @param length number of bytes to read/write. + * @return FLASH_OK if the sanity checks are passed, @ref error_codes otherwise. +*/ +static w25q_error_codes_t w25q128jw_sanity_checks(uint32_t addr, uint8_t *data, uint32_t length); + +/** + * @brief Return the minimum between two numbers. + * + * The function uses signed integers in order to handle also negative numbers. + * + * @param a first number. + * @param b second number. + * @return the minimum between a and b. +*/ +static int32_t MIN(int32_t a, int32_t b) { + return (a < b) ? a : b; +} + + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +/** + * @brief SPI structure. +*/ +spi_host_t __attribute__((section(".xheep_init_data_crt0"))) spi; //this variable is also used by the crt0, thus keep it in this section + +/** + * @brief Static vector used in the erase_and_write function. + * + * It is used to store the data of a sector (4k) of the flash. Given the dimensions + * of the vector, is not possible to allocate it dinamically as it would cause a stack + * or heap overflow. +*/ +uint8_t sector_data[FLASH_SECTOR_SIZE]; + + +/****************************************************************************/ +/** **/ +/* EXPORTED FUNCTIONS */ +/** **/ +/****************************************************************************/ + + +void w25q128jw_init_crt0() { + //make sure spi variable is into the xheep_init_data_crt0 section + spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + return; +} + +w25q_error_codes_t w25q128jw_init(spi_host_t spi_host) { + /* + * Check if memory mapped SPI is enabled. Current version of the bsp + * does not support memory mapped SPI. + */ + if (soc_ctrl_peri->USE_SPIMEMIO == 1) { + return FLASH_ERROR; // Error + } + + // Set the global spi variable to the one passed as argument. + spi = spi_host; + + #ifdef USE_SPI_FLASH + // Select SPI host as SPI output + soc_ctrl_select_spi_host((soc_ctrl_t*)soc_ctrl_peri); + #endif // USE_SPI_FLASH + + // Enable SPI host device + spi_set_enable(&spi, true); + + // Enable SPI output + spi_output_enable(&spi, true); + + // Configure SPI<->Flash connection on CSID 0 + configure_spi(); + + // Set CSID + spi_set_csid(&spi, 0); + + // Power up flash + flash_power_up(); + + // Set QE bit (only FPGA, simulation do not support status registers at all) + #ifdef TARGET_PYNQ_Z2 + if (set_QE_bit() == FLASH_ERROR) return FLASH_ERROR; // Error occurred while setting QE bit + #endif // TARGET_PYNQ_Z2 + + return FLASH_OK; // Success +} + +w25q_error_codes_t w25q128jw_read(uint32_t addr, void *data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Define the status variable + w25q_error_codes_t status; + + if (length < RX_DMA_THRESHOLD) { + status = w25q128jw_read_quad(addr, data, length); + if (status != FLASH_OK) return status; + } else { + // Wait DMA to be free + while(!dma_is_ready()); + status = w25q128jw_read_quad_dma(addr, data, length); + if (status != FLASH_OK) return status; + } + + return FLASH_OK; +} + +w25q_error_codes_t w25q128jw_write(uint32_t addr, void *data, uint32_t length, uint8_t erase_before_write) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Define the status variable + w25q_error_codes_t status = FLASH_OK; + + if (erase_before_write == 1) { + status = erase_and_write(addr, data, length); + } else { + // Wait DMA to be free + while(!dma_is_ready()); + status = w25q128jw_write_quad_dma(addr, data, length); + } + + return status; +} + +w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Address + Read command + uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); + // Load command to TX FIFO + spi_write_word(&spi, read_byte_cmd); + spi_wait_for_ready(&spi); + + // Set up segment parameters -> send command and address + const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + // Load segment parameters to COMMAND register + spi_set_command(&spi, cmd_read_1); + spi_wait_for_ready(&spi); + + // Set up segment parameters -> read length bytes + const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ + .len = length-1, // len bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi, cmd_read_2); + spi_wait_for_ready(&spi); + + /* + * Set RX watermark to length. The watermark is in words. + * If the length is not a multiple of 4, the RX watermark is set to length/4+1 + * to take into account the extra bytes. + * If the length is higher then the RX FIFO depth, the RX watermark is set to + * RX FIFO depth. In this case the flag is not set to 0, so the loop will + * continue until all the data is read. + */ + int flag = 1; + int to_read = 0; + int i_start = 0; + int length_original = length; + uint32_t *data_32bit = (uint32_t *)data; + while (flag) { + if (length >= SPI_HOST_PARAM_RX_DEPTH) { + spi_set_rx_watermark(&spi, SPI_HOST_PARAM_RX_DEPTH>>2); + length -= SPI_HOST_PARAM_RX_DEPTH; + to_read += SPI_HOST_PARAM_RX_DEPTH; + } + else { + spi_set_rx_watermark(&spi, (length%4==0 ? length>>2 : (length>>2)+1)); + to_read += length; + flag = 0; + } + // Wait till SPI RX FIFO is full (or I read all the data) + spi_wait_for_rx_watermark(&spi); + // Read data from SPI RX FIFO + for (int i = i_start; i < to_read>>2; i++) { + spi_read_word(&spi, &data_32bit[i]); // Writes a full word + } + // Update the starting index + i_start += SPI_HOST_PARAM_RX_DEPTH>>2; + } + // Take into account the extra bytes (if any) + if (length_original % 4 != 0) { + uint32_t last_word = 0; + spi_read_word(&spi, &last_word); + memcpy(&data_32bit[length_original>>2], &last_word, length%4); + } + + return FLASH_OK; // Success +} + +w25q_error_codes_t w25q128jw_write_standard(uint32_t addr, void* data, uint32_t length) { + // Call the wrapper with quad = 0, dma = 0 + return page_write_wrapper(addr, data, length, 0, 0); +} + + +w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, uint32_t length){ + + uint32_t remaining_length = length; + uint32_t current_addr = addr; + uint8_t *current_data = data; + + w25q_error_codes_t status; + + while (remaining_length > 0) { + // Start address of the sector to erase, 4kB aligned + uint32_t sector_start_addr = current_addr & 0xfffff000; + + // Read the full sector and save it into RAM + status = w25q128jw_read_standard(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Erase the sector (no need to do so in simulation) + #ifdef TARGET_PYNQ_Z2 + w25q128jw_4k_erase(sector_start_addr); + #endif // TARGET_PYNQ_Z2 + + // Calculate the length of data to write in this sector + uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); + + // Modify the data in RAM to include the new data + memcpy(§or_data[current_addr - sector_start_addr], current_data, write_length); + + // Write the modified data back to the flash + status = w25q128jw_write_standard(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Update the remaining length, address and data pointer + remaining_length -= write_length; + current_addr += write_length; + current_data += write_length; + } + + return FLASH_OK; + +} + + + +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + /* + * SET UP DMA + */ + // SPI and SPI_FLASH are the same IP so same register map + uint32_t *fifo_ptr_rx = spi.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; + + // Init DMA, the integrated DMA is used (peri == NULL) + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + #endif + + // Set up DMA source target + static dma_target_t tgt_src = { + .inc_du = 0, // Target is peripheral, no increment + .type = DMA_DATA_TYPE_WORD, // Data type is word + }; + // Size is in data units (words in this case) + tgt_src.size_du = length>>2; + // Target is SPI RX FIFO + tgt_src.ptr = (uint8_t*)fifo_ptr_rx; + // Trigger to control the data flow + tgt_src.trig = slot; + + // Set up DMA destination target + static dma_target_t tgt_dst = { + .inc_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, // Data type is byte + .trig = DMA_TRIG_MEMORY, // Read-write operation to memory + }; + tgt_dst.ptr = (uint8_t*)data; // Target is the data buffer + + // Set up DMA transaction + static dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .end = DMA_TRANS_END_POLLING, + }; + + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + res = dma_load_transaction(&trans); + res = dma_launch(&trans); + + // Address + Read command + uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); + // Load command to TX FIFO + spi_write_word(&spi, read_byte_cmd); + spi_wait_for_ready(&spi); + + // Set up segment parameters -> send command and address + const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + // Load segment parameters to COMMAND register + spi_set_command(&spi, cmd_read_1); + spi_wait_for_ready(&spi); + + // Set up segment parameters -> read length bytes + const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ + .len = length-1, // len bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi, cmd_read_2); + spi_wait_for_ready(&spi); + + // Wait for DMA to finish transaction + while(!dma_is_ready()); + + // Take into account the extra bytes (if any) + if (length % 4 != 0) { + uint32_t last_word = 0; + spi_read_word(&spi, &last_word); + memcpy(&data[length - length%4], &last_word, length%4); + } + + return FLASH_OK; +} + +w25q_error_codes_t w25q128jw_write_standard_dma(uint32_t addr, void *data, uint32_t length) { + // Call the wrapper with quad = 0, dma = 1 + return page_write_wrapper(addr, data, length, 0, 1); +} + +w25q_error_codes_t w25q128jw_erase_and_write_standard_dma(uint32_t addr, void* data, uint32_t length){ + + uint32_t remaining_length = length; + uint32_t current_addr = addr; + uint8_t *current_data = data; + + w25q_error_codes_t status; + + while (remaining_length > 0) { + // Start address of the sector to erase, 4kB aligned + uint32_t sector_start_addr = current_addr & 0xfffff000; + + // Read the full sector and save it into RAM + status = w25q128jw_read_standard_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Erase the sector (no need to do so in simulation) + #ifdef TARGET_PYNQ_Z2 + w25q128jw_4k_erase(sector_start_addr); + #endif // TARGET_PYNQ_Z2 + + // Calculate the length of data to write in this sector + uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); + + // Modify the data in RAM to include the new data + memcpy(§or_data[current_addr - sector_start_addr], current_data, write_length); + + // Write the modified data back to the flash + status = w25q128jw_write_standard_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Update the remaining length, address and data pointer + remaining_length -= write_length; + current_addr += write_length; + current_data += write_length; + } + + return FLASH_OK; + +} + + +w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void *data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Send quad read command at standard speed + uint32_t cmd_read_quadIO = FC_RDQIO; + spi_write_word(&spi, cmd_read_quadIO); + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_read); + spi_wait_for_ready(&spi); + + /* + * Send address at quad speed. + * Last byte is Fxh (here FFh) required by W25Q128JW + */ + uint32_t read_byte_cmd = (REVERT_24b_ADDR(addr) | (0xFF << 24)); + spi_write_word(&spi, read_byte_cmd); + const uint32_t cmd_address = spi_create_command((spi_command_t){ + .len = 3, // 3 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_address); + spi_wait_for_ready(&spi); + + // Quad read requires dummy clocks + const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ + #ifdef TARGET_PYNQ_Z2 + .len = DUMMY_CLOCKS_FAST_READ_QUAD_IO-1, + #else + .len = DUMMY_CLOCKS_SIM-1, + #endif + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirDummy // Dummy + }); + spi_set_command(&spi, dummy_clocks_cmd); + spi_wait_for_ready(&spi); + + // Read back the requested data at quad speed + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = length-1, // 32 Byte + .csaat = false, // End command + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi, cmd_read_rx); + spi_wait_for_ready(&spi); + + /* COMMAND FINISHED */ + + /* + * Set RX watermark to length. The watermark is in words. + * If the length is not a multiple of 4, the RX watermark is set to length/4+1 + * to take into account the extra bytes. + * If the length is higher then the RX FIFO depth, the RX watermark is set to + * RX FIFO depth. In this case the flag is not set to 0, so the loop will + * continue until all the data is read. + */ + int flag = 1; + int to_read = 0; + int i_start = 0; + int length_original = length; + uint32_t *data_32bit = (uint32_t *)data; + while (flag) { + if (length >= SPI_HOST_PARAM_RX_DEPTH) { + spi_set_rx_watermark(&spi, SPI_HOST_PARAM_RX_DEPTH>>2); + length -= SPI_HOST_PARAM_RX_DEPTH; + to_read += SPI_HOST_PARAM_RX_DEPTH; + } + else { + spi_set_rx_watermark(&spi, (length%4==0 ? length>>2 : (length>>2)+1)); + to_read += length; + flag = 0; + } + // Wait till SPI RX FIFO is full (or I read all the data) + spi_wait_for_rx_watermark(&spi); + // Read data from SPI RX FIFO + for (int i = i_start; i < to_read>>2; i++) { + spi_read_word(&spi, &data_32bit[i]); // Writes a full word + } + // Update the starting index + i_start += SPI_HOST_PARAM_RX_DEPTH>>2; + } + // Take into account the extra bytes (if any) + if (length_original%4 != 0) { + uint32_t last_word = 0; + spi_read_word(&spi, &last_word); + memcpy(&data_32bit[length_original>>2], &last_word, length%4); + } + + return FLASH_OK; // Success +} + +w25q_error_codes_t w25q128jw_write_quad(uint32_t addr, void *data, uint32_t length) { + // Call the wrapper with quad = 1, dma = 0 + return page_write_wrapper(addr, data, length, 1, 0); +} + + +w25q_error_codes_t w25q128jw_erase_and_write_quad(uint32_t addr, void *data, uint32_t length) { + + uint32_t remaining_length = length; + uint32_t current_addr = addr; + uint8_t *current_data = data; + + w25q_error_codes_t status; + + while (remaining_length > 0) { + // Start address of the sector to erase, 4kB aligned + uint32_t sector_start_addr = current_addr & 0xfffff000; + + // Read the full sector and save it into RAM + status = w25q128jw_read_quad(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Erase the sector (no need to do so in simulation) + #ifdef TARGET_PYNQ_Z2 + w25q128jw_4k_erase(sector_start_addr); + #endif // TARGET_PYNQ_Z2 + + // Calculate the length of data to write in this sector + uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); + + // Modify the data in RAM to include the new data + memcpy(§or_data[current_addr - sector_start_addr], current_data, write_length); + + // Write the modified data back to the flash + status = w25q128jw_write_quad(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Update the remaining length, address and data pointer + remaining_length -= write_length; + current_addr += write_length; + current_data += write_length; + } + + return FLASH_OK; + +} + + +w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t length) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Send quad read command at standard speed + uint32_t cmd_read_quadIO = FC_RDQIO; + spi_write_word(&spi, cmd_read_quadIO); + const uint32_t cmd_read = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_read); + spi_wait_for_ready(&spi); + + /* + * Send address at quad speed. + * Last byte is Fxh (here FFh) required by W25Q128JW + */ + uint32_t read_byte_cmd = (REVERT_24b_ADDR(addr) | (0xFF << 24)); + spi_write_word(&spi, read_byte_cmd); + const uint32_t cmd_address = spi_create_command((spi_command_t){ + .len = 3, // 3 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_address); + spi_wait_for_ready(&spi); + + // Quad read requires dummy clocks + const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ + #ifdef TARGET_PYNQ_Z2 + .len = DUMMY_CLOCKS_FAST_READ_QUAD_IO-1, // W25Q128JW flash needs 4 dummy cycles + #else + .len = DUMMY_CLOCKS_SIM-1, // SPI flash simulation model needs 8 dummy cycles + #endif + .csaat = true, // Command not finished + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirDummy // Dummy + }); + spi_set_command(&spi, dummy_clocks_cmd); + spi_wait_for_ready(&spi); + + // Read back the requested data at quad speed + const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ + .len = length-1, // length bytes + .csaat = false, // End command + .speed = kSpiSpeedQuad, // Quad speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi, cmd_read_rx); + spi_wait_for_ready(&spi); + + /* COMMAND FINISHED */ + + /* + * SET UP DMA + */ + // SPI and SPI_FLASH are the same IP so same register map + uint32_t *fifo_ptr_rx = spi.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; + + // Init DMA, the integrated DMA is used (peri == NULL) + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + #endif + + // Set up DMA source target + static dma_target_t tgt_src = { + .inc_du = 0, // Target is peripheral, no increment + .type = DMA_DATA_TYPE_WORD, // Data type is byte + }; + // Size is in data units (words in this case) + tgt_src.size_du = length>>2; + // Target is SPI RX FIFO + tgt_src.ptr = (uint8_t*)fifo_ptr_rx; + // Trigger to control the data flow + tgt_src.trig = slot; + + // Set up DMA destination target + static dma_target_t tgt_dst = { + .inc_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, // Data type is byte + .trig = DMA_TRIG_MEMORY, // Read-write operation to memory + }; + tgt_dst.ptr = (uint8_t*)data; // Target is the data buffer + + // Set up DMA transaction + static dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .end = DMA_TRANS_END_POLLING, + }; + + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + res = dma_load_transaction(&trans); + res = dma_launch(&trans); + + // Wait for DMA to finish transaction + while(!dma_is_ready()); + + // Take into account the extra bytes (if any) + if (length % 4 != 0) { + uint32_t last_word = 0; + spi_read_word(&spi, &last_word); + memcpy(&data[length - length%4], &last_word, length%4); + } + + return FLASH_OK; +} + +w25q_error_codes_t w25q128jw_write_quad_dma(uint32_t addr, void *data, uint32_t length) { + // Call the wrapper with quad = 1, dma = 1 + return page_write_wrapper(addr, data, length, 1, 1); +} + +w25q_error_codes_t w25q128jw_erase_and_write_quad_dma(uint32_t addr, void *data, uint32_t length) { + + uint32_t remaining_length = length; + uint32_t current_addr = addr; + uint8_t *current_data = data; + + w25q_error_codes_t status; + + while (remaining_length > 0) { + // Start address of the sector to erase, 4kB aligned + uint32_t sector_start_addr = current_addr & 0xfffff000; + + // Read the full sector and save it into RAM + status = w25q128jw_read_quad_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Erase the sector (no need to do so in simulation) + #ifdef TARGET_PYNQ_Z2 + w25q128jw_4k_erase(sector_start_addr); + #endif // TARGET_PYNQ_Z2 + + // Calculate the length of data to write in this sector + uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); + + // Modify the data in RAM to include the new data + memcpy(§or_data[current_addr - sector_start_addr], current_data, write_length); + + // Write the modified data back to the flash + status = w25q128jw_write_quad_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Update the remaining length, address and data pointer + remaining_length -= write_length; + current_addr += write_length; + current_data += write_length; + } + + return FLASH_OK; + +} + +w25q_error_codes_t w25q128jw_4k_erase(uint32_t addr) { + // Sanity checks + if (addr > MAX_FLASH_ADDR || addr < 0) return FLASH_ERROR; + + // Wait any other operation to finish + flash_wait(); + + // Enable flash write in order to erase + flash_write_enable(); + + // Build and send erase command + uint32_t erase_4k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_SE); + spi_write_word(&spi, erase_4k_cmd); + spi_wait_for_ready(&spi); + const uint32_t cmd_erase = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_erase); + spi_wait_for_ready(&spi); + + // Wait for the erase operation to be finished + flash_wait(); +} + +w25q_error_codes_t w25q128jw_32k_erase(uint32_t addr) { + // Sanity checks + if (addr > 0x00ffffff || addr < 0) return FLASH_ERROR; + + // Wait any other operation to finish + flash_wait(); + + // Enable flash write in order to erase + flash_write_enable(); + + // Build and send erase command + uint32_t erase_32k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_BE32); + spi_write_word(&spi, erase_32k_cmd); + spi_wait_for_ready(&spi); + const uint32_t cmd_erase = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_erase); + spi_wait_for_ready(&spi); + + // Wait for the erase operation to be finished + flash_wait(); +} + +w25q_error_codes_t w25q128jw_64k_erase(uint32_t addr) { + // Sanity checks + if (addr > 0x00ffffff || addr < 0) return FLASH_ERROR; + + // Wait any other operation to finish + flash_wait(); + + // Enable flash write in order to erase + flash_write_enable(); + + // Build and send erase command + uint32_t erase_64k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_BE64); + spi_write_word(&spi, erase_64k_cmd); + spi_wait_for_ready(&spi); + const uint32_t cmd_erase = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_erase); + spi_wait_for_ready(&spi); + + // Wait for the erase operation to be finished + flash_wait(); +} + +void w25q128jw_chip_erase(void) { + // Wait any other operation to finish + flash_wait(); + + // Enable flash write in order to erase + flash_write_enable(); + + // Build and send erase command + spi_write_word(&spi, FC_CE); + spi_wait_for_ready(&spi); + const uint32_t cmd_erase = spi_create_command((spi_command_t){ + .len = 0, // 1 Bytes + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_erase); + spi_wait_for_ready(&spi); + + // Wait for the erase operation to be finished + flash_wait(); +} + +void w25q128jw_reset(void) { + // Wait for ongoing operation to finish (if any) + flash_wait(); + + // Build and send reset command + flash_reset(); + + // Wait for the reset operation to be finished + flash_wait(); +} + +void w25q128jw_reset_force(void) { + // Build and send reset command without waiting for ongoing operation + flash_reset(); + + // Wait for the reset operation to be finished + flash_wait(); +} + +void w25q128jw_power_down(void) { + // Build and send power down command + spi_write_word(&spi, FC_PD); + const uint32_t cmd_power_down = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_power_down); + spi_wait_for_ready(&spi); +} + + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +static void flash_power_up(void) { + spi_write_word(&spi, FC_RPD); + spi_wait_for_ready(&spi); + const uint32_t cmd_powerup = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_powerup); + spi_wait_for_ready(&spi); +} + +static w25q_error_codes_t set_QE_bit(void) { + spi_set_rx_watermark(&spi,1); + + // Read Status Register 2 + const uint32_t reg2_read_cmd = FC_RSR2; + spi_write_word(&spi, reg2_read_cmd); + + const uint32_t reg2_read_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, reg2_read_1); + spi_wait_for_ready(&spi); + + const uint32_t reg2_read_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirRxOnly // Read only + }); + spi_set_command(&spi, reg2_read_2); + spi_wait_for_ready(&spi); + spi_wait_for_rx_watermark(&spi); + + /* + * the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed + * The actual register is 8 bit, but the SPI host gives a full word + */ + uint32_t reg2_data; + spi_read_word(&spi, ®2_data); + + // Set bit in position 1 (QE bit), leaving the others unchanged + reg2_data |= 0x2; + + // Enable write operation + flash_write_enable(); + + // Write Status Register 2 (set QE bit) + const uint32_t reg2_write_cmd = FC_WSR2; + spi_write_word(&spi, reg2_write_cmd); + + const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = true, // Command not finished + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, reg2_write_1); + spi_wait_for_ready(&spi); + + // Load data to TX FIFO + spi_write_word(&spi, reg2_data); + + // Create command segment + const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Standard speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, reg2_write_2); + spi_wait_for_ready(&spi); + + // Wait flash to complete write routine + flash_wait(); + + // Read back Status Register 2 + spi_write_word(&spi, reg2_read_cmd); + spi_set_command(&spi, reg2_read_1); + spi_wait_for_ready(&spi); + spi_set_command(&spi, reg2_read_2); + spi_wait_for_ready(&spi); + spi_wait_for_rx_watermark(&spi); + uint32_t reg2_data_check = 0x00; + spi_read_word(&spi, ®2_data_check); + + // Check if the QE bit is set + if ((reg2_data_check & 0x2) == 0) return FLASH_ERROR; + else return FLASH_OK; +} + +static void configure_spi(void) { + // Configure SPI clock + uint32_t core_clk = soc_ctrl_peri->SYSTEM_FREQUENCY_HZ; + uint16_t clk_div = 0; + if(FLASH_CLK_MAX_HZ < core_clk/2){ + clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated + if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 + } + // SPI Configuration + // Configure chip 0 (flash memory) + const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ + .clkdiv = clk_div, + .csnidle = 0xF, + .csntrail = 0xF, + .csnlead = 0xF, + .fullcyc = false, + .cpha = 0, + .cpol = 0 + }); + spi_set_configopts(&spi, 0, chip_cfg); +} + +static void flash_wait(void) { + spi_set_rx_watermark(&spi,1); + bool flash_busy = true; + uint8_t flash_resp[4] = {0xff,0xff,0xff,0xff}; + + while(flash_busy){ + uint32_t flash_cmd = FC_RSR1; // [CMD] Read status register 1 + spi_write_word(&spi, flash_cmd); // Push TX buffer + uint32_t spi_status_cmd = spi_create_command((spi_command_t){ + .len = 0, + .csaat = true, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + uint32_t spi_status_read_cmd = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirRxOnly + }); + spi_set_command(&spi, spi_status_cmd); + spi_wait_for_ready(&spi); + spi_set_command(&spi, spi_status_read_cmd); + spi_wait_for_ready(&spi); + spi_wait_for_rx_watermark(&spi); + spi_read_word(&spi, (uint32_t *)flash_resp); + if ((flash_resp[0] & 0x01) == 0) flash_busy = false; + } +} + +static void flash_reset(void) { + spi_write_word(&spi, FC_ERESET); + spi_write_word(&spi, FC_RESET); + spi_wait_for_ready(&spi); + + const uint32_t cmd_reset_enable = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_reset_enable); + spi_wait_for_ready(&spi); + const uint32_t cmd_reset = spi_create_command((spi_command_t){ + .len = 0, // 1 Byte + .csaat = false, // End command + .speed = kSpiSpeedStandard, // Single speed + .direction = kSpiDirTxOnly // Write only + }); + spi_set_command(&spi, cmd_reset); + spi_wait_for_ready(&spi); +} + +w25q_error_codes_t erase_and_write(uint32_t addr, uint8_t *data, uint32_t length) { + + uint32_t remaining_length = length; + uint32_t current_addr = addr; + uint8_t *current_data = data; + + w25q_error_codes_t status; + + while (remaining_length > 0) { + // Start address of the sector to erase, 4kB aligned + uint32_t sector_start_addr = current_addr & 0xfffff000; + + // Read the full sector and save it into RAM + status = w25q128jw_read(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + if (status != FLASH_OK) return FLASH_ERROR; + + // Erase the sector (no need to do so in simulation) + #ifdef TARGET_PYNQ_Z2 + w25q128jw_4k_erase(sector_start_addr); + #endif // TARGET_PYNQ_Z2 + + // Calculate the length of data to write in this sector + uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); + + // Modify the data in RAM to include the new data + memcpy(§or_data[current_addr - sector_start_addr], current_data, write_length); + + // Write the modified data back to the flash (without erasing this time) + status = w25q128jw_write(sector_start_addr, sector_data, FLASH_SECTOR_SIZE, 0); + if (status != FLASH_OK) return FLASH_ERROR; + + // Update the remaining length, address and data pointer + remaining_length -= write_length; + current_addr += write_length; + current_data += write_length; + } + + return FLASH_OK; +} + +static w25q_error_codes_t page_write_wrapper(uint32_t addr, uint8_t *data, uint32_t length, uint8_t quad, uint8_t dma) { + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Pointer arithmetics is not allowed on void pointers + uint8_t *data_8bit = (uint8_t *)data; + + /* + * Set speed and DMA flags. + * Robust implementation: no need to perform safety checks on the flags. + */ + uint8_t speed = quad==1 ? 1 : 0; + uint8_t dma_flag = dma==1 ? 1 : 0; + + /* + * Taking care of misalligned start address. + * If the start address is not aligned to a 256 bytes boundary, + * the first page is written with the first 256 - (addr % 256) bytes. + */ + if (addr % FLASH_PAGE_SIZE != 0) { + uint8_t tmp_len = FLASH_PAGE_SIZE - (addr % FLASH_PAGE_SIZE); + tmp_len = MIN(tmp_len, length); + page_write(addr, data_8bit, tmp_len, speed, dma_flag); + addr += tmp_len; + data_8bit += tmp_len; + length -= tmp_len; + } + + // Check if we already finished + if (length == 0) return FLASH_OK; + + // I cannot program more than a page (256 Bytes) at a time. + int flag = 1; + while (flag) { + if (length > FLASH_PAGE_SIZE) { + page_write(addr, data_8bit, FLASH_PAGE_SIZE, speed, dma_flag); + addr += FLASH_PAGE_SIZE; + data_8bit += FLASH_PAGE_SIZE; + length -= FLASH_PAGE_SIZE; + } else { + page_write(addr, data_8bit, length, speed, dma_flag); + flag = 0; + } + } + return FLASH_OK; +} + +static w25q_error_codes_t page_write(uint32_t addr, uint8_t *data, uint32_t length, uint8_t quad, uint8_t dma) { + // Required every time before issuing a write command + flash_write_enable(); + + /* + * Build and send write command (24bit address + command). + * The command is picked based on the quad flag. + */ + const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | (quad ? FC_PPQ : FC_PP)); + spi_write_word(&spi, write_byte_cmd); + const uint32_t cmd_write = spi_create_command((spi_command_t){ + .len = 3, + .csaat = true, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi, cmd_write); + spi_wait_for_ready(&spi); + + /* + * Place data in TX FIFO + * In simulation it do not wait for the flash to be ready, so we must check + * if the FIFO is full before writing. + */ + if (dma) { + dma_send_toflash(data, length); + } else { + uint32_t *data_32bit = (uint32_t *)data; + for (int i = 0; i < length>>2; i++) { + spi_wait_for_tx_not_full(&spi); + spi_write_word(&spi, data_32bit[i]); + } + if (length % 4 != 0) { + uint32_t last_word = 0; + memcpy(&last_word, &data[length - length % 4], length % 4); + spi_wait_for_tx_not_full(&spi); + spi_write_word(&spi, last_word); + } + } + + /* + * Set up segment parameters -> send data. + * Speed is quad if quad flag is set, standard otherwise. + */ + const uint32_t cmd_write_2 = spi_create_command((spi_command_t){ + .len = length-1, + .csaat = false, + .speed = quad ? kSpiSpeedQuad : kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi, cmd_write_2); + spi_wait_for_ready(&spi); + + // Wait for flash to be ready again (FPGA only) + #ifdef TARGET_PYNQ_Z2 + flash_wait(); + #endif // TARGET_PYNQ_Z2 +} + +static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { + // SPI and SPI_FLASH are the same IP so same register map + uint32_t *fifo_ptr_tx = spi.base_addr.base + SPI_HOST_TXDATA_REG_OFFSET; + + // Init DMA, the integrated DMA is used (peri == NULL) + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH TX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_TX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_TX; + #endif + + // Set up DMA source target + static dma_target_t tgt_src = { + .inc_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, // Data type is word + }; + // Size is in data units (words in this case) + tgt_src.size_du = length>>2; + // Target is data buffer + tgt_src.ptr = data; + // Reads from memory + tgt_src.trig = DMA_TRIG_MEMORY; + + // Set up DMA destination target + static dma_target_t tgt_dst = { + .inc_du = 0, // It's a peripheral, no increment + .type = DMA_DATA_TYPE_WORD, // Data type is word + }; + tgt_dst.trig = slot; + tgt_dst.ptr = (uint8_t*)fifo_ptr_tx; // Target is SPI TX FIFO + + // Set up DMA transaction + static dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_POLLING, + }; + + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + if (res != DMA_CONFIG_OK) return FLASH_ERROR_DMA; + res = dma_load_transaction(&trans); + if (res != DMA_CONFIG_OK) return FLASH_ERROR_DMA; + res = dma_launch(&trans); + if (res != DMA_CONFIG_OK) return FLASH_ERROR_DMA; + + // Wait for DMA to finish transaction + while(!dma_is_ready()); + + // Take into account the extra bytes (if any) + if (length % 4 != 0) { + uint32_t last_word = 0; + memcpy(&last_word, &data[length - length % 4], length % 4); + spi_wait_for_tx_not_full(&spi); + spi_write_word(&spi, last_word); + } + return FLASH_OK; +} + +static void flash_write_enable(void) { + spi_write_word(&spi, FC_WE); + const uint32_t cmd_write_en = spi_create_command((spi_command_t){ + .len = 0, + .csaat = false, + .speed = kSpiSpeedStandard, + .direction = kSpiDirTxOnly + }); + spi_set_command(&spi, cmd_write_en); + spi_wait_for_ready(&spi); +} + +static w25q_error_codes_t w25q128jw_sanity_checks(uint32_t addr, uint8_t *data, uint32_t length) { + // Check if address is out of range + if (addr > MAX_FLASH_ADDR || addr < 0) return FLASH_ERROR; + + // Check if data pointer is NULL + if (data == NULL) return FLASH_ERROR; + + // Check if length is 0 + if (length <= 0) return FLASH_ERROR; + + // Check if current address + length is out of range + if (addr + length > MAX_FLASH_ADDR) return FLASH_ERROR; + + return FLASH_OK; // Success +} + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h new file mode 100644 index 00000000..c6f29e9c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h @@ -0,0 +1,433 @@ +/* + ******************* +******************************* H HEADER FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : w25q128jw.h +** version : 1 +** date : 1/11/2023 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file w25q128jw.h +* @date 13/02/23 +* @brief Header file for the W25Q128JW flash memory. +*/ + +#ifndef W25Q128JW_H +#define W25Q128JW_H + +/****************************************************************************/ +/** **/ +/** MODULES USED **/ +/** **/ +/****************************************************************************/ + +#include "spi_host.h" +#include "soc_ctrl.h" +#include "core_v_mini_mcu.h" + +/****************************************************************************/ +/** **/ +/** DEFINITIONS AND MACROS **/ +/** **/ +/****************************************************************************/ + +/** + * In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) +*/ +#define FLASH_CLK_MAX_HZ (133*1000*1000) + +/** + * @defgroup flash_commands Flash commands + * @{ + */ +#define FC_WE 0x06 /** Write Enable */ +#define FC_SRWE 0x50 /** Volatile SR Write Enable */ +#define FC_WD 0x04 /** Write Disable */ +#define FC_RPD 0xAB /** Release Power-Down, returns Device ID */ +#define FC_MFGID 0x90 /** Read Manufacturer/Device ID */ +#define FC_JEDECID 0x9F /** Read JEDEC ID */ +#define FC_UID 0x4B /** Read Unique ID */ +#define FC_RD 0x03 /** Read Data */ +#define FC_FR 0x0B /** Fast Read */ +#define FC_RDQIO 0xEB /** Fast Read Quad I/O */ +#define FC_PP 0x02 /** Page Program */ +#define FC_PPQ 0x32 /** Quad Input Page Program */ +#define FC_SE 0x20 /** Sector Erase 4kb */ +#define FC_BE32 0x52 /** Block Erase 32kb */ +#define FC_BE64 0xD8 /** Block Erase 64kb */ +#define FC_CE 0xC7 /** Chip Erase */ +#define FC_RSR1 0x05 /** Read Status Register 1 */ +#define FC_WSR1 0x01 /** Write Status Register 1 */ +#define FC_RSR2 0x35 /** Read Status Register 2 */ +#define FC_WSR2 0x31 /** Write Status Register 2 */ +#define FC_RSR3 0x15 /** Read Status Register 3 */ +#define FC_WSR3 0x11 /** Write Status Register 3 */ +#define FC_RSFDP 0x5A /** Read SFDP Register */ +#define FC_ESR 0x44 /** Erase Security Register */ +#define FC_PSR 0x42 /** Program Security Register */ +#define FC_RSR 0x48 /** Read Security Register */ +#define FC_GBL 0x7E /** Global Block Lock */ +#define FC_GBU 0x98 /** Global Block Unlock */ +#define FC_RBL 0x3D /** Read Block Lock */ +#define FC_RPR 0x3C /** Read Sector Protection Registers (adesto) */ +#define FC_IBL 0x36 /** Individual Block Lock */ +#define FC_IBU 0x39 /** Individual Block Unlock */ +#define FC_EPS 0x75 /** Erase / Program Suspend */ +#define FC_EPR 0x7A /** Erase / Program Resume */ +#define FC_PD 0xB9 /** Power-down */ +#define FC_QPI 0x38 /** Enter QPI mode */ +#define FC_ERESET 0x66 /** Enable Reset */ +#define FC_RESET 0x99 /** Reset Device */ +/** @} */ + +/** + * @defgroup error_codes Error codes + * @{ +*/ +#define FLASH_OK 0 /** No error @hideinitializer*/ +#define FLASH_ERROR 1 /** Generic error @hideinitializer*/ +#define FLASH_ERROR_DMA 2 /** DMA error @hideinitializer*/ +/** @} */ + +/** +/** + * @brief Threshold value for switching to DMA in read mode. + * If the number of bytes to be read exceeds this threshold, + * DMA is the more efficient data transfer. + */ +#define RX_DMA_THRESHOLD 75 + +/** + * @brief Threshold value for switching to DMA in write mode. + * If the number of bytes to be wrote exceeds this threshold, + * DMA is the more efficient data transfer. + */ +#define TX_DMA_THRESHOLD 0 + +/** + * @brief Dimension of a flash page, in bytes. +*/ +#define FLASH_PAGE_SIZE 256 + +/** + * @brief Dimension of a flash sector, in bytes. +*/ +#define FLASH_SECTOR_SIZE 4096 + +/** + * @brief Number of dummy clocks cycles required by the simulation model. +*/ +#define DUMMY_CLOCKS_SIM 8 + +/** + * @brief Number of dummy clocks cycles required by the flash during + * fast read quad I/O operations (command code: EBh). +*/ +#define DUMMY_CLOCKS_FAST_READ_QUAD_IO 4 + +/** + * @brief Upper bound for the flash address. +*/ +#define MAX_FLASH_ADDR 0x00ffffff + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/** **/ +/** TYPEDEFS AND STRUCTURES **/ +/** **/ +/****************************************************************************/ + +/** + * @brief Return status type. +*/ +typedef uint8_t w25q_error_codes_t; + +/****************************************************************************/ +/** **/ +/** EXPORTED VARIABLES **/ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/** EXPORTED FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +/** + * @brief Initialize data structure used by crt0 flash_load. + * +*/ +void w25q128jw_init_crt0(); + +/** + * @brief Power up and itialize the flash. + * + * Enable the SPI interface. + * Power up the flash and set the SPI configuration specific to the flash. + * It also set the QE bit in order to accept Quad I/O commands. + * By default both error and event interrupts are disabled. + * + * @param spi_host SPI host to use. + * + * @note The flash uses CSID 0. If the CSID register value is changed, it must be + * restored back to 0 before using the flash again. + * + * @return FLASH_OK if the flash is correctly initialized, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_init(spi_host_t spi_host); + +/** + * @brief Read from flash. + * + * The function automatically uses the best parameters based on + * the current state of the system and the length of the data to read. + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer to be filled. + * @param length number of bytes to read. + * @return FLASH_OK if the read is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Write to flash. + * + * The function automatically uses the best parameters based on + * the current state of the system and the length of the data to write. + * If erase_before_write is set, the function will take care of erasing + * the correct sectors before writing. All the bytes not written will be + * copied back in their current state before the write operation. + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @param erase_before_write if set to 1, the function will take care of erasing + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_write(uint32_t addr, void* data, uint32_t length, uint8_t erase_before_write); + +/** + * @brief Read from flash at standard speed. + * + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer to be filled. + * @param length number of bytes to read. + * @retval FLASH_OK if the read is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t length); + + +/** + * @brief Write to flash at standard speed. Use this function only to write to unitialized data + * + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_write_standard(uint32_t addr, void* data, uint32_t length); + + +/** + * @brief Erase and Write to flash at standard speed. + * + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Read from flash at standard speed using DMA + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to read. + * @return FLASH_OK if the read is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void* data, uint32_t length); + + +/** + * @brief Write to flash at standard speed using DMA. Use this function only to write to unitialized data + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_write_standard_dma(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Erase and Write to flash at standard speed using DMA + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_erase_and_write_standard_dma(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Read from flash at quad speed. + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Write to flash at quad speed. Use this function only to write to unitialized data + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_write_quad(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Erase and Write to flash at quad speed. + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_erase_and_write_quad(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Read from flash at quad speed using DMA. + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Write to flash at quad speed using DMA. Use this function only to write to unitialized data + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_write_quad_dma(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Erase and Write to flash at quad speed using DMA. Use this function only to write to unitialized data + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to write. + * @return FLASH_OK if the write is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_erase_and_write_quad_dma(uint32_t addr, void* data, uint32_t length); + +/** + * @brief Erase a 4kb sector. + * + * Sets all memory within a 4kb sector to the erased state of all 1s (FFh). + * After the erase is issued, waits for the flash to be ready. + * + * @param addr 24-bit address of the sector to erase. +*/ +w25q_error_codes_t w25q128jw_4k_erase(uint32_t addr); + +/** + * @brief Erase a 32kb block. + * + * Sets all memory within a 32kb block to the erased state of all 1s (FFh). + * After the erase is issued, waits for the flash to be ready. + * + * @param addr 24-bit address of the block to erase. +*/ +w25q_error_codes_t w25q128jw_32k_erase(uint32_t addr); + +/** + * @brief Erase a 64kb block. + * + * Sets all memory within a 64kb block to the erased state of all 1s (FFh). + * After the erase is issued, waits for the flash to be ready. + * + * @param addr 24-bit address of the block to erase. +*/ +w25q_error_codes_t w25q128jw_64k_erase(uint32_t addr); + +/** + * @brief Erase the entire chip. + * + * Sets all memory within the chip to the erased state of all 1s (FFh). + * After the erase is issued, waits for the flash to be ready. +*/ +void w25q128jw_chip_erase(void); + + +/** + * @brief Reset the flash. + * + * Before issuing the reset command, the function checks (and eventually wait) + * any ongoing read/write operation in order to preserve data integrity. + * After the reset is issued, wait for the flash to be ready. +*/ +void w25q128jw_reset(void); + +/** + * @brief Reset the flash without checking for ongoing operations. + * + * This function is used to reset the flash when it is not possible to check + * for ongoing operations (e.g. when the flash is not responding). + * Upon receiving the reset command, the flash will abort any ongoing operation. + * After the reset is issued, waits for the flash to be ready. +*/ +void w25q128jw_reset_force(void); + +/** + * @brief Power down the flash. + * + * During power down state, the only command that can be issued is the + * release power down command. All other commands are going to be ignored + * by the flash. +*/ +void w25q128jw_power_down(void); + +/****************************************************************************/ +/** **/ +/** INLINE FUNCTIONS **/ +/** **/ +/****************************************************************************/ +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* W25Q128JW_H */ +/****************************************************************************/ +/** **/ +/** EOF **/ +/** **/ +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S index b5f843ab..82776471 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S @@ -14,11 +14,7 @@ #include "core_v_mini_mcu.h" #include "soc_ctrl_regs.h" -/* In case the operation is to load from FLASH -*/ -#ifdef FLASH_LOAD -#include "spi_host_regs.h" -#endif +#define RAMSIZE_COPIEDBY_BOOTROM 2048 /* Entry point for bare metal programs */ .section .text.start @@ -46,139 +42,69 @@ _start: #endif #ifdef FLASH_LOAD -/* copy the remaining (if any) text and data sections */ + + call w25q128jw_init_crt0 + + // This assumes ram base address is 0x00000000 and the section .text stars from ram0 (in the first RAMSIZE_COPIEDBY_BOOTROM Byte) + li s1, RAMSIZE_COPIEDBY_BOOTROM + li s2, FLASH_MEM_START_ADDRESS + + // copy the remaining (if any) text and data sections // // Setup the in/out pointers and copy size knowing 1KiB as already been copied - li a2, FLASH_MEM_START_ADDRESS # src ptr (flash) - addi a2, a2, 1024 - // This assumes ram base address is 0x00000000 - li s1, 1024 # dst ptr (ram) - la a0, _edata - addi a0, a0, -4 # _edata point to next address, so decrease it by one word - // Skip if everything has already been copied - blt a0, s1, _init_bss - addi a3, a0, -1024 # copy size in bytes (_edata is word aligned, so -1020 to make sure last word is copied) - - li a1, SPI_FLASH_START_ADDRESS - // Spi should already be enabled, powered-up and TXWM to 8 - // Address in byte reversed order (might be useless for the 1KiB address value) - // Highest byte is discarded(address on 3 bytes) - // ((x << 24) | (((x>>16)<<24)>>16) | (((x<<16)>>24)<<16)) - slli a4, a2, 24 - srli s0, a2, 16 - slli s0, s0, 24 - srli s0, s0, 16 - slli a5, a2, 16 - srli a5, a5, 24 - slli a5, a5, 16 - or a4, a4, s0 - or a2, a4, a5 - or a2, a2, 0x03 - sw a2, SPI_HOST_TXDATA_REG_OFFSET(a1) - nop # otherwise ready bit check is too fast - -_wait_spi_ready_read_prog: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - bgez a5, _wait_spi_ready_read_prog - // Read command: 0x11000003 - lui a4, 0x11000 - addi a4, a4, 3 # spi cmd: txonly + stdspeed + csaat + 4B - sw a4, SPI_HOST_COMMAND_REG_OFFSET(a1) - nop # otherwise ready bit check is too fast - -_wait_spi_ready_copy_cmd: - lw a4, SPI_HOST_STATUS_REG_OFFSET(a1) - bgez a4, _wait_spi_ready_copy_cmd - - // For loop until the copy from flash to ram is done - // Try first to do as much as 256-bytes copies as possible - // mv s0, a3 - li s6, 256 - // Read command: 0x90000FF - lui s5, 0x9000 - addi s5, s5, 255 # spi cmd: rxonly + stdspeed + csaat + 255 bytes - -_32B_chunk_loop: - blt s6, a3, _read_32B_chunk - // Read remaining bytes - lui a5, 0x8000 - addi a4, a3, -1 - or a5, a5, a4 # spi cmd: rxonly + stdspeed + remaining bytes (a3-1) - sw a5, SPI_HOST_COMMAND_REG_OFFSET(a1) - nop # otherwise ready bit check is too fast - -_wait_spi_ready_remaining_bytes: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - bgez a5, _wait_spi_ready_remaining_bytes - li s4, 32 - j _last_bytes_read_start - -_read_32B_chunk: - sw s5, SPI_HOST_COMMAND_REG_OFFSET(a1) - nop # otherwise ready bit check is too fast - -_wait_spi_ready_read_32B_chunk: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - bgez a5, _wait_spi_ready_read_32B_chunk - addi s7, s1, 256 # add 32*8 (256 bytes) to dst ptr - -_wait_spi_rxwm_8_words: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - srli a5, a5, 0x14 - andi a5, a5, 1 # SPI_HOST_STATUS_RXWM_BIT - beqz a5, _wait_spi_rxwm_8_words - addi a2, s1, 32 # add 32 bytes (4 words) to dst ptr - -_spi_fifo_read_8_words: - // Read 32B (8 words) from RX FIFO - lw a7, SPI_HOST_RXDATA_REG_OFFSET(a1) - sw a7, 0(s1) - addi s1, s1, 4 - bne s1, a2, _spi_fifo_read_8_words - bne s1, s7, _wait_spi_rxwm_8_words - addi a3, a3, -256 - j _32B_chunk_loop - -_wait_spi_rxwm_8_words_1: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - srli a5, a5, 0x14 - andi a5, a5, 1 # SPI_HOST_STATUS_RXWM_BIT - beqz a5, _wait_spi_rxwm_8_words_1 - addi a2, s1, 32 # add 32 bytes (4 words) to dst ptr - -_spi_fifo_read_8_words_1: - // Read 32B (8 words) from RX FIFO - lw a7, SPI_HOST_RXDATA_REG_OFFSET(a1) - sw a7, 0(s1) - addi s1, s1, 4 - bne s1, a2, _spi_fifo_read_8_words_1 - addi a3, a3, -32 - -_last_bytes_read_start: - bltu s4, a3, _wait_spi_rxwm_8_words_1 - // Update RX watermark with remaining words (<=8) - lw a4, SPI_HOST_CONTROL_REG_OFFSET(a1) - andi a4, a4, -256 # ~SPI_HOST_CONTROL_RX_WATERMARK_MASK - srli a5, a3, 0x2 # 4 bytes = 1 word - or a5, a5, a4 - sw a5, SPI_HOST_CONTROL_REG_OFFSET(a1) - -_wait_spi_rxwm_n_words: - lw a5, SPI_HOST_STATUS_REG_OFFSET(a1) - srli a5, a5, 0x14 - andi a5, a5, 1 # SPI_HOST_STATUS_RXWM_BIT - beqz a5, _wait_spi_rxwm_n_words - -_remaining_bytes_loop: - bnez a3, _spi_read_word - j _init_bss - -_spi_read_word: - lw a7, SPI_HOST_RXDATA_REG_OFFSET(a1) - sw a7, 0(s1) - addi a3, a3, -4 - addi s1, s1, 4 - j _remaining_bytes_loop - + mv a0, s2 // src ptr (flash) + add a0, a0, s1 + + la a1, _etext + // Skip if everything has already been copied, and copy the data section + blt a1, s1, _load_data_section + + // copy size in bytes, i.e. _etext - RAMSIZE_COPIEDBY_BOOTROM + sub a2, a1, s1 + + // dst ptr (ram) + mv a1, s1 + + // copy the remaining data --> w25q128jw_read_standard(a0 is src addr, a1 is dest ptr data, a2 is length) + + // this sub is redundat as we could have simply set a0 to RAMSIZE_COPIEDBY_BOOTROM+0x0, + // but like this is more readable as we set the FLASH address as memory mapped to FLASH_MEM_START_ADDRESS, and then remove the offset + // as required bz the w25q128jw_read_standard function + sub a0,a0,s2 + call w25q128jw_read_standard + +_load_data_section: + // src ptr + la a0, _lma_data_start + // dst ptr + la a1, __data_start + // copy size in bytes + la a2, _lma_data_end + sub a2, a2, a0 + + bltz a2, _load_data_interleaved_section // dont do anything if you do not have data + + sub a0,a0,s2 + call w25q128jw_read_standard + + +_load_data_interleaved_section: + #ifdef HAS_MEMORY_BANKS_IL + // src ptr + la a0, _lma_data_interleaved_start + // dst ptr + la a1, __data_interleaved_start + // copy size in bytes + la a2, _lma_data_interleaved_end + sub a2, a2, a0 + + bltz a2, _init_bss // dont do anything if you do not have interleaved data + + sub a0,a0,s2 + call w25q128jw_read_standard + #endif + +#endif + /* clear the bss segment */ _init_bss: la a0, __bss_start @@ -186,14 +112,6 @@ _init_bss: sub a2, a2, a0 li a1, 0 call memset -#else -/* clear the bss segment */ - la a0, __bss_start - la a2, __bss_end - sub a2, a2, a0 - li a1, 0 - call memset -#endif #ifdef FLASH_EXEC /* copy initialized data sections from flash to ram (to be verified, copied from picosoc)*/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c index c30b6105..d0b977d2 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c @@ -562,7 +562,7 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * No further operations are done to prevent corrupting information * that could be useful for debugging purposes. */ - uint8_t isEnv = p_trans->dst->env; + uint8_t isEnv = (p_trans->dst->env != NULL); uint8_t isOutb = is_region_outbound( p_trans->dst->ptr, p_trans->dst->env->end, @@ -689,35 +689,21 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans ) /* * SET THE POINTERS */ - dma_cb.peri->SRC_PTR = dma_cb.trans->src->ptr; + dma_cb.peri->SRC_PTR = (uint32_t)dma_cb.trans->src->ptr; if(dma_cb.trans->mode != DMA_TRANS_MODE_ADDRESS) { /* - Write to the destination pointers only if we are not in address mode, - otherwise the destination address is read in a separate port in parallel with the data - from the address port + Write to the destination pointers only if we are not in address mode, + otherwise the destination address is read in a separate port in parallel with the data + from the address port */ - dma_cb.peri->DST_PTR = dma_cb.trans->dst->ptr; - } - else - { - dma_cb.peri->ADDR_PTR = dma_cb.trans->src_addr->ptr; - } - - if(dma_cb.trans->mode != DMA_TRANS_MODE_ADDRESS) + dma_cb.peri->DST_PTR = (uint32_t)dma_cb.trans->dst->ptr; + } + else { - /* - Write to the destination pointers only if we are not in address mode, - otherwise the destination address is read in a separate port in parallel with the data - from the address port - */ - dma_cb.peri->DST_PTR = dma_cb.trans->dst->ptr; - } - else - { - dma_cb.peri->ADDR_PTR = dma_cb.trans->src_addr->ptr; - } + dma_cb.peri->ADDR_PTR = (uint32_t)dma_cb.trans->src_addr->ptr; + } /* * SET THE INCREMENTS @@ -1107,7 +1093,7 @@ static inline uint8_t is_region_outbound( uint8_t *p_start, */ uint32_t affectedUnits = ( p_size_du - 1 ) * p_inc_du + 1; uint32_t rangeSize = DMA_DATA_TYPE_2_SIZE(p_type) * affectedUnits; - uint32_t lasByteInsideRange = p_start + rangeSize -1; + uint32_t lasByteInsideRange = (uint32_t)p_start + rangeSize -1; return ( p_end < lasByteInsideRange ); // Size is be guaranteed to be non-zero before calling this function. } @@ -1166,4 +1152,4 @@ static inline uint32_t get_increment_b( dma_target_t * p_tgt ) /** **/ /* EOF */ /** **/ -/****************************************************************************/ \ No newline at end of file +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h index 1956f9e8..85ee6475 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h @@ -104,6 +104,8 @@ typedef enum DMA_TRIG_SLOT_SPI_FLASH_RX = 4, /*!< Slot 3 (MEM < SPI FLASH). */ DMA_TRIG_SLOT_SPI_FLASH_TX = 8, /*!< Slot 4 (MEM > SPI FLASH). */ DMA_TRIG_SLOT_I2S = 16,/*!< Slot 5 (I2S). */ + DMA_TRIG_SLOT_EXT_TX = 32,/*!< Slot 6 (External peripherals TX). */ + DMA_TRIG_SLOT_EXT_RX = 64,/*!< Slot 7 (External peripherals RX). */ DMA_TRIG__size, /*!< Not used, only for sanity checks. */ DMA_TRIG__undef, /*!< DMA will not be used. */ } dma_trigger_slot_mask_t; @@ -463,4 +465,4 @@ uint8_t dma_window_ratio_warning_threshold(void); /** **/ /** EOF **/ /** **/ -/****************************************************************************/ \ No newline at end of file +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c index 3e733ecd..f5cb004f 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c @@ -150,7 +150,7 @@ gpio_result_t gpio_assign_irq_handler( uint32_t intr_id, { if( intr_id >= GPIO_INTR_START && intr_id <= GPIO_INTR_END ) { - gpio_handlers[ intr_id - GPIO_INTR_START ] = handler; + gpio_handlers[ intr_id - GPIO_INTR_START ] = (void (*)(void))handler; return GpioOk; } return GpioError; @@ -160,7 +160,7 @@ void gpio_reset_handlers_list( ) { for( uint8_t i = 0; i < GPIO_INTR_QTY; i++ ) { - gpio_handlers[ i ] = &gpio_handler_irq_dummy; + gpio_handlers[ i ] = (void (*)(void))&gpio_handler_irq_dummy; } } diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo.h new file mode 100644 index 00000000..03ec588a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo.h @@ -0,0 +1,56 @@ +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : x-heep ** +** filename : i2s.h ** +** date : 28/10/2023 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL contributors. ** +** All rights reserved. ** +** ** +***************************************************************************** + +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file iffifo.h +* @date 28/10/2023 +* @author Pierre Guillod +* @brief HAL of the IFFIFO peripheral +* +*/ + +#ifndef _DRIVERS_IFFIFO_H_ +#define _DRIVERS_IFFIFO_H_ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void handler_irq_iffifo(uint32_t id); + +#ifdef __cplusplus +} +#endif + +#endif // _DRIVERS_IFFIFO_H_ + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo_regs.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo_regs.h new file mode 100644 index 00000000..6acd3aa8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/iffifo/iffifo_regs.h @@ -0,0 +1,47 @@ +// Generated register defines for iffifo + +// Copyright information found in source file: +// Copyright EPFL contributors. + +// Licensing information found in source file: +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _IFFIFO_REG_DEFS_ +#define _IFFIFO_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif +// Register width +#define IFFIFO_PARAM_REG_WIDTH 32 + +// Data coming from the FIFO (Fifo Output/Software RX) +#define IFFIFO_FIFO_OUT_REG_OFFSET 0x0 + +// Data sent to the FIFO (Fifo Input/Software TX) +#define IFFIFO_FIFO_IN_REG_OFFSET 0x4 + +// General purpose status register +#define IFFIFO_STATUS_REG_OFFSET 0x8 +#define IFFIFO_STATUS_EMPTY_BIT 0 +#define IFFIFO_STATUS_AVAILABLE_BIT 1 +#define IFFIFO_STATUS_REACHED_BIT 2 +#define IFFIFO_STATUS_FULL_BIT 3 + +// Current number of occupied FIFO slots +#define IFFIFO_OCCUPANCY_REG_OFFSET 0xc + +// FIFO occupancy at which the STATUS:REACHED bit is asserted +#define IFFIFO_WATERMARK_REG_OFFSET 0x10 + +// Write any value to assert an interrupt. Write 0 or 1 to disable or enable +// an interrupt. +#define IFFIFO_INTERRUPTS_REG_OFFSET 0x14 +#define IFFIFO_INTERRUPTS_REACHED_BIT 0 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _IFFIFO_REG_DEFS_ +// End generated register defines for iffifo \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c index 7b6ba5f4..ffbb822d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c @@ -371,7 +371,7 @@ plic_result_t plic_assign_external_irq_handler( uint32_t id, { if( id >= EXT_IRQ_START && id <= QTY_INTR ) { - handlers[ id ] = (handler_funct_t*) handler; + handlers[ id ] = (handler_funct_t) handler; return kPlicOk; } return kPlicBadArg; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h index b5db646d..af81fe21 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h @@ -302,6 +302,15 @@ static inline __attribute__((always_inline)) void spi_wait_for_tx_not_empty(cons while (mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXEMPTY_BIT)); } +/** + * Wait TX FIFO not full. + * + * @param spi Pointer to spi_host_t representing the target SPI. + */ +static inline __attribute__((always_inline)) void spi_wait_for_tx_not_full(const spi_host_t *spi) { + while (mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXFULL_BIT)); +} + /** * Wait RX FIFO reach watermark. * diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.c new file mode 100644 index 00000000..326fd963 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.c @@ -0,0 +1,37 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include "core_v_mini_mcu.h" +#include + +//heep functions prototypes +uint32_t * heep_get_flash_address_offset(uint32_t* data_address_lma); +void heep_init_lfsr(); +uint32_t heep_rand_lfsr(); + +// this translates the logical address of the FLASH relative to 0 instead of FLASH_MEM_START_ADDRESS, as used by the BSP +uint32_t * heep_get_flash_address_offset(uint32_t* data_address_lma){ + +#ifdef ON_CHIP + // no need to translate as FLASH is not memory mapped + return data_address_lma; +#else + uint32_t* data_address_adjusted = (uint32_t*) ((uint32_t)(data_address_lma) - FLASH_MEM_START_ADDRESS); + return data_address_adjusted; +#endif + +} + +//get random values +uint32_t lfsr; + +void heep_init_lfsr() { + lfsr = (uint32_t)0xAABBCCDD; +} + +uint32_t heep_rand_lfsr() { + uint32_t bit = (lfsr ^ (lfsr >> 10) ^ (lfsr >> 11) ^ (lfsr >> 12)) & 1; + lfsr = (lfsr >> 1) | (bit << 31); + return lfsr; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl index 1491a6ed..2bfec7d9 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl @@ -10,6 +10,9 @@ extern "C" { #endif // __cplusplus #define MEMORY_BANKS ${ram_numbanks} +% if ram_numbanks_il > 0: +#define HAS_MEMORY_BANKS_IL +% endif #define EXTERNAL_DOMAINS ${external_domains} @@ -67,6 +70,7 @@ extern "C" { #define GPIO_AO_DOMAIN_LIMIT 8 + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c index 8ee1a0d8..c9cd02d3 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c @@ -3,9 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "handler.h" - #include "csr.h" #include "stdasm.h" +#include ' /** * Return value of mtval diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c index 05dd28f9..a9a7fcc2 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c @@ -18,33 +18,41 @@ */ #include +#include #include #include +#include #include #include "uart.h" #include "soc_ctrl.h" #include "core_v_mini_mcu.h" #include "error.h" #include "x-heep.h" +#include #undef errno extern int errno; #define STDOUT_FILENO 1 -/* It turns out that older newlib versions use different symbol names which goes - * against newlib recommendations. Anyway this is fixed in later version. - */ -#if __NEWLIB__ <= 2 && __NEWLIB_MINOR__ <= 5 -# define _sbrk sbrk -# define _write write -# define _close close -# define _lseek lseek -# define _read read -# define _fstat fstat -# define _isatty isatty +#ifndef _LIBC +/* Provide prototypes for most of the _ names that are + provided in newlib for some compilers. */ +int _close (int __fildes); +pid_t _fork (void); +pid_t _getpid (void); +int _isatty (int __fildes); +int _link (const char *__path1, const char *__path2); +_off_t _lseek (int __fildes, _off_t __offset, int __whence); +ssize_t _read (int __fd, void *__buf, size_t __nbyte); +void * _sbrk (ptrdiff_t __incr); +int _unlink (const char *__path); +ssize_t _write (int __fd, const void *__buf, size_t __nbyte); +int _execve (const char *__path, char * const __argv[], char * const __envp[]); +int _kill (pid_t pid, int sig); #endif + void unimplemented_syscall() { const char *p = "Unimplemented system call called!\n"; @@ -108,7 +116,7 @@ int _faccessat(int dirfd, const char *file, int mode, int flags) return -1; } -int _fork(void) +pid_t _fork(void) { errno = EAGAIN; return -1; @@ -140,7 +148,7 @@ char *_getcwd(char *buf, size_t size) return NULL; } -int _getpid() +pid_t _getpid() { return 1; } @@ -156,7 +164,7 @@ int _isatty(int file) return (file == STDOUT_FILENO); } -int _kill(int pid, int sig) +int _kill(pid_t pid, int sig) { errno = EINVAL; return -1; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h new file mode 100644 index 00000000..c1ef5c5c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h @@ -0,0 +1,30 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef X_HEEP +#define X_HEEP + +#pragma message ( "the x-heep.h for NEXYS-A7-100T is used" ) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +#define REFERENCE_CLOCK_Hz 15*1000*1000 +#define UART_BAUDRATE 9600 +#define TARGET_NEXYS_A7_100T 1 + +/** + * As the hw is configurable, we can have setups with different number of + * Gpio pins + */ +#define MAX_PIN 32 + + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // X_HEEP diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/systemc/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/systemc/x-heep.h new file mode 100644 index 00000000..1c1390cb --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/systemc/x-heep.h @@ -0,0 +1,30 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef X_HEEP +#define X_HEEP + +#pragma message ( "the x-heep.h for SIMULATION in SYSTEMC is used" ) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +#define REFERENCE_CLOCK_Hz 100*1000*1000 +#define UART_BAUDRATE 256000 +#define TARGET_SYSTEMC 1 + +/** + * As the hw is configurable, we can have setups with different number of + * Gpio pins + */ +#define MAX_PIN 32 + + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // X_HEEP diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h new file mode 100644 index 00000000..af1b4cd5 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h @@ -0,0 +1,28 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef X_HEEP +#define X_HEEP + +#pragma message ( "the x-heep.h for ZCU104 is used" ) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define REFERENCE_CLOCK_Hz 15*1000*1000 +#define UART_BAUDRATE 9600 +#define TARGET_ZCU104 1 + +/** + * As the hw is configurable, we can have setups with different number of + * Gpio pins + */ +#define MAX_PIN 32 + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // X_HEEP diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl index 98f491ce..7403248d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl @@ -24,7 +24,7 @@ MEMORY ram1 (rwxai) : ORIGIN = 0x${linker_onchip_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} % if ram_numbanks_cont > 1 and ram_numbanks_il > 0: ram_il (rwxai) : ORIGIN = 0x${linker_onchip_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} -% endif +% endif } /* @@ -38,51 +38,13 @@ SECTIONS PROVIDE(__boot_address = 0x180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x800; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x800; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS; - /* We don't do any dynamic linking so we remove everything related to it */ -/* - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) - *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) - *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) - *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rela_iplt_start = .); - *(.rela.iplt) - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rela.plt : - { - *(.rela.plt) - } -*/ - /* interrupt vectors */ .vectors (ORIGIN(ram0)): { @@ -97,11 +59,6 @@ SECTIONS KEEP (*(.text.start)) } >ram0 - /* More dynamic linking sections */ -/* - .plt : { *(.plt) } - .iplt : { *(.iplt) } -*/ /* the bulk of the program: main, libc, functions etc. */ .text : @@ -268,6 +225,8 @@ SECTIONS *(.data1) } >ram1 + _lma_vma_data_offset = 0x0; + /* no dynamic linking, no object tables required */ /* .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } */ @@ -335,12 +294,14 @@ SECTIONS PROVIDE(__freertos_irq_stack_top = .); } >ram1 -.data_interleaved : +% if ram_numbanks_cont > 1 and ram_numbanks_il > 0: + .data_interleaved : { . = ALIGN(4); *(.xheep_data_interleaved) . = ALIGN(4); } >ram_il +% endif /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl index f8e0f83f..8bd9e64e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl @@ -17,9 +17,9 @@ SECTIONS { PROVIDE(__boot_address = 0x40000180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x1000; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x1000; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* interrupt vectors */ .vectors (ORIGIN(FLASH)): @@ -70,6 +70,8 @@ SECTIONS { _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ } >RAM AT >FLASH + _lma_vma_data_offset = 0x0; + .power_manager : ALIGN(4096) { PROVIDE(__power_manager_start = .); diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl index a33ca3dd..541b2233 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl @@ -7,47 +7,70 @@ ENTRY(_start) MEMORY { - FLASH (rx) : ORIGIN = 0x${flash_mem_start_address}, LENGTH = 0x${flash_mem_size_address} - RAM (xrw) : ORIGIN = 0x${'{:08X}'.format(int(ram_start_address,16))}, LENGTH = 0x${'{:08X}'.format(int(ram_size_address,16) - 4)} + ram0 (rwxai) : ORIGIN = 0x${linker_onchip_code_start_address}, LENGTH = 0x${linker_onchip_code_size_address} + ram1 (rwxai) : ORIGIN = 0x${linker_onchip_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} + FLASH0 (rx) : ORIGIN = 0x${linker_flash_code_start_address}, LENGTH = 0x${linker_onchip_code_size_address} + FLASH1 (rx) : ORIGIN = 0x${linker_flash_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} + % if ram_numbanks_cont > 1 and ram_numbanks_il > 0: + ram_il (rwxai) : ORIGIN = 0x${linker_onchip_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} + FLASH_il (rx) : ORIGIN = 0x${linker_flash_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} + % endif + FLASH_left (rx) : ORIGIN = 0x${linker_flash_left_start_address}, LENGTH = 0x${linker_flash_left_size_address} } + + SECTIONS { /* we want a fixed entry point */ PROVIDE(__boot_address = 0x180); /* stack and heap related settings */ - __stack_size = DEFINED(__stack_size) ? __stack_size : 0x1000; + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x${stack_size}; PROVIDE(__stack_size = __stack_size); - __heap_size = DEFINED(__heap_size) ? __heap_size : 0x1000; + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x${heap_size}; /* interrupt vectors */ - .vectors (ORIGIN(RAM)): + .vectors (ORIGIN(ram0)): { PROVIDE(__vector_start = .); + _lma_text_start = LOADADDR(.vectors); KEEP(*(.vectors)); __VECTORS_AT = .; - } >RAM AT >FLASH + } >ram0 AT >FLASH0 /* Fill memory up to __boot_address */ .fill : { FILL(0xDEADBEEF); - . = ORIGIN(RAM) + (__boot_address) - 1; + . = ORIGIN(ram0) + (__boot_address) - 1; BYTE(0xEE) - } >RAM AT >FLASH + } >ram0 AT >FLASH0 /* crt0 init code */ .init (__boot_address): { KEEP (*(SORT_NONE(.init))) KEEP (*(.text.start)) - } >RAM AT >FLASH + KEEP (*(.text.w25q128jw_init_crt0)) + KEEP (*(.text.w25q128jw_sanity_checks)) + KEEP (*(.text.spi_write_word*)) + KEEP (*(.text.spi_wait_for_ready*)) + KEEP (*(.text.spi_create_command*)) + KEEP (*(.text.spi_set_command*)) + KEEP (*(.text.spi_set_rx_watermark*)) + KEEP (*(.text.spi_wait_for_rx_watermark*)) + KEEP (*(.text.spi_read_word*)) + KEEP (*(.text.memcpy)) + KEEP (*(.text.w25q128jw_read_standard)) /* as this function is used in the crt0, link it in the top, should be before 1024 Bytes loaded by the bootrom */ + *(.xheep_init_data_crt0) /* this global variables are used in the crt0 */ + } >ram0 AT >FLASH0 /* The program code and other data goes into FLASH */ .text : ALIGN_WITH_INPUT { . = ALIGN(4); + __text_start = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ @@ -56,16 +79,17 @@ SECTIONS { *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(4); _etext = .; /* define a global symbol at end of code */ - } >RAM AT >FLASH + } >ram0 AT >FLASH0 /* This is the initialized data section The program executes knowing that the data is in the RAM but the loader puts the initial values in the FLASH (inidata). It is one task of the startup to copy the initial values from FLASH to RAM. */ - .data : ALIGN_WITH_INPUT + .data : ALIGN(256) { - . = ALIGN(4); + __data_start = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ _sidata = LOADADDR(.data); + _lma_data_start = LOADADDR(.data); _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ _ram_start = .; /* create a global symbol at ram start for garbage collector */ . = ALIGN(4); @@ -75,18 +99,20 @@ SECTIONS { __SDATA_BEGIN__ = .; *(.sdata) /* .sdata sections */ *(.sdata*) /* .sdata* sections */ - . = ALIGN(4); - _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ - } >RAM AT >FLASH + } >ram1 AT >FLASH1 + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ - .power_manager : ALIGN(4096) + .power_manager : ALIGN_WITH_INPUT { + . = ALIGN(4); PROVIDE(__power_manager_start = .); . += 256; - } >RAM + } >ram1 AT >FLASH1 /* Uninitialized data section */ - .bss : + .bss : ALIGN_WITH_INPUT { . = ALIGN(4); __bss_start = .; /* define a global symbol at bss start; used by startup code */ @@ -99,7 +125,14 @@ SECTIONS { . = ALIGN(4); __bss_end = .; /* define a global symbol at bss end; used by startup code */ __BSS_END__ = .; - } >RAM + } >ram1 AT >FLASH1 + + _lma_data_end = _lma_data_start + SIZEOF(.data) + SIZEOF(.power_manager) + SIZEOF(.bss); + _lma_vma_data_offset = _lma_data_start - __data_start; + + _lma_text_end = _lma_text_start + SIZEOF(.vectors) + SIZEOF(.init) + SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.power_manager) + SIZEOF(.bss); + _lma_text_vma_offset = _lma_text_start - __vector_start; + /* The compiler uses this to access data in the .sdata, .data, .sbss and .bss sections with fewer instructions (relaxation). This reduces code size. */ @@ -112,7 +145,7 @@ SECTIONS { PROVIDE(__heap_start = .); . = __heap_size; PROVIDE(__heap_end = .); - } >RAM + } >ram1 /* stack: we should consider putting this further to the top of the address space */ @@ -123,5 +156,29 @@ SECTIONS { PROVIDE(_sp = .); PROVIDE(__stack_end = .); PROVIDE(__freertos_irq_stack_top = .); - } >RAM + } >ram1 + + % if ram_numbanks_cont > 1 and ram_numbanks_il > 0: + .data_interleaved : ALIGN_WITH_INPUT + { + PROVIDE(__data_interleaved_start = .); + _lma_data_interleaved_start = LOADADDR(.data_interleaved); + . = ALIGN(4); + *(.xheep_data_interleaved) + . = ALIGN(4); + } >ram_il AT >FLASH_il + + . = ALIGN(4); + _eddata_interleaved = .; + _lma_data_interleaved_end = _lma_data_interleaved_start + SIZEOF(.data_interleaved); + + % endif + + .data_flash_only : ALIGN(256) + { + . = ALIGN(4); + *(.xheep_data_flash_only) + . = ALIGN(4); + } >FLASH_left + } diff --git a/hw/vendor/esl_epfl_x_heep/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch b/hw/vendor/esl_epfl_x_heep/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch index b325b7bc..1af9cacb 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch +++ b/hw/vendor/esl_epfl_x_heep/sw/vendor/patches/yosyshq_icestorm/0001-Add-flash-prgraner-iceprog-custom-for-heep-with-gpio.patch @@ -1,8 +1,43 @@ diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c -index 8ee6443..38e308f 100644 +index 8ee6443..0413697 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c -@@ -506,6 +506,7 @@ static void help(const char *progname) +@@ -480,6 +480,34 @@ static void flash_enable_quad() + fprintf(stderr, "SR2: %08x\n", data[1]); + } + ++static void flash_disable_quad() ++{ ++ fprintf(stderr, "Disabling Quad operation...\n"); ++ ++ // Allow write ++ flash_write_enable(); ++ ++ // Write Status Register 2 <- 0x00 ++ uint8_t data[2] = { FC_WSR2, 0x00 }; ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ flash_wait(); ++ ++ // Read Status Register 1 ++ data[0] = FC_RSR2; ++ ++ flash_chip_select(); ++ mpsse_xfer_spi(data, 2); ++ flash_chip_deselect(); ++ ++ if ((data[1] & 0x02) != 0x00) ++ fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); ++ ++ fprintf(stderr, "SR2: %08x\n", data[1]); ++} ++ + // --------------------------------------------------------- + // iceprog implementation + // --------------------------------------------------------- +@@ -506,11 +534,13 @@ static void help(const char *progname) fprintf(stderr, " -s slow SPI (50 kHz instead of 6 MHz)\n"); fprintf(stderr, " -k keep flash in powered up state (i.e. skip power down command)\n"); fprintf(stderr, " -v verbose output\n"); @@ -10,25 +45,61 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " -i [4,32,64] select erase block size [default: 64k]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Mode of operation:\n"); -@@ -587,6 +588,8 @@ int main(int argc, char **argv) + fprintf(stderr, " [default] write file contents to flash, then verify\n"); + fprintf(stderr, " -X write file contents to flash only\n"); ++ fprintf(stderr, " -a provides file size of the file to program\n"); + fprintf(stderr, " -r read first 256 kB from flash and write to file\n"); + fprintf(stderr, " -R read the specified number of bytes from flash\n"); + fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n"); +@@ -578,6 +608,7 @@ int main(int argc, char **argv) + bool bulk_erase = false; + bool dont_erase = false; + bool prog_sram = false; ++ bool filesize_mode = false; + int test_mode = 0; + bool slow_clock = false; + bool disable_protect = false; +@@ -587,6 +618,9 @@ int main(int argc, char **argv) const char *devstr = NULL; int ifnum = 0; + bool stop_spi = false; ++ long file_size = -1; + #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); -@@ -600,7 +603,7 @@ int main(int argc, char **argv) +@@ -600,7 +634,7 @@ int main(int argc, char **argv) /* Decode command line parameters */ int opt; char *endptr; - while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStQvspXk", long_options, NULL)) != -1) { -+ while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStQvTspXk", long_options, NULL)) != -1) { ++ while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:a:cbnStQvTspXk", long_options, NULL)) != -1) { switch (opt) { case 'd': /* device string */ devstr = optarg; -@@ -696,6 +699,9 @@ int main(int argc, char **argv) +@@ -648,6 +682,20 @@ int main(int argc, char **argv) + return EXIT_FAILURE; + } + break; ++ case 'a': /* filesize used to program flash */ ++ filesize_mode = true; ++ file_size = strtol(optarg, &endptr, 0); ++ if (*endptr == '\0') ++ /* ok */; ++ else if (!strcmp(endptr, "k")) ++ file_size *= 1024; ++ else if (!strcmp(endptr, "M")) ++ file_size *= 1024 * 1024; ++ else { ++ fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg); ++ return EXIT_FAILURE; ++ } ++ break; + case 'e': /* Erase blocks as if we were writing n bytes */ + erase_mode = true; + erase_size = strtol(optarg, &endptr, 0); +@@ -696,6 +744,9 @@ int main(int argc, char **argv) case 'v': /* provide verbose output */ verbose = true; break; @@ -38,7 +109,46 @@ index 8ee6443..38e308f 100644 case 's': /* use slow SPI clock */ slow_clock = true; break; -@@ -997,22 +1003,59 @@ int main(int argc, char **argv) +@@ -778,7 +829,7 @@ int main(int argc, char **argv) + so we can fail before initializing the hardware */ + + FILE *f = NULL; +- long file_size = -1; ++ + + if (test_mode) { + /* nop */; +@@ -809,7 +860,7 @@ int main(int argc, char **argv) + named pipe, or contrarily, the standard input may be an + ordinary file. */ + +- if (!prog_sram && !check_mode) { ++ if (!prog_sram && !check_mode && !filesize_mode) { + if (fseek(f, 0L, SEEK_END) != -1) { + file_size = ftell(f); + if (file_size == -1) { +@@ -943,6 +994,8 @@ int main(int argc, char **argv) + flash_reset(); + flash_power_up(); + ++ flash_disable_quad(); ++ + flash_read_id(); + + +@@ -968,7 +1021,10 @@ int main(int argc, char **argv) + } + else + { +- fprintf(stderr, "file size: %ld\n", file_size); ++ if(filesize_mode) ++ fprintf(stderr, "provided file size: %ld\n", file_size); ++ else ++ fprintf(stderr, "file size: %ld\n", file_size); + + int block_size = erase_block_size << 10; + int block_mask = block_size - 1; +@@ -997,22 +1053,59 @@ int main(int argc, char **argv) } } @@ -62,7 +172,7 @@ index 8ee6443..38e308f 100644 + size_t len = 0; + uint8_t buffer[256]; + int count = 0; -+ while (true) { ++ while (true) { + rc = getline(&line_buffer, &len, f); + if (rc <= 0){ + if(count > 0){ @@ -107,20 +217,22 @@ index 8ee6443..38e308f 100644 fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); -@@ -1026,6 +1069,12 @@ int main(int argc, char **argv) +@@ -1026,7 +1119,13 @@ int main(int argc, char **argv) // --------------------------------------------------------- if (read_mode) { +- fprintf(stderr, "reading..\n"); + if(stop_spi){ + /* Just to debug reading of values with the logic analyzer*/ + printf("Stoped before writting. Press ENTER to continue\n"); + getchar(); + } + - fprintf(stderr, "reading..\n"); ++ fprintf(stderr, "reading.."); for (int addr = 0; addr < read_size; addr += 256) { uint8_t buffer[256]; -@@ -1037,23 +1086,40 @@ int main(int argc, char **argv) + fprintf(stderr, " \r"); +@@ -1037,23 +1136,40 @@ int main(int argc, char **argv) fprintf(stderr, " \r"); fprintf(stderr, "done.\n"); } else if (!erase_mode && !disable_verify) { @@ -134,7 +246,7 @@ index 8ee6443..38e308f 100644 + int rc, addr = 0; + size_t len = 0; + uint8_t buffer_flash[256], buffer_file[256]; -+ while (true) { ++ while (true) { + rc = getline(&line_buffer, &len, f); if (rc <= 0) break; diff --git a/hw/vendor/esl_epfl_x_heep/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c b/hw/vendor/esl_epfl_x_heep/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c index 38e308f8..0413697d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c +++ b/hw/vendor/esl_epfl_x_heep/sw/vendor/yosyshq_icestorm/iceprog/iceprog.c @@ -480,6 +480,34 @@ static void flash_enable_quad() fprintf(stderr, "SR2: %08x\n", data[1]); } +static void flash_disable_quad() +{ + fprintf(stderr, "Disabling Quad operation...\n"); + + // Allow write + flash_write_enable(); + + // Write Status Register 2 <- 0x00 + uint8_t data[2] = { FC_WSR2, 0x00 }; + flash_chip_select(); + mpsse_xfer_spi(data, 2); + flash_chip_deselect(); + + flash_wait(); + + // Read Status Register 1 + data[0] = FC_RSR2; + + flash_chip_select(); + mpsse_xfer_spi(data, 2); + flash_chip_deselect(); + + if ((data[1] & 0x02) != 0x00) + fprintf(stderr, "failed to set QE=0, SR2 now equal to 0x%02x (expected 0x%02x)\n", data[1], data[1] | 0x00); + + fprintf(stderr, "SR2: %08x\n", data[1]); +} + // --------------------------------------------------------- // iceprog implementation // --------------------------------------------------------- @@ -512,6 +540,7 @@ static void help(const char *progname) fprintf(stderr, "Mode of operation:\n"); fprintf(stderr, " [default] write file contents to flash, then verify\n"); fprintf(stderr, " -X write file contents to flash only\n"); + fprintf(stderr, " -a provides file size of the file to program\n"); fprintf(stderr, " -r read first 256 kB from flash and write to file\n"); fprintf(stderr, " -R read the specified number of bytes from flash\n"); fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n"); @@ -579,6 +608,7 @@ int main(int argc, char **argv) bool bulk_erase = false; bool dont_erase = false; bool prog_sram = false; + bool filesize_mode = false; int test_mode = 0; bool slow_clock = false; bool disable_protect = false; @@ -589,6 +619,7 @@ int main(int argc, char **argv) int ifnum = 0; bool stop_spi = false; + long file_size = -1; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); @@ -603,7 +634,7 @@ int main(int argc, char **argv) /* Decode command line parameters */ int opt; char *endptr; - while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStQvTspXk", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:a:cbnStQvTspXk", long_options, NULL)) != -1) { switch (opt) { case 'd': /* device string */ devstr = optarg; @@ -651,6 +682,20 @@ int main(int argc, char **argv) return EXIT_FAILURE; } break; + case 'a': /* filesize used to program flash */ + filesize_mode = true; + file_size = strtol(optarg, &endptr, 0); + if (*endptr == '\0') + /* ok */; + else if (!strcmp(endptr, "k")) + file_size *= 1024; + else if (!strcmp(endptr, "M")) + file_size *= 1024 * 1024; + else { + fprintf(stderr, "%s: `%s' is not a valid size\n", my_name, optarg); + return EXIT_FAILURE; + } + break; case 'e': /* Erase blocks as if we were writing n bytes */ erase_mode = true; erase_size = strtol(optarg, &endptr, 0); @@ -784,7 +829,7 @@ int main(int argc, char **argv) so we can fail before initializing the hardware */ FILE *f = NULL; - long file_size = -1; + if (test_mode) { /* nop */; @@ -815,7 +860,7 @@ int main(int argc, char **argv) named pipe, or contrarily, the standard input may be an ordinary file. */ - if (!prog_sram && !check_mode) { + if (!prog_sram && !check_mode && !filesize_mode) { if (fseek(f, 0L, SEEK_END) != -1) { file_size = ftell(f); if (file_size == -1) { @@ -949,6 +994,8 @@ int main(int argc, char **argv) flash_reset(); flash_power_up(); + flash_disable_quad(); + flash_read_id(); @@ -974,7 +1021,10 @@ int main(int argc, char **argv) } else { - fprintf(stderr, "file size: %ld\n", file_size); + if(filesize_mode) + fprintf(stderr, "provided file size: %ld\n", file_size); + else + fprintf(stderr, "file size: %ld\n", file_size); int block_size = erase_block_size << 10; int block_mask = block_size - 1; @@ -1018,7 +1068,7 @@ int main(int argc, char **argv) size_t len = 0; uint8_t buffer[256]; int count = 0; - while (true) { + while (true) { rc = getline(&line_buffer, &len, f); if (rc <= 0){ if(count > 0){ @@ -1075,7 +1125,7 @@ int main(int argc, char **argv) getchar(); } - fprintf(stderr, "reading..\n"); + fprintf(stderr, "reading.."); for (int addr = 0; addr < read_size; addr += 256) { uint8_t buffer[256]; fprintf(stderr, " \r"); @@ -1093,7 +1143,7 @@ int main(int argc, char **argv) int rc, addr = 0; size_t len = 0; uint8_t buffer_flash[256], buffer_file[256]; - while (true) { + while (true) { rc = getline(&line_buffer, &len, f); if (rc <= 0) break; diff --git a/hw/vendor/esl_epfl_x_heep/tb/XHEEP_CmdLineOptions.cpp b/hw/vendor/esl_epfl_x_heep/tb/XHEEP_CmdLineOptions.cpp new file mode 100644 index 00000000..947d31ef --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/XHEEP_CmdLineOptions.cpp @@ -0,0 +1,100 @@ +#include "XHEEP_CmdLineOptions.hh" +#include +#include + +XHEEP_CmdLineOptions::XHEEP_CmdLineOptions(int argc, char* argv[]) // define default constructor +{ + this->argc = argc; + this->argv = argv; +} + +std::string XHEEP_CmdLineOptions::getCmdOption(int argc, char* argv[], const std::string& option) +{ + std::string cmd; + for( int i = 0; i < argc; ++i) + { + std::string arg = argv[i]; + size_t arg_size = arg.length(); + size_t option_size = option.length(); + + if(arg.find(option)==0){ + cmd = arg.substr(option_size,arg_size-option_size); + } + } + return cmd; +} + +bool XHEEP_CmdLineOptions::get_use_openocd() +{ + + std::string arg_openocd = this->getCmdOption(this->argc, this->argv, "+openOCD=");; + + bool use_openocd = false; + + if(arg_openocd.empty()){ + std::cout<<"[TESTBENCH]: No OpenOCD is used"<getCmdOption(this->argc, this->argv, "+firmware="); + + if(firmware.empty()){ + std::cout<<"[TESTBENCH]: No firmware specified"<getCmdOption(this->argc, this->argv, "+max_sim_time="); + unsigned int max_sim_time; + + max_sim_time = 0; + if(arg_max_sim_time.empty()){ + std::cout<<"[TESTBENCH]: No Max time specified"<getCmdOption(this->argc, this->argv, "+boot_sel="); + unsigned int boot_sel = 0; + + if(arg_boot_sel.empty()){ + std::cout<<"[TESTBENCH]: No Boot Option specified, using jtag (boot_sel=0)"< + +class XHEEP_CmdLineOptions // declare Calculator class +{ + + public: // public members + XHEEP_CmdLineOptions(int argc, char* argv[]); // default constructor + + std::string getCmdOption(int argc, char* argv[], const std::string& option); // get options from cmd lines + bool get_use_openocd(); + std::string get_firmware(); + unsigned int get_max_sim_time(bool& run_all); + unsigned int get_boot_sel(); + int argc; + char** argv; + +}; + + + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/tb/core-v-mini-mcu-pynq-z2-bscan.cfg b/hw/vendor/esl_epfl_x_heep/tb/core-v-mini-mcu-pynq-z2-bscan.cfg new file mode 100644 index 00000000..f0134765 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/core-v-mini-mcu-pynq-z2-bscan.cfg @@ -0,0 +1,44 @@ +adapter driver ftdi +adapter speed 1000 +transport select jtag + + +# FT2232HQ Adapter Pynq Z2 +ftdi_vid_pid 0x0403 0x6010 + +ftdi_channel 0 +ftdi_layout_init 0x0088 0x008b + +reset_config none + +echo "ftdi setting..." + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id 0x23727093 +jtag newtap arm_dap_0 tap -irlen 4 -expected-id 0x4ba00477 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x000 + +echo "target created..." + +#log_output openocd_fpga.log + +riscv set_ir idcode 0x09 +riscv set_ir dtmcs 0x22 +riscv set_ir dmi 0x23 + +riscv set_reset_timeout_sec 2000 +riscv set_command_timeout_sec 2000 + +echo "setting preferences..." + +scan_chain + +init + +echo "init routine started" + +halt + +echo "Ready for Remote Connections" \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/Cache.h b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/Cache.h new file mode 100644 index 00000000..d9c94b5d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/Cache.h @@ -0,0 +1,221 @@ +#ifndef CACHE_H +#define CACHE_H + +#include +#include +#include +#include + + +// Target module representing a simple direct mapped cache +class CacheMemory +{ + +public: + uint32_t cache_size_byte = 4*1024; + uint32_t number_of_blocks = 256; + + uint32_t nbits_blocks = 0; + uint32_t nbits_tags = 0; + uint32_t nbits_index = 0; + uint32_t block_size_byte = 0; + + enum { ARCHITECTURE_bits = 32 }; + + std::ofstream cacheFile; + + typedef struct cache_line { + uint32_t tag; + bool valid; + uint8_t* data; + } cache_line_t; + + cache_line_t* cache_array; + + + CacheMemory(): cacheFile("cache_status.log") + { + cache_array = NULL; + } + + void create_cache() { + cache_array = new cache_line_t[number_of_blocks]; + this->block_size_byte = get_block_size(); + this->nbits_blocks = log2(block_size_byte); + this->nbits_index = log2(number_of_blocks); + this->nbits_tags = ARCHITECTURE_bits - nbits_index - nbits_blocks; + printf("bits block %d, index %d, tags %d\n",nbits_blocks, nbits_index, nbits_tags ); + } + + void create_cache(uint32_t cache_size_byte, uint32_t number_of_blocks) { + this->cache_size_byte = cache_size_byte; + this->number_of_blocks = number_of_blocks; + cache_array = new cache_line_t[number_of_blocks]; + this->block_size_byte = get_block_size(); + this->nbits_blocks = log2(block_size_byte); + this->nbits_index = log2(number_of_blocks); + this->nbits_tags = ARCHITECTURE_bits - nbits_index - nbits_blocks; + } + + uint32_t initialize_cache() { + if(cache_array == NULL) { + return -1; + } + // Initialize memory with random data + for (int i = 0; i < number_of_blocks; i++) { + cache_array[i].valid = false; + cache_array[i].tag = 0; + cache_array[i].data = new uint8_t[block_size_byte]; + for(int j = 0; j> nbits_blocks) & mask_index ); + } + + uint32_t get_block_offset(uint32_t address) { + uint32_t mask_block = (1 << nbits_blocks) - 1; + return (uint32_t)(address & mask_block); + } + + uint32_t get_base_address(uint32_t address) { + return (uint32_t)((address >> nbits_blocks) << nbits_blocks); + } + + uint32_t get_tag(uint32_t address) { + return (uint32_t)(address >> (nbits_index+nbits_blocks)); + } + + uint32_t get_tag_from_index(uint32_t index) { + return cache_array[index].tag; + } + + + bool cache_hit(uint32_t address) { + uint32_t index = get_index(address); + uint32_t tag = get_tag(address); + return ( cache_array[index].valid && tag == cache_array[index].tag); + + } + + void add_entry(uint32_t address, uint8_t* new_data) { + uint32_t index = get_index(address); + uint32_t tag = get_tag(address); + cache_array[index].valid = true; + cache_array[index].tag = tag; + memcpy(cache_array[index].data, new_data, block_size_byte); + } + + void get_data(uint32_t address, uint8_t* new_data) { + uint32_t index = get_index(address); + memcpy(new_data, cache_array[index].data, block_size_byte); + } + + void get_data_at_index(uint32_t index, uint8_t* new_data) { + memcpy(new_data, cache_array[index].data, block_size_byte); + } + + uint32_t get_address(uint32_t address){ + uint32_t index = get_index(address); + uint32_t tag = cache_array[index].tag; + uint32_t new_address = (tag << (nbits_index+nbits_blocks)) | (index<get_block_offset(address); + uint8_t* new_data = new uint8_t[block_size_byte]; + this->get_data(address, new_data); + data_word = *((int32_t *)&new_data[block_offset]); + delete new_data; + return data_word; + } + + void set_word(uint32_t address, int32_t data_word) { + uint32_t block_offset = this->get_block_offset(address); + uint8_t* new_data = new uint8_t[block_size_byte]; + this->get_data(address, new_data); + *((int32_t *)&new_data[block_offset]) = data_word; + for(int i=0;iadd_entry(address, new_data); + delete new_data; + } + + bool is_entry_valid(uint32_t address) { + uint32_t index = get_index(address); + return cache_array[index].valid; + } + + bool is_entry_valid_at_index(uint32_t index) { + return cache_array[index].valid; + } + + void print_cache_status(uint32_t operation_id, std::string time_str) { + if (cacheFile.is_open()) { + std::string log_cache = ""; + std::ostringstream ss; + + log_cache+= std::to_string(operation_id) + "): " + time_str + "\n"; + log_cache+= "INDEX | TAG | DATA BLOCK | VALID\n"; + + for(int i=0;inbits_index/4) << std::setfill('0') << std::hex << static_cast(i); + log_cache+= ss.str() + " | "; + ss.str(""); + ss.clear(); + ss << "0x" << std::setw(this->nbits_tags/4) << std::setfill('0') << std::hex << cache_array[i].tag; + log_cache+= ss.str() + " | 0x"; + ss.str(""); + ss.clear(); + for(int j = 0; j(cache_array[i].data[j]); + log_cache+= ss.str() + " | "; + log_cache+= std::string( cache_array[i].valid ? "1" : "0" ) + "\n"; + + cacheFile << log_cache; + ss.str(""); + ss.clear(); + log_cache = std::string(""); + } + } else { + std::cout << "Failed to create the Cache file." << std::endl; + } + } + + /* main memory address + 0x7052 = 'b111_0000_0101_0010' + + cache size = 4KB, + number_of_blocks = 256, thus index is on 8bit + block_size_in_byte = 4KB/256 = 16bytes, i.e. 4 words + + 111: tag + 0000_0101: used as index + 0010: used for block offset , 4bits as 16 bytes + + + get_tag(0x7052) --> 0x7 + get_index(0x7052) --> 0x5 + get_block_offset(0x7052) --> 0x2 + + + */ +}; + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MainMemory.h b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MainMemory.h new file mode 100644 index 00000000..984f81cf --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MainMemory.h @@ -0,0 +1,68 @@ +#ifndef MEMORY_H +#define MEMORY_H + +// Needed for the simple_target_socket +#define SC_INCLUDE_DYNAMIC_PROCESSES + +#include "systemc" +using namespace sc_core; +using namespace sc_dt; +using namespace std; + +#include "tlm.h" +#include "tlm_utils/simple_target_socket.h" + + +// Target module representing a simple direct mapped cache +SC_MODULE(MainMemory) +{ + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; + + enum { SIZE = 32*1024/4 }; //32KB word addressable + + int32_t mem[SIZE]; + + + SC_CTOR(MainMemory) + : socket("socket") + { + // Register callback for incoming b_transport interface method call + socket.register_b_transport(this, &MainMemory::b_transport); + + // Initialize memory with random data + for (int i = 0; i < SIZE; i++) + mem[i] = 0xAA000000 | (rand() % 256); + } + + // TLM-2 blocking transport method + virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) + { + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 adr = trans.get_address() / 4; + unsigned char* ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + unsigned char* byt = trans.get_byte_enable_ptr(); + unsigned int wid = trans.get_streaming_width(); + + // Obliged to check address range and check for unsupported features, + // i.e. byte enables, streaming, and bursts + // Can ignore DMI hint and extensions + // Using the SystemC report handler is an acceptable way of signalling an error + + if (adr >= sc_dt::uint64(SIZE) || byt != 0 || len > 4 || wid < len) + SC_REPORT_ERROR("TLM-2", "Target does not support given generic payload transaction"); + + // Obliged to implement read and write commands + if ( cmd == tlm::TLM_READ_COMMAND ) + memcpy(ptr, &mem[adr], len); + else if ( cmd == tlm::TLM_WRITE_COMMAND ) + memcpy(&mem[adr], ptr, len); + + // Obliged to set response status to indicate successful completion + trans.set_response_status( tlm::TLM_OK_RESPONSE ); + } + +}; + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MemoryRequest.h b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MemoryRequest.h new file mode 100644 index 00000000..c0a7d1c7 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/systemc_tb/MemoryRequest.h @@ -0,0 +1,241 @@ +#ifndef MEMORYREQUEST_H +#define MEMORYREQUEST_H + +#include "systemc" +using namespace sc_core; +using namespace sc_dt; +using namespace std; + +#include "tlm.h" +#include "tlm_utils/simple_initiator_socket.h" + +#include "Cache.h" + +#include +#include +#include +#include + +// MemoryRequest module generating generic payload transactions + +SC_MODULE(MemoryRequest) +{ + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_initiator_socket socket; + bool we_i; + uint32_t be_i; + uint32_t addr_i; + uint32_t rwdata_io; + CacheMemory* cache; + std::ofstream heep_mem_transactions; + bool bypass_state = false; + + typedef struct cache_statistics + { + uint32_t number_of_transactions; + uint32_t number_of_hit; + uint32_t number_of_miss; + } cache_statistics_t; + + cache_statistics_t cache_stat; + + SC_CTOR(MemoryRequest) + : socket("socket"), // Construct and name socket + heep_mem_transactions("heep_mem_transactions.log") + { + + cache = new CacheMemory; + cache->create_cache(); + cache->initialize_cache(); + cache_stat.number_of_transactions = 0; + cache_stat.number_of_hit = 0; + cache_stat.number_of_miss = 0; + cache->print_cache_status(cache_stat.number_of_transactions++, sc_time_stamp().to_string()); + + SC_THREAD(thread_process); + } + + + uint32_t memory_copy(uint32_t addr, int32_t* buffer_data, int N, bool write_enable, tlm::tlm_generic_payload* trans, sc_time delay) { + + tlm::tlm_command cmd = write_enable ? tlm::TLM_WRITE_COMMAND : tlm::TLM_READ_COMMAND; + + //first read block_size bytes from memory to place them in cache regardless of the cmd + for(int i=0; i < N; i++){ + trans->set_command( cmd ); + trans->set_address( (addr + i*4) & 0x00007FFF ); //15bits + trans->set_data_ptr( reinterpret_cast(&buffer_data[i]) ); + trans->set_data_length( 4 ); + trans->set_streaming_width( 4 ); // = data_length to indicate no streaming + trans->set_byte_enable_ptr( 0 ); // 0 indicates unused + trans->set_dmi_allowed( false ); // Mandatory initial value + trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); // Mandatory initial value + socket->b_transport( *trans, delay ); // Blocking transport call + + if(bypass_state){ + if(write_enable) + heep_mem_transactions << "Writing to Mem[" << hex << ((addr + i*4) & 0x00007FFF) << "]: " << buffer_data[i] << " at time " << sc_time_stamp() <is_response_error() ) + SC_REPORT_ERROR("TLM-2", "Response error from b_transport"); + } + return N; + } + + + void thread_process() + { + // TLM-2 generic payload transaction, reused across calls to b_transport + tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload; + + sc_time delay_gnt_miss = sc_time(100, SC_NS); + sc_time delay_rvalid_miss = sc_time(100, SC_NS); + + sc_time delay_rvalid_hit = sc_time(20, SC_NS); //as of today, it must be >=20 + + sc_time delay = sc_time(1, SC_NS); + + uint32_t cache_block_size_byte = cache->get_block_size(); + uint32_t cache_block_size_word = cache->get_block_size()/4; + uint8_t* cache_data = new uint8_t[cache_block_size_byte]; + int32_t* main_mem_data = new int32_t[cache_block_size_word]; + uint32_t address_to_replace; + uint32_t cache_flushed; + + while(true) { + + wait(obi_new_req); + + heep_mem_transactions << "X-HEEP tlm_generic_payload REQ: { " << (we_i ? 'W' : 'R') << ", @0x" << hex << addr_i + << " , DATA = 0x" << hex << rwdata_io << " BE = " << hex << be_i <<", at time " << sc_time_stamp() << " }" << std::endl; + + if(be_i!=0xF) { + SC_REPORT_ERROR("OBI External Memory SystemC", "ByteEnable different than 0xF is not supported"); + } + + //if we are writing 1 or 2 to last address, flush cache or bypass + if(we_i && ((addr_i & 0x00007FFF) == 0x7FFC)){ + + if(rwdata_io == 1){ + //FLUSH Cache + heep_mem_transactions << "X-HEEP Flush Cache, at time " << sc_time_stamp() << " }" << std::endl; + uint32_t cache_number_of_blocks = cache->number_of_blocks; + heep_mem_transactions<<"Cache Flushing at time "<is_entry_valid_at_index(i)) { + cache_flushed++; + //if we are going to replace a valid entry + cache->get_data_at_index(i, cache_data); + address_to_replace = cache->get_address_at_index(i); + //write back + memory_copy(address_to_replace, (uint32_t *)cache_data, cache_block_size_word, true, trans, delay); + } + } + heep_mem_transactions<<"Cache Flushed "<< dec << cache_flushed << " entries"<cache_hit(addr_i)){ + + heep_mem_transactions << "Cache HIT on address " << hex << addr_i << " at time " << sc_time_stamp() <get_word(addr_i); + //if Write, writes to cache + if(we_i) + cache->set_word(addr_i, rwdata_io); + else + rwdata_io = main_mem_data[0]; + wait(delay_rvalid_hit); + } + + else { //miss case + + cache_stat.number_of_miss++; + + heep_mem_transactions << "Cache MISS on address " << hex << addr_i << " at time " << sc_time_stamp() <get_base_address(addr_i); + uint32_t addr_offset = cache->get_block_offset(addr_i); + + //first read block_size bytes from memory to place them in cache regardless of the cmd + memory_copy(addr_to_read, main_mem_data, cache_block_size_word, false, trans, delay); + uint32_t index_to_add = cache->get_index(addr_i); + uint32_t tag_to_add = cache->get_tag(addr_i); + + heep_mem_transactions << "Adding to Cache TAG " << hex << tag_to_add << " and index " << hex << index_to_add <is_entry_valid(addr_i)) { + //if we are going to replace a valid entry + cache->get_data(addr_i, cache_data); + address_to_replace = cache->get_address(addr_i); + uint32_t index_to_replace = cache->get_index(addr_i); + uint32_t tag_to_replace = cache->get_tag_from_index(index_to_replace); + + heep_mem_transactions << "Cache Replace address " << hex << addr_i << " with address " << hex << address_to_replace << " due to the MISS at time " << sc_time_stamp() <add_entry(addr_i, (uint8_t*)main_mem_data); + + //if Write, writes to cache + if(we_i) + cache->set_word(addr_i, rwdata_io); + + //now give back the rdata + rwdata_io = main_mem_data[addr_offset>>2]; //>>2 as addr_offset is for byte address, not words + + //wait some time before giving the rvalid + wait(delay_rvalid_miss); + + } + } + } + + heep_mem_transactions << "X-HEEP tlm_generic_payload RESP: { DATA = 0x" << hex << rwdata_io <<", at time " << sc_time_stamp() << " }" << std::endl; + cache->print_cache_status(cache_stat.number_of_transactions++, sc_time_stamp().to_string()); + + obi_new_rvalid.notify(); + + } + } +}; + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/tb/tb_sc_top.cpp b/hw/vendor/esl_epfl_x_heep/tb/tb_sc_top.cpp new file mode 100644 index 00000000..b619d950 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/tb/tb_sc_top.cpp @@ -0,0 +1,342 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include "verilated.h" +#include +#include "Vtestharness.h" +#include "Vtestharness__Syms.h" +#include "systemc.h" +#include +#include +#include "XHEEP_CmdLineOptions.hh" + +sc_event reset_done_event; +sc_event obi_new_gnt; +sc_event obi_new_rvalid; +sc_event obi_new_req; + + +#include "systemc_tb/MemoryRequest.h" +#include "systemc_tb/MainMemory.h" + + +#define CLK_PERIOD 10 + +SC_MODULE(external_memory) +{ + MemoryRequest *memory_request; + MainMemory *memory; + + sc_in clk_i; + sc_in ext_systemc_req_req_i; + sc_in ext_systemc_req_we_i; + sc_in ext_systemc_req_be_i; + sc_in ext_systemc_req_addr_i; + sc_in ext_systemc_req_wdata_i; + sc_out ext_systemc_resp_gnt_o; + sc_out ext_systemc_resp_rvalid_o; + sc_out ext_systemc_resp_rdata_o; + + void notify_obi_transaction () { + if(ext_systemc_req_req_i) { + obi_new_req.notify(); + memory_request->we_i = ext_systemc_req_we_i; + memory_request->be_i = ext_systemc_req_be_i; + memory_request->addr_i = ext_systemc_req_addr_i; + memory_request->rwdata_io = ext_systemc_req_wdata_i; + } + } + + void give_gnt_back () { + while (true) { + ext_systemc_resp_gnt_o.write(false); + wait(obi_new_gnt); + ext_systemc_resp_gnt_o.write(true); + wait(); + } + } + + void give_rvalid_rdata_back () { + while (true) { + ext_systemc_resp_rvalid_o.write(false); + wait(obi_new_rvalid); + ext_systemc_resp_rvalid_o.write(true); + ext_systemc_resp_rdata_o.write(memory_request->rwdata_io); + wait(); + } + } + + SC_CTOR(external_memory) + { + // Instantiate components + memory_request = new MemoryRequest("memory_request"); + memory = new MainMemory ("main_memory"); + + SC_METHOD(notify_obi_transaction); + sensitive << ext_systemc_req_req_i; + + SC_CTHREAD(give_gnt_back, clk_i.pos()); + SC_CTHREAD(give_rvalid_rdata_back, clk_i.pos()); + + // Bind memory_request socket to target socket + memory_request->socket.bind( memory->socket ); + } +}; + + +SC_MODULE(testbench) +{ + + sc_in clk_i; + sc_out clk_o; + sc_out rst_no; + sc_out boot_select_o; + sc_out execute_from_flash_o; + sc_out jtag_tck_o; + sc_out jtag_tms_o; + sc_out jtag_trst_n_o; + sc_out jtag_tdi_o; + + Vtestharness* dut; + std::string* firmware; + + bool boot_select_option; + unsigned int reset_cycles = 30; + + void make_clock () { + while(1) { + clk_o.write(false); + wait(); + clk_o.write(true); + wait(); + } + } + + void do_reset_cycle () { + //active low + //----- + rst_no.write(false); + + for(int i=0;itb_loadHEX(firmware->c_str()); + } + + void set_exit_loop () { + wait(); + dut->tb_set_exit_loop(); + } + + void make_stimuli () { + + boot_select_o.write(boot_select_option); + execute_from_flash_o.write(true); + jtag_tck_o.write(false); + jtag_tms_o.write(false); + jtag_trst_n_o.write(false); + jtag_tdi_o.write(false); + + std::cout<<"Start Reset Cycle: "<c_str()<get_use_openocd(); + firmware = cmd_lines_options->get_firmware(); + + if(firmware.empty() && use_openocd==false) { + std::cout<<"You must specify the firmware if you are not using OpenOCD"<get_max_sim_time(run_all); + + boot_sel = cmd_lines_options->get_boot_sel(); + + if(use_openocd) { + std::cout<<"[TESTBENCH]: ERROR: Executing from OpenOCD in SystemC is not supported (yet) in X-HEEP"<>1, SC_NS, 0.5); + + Vtestharness dut("TOP"); + testbench tb("testbench"); + external_memory ext_mem("external_memory"); + + svSetScope(svGetScopeFromName("TOP.testharness")); + svScope scope = svGetScope(); + if (!scope) { + std::cout<<"Warning: svGetScope failed"<< std::endl; + exit(EXIT_FAILURE); + } + + + // static values + tb.boot_select_option = boot_sel == 1; + + + // Vtestharness interface + sc_signal clk; + sc_signal rst_n; + sc_signal boot_select; + sc_signal execute_from_flash; + sc_signal jtag_tck; + sc_signal jtag_tms; + sc_signal jtag_trst_n; + sc_signal jtag_tdi; + sc_signal jtag_tdo; + sc_signal exit_value; + sc_signal exit_valid; + sc_signal ext_systemc_req_req; + sc_signal ext_systemc_req_we; + sc_signal ext_systemc_req_be; + sc_signal ext_systemc_req_addr; + sc_signal ext_systemc_req_wdata; + sc_signal ext_systemc_resp_gnt; + sc_signal ext_systemc_resp_rvalid; + sc_signal ext_systemc_resp_rdata; + + + + tb.clk_i(clock_sig); + tb.clk_o(clk); + tb.rst_no(rst_n); + tb.boot_select_o(boot_select); + tb.execute_from_flash_o(execute_from_flash); + tb.jtag_tck_o(jtag_tck); + tb.jtag_tms_o(jtag_tms); + tb.jtag_trst_n_o(jtag_trst_n); + tb.jtag_tdi_o(jtag_tdi); + + tb.dut = &dut; + tb.firmware = &firmware; + + dut.clk_i(clk); + dut.rst_ni(rst_n); + dut.boot_select_i(boot_select); + dut.execute_from_flash_i(execute_from_flash); + dut.jtag_tck_i(jtag_tck); + dut.jtag_tms_i(jtag_tms); + dut.jtag_trst_ni(jtag_trst_n); + dut.jtag_tdi_i(jtag_tdi); + dut.jtag_tdo_o(jtag_tdo); + dut.exit_value_o(exit_value); + dut.exit_valid_o(exit_valid); + dut.ext_systemc_req_req_o(ext_systemc_req_req); + dut.ext_systemc_req_we_o(ext_systemc_req_we); + dut.ext_systemc_req_be_o(ext_systemc_req_be); + dut.ext_systemc_req_addr_o(ext_systemc_req_addr); + dut.ext_systemc_req_wdata_o(ext_systemc_req_wdata); + dut.ext_systemc_resp_gnt_i(ext_systemc_resp_gnt); + dut.ext_systemc_resp_rvalid_i(ext_systemc_resp_rvalid); + dut.ext_systemc_resp_rdata_i(ext_systemc_resp_rdata); + + ext_mem.clk_i(clk); + ext_mem.ext_systemc_req_req_i(ext_systemc_req_req); + ext_mem.ext_systemc_req_we_i(ext_systemc_req_we); + ext_mem.ext_systemc_req_be_i(ext_systemc_req_be); + ext_mem.ext_systemc_req_addr_i(ext_systemc_req_addr); + ext_mem.ext_systemc_req_wdata_i(ext_systemc_req_wdata); + ext_mem.ext_systemc_resp_gnt_o(ext_systemc_resp_gnt); + ext_mem.ext_systemc_resp_rdata_o(ext_systemc_resp_rdata); + ext_mem.ext_systemc_resp_rvalid_o(ext_systemc_resp_rvalid); + + + + // You must do one evaluation before enabling waves, in order to allow + // SystemC to interconnect everything for testing. + sc_start(1, SC_NS); + + + VerilatedVcdSc* tfp = nullptr; + tfp = new VerilatedVcdSc; + dut.trace(tfp, 99); // Trace 99 levels of hierarchy + tfp->open("waveform.vcd"); + + // Simulate until $finish + while (!Verilated::gotFinish() && exit_valid !=1 ) { + // Flush the wave files each cycle so we can immediately see the output + // Don't do this in "real" programs, do it in an abort() handler instead + if (tfp) tfp->flush(); + // Simulate 1ns + sc_start(1, SC_NS); + } + + if(exit_valid == 1) { + std::cout<<"Program Finished with value "<< exit_value <close(); + tfp = nullptr; + } + + + exit(exit_val); + +} diff --git a/hw/vendor/esl_epfl_x_heep/tb/tb_top.cpp b/hw/vendor/esl_epfl_x_heep/tb/tb_top.cpp index 956b77d6..7dd4757e 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/tb_top.cpp +++ b/hw/vendor/esl_epfl_x_heep/tb/tb_top.cpp @@ -10,26 +10,10 @@ #include #include +#include "XHEEP_CmdLineOptions.hh" vluint64_t sim_time = 0; - -std::string getCmdOption(int argc, char* argv[], const std::string& option) -{ - std::string cmd; - for( int i = 0; i < argc; ++i) - { - std::string arg = argv[i]; - size_t arg_size = arg.length(); - size_t option_size = option.length(); - - if(arg.find(option)==0){ - cmd = arg.substr(option_size,arg_size-option_size); - } - } - return cmd; -} - void runCycles(unsigned int ncycles, Vtestharness *dut, VerilatedFstC *m_trace){ for(unsigned int i = 0; i < ncycles; i++) { dut->clk_i ^= 1; @@ -42,12 +26,11 @@ void runCycles(unsigned int ncycles, Vtestharness *dut, VerilatedFstC *m_trace){ int main (int argc, char * argv[]) { - unsigned int SRAM_SIZE; - std::string firmware, arg_max_sim_time, arg_openocd, arg_boot_sel, arg_execute_from_flash; - unsigned int max_sim_time; + std::string firmware; + unsigned int max_sim_time, boot_sel, exit_val; bool use_openocd; bool run_all = false; - int i,j, exit_val, boot_sel, execute_from_flash; + Verilated::commandArgs(argc, argv); // Instantiate the model @@ -59,59 +42,24 @@ int main (int argc, char * argv[]) dut->trace (m_trace, 99); m_trace->open ("waveform.vcd"); - arg_openocd = getCmdOption(argc, argv, "+openOCD="); - use_openocd = false; - if(arg_openocd.empty()){ - std::cout<<"[TESTBENCH]: No OpenOCD is used"<get_use_openocd(); + firmware = cmd_lines_options->get_firmware(); - arg_max_sim_time = getCmdOption(argc, argv, "+max_sim_time="); - max_sim_time = 0; - if(arg_max_sim_time.empty()){ - std::cout<<"[TESTBENCH]: No Max time specified"<get_max_sim_time(run_all); - arg_boot_sel = getCmdOption(argc, argv, "+execute_from_flash="); - execute_from_flash = 1; + boot_sel = cmd_lines_options->get_boot_sel(); if(boot_sel == 1) { std::cout<<"[TESTBENCH]: ERROR: Executing from SPI is not supported (yet) in Verilator"<jtag_tms_i = 0; dut->jtag_trst_ni = 0; dut->jtag_tdi_i = 0; - dut->execute_from_flash_i = execute_from_flash; + dut->execute_from_flash_i = 1; //this cause boot_sel cannot be 1 anyway dut->boot_select_i = boot_sel; dut->eval(); @@ -172,6 +120,7 @@ int main (int argc, char * argv[]) m_trace->close(); delete dut; + delete cmd_lines_options; exit(exit_val); diff --git a/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl b/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl index ece91031..a0f295a4 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl +++ b/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl @@ -96,7 +96,7 @@ endtask % for bank in range(ram_numbanks): task tb_writetoSram${bank}; - input integer addr; + input int addr; input [7:0] val3; input [7:0] val2; input [7:0] val1; diff --git a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv index fc216e7b..2a4c7040 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv @@ -21,6 +21,17 @@ module testharness #( inout wire boot_select_i, inout wire execute_from_flash_i, +`ifdef SIM_SYSTEMC + output logic ext_systemc_req_req_o, + output logic ext_systemc_req_we_o, + output logic [ 3:0] ext_systemc_req_be_o, + output logic [31:0] ext_systemc_req_addr_o, + output logic [31:0] ext_systemc_req_wdata_o, + + input logic ext_systemc_resp_gnt_i, + input logic ext_systemc_resp_rvalid_i, + input logic [31:0] ext_systemc_resp_rdata_i, +`endif input wire jtag_tck_i, input wire jtag_tms_i, input wire jtag_trst_ni, @@ -74,6 +85,9 @@ module testharness #( logic [EXT_PERIPHERALS_PORT_SEL_WIDTH-1:0] ext_periph_select; + logic iffifo_in_ready, iffifo_out_valid; + logic iffifo_int_o; + // External xbar master/slave and peripheral ports obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_master_req; obi_req_t [EXT_XBAR_NMASTER_RND-1:0] heep_slave_req; @@ -99,10 +113,6 @@ module testharness #( reg_pkg::reg_req_t [testharness_pkg::EXT_NPERIPHERALS-1:0] ext_periph_slv_req; reg_pkg::reg_rsp_t [testharness_pkg::EXT_NPERIPHERALS-1:0] ext_periph_slv_rsp; - // External xbar slave example port - obi_req_t slow_ram_slave_req; - obi_resp_t slow_ram_slave_resp; - // External interrupts logic [NEXT_INT_RND-1:0] intr_vector_ext; logic memcopy_intr; @@ -132,6 +142,7 @@ module testharness #( end // Re-assign the interrupt lines used here intr_vector_ext[0] = memcopy_intr; + intr_vector_ext[1] = iffifo_int_o; end //log parameters @@ -249,7 +260,9 @@ module testharness #( .external_subsystem_powergate_iso_no(external_subsystem_powergate_iso_n), .external_subsystem_rst_no(external_subsystem_rst_n), .external_ram_banks_set_retentive_no(external_ram_banks_set_retentive_n), - .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n) + .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n), + .ext_dma_slot_tx_i(iffifo_in_ready), + .ext_dma_slot_rx_i(iffifo_out_valid) ); // Testbench external bus @@ -360,20 +373,45 @@ module testharness #( .exit() ); - assign mux_jtag_tck = JTAG_DPI ? sim_jtag_tck : jtag_tck_i; - assign mux_jtag_tms = JTAG_DPI ? sim_jtag_tms : jtag_tms_i; - assign mux_jtag_tdi = JTAG_DPI ? sim_jtag_tdi : jtag_tdi_i; - assign mux_jtag_trstn = JTAG_DPI ? sim_jtag_trstn : jtag_trst_ni; + assign mux_jtag_tck = JTAG_DPI ? sim_jtag_tck : jtag_tck_i; + assign mux_jtag_tms = JTAG_DPI ? sim_jtag_tms : jtag_tms_i; + assign mux_jtag_tdi = JTAG_DPI ? sim_jtag_tdi : jtag_tdi_i; + assign mux_jtag_trstn = JTAG_DPI ? sim_jtag_trstn : jtag_trst_ni; + + assign sim_jtag_tdo = JTAG_DPI ? mux_jtag_tdo : '0; + assign jtag_tdo_o = !JTAG_DPI ? mux_jtag_tdo : '0; - assign sim_jtag_tdo = JTAG_DPI ? mux_jtag_tdo : '0; - assign jtag_tdo_o = !JTAG_DPI ? mux_jtag_tdo : '0; + // External xbar slave example port + obi_req_t slow_ram_slave_req; + obi_resp_t slow_ram_slave_resp; + +`ifndef SIM_SYSTEMC assign slow_ram_slave_req = ext_slave_req[SLOW_MEMORY_IDX]; assign ext_slave_resp[SLOW_MEMORY_IDX] = slow_ram_slave_resp; +`else + + obi_req_t ext_systemc_req; + obi_resp_t ext_systemc_resp; + + assign ext_systemc_req_req_o = ext_systemc_req.req; + assign ext_systemc_req_we_o = ext_systemc_req.we; + assign ext_systemc_req_be_o = ext_systemc_req.be; + assign ext_systemc_req_addr_o = ext_systemc_req.addr; + assign ext_systemc_req_wdata_o = ext_systemc_req.wdata; + + assign ext_systemc_resp.gnt = ext_systemc_resp_gnt_i; + assign ext_systemc_resp.rvalid = ext_systemc_resp_rvalid_i; + assign ext_systemc_resp.rdata = ext_systemc_resp_rdata_i; + + assign ext_systemc_req = ext_slave_req[SLOW_MEMORY_IDX]; + assign ext_slave_resp[SLOW_MEMORY_IDX] = ext_systemc_resp; +`endif generate if (USE_EXTERNAL_DEVICE_EXAMPLE) begin : gen_USE_EXTERNAL_DEVICE_EXAMPLE +`ifndef SIM_SYSTEMC obi_pkg::obi_req_t slave_fifoout_req; obi_pkg::obi_resp_t slave_fifoout_resp; @@ -389,14 +427,14 @@ module testharness #( // External xbar slave memory example slow_memory #( - .NumWords (128), + .NumWords (8192), .DataWidth(32'd32) ) slow_ram_i ( .clk_i, .rst_ni, .req_i(slave_fifoout_req.req), .we_i(slave_fifoout_req.we), - .addr_i(slave_fifoout_req.addr[8:2]), + .addr_i(slave_fifoout_req.addr[15:2]), .wdata_i(slave_fifoout_req.wdata), .be_i(slave_fifoout_req.be), // output ports @@ -404,6 +442,7 @@ module testharness #( .rdata_o(slave_fifoout_resp.rdata), .rvalid_o(slave_fifoout_resp.rvalid) ); +`endif parameter DMA_TRIGGER_SLOT_NUM = 4; @@ -430,6 +469,22 @@ module testharness #( .dma_window_intr_o() ); + simple_accelerator #( + .reg_req_t (reg_pkg::reg_req_t), + .reg_rsp_t (reg_pkg::reg_rsp_t), + .obi_req_t (obi_pkg::obi_req_t), + .obi_resp_t(obi_pkg::obi_resp_t) + ) simple_accelerator_i ( + .clk_i, + .rst_ni, + .reg_req_i(ext_periph_slv_req[testharness_pkg::SIMPLE_ACC_IDX]), + .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::SIMPLE_ACC_IDX]), + .acc_read_ch0_req_o(ext_master_req[testharness_pkg::EXT_MASTER2_IDX]), + .acc_read_ch0_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER2_IDX]), + .acc_write_ch0_req_o(ext_master_req[testharness_pkg::EXT_MASTER3_IDX]), + .acc_write_ch0_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER3_IDX]) + ); + // AMS external peripheral ams #( .reg_req_t(reg_pkg::reg_req_t), @@ -441,6 +496,22 @@ module testharness #( .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::AMS_IDX]) ); + // InterFaced FIFO (IFFIFO) external peripheral + iffifo #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) iffifo_i ( + .clk_i, + .rst_ni, + .reg_req_i(ext_periph_slv_req[testharness_pkg::IFFIFO_IDX]), + .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::IFFIFO_IDX]), + // DMA slots + .iffifo_in_ready_o(iffifo_in_ready), + .iffifo_out_valid_o(iffifo_out_valid), + // Interrupt lines + .iffifo_int_o(iffifo_int_o) + ); + addr_decode #( .NoIndices(testharness_pkg::EXT_NPERIPHERALS), .NoRules(testharness_pkg::EXT_NPERIPHERALS), @@ -557,6 +628,7 @@ module testharness #( assign ext_master_req[testharness_pkg::EXT_MASTER0_IDX].wdata = '0; assign memcopy_intr = '0; + assign iffifo_int_o = '0; assign periph_slave_rsp = '0; end diff --git a/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv b/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv index 58e202ce..d74011f4 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv @@ -7,12 +7,14 @@ package testharness_pkg; import addr_map_rule_pkg::*; import core_v_mini_mcu_pkg::*; - localparam EXT_XBAR_NMASTER = 2; + localparam EXT_XBAR_NMASTER = 4; localparam EXT_XBAR_NSLAVE = 1; //master idx localparam logic [31:0] EXT_MASTER0_IDX = 0; localparam logic [31:0] EXT_MASTER1_IDX = 1; + localparam logic [31:0] EXT_MASTER2_IDX = 2; + localparam logic [31:0] EXT_MASTER3_IDX = 3; //slave mmap and idx localparam logic [31:0] SLOW_MEMORY_START_ADDRESS = core_v_mini_mcu_pkg::EXT_SLAVE_START_ADDRESS; @@ -29,7 +31,7 @@ package testharness_pkg; }; //slave encoder - localparam EXT_NPERIPHERALS = 2; + localparam EXT_NPERIPHERALS = 4; // Memcopy controller (external peripheral example) localparam logic [31:0] MEMCOPY_CTRL_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h0; @@ -38,11 +40,22 @@ package testharness_pkg; localparam logic [31:0] MEMCOPY_CTRL_IDX = 32'd0; // External AMS Peripheral - localparam logic [31:0] AMS_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h001000; + localparam logic [31:0] AMS_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h01000; localparam logic [31:0] AMS_SIZE = 32'h100; localparam logic [31:0] AMS_END_ADDRESS = AMS_START_ADDRESS + AMS_SIZE; localparam logic [31:0] AMS_IDX = 32'd1; + // External InterFaced FIFO (IFFIFO) Peripheral + localparam logic [31:0] IFFIFO_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h02000; + localparam logic [31:0] IFFIFO_SIZE = 32'h100; + localparam logic [31:0] IFFIFO_END_ADDRESS = IFFIFO_START_ADDRESS + IFFIFO_SIZE; + localparam logic [31:0] IFFIFO_IDX = 32'd2; + + // External Simple Accelerator Peripheral + localparam logic [31:0] SIMPLE_ACC_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h03000; + localparam logic [31:0] SIMPLE_ACC_SIZE = 32'h100; + localparam logic [31:0] SIMPLE_ACC_END_ADDRESS = SIMPLE_ACC_START_ADDRESS + SIMPLE_ACC_SIZE; + localparam logic [31:0] SIMPLE_ACC_IDX = 32'd3; localparam addr_map_rule_t [EXT_NPERIPHERALS-1:0] EXT_PERIPHERALS_ADDR_RULES = '{ '{ @@ -50,7 +63,13 @@ package testharness_pkg; start_addr: MEMCOPY_CTRL_START_ADDRESS, end_addr: MEMCOPY_CTRL_END_ADDRESS }, - '{idx: AMS_IDX, start_addr: AMS_START_ADDRESS, end_addr: AMS_END_ADDRESS} + '{idx: AMS_IDX, start_addr: AMS_START_ADDRESS, end_addr: AMS_END_ADDRESS}, + '{idx: IFFIFO_IDX, start_addr: IFFIFO_START_ADDRESS, end_addr: IFFIFO_END_ADDRESS}, + '{ + idx: SIMPLE_ACC_IDX, + start_addr: SIMPLE_ACC_START_ADDRESS, + end_addr: SIMPLE_ACC_END_ADDRESS + } }; localparam int unsigned EXT_PERIPHERALS_PORT_SEL_WIDTH = EXT_NPERIPHERALS > 1 ? $clog2( diff --git a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py index e8c012f8..5c86308f 100755 --- a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py +++ b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py @@ -540,8 +540,28 @@ def len_extracted_peripherals(peripherals): linker_onchip_il_start_address = str('{:08X}'.format(int(linker_onchip_data_start_address,16) + int(linker_onchip_data_size_address,16))) linker_onchip_il_size_address = str('{:08X}'.format(ram_numbanks_il*32*1024)) + stack_size = string2int(obj['linker_script']['stack_size']) + heap_size = string2int(obj['linker_script']['heap_size']) + + + linker_flash_code_start_address = str('{:08X}'.format(int(linker_onchip_code_start_address,16) + int(flash_mem_start_address,16))) + linker_flash_data_start_address = str('{:08X}'.format(int(linker_onchip_data_start_address,16) + int(flash_mem_start_address,16))) + linker_flash_il_start_address = str('{:08X}'.format(int(linker_onchip_il_start_address,16) + int(flash_mem_start_address,16))) + + if ram_numbanks_il == 0 or (ram_numbanks_cont == 1 and ram_numbanks_il > 0): + linker_flash_left_start_address = str('{:08X}'.format(int(linker_flash_data_start_address,16) + int(linker_onchip_data_size_address,16))) + linker_flash_left_size_address = str('{:08X}'.format(int(flash_mem_size_address,16) - int(linker_onchip_code_size_address,16) - int(linker_onchip_data_size_address,16))) + else: + linker_flash_left_start_address = str('{:08X}'.format(int(linker_flash_il_start_address,16) + int(linker_onchip_il_size_address,16))) + linker_flash_left_size_address = str('{:08X}'.format(int(flash_mem_size_address,16) - int(linker_onchip_code_size_address,16) - int(linker_onchip_data_size_address,16) - int(linker_onchip_il_size_address,16))) + + if ((int(linker_onchip_data_size_address,16) + int(linker_onchip_code_size_address,16)) > int(ram_size_address,16)): exit("The code and data section must fit in the RAM size, instead they takes " + str(linker_onchip_data_size_address + linker_onchip_code_size_address)) + + if ((int(stack_size,16) + int(heap_size,16)) > int(ram_size_address,16)): + exit("The stack and heap section must fit in the RAM size, instead they takes " + str(stack_size + heap_size)) + plic_used_n_interrupts = len(obj['interrupts']['list']) plit_n_interrupts = obj['interrupts']['number'] @@ -841,12 +861,19 @@ def len_extracted_peripherals(peripherals): "ext_slave_size_address" : ext_slave_size_address, "flash_mem_start_address" : flash_mem_start_address, "flash_mem_size_address" : flash_mem_size_address, + "linker_flash_code_start_address" : linker_flash_code_start_address, + "linker_flash_data_start_address" : linker_flash_data_start_address, + "linker_flash_il_start_address" : linker_flash_il_start_address, + "linker_flash_left_start_address" : linker_flash_left_start_address, + "linker_flash_left_size_address" : linker_flash_left_size_address, "linker_onchip_code_start_address" : linker_onchip_code_start_address, "linker_onchip_code_size_address" : linker_onchip_code_size_address, "linker_onchip_data_start_address" : linker_onchip_data_start_address, "linker_onchip_data_size_address" : linker_onchip_data_size_address, "linker_onchip_il_start_address" : linker_onchip_il_start_address, "linker_onchip_il_size_address" : linker_onchip_il_size_address, + "stack_size" : stack_size, + "heap_size" : heap_size, "plic_used_n_interrupts" : plic_used_n_interrupts, "plit_n_interrupts" : plit_n_interrupts, "interrupts" : interrupts, diff --git a/hw/vendor/esl_epfl_x_heep/util/structs_gen.py b/hw/vendor/esl_epfl_x_heep/util/structs_gen.py index f815de76..3c776b42 100644 --- a/hw/vendor/esl_epfl_x_heep/util/structs_gen.py +++ b/hw/vendor/esl_epfl_x_heep/util/structs_gen.py @@ -1,4 +1,5 @@ import hjson +from math import ceil import string import argparse import sys @@ -297,7 +298,7 @@ def add_registers(peripheral_json): n_bits += count_bits(f["bits"]) # computes the number of registers needed to pack all the bit fields needed - n_multireg = int((count * n_bits) / int(peripheral_json["regwidth"])) + n_multireg = ceil((count * n_bits) / int(peripheral_json["regwidth"])) # generate the multiregisters for r in range(n_multireg): diff --git a/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core b/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core index 05b75ba5..98252573 100644 --- a/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core +++ b/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core @@ -14,7 +14,9 @@ filesets: - example:ip:gpio_cnt - example:ip:pdm2pcm_dummy - example:ip:ams + - example:ip:iffifo - example:ip:i2s_microphone + - example:ip:simple_accelerator files: file_type: systemVerilogSource @@ -22,6 +24,8 @@ filesets: files: - hw/ip_examples/slow_memory/slow_memory.vlt - hw/ip_examples/ams/ams.vlt + - hw/ip_examples/iffifo/iffifo.vlt + - hw/ip_examples/simple_accelerator/simple_accelerator.vlt - tb/tb.vlt file_type: vlt @@ -67,6 +71,11 @@ filesets: - tb/tb_top.cpp file_type: cppSource + tb-sc-verilator: + files: + - tb/tb_sc_top.cpp + file_type: cppSource + targets: default: &default_target filesets: @@ -75,13 +84,17 @@ targets: - tool_verilator? (uartdpi) - tool_modelsim? (systemverilog_only_uart) - tool_vcs? (systemverilog_only_uart) + - tool_xcelium? (systemverilog_only_uart) - tool_verilator? (files_verilator_waiver) - tool_verilator? (remote_bitbang_dpi) - tool_modelsim? (systemverilog_only_simjtag) - tool_vcs? (systemverilog_only_simjtag) + - tool_xcelium? (systemverilog_only_simjtag) - tool_modelsim? (cypress_flash) - tool_vcs? (cypress_flash) + - tool_xcelium? (cypress_flash) toplevel: - tool_modelsim? (tb_top) - tool_vcs? (tb_top) + - tool_xcelium? (tb_top) - tool_verilator? (testharness) diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index 04dcb944..0ae40dc6 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/x-heep.git - rev: df569a88fc7eaa447645262f0d3a76dd22c519f7 + rev: 76d58efe7b9dec0723c1cb9aaf8ad76ad6c85373 } } From 812bd681ee782770e943f69642ab78f816dc6b4a Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:53:38 +0100 Subject: [PATCH 04/27] revendor x-heep Luigi fix --- hw/vendor/eslepfl_x_heep.vendor.hjson | 4 ++-- sw/applications/transformer/SYLT-FFT | 1 + sw/applications/transformer_il/SYLT-FFT | 1 + sw/applications/transformer_without_cgra/SYLT-FFT | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) create mode 160000 sw/applications/transformer/SYLT-FFT create mode 160000 sw/applications/transformer_il/SYLT-FFT create mode 160000 sw/applications/transformer_without_cgra/SYLT-FFT diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index 2571c6da..e60b27ec 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -7,8 +7,8 @@ target_dir: "esl_epfl_x_heep", upstream: { - url: "https://github.com/esl-epfl/x-heep.git", - rev: "76d58efe7b9dec0723c1cb9aaf8ad76ad6c85373", + url: "https://github.com/Luigi2898/x-heep.git", + rev: "849539ddf996926f9b679837f3bc84c0799287bb", }, patch_dir: "patches/esl_epfl_x_heep", diff --git a/sw/applications/transformer/SYLT-FFT b/sw/applications/transformer/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b diff --git a/sw/applications/transformer_il/SYLT-FFT b/sw/applications/transformer_il/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/transformer_il/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b diff --git a/sw/applications/transformer_without_cgra/SYLT-FFT b/sw/applications/transformer_without_cgra/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/transformer_without_cgra/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b From ac9f32d584b234c108f25ca05a8829b18823f3b6 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:55:02 +0100 Subject: [PATCH 05/27] Update esl_epfl_x_heep to Luigi2898/x-heep@849539d Update code from upstream repository https://github.com/Luigi2898/x-heep.git to revision 849539ddf996926f9b679837f3bc84c0799287bb Signed-off-by: mbelda <11842513+mbelda@users.noreply.github.com> --- hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt | 24 ++++++++++----------- hw/vendor/eslepfl_x_heep.lock.hjson | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt index 9639d6cf..ef5743c6 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt +++ b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt @@ -63,19 +63,19 @@ FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS ${SOURCE_PATH}*.h) SET(dir_list_str "") FOREACH(file_path ${new_list}) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list - if(${file_path} MATCHES "${ROOT_PROJECT}device/") - if(${file_path} MATCHES "${ROOT_PROJECT}device/target/") # Add it if its not in target, or if its in target/${TARGET} - if(${file_path} MATCHES "${ROOT_PROJECT}device/target/${TARGET}") + if(${file_path} MATCHES "${SOURCE_PATH}device/") + if(${file_path} MATCHES "${SOURCE_PATH}device/target/") # Add it if its not in target, or if its in target/${TARGET} + if(${file_path} MATCHES "${SOURCE_PATH}device/target/${TARGET}") SET(add 1) endif() else() SET(add 1) endif() - elseif(${file_path} MATCHES ${PROJECT}) + elseif(${file_path} MATCHES ${SOURCE_PATH}applications/${PROJECT}/) SET(add 1) - elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) ) + elseif( ( ${file_path} MATCHES "${SOURCE_PATH}freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) ) SET(add 1) - elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" ) + elseif( ${file_path} MATCHES "${SOURCE_PATH}external/" ) SET(add 1) endif() @@ -124,14 +124,14 @@ SET( c_dir_list "" ) SET( app_found 0 ) FOREACH(file_path IN LISTS new_list) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list - if(${file_path} MATCHES "${ROOT_PROJECT}device/") + if(${file_path} MATCHES "${SOURCE_PATH}device/") SET(add 1) - elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" ) + elseif( ${file_path} MATCHES "${SOURCE_PATH}external/" ) SET(add 1) - elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) ) - SET(add 1) - elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( ${file_path} MATCHES ${MAINFILE} ) ) + elseif( ${file_path} MATCHES "${SOURCE_PATH}applications/${PROJECT}/.*${MAINFILE}\." ) # look for main.* SET(app_found 1) + elseif( ${file_path} MATCHES "${SOURCE_PATH}applications/${PROJECT}/" ) # other sources + SET(add 1) endif() if( add EQUAL 1 ) # If the file path mathced one of the criterion, add it to the list @@ -155,7 +155,7 @@ if( app_found EQUAL 0 ) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list if(${file_path} MATCHES "${ROOT_PROJECT}device/") SET(add 1) - elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) ) + elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}/applications/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES "${ROOT_PROJECT}applications/${PROJECT}/.*${MAINFILE}\." ) ) SET(add 1) endif() diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index 0ae40dc6..e6880390 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -8,7 +8,7 @@ { upstream: { - url: https://github.com/esl-epfl/x-heep.git - rev: 76d58efe7b9dec0723c1cb9aaf8ad76ad6c85373 + url: https://github.com/Luigi2898/x-heep.git + rev: 849539ddf996926f9b679837f3bc84c0799287bb } } From 9c5dd988382b89c09538a16ca6127cef909d660c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miranda=20Calero=20Jos=C3=A9=20Angel?= Date: Fri, 7 Jun 2024 17:17:10 +0200 Subject: [PATCH 06/27] 1. Port ZCU / 2. fix xdc file for the ZCU / 3. Fix top to include dif clk for ZCU --- cgra_x_heep.core | 43 ++++++++++++++++++- hw/fpga_cgra/xilinx_cgra_x_heep_wrapper.sv | 17 +++++++- .../hw/fpga/constraints/zcu104/pin_assign.xdc | 34 +++++++++------ 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/cgra_x_heep.core b/cgra_x_heep.core index d828a37c..a548bd1c 100644 --- a/cgra_x_heep.core +++ b/cgra_x_heep.core @@ -107,7 +107,6 @@ filesets: ip-fpga: files: - - hw/fpga/scripts/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } - hw/fpga/scripts/generate_sram.tcl: { file_type: tclSource } - hw/fpga/prim_xilinx_clk.sv: { file_type: systemVerilogSource } # Here there are the following modules - hw/fpga/cve2_xilinx_clock_gate.sv: { file_type: systemVerilogSource } @@ -117,6 +116,16 @@ filesets: - hw/fpga/pad_cell_bypass_input_xilinx.sv: { file_type: systemVerilogSource } - hw/fpga/pad_cell_bypass_output_xilinx.sv: { file_type: systemVerilogSource } + ip-fpga-pynq-z2: + files: + - hw/fpga/scripts/pynq-z2/set_board.tcl: { file_type: tclSource } + - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + ip-fpga-zcu104: + files: + - hw/fpga/scripts/zcu104/set_board.tcl: { file_type: tclSource } + - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + fpga-arm-emulation: depend: - pulp-platform.org::axi_spi_slave @@ -129,7 +138,13 @@ filesets: xdc-fpga-pynq-z2: files: - - hw/fpga_cgra/constraints/pin_assign.xdc + - hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc + - hw/fpga/constraints/pynq-z2/constraints.xdc + file_type: xdc + + xdc-fpga-zcu104: + files: + - hw/fpga_cgra/constraints/zcu104/pin_assign.xdc file_type: xdc netlist-fpga: @@ -154,6 +169,10 @@ parameters: datatype: bool paramtype: vlogdefine default: false + FPGA_ZCU104: + datatype: bool + paramtype: vlogdefine + default: false # Make the parameter known to FuseSoC to enable overrides from the # command line. If not overwritten, use the generic technology library. PRIM_DEFAULT_IMPL: @@ -277,4 +296,24 @@ targets: tools: vivado: part: xc7z020clg400-1 + toplevel: [xilinx_cgra_x_heep_wrapper] + + zcu104: + <<: *default_target + default_tool: vivado + description: ZCU104 Evaluation Board + filesets_append: + - x_heep_system + - rtl-fpga + - ip-fpga-zcu104 + - ip-fpga + - xdc-fpga-zcu104 + - ext_bus + parameters: + - COREV_PULP=0 + - SYNTHESIS=true + - FPGA_ZCU104=true + tools: + vivado: + part: xczu7ev-ffvc1156-2-e toplevel: [xilinx_cgra_x_heep_wrapper] \ No newline at end of file diff --git a/hw/fpga_cgra/xilinx_cgra_x_heep_wrapper.sv b/hw/fpga_cgra/xilinx_cgra_x_heep_wrapper.sv index ca4f6ab4..ddba0861 100644 --- a/hw/fpga_cgra/xilinx_cgra_x_heep_wrapper.sv +++ b/hw/fpga_cgra/xilinx_cgra_x_heep_wrapper.sv @@ -11,8 +11,13 @@ module xilinx_cgra_x_heep_wrapper parameter ZFINX = 0, parameter CLK_LED_COUNT_LENGTH = 27 ) ( - inout logic clk_i, - inout logic rst_i, +`ifdef FPGA_ZCU104 + inout logic clk_300mhz_n, + inout logic clk_300mhz_p, +`else + inout logic clk_i, +`endif + inout logic rst_i, //visibility signals output logic rst_led, @@ -84,10 +89,18 @@ module xilinx_cgra_x_heep_wrapper // clock output for debugging assign clk_out = clk_gen; +`ifdef FPGA_ZCU104 + xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( + .CLK_IN1_D_0_clk_n(clk_300mhz_n), + .CLK_IN1_D_0_clk_p(clk_300mhz_p), + .clk_out1_0(clk_gen) + ); +`else // FPGA PYNQ-Z2 xilinx_clk_wizard_wrapper xilinx_clk_wizard_wrapper_i ( .clk_125MHz(clk_i), .clk_out1_0(clk_gen) ); +`endif cgra_x_heep_top #( .COREV_PULP (0), diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc index 4b523cdf..2a431086 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc @@ -12,8 +12,9 @@ set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS33} [get_ports rst_i] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_i] # LEDS -set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led_o] -set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led_o] +set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led] +set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led] +set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports clk_out] set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] set_property -dict {PACKAGE_PIN B5 IOSTANDARD LVCMOS33} [get_ports exit_value_o] @@ -81,19 +82,24 @@ set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS18} [get_ports {gpio_io[16]} set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[17]}] # PDM2PCM -set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] -set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] +# set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] +# set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] +set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports {gpio_io[19]}] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[18]}] # I2S -set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] -set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] -set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] +# set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] +# set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] +# set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[20]}] +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[21]}] +set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[22]}] # SPI2 -set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[0]}] -set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[1]}] -set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports spi2_sck_o] -set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[0]}] -set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[1]}] -set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[2]}] -set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[3]}] +set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[0]}] +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[1]}] +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports {spi2_sck_o}] +set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_0_io}] +set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_1_io}] +set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_2_io}] +set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_3_io}] From 17aecfd28a26ef961f7d817c6e2e1332ce067d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miranda=20Calero=20Jos=C3=A9=20Angel?= Date: Fri, 7 Jun 2024 17:18:19 +0200 Subject: [PATCH 07/27] added new pin and constraint files --- .../constraints/pynq-z2/constraints.xdc | 1 + .../constraints/pynq-z2/pin_assign.xdc | 93 ++++++++++++++++ .../constraints/zcu104/pin_assign.xdc | 105 ++++++++++++++++++ .../pynq-z2/xilinx_generate_clk_wizard.tcl | 44 ++++++++ .../zcu104/xilinx_generate_clk_wizard.tcl | 40 +++++++ 5 files changed, 283 insertions(+) create mode 100644 hw/fpga_cgra/constraints/pynq-z2/constraints.xdc create mode 100644 hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc create mode 100644 hw/fpga_cgra/constraints/zcu104/pin_assign.xdc create mode 100644 hw/fpga_cgra/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl create mode 100644 hw/fpga_cgra/scripts/zcu104/xilinx_generate_clk_wizard.tcl diff --git a/hw/fpga_cgra/constraints/pynq-z2/constraints.xdc b/hw/fpga_cgra/constraints/pynq-z2/constraints.xdc new file mode 100644 index 00000000..38e2f6b3 --- /dev/null +++ b/hw/fpga_cgra/constraints/pynq-z2/constraints.xdc @@ -0,0 +1 @@ +create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 5} [get_ports {clk_i}]; diff --git a/hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc b/hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc new file mode 100644 index 00000000..deb10d68 --- /dev/null +++ b/hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc @@ -0,0 +1,93 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports clk_i] +set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports rst_i] + +set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports rst_led] +set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports clk_led] +set_property -dict {PACKAGE_PIN W9 IOSTANDARD LVCMOS33} [get_ports clk_out] + +set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports boot_select_i] +set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] + +## Pmoda +## RPi GPIO 7-0 are shared with pmoda_rpi_gpio_tri_io[7:0] + +# QSPI +# Q0 / MOSI +# Q1 / MISO +# Q2 / nWP +# Q3 / nHLD + + +## Pmodb +#set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {crst}] +set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] +set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] +set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] +set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] +set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] + +set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] +set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] + +set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[0]}] +set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[1]}] +set_property -dict {PACKAGE_PIN W8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]}] +set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}] +set_property -dict {PACKAGE_PIN Y6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}] +set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {gpio_io[5]}] +set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[6]}] +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {gpio_io[7]}] +set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[8]}] +set_property -dict {PACKAGE_PIN U8 IOSTANDARD LVCMOS33} [get_ports {gpio_io[9]}] +set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[10]}] +set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports {gpio_io[11]}] +set_property -dict {PACKAGE_PIN V6 IOSTANDARD LVCMOS33} [get_ports {gpio_io[12]}] +set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[13]}] +set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {gpio_io[14]}] +set_property -dict {PACKAGE_PIN Y9 IOSTANDARD LVCMOS33} [get_ports {gpio_io[15]}] +set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[16]}] +set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {gpio_io[17]}] +set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {gpio_io[18]}] +set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[19]}] +## Tri-color LD5 for TARGET_PYNQ_Z2 +set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {gpio_io[20]}] +set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[21]}] +set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {gpio_io[22]}] + +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports exit_value_o] + +set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] +set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] +set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] +set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] +set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] + +set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[0]}] +set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[1]}] +set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[2]}] +set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {spi_sd_io[3]}] +set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports spi_csb_o] +set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports spi_sck_o] + +set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_0_io}] +set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_1_io}] +set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_2_io}] +set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {spi2_sd_3_io}] +set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_io[0]}] +set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {spi2_csb_io[1]}] +set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {spi2_sck_o}] + +set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {i2c_scl_io}] +set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {i2c_sda_io}] + +# Removing this line (but leaving the one in constraints.xdc gives an error and recommends adding exactly this to turn it into a warning) +# Having this line along with the one in constrains.xdc gives an critical warning +# Not having the line in constraints.xdc synthezises SUPER slow (>1h), or at least thats a candidate for that. +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] + diff --git a/hw/fpga_cgra/constraints/zcu104/pin_assign.xdc b/hw/fpga_cgra/constraints/zcu104/pin_assign.xdc new file mode 100644 index 00000000..48044127 --- /dev/null +++ b/hw/fpga_cgra/constraints/zcu104/pin_assign.xdc @@ -0,0 +1,105 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +# CLOCK +set_property -dict {PACKAGE_PIN AH18 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p] +set_property -dict {PACKAGE_PIN AH17 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i] + +# RESET +set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS33} [get_ports rst_i] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_i] + +# LEDS +set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led] +set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led] +set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports clk_out] +set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] +set_property -dict {PACKAGE_PIN B5 IOSTANDARD LVCMOS33} [get_ports exit_value_o] + +# SWITCHES +set_property -dict {PACKAGE_PIN E4 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] +set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports boot_select_i] + +# FLASH +# QSPI +# Q0 / MOSI +# Q1 / MISO +# Q2 / nWP +# Q3 / nHLD +set_property -dict {PACKAGE_PIN L10 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] +set_property -dict {PACKAGE_PIN J9 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] +set_property -dict {PACKAGE_PIN M10 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] +set_property -dict {PACKAGE_PIN K9 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] +set_property -dict {PACKAGE_PIN M8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] +set_property -dict {PACKAGE_PIN K8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] + +# UART +set_property -dict {PACKAGE_PIN G8 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] +set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] + +# JTAG +set_property -dict {PACKAGE_PIN H8 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] +set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] +set_property -dict {PACKAGE_PIN G7 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] +set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] +set_property -dict {PACKAGE_PIN M9 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] + +# I2C +set_property -dict {PACKAGE_PIN J7 IOSTANDARD LVCMOS33} [get_ports i2c_scl_io] +set_property -dict {PACKAGE_PIN H7 IOSTANDARD LVCMOS33} [get_ports i2c_sda_io] + +## The following pins are sent to the FMC connector, using the LA pins as single-ended. +## The bank only supports up to 1.8 V. + +# SPI SD +set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS18} [get_ports spi_csb_o] +set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS18} [get_ports spi_sck_o] +set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[0]}] +set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[1]}] +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[2]}] +set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[3]}] + +# GPIOs +set_property -dict {PACKAGE_PIN D11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[0]}] +set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[1]}] +set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[2]}] +set_property -dict {PACKAGE_PIN A7 IOSTANDARD LVCMOS18} [get_ports {gpio_io[3]}] +set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[4]}] +set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[5]}] +set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[6]}] +set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[7]}] +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[8]}] +set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[9]}] +set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[10]}] +set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[11]}] +set_property -dict {PACKAGE_PIN F11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[12]}] +set_property -dict {PACKAGE_PIN E10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[13]}] +set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[14]}] +set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[15]}] +set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS18} [get_ports {gpio_io[16]}] +set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[17]}] + +# PDM2PCM +# set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] +# set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] +set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports {gpio_io[19]}] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[18]}] + +# I2S +# set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] +# set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] +# set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[20]}] +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[21]}] +set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[22]}] + +# SPI2 +set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[0]}] +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[1]}] +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports spi2_sck_o] +set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports spi2_sd_0_io] +set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports spi2_sd_1_io] +set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports spi2_sd_2_io] +set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports spi2_sd_3_io] \ No newline at end of file diff --git a/hw/fpga_cgra/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl b/hw/fpga_cgra/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl new file mode 100644 index 00000000..e61c5832 --- /dev/null +++ b/hw/fpga_cgra/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl @@ -0,0 +1,44 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# Define design macros + +set design_name xilinx_clk_wizard +set in_clk_freq_MHz 125 +set out_clk_freq_MHz 15 + + +# Create block design +create_bd_design $design_name + +# Create ports +set clk_125MHz [ create_bd_port -dir I -type clk -freq_hz [ expr $in_clk_freq_MHz * 1000000 ] clk_125MHz ] +set clk_out1_0 [ create_bd_port -dir O -type clk clk_out1_0 ] +set_property -dict [ list CONFIG.FREQ_HZ [ expr $out_clk_freq_MHz * 1000000 ] ] $clk_out1_0 + +# Create instance and set properties +set clk_wiz_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0 ] +set_property -dict [ list \ + CONFIG.CLKIN1_JITTER_PS {80.0} \ + CONFIG.CLKOUT1_JITTER {172.798} \ + CONFIG.CLKOUT1_PHASE_ERROR {96.948} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {15} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {8.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {8.000} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {50.000} \ + CONFIG.PRIM_IN_FREQ $in_clk_freq_MHz \ + CONFIG.USE_LOCKED {false} \ + CONFIG.USE_RESET {false} \ +] $clk_wiz_0 + +# Create port connections +connect_bd_net -net clk_in1_0_1 [ get_bd_ports clk_125MHz ] [ get_bd_pins clk_wiz_0/clk_in1 ] +connect_bd_net -net clk_wiz_0_clk_out1 [ get_bd_ports clk_out1_0 ] [ get_bd_pins clk_wiz_0/clk_out1 ] + +# Save and close block design +save_bd_design +close_bd_design $design_name + +# create wrapper +set wrapper_path [ make_wrapper -fileset sources_1 -files [ get_files -norecurse xilinx_clk_wizard.bd ] -top ] +add_files -norecurse -fileset sources_1 $wrapper_path diff --git a/hw/fpga_cgra/scripts/zcu104/xilinx_generate_clk_wizard.tcl b/hw/fpga_cgra/scripts/zcu104/xilinx_generate_clk_wizard.tcl new file mode 100644 index 00000000..d67e4054 --- /dev/null +++ b/hw/fpga_cgra/scripts/zcu104/xilinx_generate_clk_wizard.tcl @@ -0,0 +1,40 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# Define design macros + +set design_name xilinx_clk_wizard + +# Create block design +create_bd_design $design_name + +# Create instance and set properties +create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0 +set_property -dict [list \ + CONFIG.CLKIN1_JITTER_PS {33.330000000000005} \ + CONFIG.CLKOUT1_JITTER {282.792} \ + CONFIG.CLKOUT1_PHASE_ERROR {207.545} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {15} \ + CONFIG.CLK_IN1_BOARD_INTERFACE {clk_300mhz} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {32.875} \ + CONFIG.MMCM_CLKIN1_PERIOD {3.333} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {65.750} \ + CONFIG.MMCM_DIVCLK_DIVIDE {10} \ + CONFIG.OPTIMIZE_CLOCKING_STRUCTURE_EN {true} \ + CONFIG.PRIM_SOURCE {Differential_clock_capable_pin} \ + CONFIG.USE_LOCKED {false} \ + CONFIG.USE_RESET {true} \ +] [get_bd_cells clk_wiz_0] + +# Create ports +make_bd_pins_external [get_bd_cells clk_wiz_0] +make_bd_intf_pins_external [get_bd_cells clk_wiz_0] + +# Save and close block design +save_bd_design +close_bd_design $design_name + +# Create wrapper +set wrapper_path [ make_wrapper -fileset sources_1 -files [ get_files -norecurse xilinx_clk_wizard.bd ] -top ] +add_files -norecurse -fileset sources_1 $wrapper_path From 08e2c122568f6fb0e434acf18746d62ddb8932b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miranda=20Calero=20Jos=C3=A9=20Angel?= Date: Fri, 7 Jun 2024 17:27:12 +0200 Subject: [PATCH 08/27] removed vendor modification --- .../hw/fpga/constraints/zcu104/pin_assign.xdc | 105 ------------------ 1 file changed, 105 deletions(-) delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc deleted file mode 100644 index 2a431086..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2022 EPFL -# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -# CLOCK -set_property -dict {PACKAGE_PIN AH18 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p] -set_property -dict {PACKAGE_PIN AH17 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n] -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i] - -# RESET -set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS33} [get_ports rst_i] -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_i] - -# LEDS -set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led] -set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led] -set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports clk_out] -set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] -set_property -dict {PACKAGE_PIN B5 IOSTANDARD LVCMOS33} [get_ports exit_value_o] - -# SWITCHES -set_property -dict {PACKAGE_PIN E4 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] -set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports boot_select_i] - -# FLASH -# QSPI -# Q0 / MOSI -# Q1 / MISO -# Q2 / nWP -# Q3 / nHLD -set_property -dict {PACKAGE_PIN L10 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] -set_property -dict {PACKAGE_PIN J9 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] -set_property -dict {PACKAGE_PIN M10 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] -set_property -dict {PACKAGE_PIN K9 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] -set_property -dict {PACKAGE_PIN M8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] -set_property -dict {PACKAGE_PIN K8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] - -# UART -set_property -dict {PACKAGE_PIN G8 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] -set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] - -# JTAG -set_property -dict {PACKAGE_PIN H8 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] -set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] -set_property -dict {PACKAGE_PIN G7 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] -set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] -set_property -dict {PACKAGE_PIN M9 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] - -# I2C -set_property -dict {PACKAGE_PIN J7 IOSTANDARD LVCMOS33} [get_ports i2c_scl_io] -set_property -dict {PACKAGE_PIN H7 IOSTANDARD LVCMOS33} [get_ports i2c_sda_io] - -## The following pins are sent to the FMC connector, using the LA pins as single-ended. -## The bank only supports up to 1.8 V. - -# SPI SD -set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS18} [get_ports spi_csb_o] -set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS18} [get_ports spi_sck_o] -set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[0]}] -set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[1]}] -set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[2]}] -set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[3]}] - -# GPIOs -set_property -dict {PACKAGE_PIN D11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[0]}] -set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[1]}] -set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[2]}] -set_property -dict {PACKAGE_PIN A7 IOSTANDARD LVCMOS18} [get_ports {gpio_io[3]}] -set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[4]}] -set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[5]}] -set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[6]}] -set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[7]}] -set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[8]}] -set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[9]}] -set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[10]}] -set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[11]}] -set_property -dict {PACKAGE_PIN F11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[12]}] -set_property -dict {PACKAGE_PIN E10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[13]}] -set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[14]}] -set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[15]}] -set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS18} [get_ports {gpio_io[16]}] -set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[17]}] - -# PDM2PCM -# set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] -# set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] -set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports {gpio_io[19]}] -set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[18]}] - -# I2S -# set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] -# set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] -# set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] -set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[20]}] -set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[21]}] -set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[22]}] - -# SPI2 -set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[0]}] -set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_io[1]}] -set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports {spi2_sck_o}] -set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_0_io}] -set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_1_io}] -set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_2_io}] -set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_3_io}] From 5a2ace28f72bc0a25bde6328d55e805c3f0ec286 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:41:34 +0200 Subject: [PATCH 09/27] Add matmul example --- sw/applications/transformer/SYLT-FFT | 1 - sw/applications/transformer_il/SYLT-FFT | 1 - 2 files changed, 2 deletions(-) delete mode 160000 sw/applications/transformer/SYLT-FFT delete mode 160000 sw/applications/transformer_il/SYLT-FFT diff --git a/sw/applications/transformer/SYLT-FFT b/sw/applications/transformer/SYLT-FFT deleted file mode 160000 index c6f58caa..00000000 --- a/sw/applications/transformer/SYLT-FFT +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b diff --git a/sw/applications/transformer_il/SYLT-FFT b/sw/applications/transformer_il/SYLT-FFT deleted file mode 160000 index c6f58caa..00000000 --- a/sw/applications/transformer_il/SYLT-FFT +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b From 0c780bd39ff26410cd7a26ffceb2014caf48bda0 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:43:18 +0200 Subject: [PATCH 10/27] Add matmul os example --- sw/applications/mmul_os/4x4/bitstreams | 2 + sw/applications/mmul_os/4x4/out.sat | 477 +++++++++++++++++++++++ sw/applications/mmul_os/cgra_bitstream.h | 14 + sw/applications/mmul_os/main.c | 294 ++++++++++++++ sw/applications/mmul_os/mulSoftware.py | 51 +++ sw/applications/mmul_os/performance.c | 62 +++ sw/applications/mmul_os/performance.h | 62 +++ sw/applications/mmul_os/transformer.h | 16 + 8 files changed, 978 insertions(+) create mode 100644 sw/applications/mmul_os/4x4/bitstreams create mode 100644 sw/applications/mmul_os/4x4/out.sat create mode 100644 sw/applications/mmul_os/cgra_bitstream.h create mode 100644 sw/applications/mmul_os/main.c create mode 100644 sw/applications/mmul_os/mulSoftware.py create mode 100644 sw/applications/mmul_os/performance.c create mode 100644 sw/applications/mmul_os/performance.h create mode 100644 sw/applications/mmul_os/transformer.h diff --git a/sw/applications/mmul_os/4x4/bitstreams b/sw/applications/mmul_os/4x4/bitstreams new file mode 100644 index 00000000..4e32db09 --- /dev/null +++ b/sw/applications/mmul_os/4x4/bitstreams @@ -0,0 +1,2 @@ +kmem: 0x0, 0xf01c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +imem: 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4081ff4, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x850d0000, 0x0, 0x0, 0xc80000, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xab0000, 0xd0000, 0x8780001c, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a0d0001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xab0000, 0xd0000, 0xd0000, 0x87800018, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x7a180004, 0x0, 0x5a080010, 0x8a0d0001, 0x7a181ff0, 0x1a181ffd, 0xd0000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x5080000, 0x0, 0x820d0000, 0x0, 0x820d0000, 0x2080000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x2080000, 0x0, 0x0, 0x0, 0x5080000, 0x820d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x820d0000, 0x0, 0x3080000, 0x0, 0x820d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x43180000, 0x0, 0x830d0000, 0x0, 0x830d0000, 0x4080000, 0x840d0000, 0x0, 0xab0000, 0xd0000, 0x0, 0x0, 0xf0000, 0x87800010, 0x8a0d0001, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x7a181ffc, 0x0, 0x0, 0xd0000, 0x7a180010, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x830d0000, 0x0, 0x2080000, 0x0, 0x830d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x3a080010, 0x0, 0x0, 0x0, 0x4080000, 0x830d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x800005, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x800003, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa508000c, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x840d0000, 0x0, 0x800002, 0x0, 0xab0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, \ No newline at end of file diff --git a/sw/applications/mmul_os/4x4/out.sat b/sw/applications/mmul_os/4x4/out.sat new file mode 100644 index 00000000..d661655a --- /dev/null +++ b/sw/applications/mmul_os/4x4/out.sat @@ -0,0 +1,477 @@ +T = 0 +LWD R2 +LWD R2 +LWD R2 +LWD R1 +LWD R1 +LWD R2 +LWD R2 +LWD R2 +LWD R2 +LWD R1 +LWD R2 +LWD R2 +LWD R2 +LWD R2 +LWD R1 +LWD R2 +T = 1 +NOP +NOP +NOP +SADD R2, ZERO, ZERO +SADD R2, ZERO, ZERO +NOP +NOP +NOP +NOP +SADD R2, ZERO, ZERO +NOP +NOP +NOP +NOP +NOP +NOP +T = 2 +NOP +NOP +NOP +BEQ R2, R1, 28 +SADD R2, ZERO, ZERO +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +T = 3 +NOP +NOP +NOP +NOP +BEQ R2, R1, 24 +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +T = 4 +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +SADD R3, ZERO, ZERO +T = 5 +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +NOP +BEQ R2, R1, 16 +NOP +NOP +NOP +NOP +NOP +NOP +T = 6 +NOP +NOP +LWI R0, R2 +NOP +NOP +NOP +NOP +LWI R0, R2 +LWI R0, R2 +SADD R2, R2, 1 +NOP +NOP +NOP +LWI R0, R2 +NOP +NOP +T = 7 +NOP +SADD R0, ZERO, RCT +NOP +SADD R0, ZERO, RCB +SADD R0, ZERO, RCB +NOP +SADD R0, ZERO, RCT +NOP +NOP +SADD R0, ZERO, RCB +NOP +SADD R0, ZERO, RCT +SADD R0, ZERO, RCT +NOP +SADD R0, ZERO, RCB +NOP +T = 8 +SADD R0, ZERO, RCB +NOP +NOP +NOP +NOP +SADD R0, ZERO, RCB +NOP +NOP +NOP +NOP +SADD R0, ZERO, RCB +NOP +NOP +NOP +NOP +SADD R0, ZERO, RCB +T = 9 +LWI ROUT, R2 +NOP +NOP +NOP +NOP +LWI ROUT, R2 +NOP +NOP +NOP +NOP +LWI ROUT, R2 +NOP +NOP +NOP +NOP +LWI ROUT, R2 +T = 10 +NOP +SADD ROUT, ZERO, RCL +NOP +SADD ROUT, ZERO, RCR +SADD ROUT, ZERO, RCR +NOP +SADD ROUT, ZERO, RCL +NOP +NOP +SADD ROUT, ZERO, RCR +NOP +SADD ROUT, ZERO, RCL +SADD ROUT, ZERO, RCL +NOP +SADD ROUT, ZERO, RCR +NOP +T = 11 +NOP +NOP +SADD ROUT, ZERO, RCL +NOP +NOP +NOP +NOP +SADD ROUT, ZERO, RCL +SADD ROUT, ZERO, RCL +NOP +NOP +NOP +NOP +SADD ROUT, ZERO, RCL +NOP +NOP +T = 12 +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +SMUL ROUT, R0, ROUT +T = 13 +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +SADD R3, R3, ROUT +T = 14 +NOP +NOP +SADD R2, R2, 4 +NOP +SMUL ROUT, R1, 16 +NOP +NOP +SADD R2, R2, 4 +SADD R2, R2, 4 +NOP +NOP +NOP +NOP +SADD R2, R2, 4 +SMUL ROUT, R1, 16 +NOP +T = 15 +SADD R2, R2, RCB +NOP +NOP +NOP +NOP +SADD R2, R2, RCL +NOP +NOP +NOP +NOP +SADD R2, R2, RCB +NOP +BEQ ZERO, ZERO, 5 +NOP +NOP +SADD R2, R2, RCL +T = 16 +NOP +SADD ROUT, ZERO, R2 +NOP +NOP +NOP +NOP +SADD ROUT, ZERO, R2 +NOP +NOP +NOP +NOP +SADD ROUT, ZERO, R2 +SADD ROUT, ZERO, R2 +NOP +NOP +NOP +T = 17 +SADD ROUT, -12, RCT +SADD R2, R2, 16 +SADD ROUT, -4, RCB +NOP +NOP +SADD ROUT, 4, RCT +SADD R2, R2, 16 +SADD ROUT, -4, RCB +SADD ROUT, -4, RCB +NOP +SADD ROUT, 4, RCT +SADD R2, R2, 16 +SADD R2, R2, 16 +SADD ROUT, 12, RCB +NOP +SADD ROUT, 4, RCT +T = 18 +NOP +SADD ROUT, R2, -16 +NOP +SADD ROUT, -4, RCB +SADD ROUT, -4, RCB +NOP +SADD ROUT, R2, -16 +NOP +NOP +SADD ROUT, 4, RCT +NOP +SADD ROUT, R2, -16 +SADD ROUT, R2, -16 +NOP +SADD ROUT, 4, RCT +NOP +T = 19 +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +SWI R3, ROUT +T = 20 +NOP +NOP +NOP +NOP +SMUL ROUT, R1, 4 +NOP +NOP +NOP +NOP +SMUL ROUT, R1, -4 +NOP +NOP +NOP +NOP +NOP +NOP +T = 21 +NOP +NOP +NOP +NOP +NOP +SADD ROUT, ZERO, RCB +NOP +NOP +SMUL ROUT, RCT, RCR +NOP +NOP +NOP +NOP +NOP +NOP +NOP +T = 22 +NOP +NOP +NOP +NOP +SADD ROUT, RCB, 16 +NOP +SADD ROUT, ZERO, RCL +NOP +NOP +NOP +NOP +SADD ROUT, RCR, 16 +NOP +NOP +NOP +NOP +T = 23 +SADD R2, R2, RCB +NOP +SADD R2, R2, RCB +NOP +SADD R2, R2, 1 +SADD R2, R2, RCL +NOP +SADD R2, R2, RCL +SADD R2, R2, RCR +SADD R2, ZERO, ZERO +SADD R2, R2, RCR +NOP +BEQ ZERO, ZERO, 3 +SADD R2, R2, RCT +NOP +SADD R2, R2, RCT +T = 24 +NOP +NOP +NOP +NOP +SMUL ROUT, R1, -16 +NOP +NOP +NOP +NOP +SMUL ROUT, R1, 16 +NOP +NOP +NOP +NOP +NOP +NOP +T = 25 +SADD R2, R2, RCB +NOP +NOP +NOP +SMUL ROUT, ROUT, -3 +SADD R2, R2, RCL +NOP +SADD ROUT, ZERO, RCR +SADD R2, R2, RCR +NOP +SADD ROUT, ZERO, RCL +NOP +NOP +SADD R2, R2, RCT +NOP +NOP +T = 26 +NOP +NOP +NOP +NOP +SADD R2, ZERO, ZERO +SADD ROUT, ZERO, RCL +SADD ROUT, ZERO, RCB +NOP +SADD ROUT, ZERO, RCT +NOP +NOP +SADD ROUT, ZERO, RCT +NOP +NOP +NOP +NOP +T = 27 +NOP +SADD R2, R2, RCB +SADD R2, R2, RCB +SADD R2, R2, 1 +NOP +NOP +SADD R2, R2, RCL +SADD R2, R2, RCL +SADD R2, R2, RCT +NOP +SADD R2, R2, RCR +SADD R2, R2, RCR +SADD R2, R2, RCT +BEQ ZERO, ZERO, 2 +NOP +SADD R2, R2, RCT +T = 0 diff --git a/sw/applications/mmul_os/cgra_bitstream.h b/sw/applications/mmul_os/cgra_bitstream.h new file mode 100644 index 00000000..92eb977f --- /dev/null +++ b/sw/applications/mmul_os/cgra_bitstream.h @@ -0,0 +1,14 @@ +#ifndef _CGRA_BITSTREAM_H_ +#define _CGRA_BITSTREAM_H_ + +#include + +#include "cgra.h" + +// Kernel 0 => NULL +#define TRANSFORMER 1 + +static uint32_t cgra_kmem_bitstream[CGRA_KMEM_SIZE] = { 0x0, 0xf01c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; +const uint32_t cgra_imem_bitstream[CGRA_IMEM_SIZE] = { 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4081ff4, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x850d0000, 0x0, 0x0, 0xc80000, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xab0000, 0xd0000, 0x8780001c, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a0d0001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xab0000, 0xd0000, 0xd0000, 0x87800018, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x7a180004, 0x0, 0x5a080010, 0x8a0d0001, 0x7a181ff0, 0x1a181ffd, 0xd0000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x5080000, 0x0, 0x820d0000, 0x0, 0x820d0000, 0x2080000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x2080000, 0x0, 0x0, 0x0, 0x5080000, 0x820d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x820d0000, 0x0, 0x3080000, 0x0, 0x820d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x43180000, 0x0, 0x830d0000, 0x0, 0x830d0000, 0x4080000, 0x840d0000, 0x0, 0xab0000, 0xd0000, 0x0, 0x0, 0xf0000, 0x87800010, 0x8a0d0001, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x7a181ffc, 0x0, 0x0, 0xd0000, 0x7a180010, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x830d0000, 0x0, 0x2080000, 0x0, 0x830d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x3a080010, 0x0, 0x0, 0x0, 0x4080000, 0x830d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x800005, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x800003, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa508000c, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x840d0000, 0x0, 0x800002, 0x0, 0xab0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + +#endif // _CGRA_BITSTREAM_H_ diff --git a/sw/applications/mmul_os/main.c b/sw/applications/mmul_os/main.c new file mode 100644 index 00000000..2d9a386f --- /dev/null +++ b/sw/applications/mmul_os/main.c @@ -0,0 +1,294 @@ +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : HEEPsilon ** +** filename : main.c ** +** version : 1 ** +** date : 01/10/23 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL ** +** All rights reserved. ** +** ** +***************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file main.c +* @date 01/10/23 +* @brief An application to run a matrix multiplication. +* +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "transformer.h" +#include "cgra_bitstream.h" +#include "cgra_x_heep.h" +#include "performance.h" + +// For interrupt handling +#include "csr.h" +#include "handler.h" +#include "rv_plic.h" +#include "rv_plic_regs.h" +#include "hart.h" + + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +// Size of the input buffer for the CGRA +#define CGRA_COL_INPUT_SIZE 4 + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +// Matrix multiplication using the standard three loops +void mmulSoftware(int32_t * output); +// Fill input matrixes with numbers +void fillMatrixInputs(); +// Handler for the CGRA interruption +void handler_irq_cgra(uint32_t id); +// Record the cycle number at the start +void kcom_perfRecordStart( kcom_time_diff_t *perf ); +// Record the cycle number and compute the total cycles +void kcom_perfRecordStop( kcom_time_diff_t *perf ); +// Show the performance metrics +void showPerformance( kcom_perf_t* kperf, int full); +// Print a matrix +void printMatrix(int * matrix, int rows, int cols); + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +// Performance variable +static kcom_perf_t kperf; + +// Plic controller variables +volatile bool cgra_intr_flag; + +// CGRA variables +static cgra_t cgra; +static uint8_t cgra_slot; + +// CGRA input and output buffers +static int32_t cgra_input[CGRA_N_COLS][CGRA_COL_INPUT_SIZE] __attribute__ ((aligned (4))); + +// Input and output matrixes +int32_t matrixA[ROWS_A*COLS_A]; +int32_t matrixB[ROWS_B*COLS_B]; +int32_t matrixC[ROWS_C*COLS_C]; +int32_t outSW[ROWS_C*COLS_C]; + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +void main() +{ + fillMatrixInputs(); + + // Init timer + timerInit(); + + // Enable and reset the CGRA performance counters + cgra_perf_cnt_enable(&cgra, 1); + cgra_perf_cnt_reset( &cgra ); + + if(ROWS_C < CGRA_N_COLS || COLS_C < CGRA_N_ROWS){ + kcom_perfRecordStart(&(kperf.time.sw)); + mmulSoftware(matrixC); + kcom_perfRecordStop(&(kperf.time.sw)); + } else { + + // Initialize the CGRA + kcom_perfRecordStart(&(kperf.time.load)); + initCGRA(); + kcom_perfRecordStop(&(kperf.time.load)); + + // Prepare the input vector for the CGRA + kcom_perfRecordStart(&(kperf.time.input)); + // Col 0: &B[0][0], nItLoopColsC, &A[0][0], &C[0][3] + cgra_input[0][0] = &matrixB[0]; + cgra_input[0][1] = COLS_C/CGRA_N_ROWS; + cgra_input[0][2] = &matrixA[0]; + cgra_input[0][3] = &matrixC[3]; + // Col 1: &C[1][0], &B[0][1], nItLoopsColsA, &A[1][0] + cgra_input[1][0] = &matrixC[COLS_C]; + cgra_input[1][1] = &matrixB[1]; + cgra_input[1][2] = COLS_A; + cgra_input[1][3] = &matrixA[COLS_A]; + // Col 2: &A[2][0], &C[2][1], &B[0][2], nItLoopColsC + cgra_input[2][0] = &matrixA[2*COLS_A]; + cgra_input[2][1] = &matrixC[2*COLS_C+1]; + cgra_input[2][2] = &matrixB[2]; + cgra_input[2][3] = COLS_C/CGRA_N_ROWS; + // Col 3: nItLoopRowsC, &A[3][0], &C[3][2], &B[0][3], + cgra_input[3][0] = ROWS_C/CGRA_N_COLS; + cgra_input[3][1] = &matrixA[3*COLS_A]; + cgra_input[3][2] = &matrixC[3*COLS_C+2]; + cgra_input[3][3] = &matrixB[3]; + kcom_perfRecordStop(&(kperf.time.input)); + + // Set CGRA kernel L/S pointers + kcom_perfRecordStart( &(kperf.time.reprogramCols) ); + for(int col_idx = 0 ; col_idx < CGRA_N_COLS ; col_idx++){ + cgra_set_read_ptr ( &cgra, cgra_slot, (uint32_t) cgra_input[col_idx], col_idx ); + } + kcom_perfRecordStop( &(kperf.time.reprogramCols) ); + + // CGRA Execution + kcom_perfRecordStart( &(kperf.time.cgra) ); + cgra_intr_flag = 0; + cgra_set_kernel( &cgra, cgra_slot, TRANSFORMER ); + // Wait until CGRA is done + while(cgra_intr_flag==0) { + wait_for_interrupt(); + } + kcom_perfRecordStop( &(kperf.time.cgra) ); + + + // Software + kcom_perfRecordStart(&(kperf.time.sw)); + mmulSoftware(outSW); + kcom_perfRecordStop(&(kperf.time.sw)); + + checkErrors(); + } + + showPerformance(&kperf, 0); + + return EXIT_SUCCESS; +} + +// Check if the SW and CGRA executions give the same result +void checkErrors(){ + int errors = 0; + for(int i = 0; i < ROWS_C*COLS_C; i++ ){ + if(outSW[i]!=matrixC[i]){ + errors++; + } + } + printf("\rErrors: %d\n", errors); + + if(errors>0){ + printMatrix(matrixC, ROWS_C, COLS_C); + } +} + +// Initialize the CGRA +void initCGRA(){ + // Init the PLIC + plic_Init(); + plic_irq_set_priority(CGRA_INTR, 1); + plic_irq_set_enabled(CGRA_INTR, kPlicToggleEnabled); + plic_assign_external_irq_handler( CGRA_INTR, (void *) &handler_irq_cgra); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; + CSR_SET_BITS(CSR_REG_MIE, mask); + cgra_intr_flag = 0; + + // Load kernel + cgra_cmem_init(cgra_imem_bitstream, cgra_kmem_bitstream); + + cgra.base_addr = mmio_region_from_addr((uintptr_t)CGRA_PERIPH_START_ADDRESS); + // Select request slot of CGRA + cgra_slot = cgra_get_slot(&cgra); +} + +// Fill matrix inputs +void fillMatrixInputs(){ + for(int i = 0; i < ROWS_A; i++){ + for(int j=0; j < COLS_A; j++){ + matrixA[i*COLS_A+j] = (i*COLS_A+j+1)%100; + } + } + + for(int i = 0; i < ROWS_B; i++){ + for(int j=0;j < COLS_B; j++){ + matrixB[i*COLS_B+j] = (i*COLS_B+j+1)%100; + } + } +} + +// Software matrix multiplication +void mmulSoftware(int32_t * out){ + for(int i = 0; i < ROWS_A; i++){ + for(int j=0;j < COLS_B; j++){ + for(int k=0; k < COLS_A; k++){ + out[i*COLS_C+j] += matrixA[i*COLS_A+k]*matrixB[k*COLS_B+j]; + } + } + } +} + +// Print matrix +void printMatrix(int * matrix, int rows, int cols){ + for(int i = 0; i < rows; i++){ + printf("[ "); + for(int j=0; j < cols; j++){ + printf("%d ", matrix[i*cols+j]); + } + printf("]\n"); + } +} + +// Interrupt controller variables +void handler_irq_cgra(uint32_t id) { + cgra_intr_flag = 1; +} + +// Display the performance values +void showPerformance( kcom_perf_t* kperf, int full){ + printf("\rA:%dx%d, B:%dx%d\n", ROWS_A, COLS_A, ROWS_B, COLS_B); + printf("\rSw: %d\n", kperf->time.sw.spent_cy); + if (full){ + printf("\rLoad: %d\n", kperf->time.load.spent_cy); + printf("\rProgram cols: %d\n", kperf->time.reprogramCols.spent_cy); + printf("\rInput: %d\n", kperf->time.input.spent_cy); + printf("\rCgra: %d\n", kperf->time.cgra.spent_cy); + } + int32_t overhead = kperf->time.input.spent_cy + kperf->time.reprogramCols.spent_cy + kperf->time.load.spent_cy; + //printf("\rOverhead: %d\n", overhead); + printf("\rTotal cgra: %d\n", overhead + kperf->time.cgra.spent_cy); +} + + + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/applications/mmul_os/mulSoftware.py b/sw/applications/mmul_os/mulSoftware.py new file mode 100644 index 00000000..fe38a9e4 --- /dev/null +++ b/sw/applications/mmul_os/mulSoftware.py @@ -0,0 +1,51 @@ + +def crear_matriz(filas, columnas): + matriz = [[i*columnas + j + 1 for j in range(columnas)] for i in range(filas)] + return matriz + +def mostrar_matriz(matriz): + for fila in matriz: + print(fila) + +def multiplicar_matrices(matriz_a, matriz_b): + resultado = [[0 for _ in range(len(matriz_b[0]))] for _ in range(len(matriz_a))] + + for i in range(len(matriz_a)): + for j in range(len(matriz_b[0])): + for k in range(len(matriz_b)): + resultado[i][j] += matriz_a[i][k] * matriz_b[k][j] + + return resultado + + +def main(): + filas_a = int(input("Ingrese el número de filas para la matriz A: ")) + columnas_a = int(input("Ingrese el número de columnas para la matriz A: ")) + + filas_b = int(input("Ingrese el número de filas para la matriz B: ")) + columnas_b = int(input("Ingrese el número de columnas para la matriz B: ")) + + if columnas_a != filas_b: + print("No se pueden multiplicar matrices con estas dimensiones.") + return + + # Crear matrices A y B + matriz_a = crear_matriz(filas_a, columnas_a) + matriz_b = crear_matriz(filas_b, columnas_b) + + # Mostrar matrices A y B + #print("\nMatriz A:") + #mostrar_matriz(matriz_a) + + #print("\nMatriz B:") + #mostrar_matriz(matriz_b) + + # Multiplicar matrices A y B + matriz_resultado = multiplicar_matrices(matriz_a, matriz_b) + + # Mostrar resultado + print("\nResultado de la multiplicación:") + mostrar_matriz(matriz_resultado) + +if __name__ == "__main__": + main() diff --git a/sw/applications/mmul_os/performance.c b/sw/applications/mmul_os/performance.c new file mode 100644 index 00000000..421d39be --- /dev/null +++ b/sw/applications/mmul_os/performance.c @@ -0,0 +1,62 @@ +#include "performance.h" + +// For the timer +#include "rv_timer.h" +#include "soc_ctrl.h" +#include "core_v_mini_mcu.h" + +// Timer +static rv_timer_t timer; + +void kcom_perfRecordStart( kcom_time_diff_t *perf ) +{ + timeStart( perf ); +} + +void kcom_perfRecordStop( kcom_time_diff_t *perf ) +{ + timeStop( perf ); +} + +void timeStart( kcom_time_diff_t *perf ) +{ + perf->start_cy = getTime_cy(); +} + +void timeStop( kcom_time_diff_t *perf ) +{ + perf->end_cy = getTime_cy(); + perf->spent_cy += perf->end_cy - perf->start_cy; +} + +uint64_t getTime_cy( ) +{ + static uint64_t out; + rv_timer_counter_read( &timer, HART_ID, &out ); + return out; +} + +//Initialize the timer +void timerInit() +{ + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + mmio_region_t timer_0_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); + + rv_timer_init( timer_0_reg, (rv_timer_config_t) { .hart_count = 2, .comparator_count = 1 }, &timer ); + + rv_timer_tick_params_t tick_params; + + // The same frequency is provaided to get one tick per cycle. + rv_timer_approximate_tick_params( freq_hz, freq_hz, &tick_params ); + rv_timer_set_tick_params(&timer, HART_ID, tick_params); + + // Juan: see if i cannot remove this! + rv_timer_irq_enable(&timer, HART_ID, 0, kRvTimerEnabled); + rv_timer_arm(&timer, HART_ID, 0, 1); + + rv_timer_counter_set_enabled(&timer, HART_ID, kRvTimerEnabled); + +} \ No newline at end of file diff --git a/sw/applications/mmul_os/performance.h b/sw/applications/mmul_os/performance.h new file mode 100644 index 00000000..b7e17578 --- /dev/null +++ b/sw/applications/mmul_os/performance.h @@ -0,0 +1,62 @@ +#include +#include "cgra.h" + +typedef long int kcom_time_t; +typedef kcom_time_t kcom_param_t; + +typedef struct +{ + uint32_t cyc_act; + uint32_t cyc_stl; +} kcom_col_perf_t; + +typedef struct +{ + kcom_time_t start_cy; + kcom_time_t end_cy; + kcom_time_t spent_cy; +} kcom_time_diff_t; + +typedef struct +{ + kcom_time_diff_t sw; + kcom_time_diff_t cgra; + kcom_time_diff_t load; + kcom_time_diff_t input; + kcom_time_diff_t output; + kcom_time_diff_t reprogramCols; + kcom_time_diff_t bitstream; +} kcom_timing_t; + +typedef struct +{ + kcom_col_perf_t cols[CGRA_N_COLS]; + kcom_col_perf_t cols_max; + uint32_t cyc_ratio; // Stored *CGRA_STAT_PERCENT_MULTIPLIER + kcom_timing_t time; +} kcom_perf_t; + +typedef struct +{ + kcom_param_t sw; + kcom_param_t conf; + kcom_param_t cgra; + kcom_param_t repo; +} kcom_run_t; + +typedef struct +{ + kcom_run_t avg; + uint32_t n; + uint32_t errors; + uint8_t *name; +} kcom_stats_t; + +#define HART_ID 0 + +void timerInit(); +uint64_t getTime_cy( ); +void timeStop( kcom_time_diff_t *perf ); +void timeStart( kcom_time_diff_t *perf ); +void kcom_perfRecordStop( kcom_time_diff_t *perf ); +void kcom_perfRecordStart( kcom_time_diff_t *perf ); \ No newline at end of file diff --git a/sw/applications/mmul_os/transformer.h b/sw/applications/mmul_os/transformer.h new file mode 100644 index 00000000..7fe11944 --- /dev/null +++ b/sw/applications/mmul_os/transformer.h @@ -0,0 +1,16 @@ +#ifndef _STIMULI_H_ +#define _STIMULI_H_ + +#include +#include "cgra.h" + +// C multiple of 4x4 + +#define ROWS_A 16 +#define COLS_A 16 +#define COLS_B 16 +#define ROWS_B COLS_A +#define ROWS_C ROWS_A +#define COLS_C COLS_B + +#endif // _STIMULI_H_ From 38c546bde2070166cc27edbcbcb4d7b7667c8d8d Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:44:51 +0200 Subject: [PATCH 11/27] Add transformer example --- sw/applications/transformer/addNormC.c | 71 +++++++ sw/applications/transformer/addNormC.h | 26 +++ sw/applications/transformer/cgra_bitstream.h | 12 ++ sw/applications/transformer/data_cpp/data.cpp | 104 ++++++++++ .../transformer/data_cpp/signal.cpp | 5 + sw/applications/transformer/dense_layerC.c | 69 +++++++ sw/applications/transformer/dense_layerC.h | 30 +++ sw/applications/transformer/main.c | 156 +++++++++++++++ sw/applications/transformer/main.h | 17 ++ sw/applications/transformer/matMulC.c | 22 +++ sw/applications/transformer/matMulC.h | 21 ++ sw/applications/transformer/multiply_cgra.c | 177 +++++++++++++++++ sw/applications/transformer/multiply_cgra.h | 6 + sw/applications/transformer/param.h | 26 +++ sw/applications/transformer/performance.c | 62 ++++++ sw/applications/transformer/performance.h | 63 ++++++ sw/applications/transformer/selfattentionC.c | 68 +++++++ sw/applications/transformer/selfattentionC.h | 35 ++++ sw/applications/transformer/softmaxC.c | 38 ++++ sw/applications/transformer/softmaxC.h | 17 ++ sw/applications/transformer/stftVec.h | 3 + .../transformer/tokenPosEmbeddingC.c | 33 ++++ .../transformer/tokenPosEmbeddingC.h | 24 +++ .../transformer/transformerBlockC.c | 115 +++++++++++ .../transformer/transformerBlockC.h | 48 +++++ sw/applications/transformer/transposeC.c | 31 +++ sw/applications/transformer/transposeC.h | 22 +++ .../transformer/weightsAndBiasesC.c | 181 ++++++++++++++++++ .../transformer/weightsAndBiasesC.h | 15 ++ 29 files changed, 1497 insertions(+) create mode 100644 sw/applications/transformer/addNormC.c create mode 100644 sw/applications/transformer/addNormC.h create mode 100644 sw/applications/transformer/cgra_bitstream.h create mode 100644 sw/applications/transformer/data_cpp/data.cpp create mode 100644 sw/applications/transformer/data_cpp/signal.cpp create mode 100644 sw/applications/transformer/dense_layerC.c create mode 100644 sw/applications/transformer/dense_layerC.h create mode 100644 sw/applications/transformer/main.c create mode 100644 sw/applications/transformer/main.h create mode 100644 sw/applications/transformer/matMulC.c create mode 100644 sw/applications/transformer/matMulC.h create mode 100644 sw/applications/transformer/multiply_cgra.c create mode 100644 sw/applications/transformer/multiply_cgra.h create mode 100644 sw/applications/transformer/param.h create mode 100644 sw/applications/transformer/performance.c create mode 100644 sw/applications/transformer/performance.h create mode 100644 sw/applications/transformer/selfattentionC.c create mode 100644 sw/applications/transformer/selfattentionC.h create mode 100644 sw/applications/transformer/softmaxC.c create mode 100644 sw/applications/transformer/softmaxC.h create mode 100644 sw/applications/transformer/stftVec.h create mode 100644 sw/applications/transformer/tokenPosEmbeddingC.c create mode 100644 sw/applications/transformer/tokenPosEmbeddingC.h create mode 100644 sw/applications/transformer/transformerBlockC.c create mode 100644 sw/applications/transformer/transformerBlockC.h create mode 100644 sw/applications/transformer/transposeC.c create mode 100644 sw/applications/transformer/transposeC.h create mode 100644 sw/applications/transformer/weightsAndBiasesC.c create mode 100644 sw/applications/transformer/weightsAndBiasesC.h diff --git a/sw/applications/transformer/addNormC.c b/sw/applications/transformer/addNormC.c new file mode 100644 index 00000000..31828e28 --- /dev/null +++ b/sw/applications/transformer/addNormC.c @@ -0,0 +1,71 @@ +// +// Created by alireza on 10/6/23. +// + +#include "addNormC.h" + + + +// Function implementations +AddNormalize createAddNormalize(int seq_len, int input_dim, quant_bit_width *weight, quant_bit_width *bias) { + AddNormalize addNorm; + addNorm.seq_len_ = seq_len; + addNorm.input_dim_ = input_dim; + addNorm.weight_ = weight; + addNorm.bias_ = bias; + // Initialize other fields as needed + return addNorm; +} + + + + +void normalize(AddNormalize *addNorm, quant_bit_width *input, quant_bit_width *input_normalized) { + for (int i = 0; i < addNorm->seq_len_; i++) { + quant_bit_width *input_ptr = input + i * (addNorm->input_dim_); + quant_bit_width *input_normalized_ptr = input_normalized + i * (addNorm->input_dim_); + + int sum = 0; + for (int j = 0; j < addNorm->input_dim_; j++) { + sum += *input_ptr; + input_ptr++; + } + + input_ptr = input + i * (addNorm->input_dim_); + quant_bit_width mean = (quant_bit_width)((float)sum / (float)addNorm->input_dim_); + + int64_t variance = 0; + for (int j = 0; j < addNorm->input_dim_; j++) { + variance += MUL_HQ((*input_ptr - mean), (*input_ptr - mean)); + input_ptr++; + } + + variance = SHIFT(variance); + float variance_float = (float)variance / (float)(addNorm->input_dim_); + variance_float = variance_float / (float)(1 << NUM_FRACTION_BITS); + float sd = sqrtf(variance_float); + float sd_inv = (float)(1 / (sd + 0.00001)); // prevent zero divide! + quant_bit_width sd_inv_int = (quant_bit_width)(sd_inv * (1 << NUM_FRACTION_BITS)); + + input_ptr = input + i * (addNorm->input_dim_); + input_normalized_ptr = input_normalized + i * (addNorm->input_dim_); + + for (int j = 0; j < addNorm->input_dim_; j++) { + *input_normalized_ptr = (quant_bit_width)MUL((*input_ptr - mean), sd_inv_int); + *input_normalized_ptr = (quant_bit_width)(MUL((*input_normalized_ptr), addNorm->weight_[j]) + addNorm->bias_[j]); + input_ptr++; + input_normalized_ptr++; + } + } +} + +void add(quant_bit_width *input, quant_bit_width *to_be_added, int seq_len, int input_dim) { + int32_t sum; + for (int i = 0; i < seq_len * input_dim; i++) { + sum = input[i] + to_be_added[i]; + if ((quant_bit_width)sum != sum) // In case of overflow in 16 bits + input[i] = (sum > 0) ? INT16_MAX : INT16_MIN; + else + input[i] = (quant_bit_width)sum; + } +} diff --git a/sw/applications/transformer/addNormC.h b/sw/applications/transformer/addNormC.h new file mode 100644 index 00000000..c2132867 --- /dev/null +++ b/sw/applications/transformer/addNormC.h @@ -0,0 +1,26 @@ +// +// Created by alireza on 10/5/23. +// + +#ifndef FVLLMONTITRANSFORMER_ADDNORMC_H +#define FVLLMONTITRANSFORMER_ADDNORMC_H + + +#include +#include +#include "math.h" +#include "param.h" + +typedef struct { + int seq_len_; + int input_dim_; + quant_bit_width *weight_; + quant_bit_width *bias_; +} AddNormalize; + + +AddNormalize createAddNormalize(int seq_len, int input_dim, quant_bit_width *weight, quant_bit_width *bias); +void normalize(AddNormalize *addNorm, quant_bit_width *input, quant_bit_width *input_normalized); +void add(quant_bit_width *input, quant_bit_width *to_be_added, int seq_len, int input_dim); + +#endif //FVLLMONTITRANSFORMER_ADDNORMC_H diff --git a/sw/applications/transformer/cgra_bitstream.h b/sw/applications/transformer/cgra_bitstream.h new file mode 100644 index 00000000..014ee6b8 --- /dev/null +++ b/sw/applications/transformer/cgra_bitstream.h @@ -0,0 +1,12 @@ +#ifndef _CGRA_BITSTREAM_H_ +#define _CGRA_BITSTREAM_H_ + +#include + +#include "cgra.h" + + +static uint32_t cgra_kmem_bitstream[CGRA_KMEM_SIZE] = { 0x0, 0xf01c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; +const uint32_t cgra_imem_bitstream[CGRA_IMEM_SIZE] = { 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4081ff4, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x850d0000, 0x0, 0x0, 0xc80000, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xab0000, 0xd0000, 0x8780001c, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a0d0001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xab0000, 0xd0000, 0xd0000, 0x87800018, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x7a180004, 0x0, 0x5a080010, 0x8a0d0001, 0x7a181ff0, 0x1a181ffd, 0xd0000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x5080000, 0x0, 0x820d0000, 0x0, 0x820d0000, 0x2080000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x2080000, 0x0, 0x0, 0x0, 0x5080000, 0x820d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x820d0000, 0x0, 0x3080000, 0x0, 0x820d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x43180000, 0x0, 0x830d0000, 0x0, 0x830d0000, 0x4080000, 0x840d0000, 0x0, 0xab0000, 0xd0000, 0x0, 0x0, 0xf0000, 0x87800010, 0x8a0d0001, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x7a181ffc, 0x0, 0x0, 0xd0000, 0x7a180010, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x830d0000, 0x0, 0x2080000, 0x0, 0x830d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x3a080010, 0x0, 0x0, 0x0, 0x4080000, 0x830d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x800005, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x800003, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa508000c, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x840d0000, 0x0, 0x800002, 0x0, 0xab0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + +#endif // _CGRA_BITSTREAM_H_ diff --git a/sw/applications/transformer/data_cpp/data.cpp b/sw/applications/transformer/data_cpp/data.cpp new file mode 100644 index 00000000..4e7efc7a --- /dev/null +++ b/sw/applications/transformer/data_cpp/data.cpp @@ -0,0 +1,104 @@ +#include "stdint-gcc.h" + +int32_t pos_embedding[1936] = {-1383, 964, -5839, -3654, -5069, 4064, -1907, -3855, -3658, -8857, 316, -1245, -3385, 1368, -2997, 13377, 7049, -1252, 2205, -219, -1524, -1316, 4386, 3600, 244, 6103, 1171, 2736, -222, -10278, 728, -1065, 297, 490, 2032, 4887, 4769, -2205, -2950, 3033, 1045, -84, -924, -9504, 871, 6262, -6855, -7938, 3453, -1851, 2541, 741, 10731, 1307, 2100, -4055, -1536, 5267, -2867, -2898, 1939, 25, 3560, 3399, -2064, 139, -1077, 4781, -8273, -6488, 403, 439, 1265, 8417, -106, -211, -4182, 3988, 6307, 104, 3200, -2645, 2750, 1677, 5047, 1988, -368, 784, 2920, 1074, -3975, 322, 2831, -2976, -1221, 4132, -8774, -3231, -3688, -1704, 6092, 4813, -2799, -686, 6206, 460, 10634, 6885, -3182, 5878, 920, -1219, 461, 2684, -2039, -7031, -5283, -6447, 5388, 490, 692, -1467, 28, -72, -766, 6259, 2560, 9225, -6087, -4768, -285, 933, -5913, 6449, 840, -2466, 1073, 2144, 2515, -2408, -7375, 7211, -1006, 1794, -9011, -5, 2908, 3234, 891, -2127, 2135, 1420, -1477, -820, 486, 2927, 2929, -6034, -4795, 6535, 981, 1943, -2114, 112, 1866, 3449, 114, 4353, -3075, 722, 8027, -2035, -2310, 1004, -1842, 766, -193, -4143, -468, -10321, -641, -4879, -58, -4413, -6004, 1211, 2336, -7301, -2585, -2329, -2014, -9458, -2424, -2518, -2531, -1006, -11344, -79, 579, -2929, -3784, -115, 1487, 338, -6021, 6798, -3510, -1279, -584, 4754, 4306, 6089, 5313, -7733, -5283, -1086, -4182, -10, 1619, 7458, 4068, 3304, -3974, -2321, -3290, 1892, 4567, 3601, 3791, 6113, -2470, -1036, 3080, 2368, -84, -365, -3006, 2347, -2591, -3977, -5959, 1168, 475, -7409, 4234, -3694, -3462, -2384, -1386, 6249, 2631, -3582, -2584, -3016, -4120, -3507, 6681, 9170, -512, 2289, 437, -7173, -4825, -7726, -3024, 3, -152, 2356, -125, -793, 1257, 11753, 841, 689, -5175, 525, -30, 2126, 399, 4477, -6030, -8924, 6246, 2527, 4445, 3728, 3477, -4071, -2582, 265, 2704, 4541, 4935, -4722, -661, 2167, -1137, 4947, 484, -7557, 2390, -604, 5174, -1680, -7771, 5151, -2544, 4752, -5385, -5953, 6899, 1995, -3538, -1964, -2005, -2899, -3806, -2889, -875, -6668, 2421, 7852, -4135, 3480, -2472, 1312, -372, -1592, -4654, 2972, 6772, -1416, 1550, 956, 858, -2759, 3268, -2765, -4870, -2471, -794, 679, -6719, -659, -159, -987, -247, -3032, -1714, 232, -1652, -3874, -919, -7050, -1827, -5084, -771, -4296, 3897, -3539, 3699, 7776, -7566, 1318, -3243, -2937, -3200, 4591, 5992, -2227, -1440, 112, 4378, 5404, -8718, 279, -1468, -10044, 2330, -4613, -4171, 344, 3440, 8488, -3674, 51, 1177, 2204, -716, -1666, -1899, -2359, 4873, -2739, 1130, 1508, 492, -4401, 7262, -369, -4263, -383, -833, 4751, -292, 2986, -3862, 5871, 1335, 280, 2117, -4211, -2144, -2733, 1554, 2206, -3493, -6634, 491, 3879, 2548, 1455, 4467, 1138, 2686, 3161, 16872, -5, 1346, -7243, -3078, 757, 76, 647, 3155, -7469, 5539, -4297, 2788, -2706, -824, 9735, 227, -164, 1836, -2907, -902, 3414, 9070, 448, -365, 3590, 1785, 3155, -4327, 1762, -192, 5660, -4526, -2613, -5665, 4197, -7165, 6556, -575, -2809, 9670, -1455, 3162, 5698, -2530, 6970, -1283, 2194, 3080, 5368, -2841, 1661, -3814, 734, 2233, 1298, -2275, 2558, -663, 337, -1486, 5124, -4945, -705, 2226, 3647, 3922, -1636, -3246, -1121, 5034, 6748, 1672, -7449, 4429, 7100, -2473, 7379, -947, 96, 883, -571, 5956, 2154, -4363, -5640, 483, 4663, 4230, -1531, 4186, 8916, 2290, 2685, -3635, -2636, -10375, -359, -763, 3008, 1932, -3181, 4049, -2683, -1566, 218, 1499, -4272, 8315, -5687, -3909, -10107, -2763, 49, 4835, -3659, 5096, 2762, 1572, -1215, -1102, 1778, -304, -3823, -7065, -3514, 842, 1533, 3766, 7351, 2417, -4943, 3180, -1947, 1386, -76, 3659, -998, -3692, 1470, -4130, -4735, -920, -3834, -142, -1852, 1681, 1398, -1615, -395, -5920, 1152, 2867, -8946, -1574, -4741, 2136, 2927, -3393, 1605, 1767, 624, -161, -9984, -9672, -1855, -1974, 2349, -7959, 8138, 405, 3118, -5967, -400, -2649, 1157, 5872, 3428, 3737, -1628, 1432, 319, -1607, 1023, -2374, 3938, 1798, -3673, 1438, 3258, -753, -1809, 5015, 4319, -5591, 8596, 1887, -4751, -4368, 2422, -1443, -134, -788, -21, -2064, 1963, -10361, -3825, -3084, 10016, 2496, 7829, -1263, 10488, -6681, -2736, -3243, -2854, -5366, 4789, 3023, 5010, -1605, 818, 3508, 4327, 1620, 5211, 1638, -1602, -6396, -1011, -4742, -2177, -769, -7017, -5381, 6374, -434, 5859, -1740, -3273, -1150, -272, -4498, -1411, 3119, -2595, -3171, 2275, 4851, -2317, 9149, -5869, -470, -6065, -5685, -3181, -3491, 2468, 1930, -3545, -4076, 4313, -2524, -3857, -800, -2219, 3414, 477, -968, -2669, -3937, 7518, -421, -2605, -230, -2500, 1462, -3009, 1442, 3465, -1343, -4661, 9064, -1488, 2426, 4510, 5118, -6978, -8568, -3232, -803, 1624, -3680, -2136, -3299, -5547, -4491, -6242, 1845, 5622, -710, 3020, 5498, -3608, 1922, 1233, -851, 623, 1153, 2165, -5331, 5668, -4262, 6967, 5474, -86, 3346, -2149, 1429, 1485, 4000, 2078, 1875, 5851, -3715, 4393, 1652, 1144, 5240, 728, 1415, -864, 3615, 1811, 3974, -92, 4902, -8521, -4400, -627, 675, -3433, -3801, -2291, 3850, -6717, 0, -3766, -5335, -5421, -3057, 3809, -5880, 1665, 378, 4789, 3382, -5372, 4777, -1177, 329, -4118, -724, -6930, -1720, -1816, 436, 7447, -533, 4725, -2361, -1161, -3119, 4255, 8766, -1131, 22, 1182, 3252, 4970, -3812, -5076, 971, 7043, -2200, -4456, 3164, 707, -6497, -5324, -218, 9741, -6039, -8101, 6605, 6995, 2298, -10900, -9604, 14083, -2495, 1095, 6337, 1553, 636, 2874, -2222, -2863, 3775, 4896, 8593, -1049, -760, 1582, -720, 54, -1277, -493, -2055, -4673, 2164, -5176, -8766, 3986, 538, 1980, 3639, -5559, 2434, -6174, -2313, -933, 2087, 5489, 1018, -3362, 2350, 8964, 3414, -2611, 5676, -6438, -441, 4548, -3126, 454, 4305, -6046, -1526, 8867, -2809, -3597, 4805, 2720, 5284, -3439, -4167, -1973, -6302, -2436, 693, 2798, -3159, -3125, -1843, -9666, -2709, 6212, -2448, -2614, 9744, 7912, -2084, 6710, -519, -3216, -2973, 339, -1878, 5720, 1510, 3180, 2514, -516, -6191, 8129, -1176, 2473, -1280, -5885, 1885, 2574, 3670, -3595, 5584, 2165, -6515, 5554, -23, 9021, -1911, -881, 465, -2769, -1336, 4516, 781, 1487, 826, -239, 3450, -4089, 312, 4057, -1917, -4253, 2178, 3868, 2352, -96, 3171, 1883, -4054, 7586, -11703, -329, 4425, -6981, 5046, 3208, -4103, -112, -1376, 4341, -2181, -2487, -892, -589, 271, 3055, -346, -137, 741, 2066, 6128, 2551, -4083, -6775, -1311, -4114, 1237, 3796, -616, 3564, 352, -4720, -765, -1952, -3557, 4101, -1777, 4274, 887, 295, 951, -3343, -646, 5854, 4607, -1567, -3609, -4403, 6565, -7334, 109, 1943, 2694, -3486, 2950, -515, 2109, -4209, -3735, -7865, 324, -7742, 8839, 2293, -3205, -2644, 295, 1396, 861, -2310, -6156, -1106, 802, 3566, 486, -1692, 5686, 1646, -1695, 769, 2990, 5526, -2497, -3342, -533, -3074, -5231, 5510, 936, 4001, -324, 4587, 10056, 4353, 1130, -421, 674, -6294, 1722, 2558, 4, -2187, 6847, 2125, -6077, 2690, -719, 2561, 4669, -2845, 5001, 2939, -7002, 2354, 742, 2684, -799, -4004, -5759, 2889, -4625, -6648, 1569, 735, -553, 6963, 2696, 2508, -8183, 5055, -1470, 4075, -5437, -7301, 1969, 2904, 134, -4279, 6075, -1524, 355, -3125, 10803, 1276, -1346, 3689, 794, 742, 1634, 3327, 2022, -3683, 3090, 7283, 1861, -4229, 7780, 3606, -238, -4646, 5503, -2117, -1909, 1908, 6075, -6532, -1732, 5579, 3041, -3126, 4348, 4055, 692, -753, -4153, -1657, 2367, 6320, -235, -9175, -3784, -615, 2829, 2843, -2256, -1470, -5818, -6843, -196, -151, 1301, 2017, -4884, -203, 9959, -4350, 462, 3320, 4236, 1534, -4264, 699, 1578, 3318, 4140, 4835, 1014, -440, 8480, 1889, -706, -1703, 7888, -4966, 2139, 283, -2559, -1652, -1207, 999, 5663, 3620, -9024, 1337, -331, 4966, 1586, -5856, 6659, 4837, -3025, 1162, 204, -2217, -2655, -3015, 3457, -415, -10613, 4144, 4124, -2337, 4753, -2210, 6730, 5633, -4650, 6065, 1790, 4687, 1802, 5954, 3767, 1889, 3277, 1196, -3345, -50, -582, -976, 1391, 4427, -2472, 10868, 1423, -4134, 1687, 616, -5144, 3766, 7614, -3716, -2228, 8223, -4436, -49, 4142, 6244, 2533, 1008, 3650, 3387, 2705, 228, -1405, 1866, -2994, 6573, 6639, 2522, 892, -6028, -7974, -1034, -2814, -5937, -1890, -5217, -7161, -11827, 1492, -355, 5499, -1280, 6, -5161, -3852, 2855, -353, -2529, 999, -5875, 540, 690, 2957, 2639, -5606, 3065, -912, -8014, -2138, 11664, -2999, 3785, -3479, -443, 5357, 3674, 6408, 7416, -2708, -3874, 1420, -8040, 123, -5179, -1861, -68, 2909, 2095, 398, 3777, 2569, 10516, -3511, -10, -4321, -4616, 1167, -8103, 3211, -8598, -1242, -3099, 521, 3416, -4465, 1157, -5550, -219, -164, 3618, 795, -2932, -2417, -3135, 3185, -4072, -229, -5254, -9385, -2973, 7064, 1924, 6405, -2424, 2374, 3312, 1684, 46, 2385, 788, 6867, 1158, 1092, -1723, -3498, 1711, 106, -958, -2024, -2930, 8257, 7091, -1887, -2165, -1379, -4090, 3170, -1518, -1696, -461, -95, -1146, -3041, -486, -1225, 2840, 2454, -535, 4306, 4365, 1027, -7522, 6268, -3390, 1507, -4160, 3606, 4296, 844, 6481, 5322, 845, 1058, -2461, -770, 5714, -1310, 2248, -2115, 8250, -729, -3421, 4037, -2574, -1750, 5356, -6683, -4439, -2797, -5302, -5110, 398, -3725, -2597, 2897, -2513, 1987, -416, -2444, 6916, 349, -1110, -4154, -4623, 53, 3865, -993, -8210, -651, 1280, -4261, -4337, -7605, 2074, -413, -2321, 837, -2882, -3536, 8512, -3100, -751, -1466, -1352, -3046, 833, -538, -378, -5832, -2967, 3981, -608, -274, 39, 1911, -811, 6059, 1289, 6744, -3978, -2821, 2813, 3185, 1641, 4621, -5059, 5139, -4251, 7102, 2009, 4088, 13455, 3158, 2023, 845, -2790, -6827, -7613, 2793, 362, -2562, 7864, -4174, 2552, 30, -2629, -8870, 6764, 478, -2226, 1224, 1911, 2986, -6839, 750, -4442, 43, -4298, 2500, 1377, 4444, -1386, -903, 5267, 3429, 3397, -128, -314, -1175, 557, -1281, 3879, -6261, -2378, -4673, -4546, -9533, -434, -1251, 4867, -478, 6570, 1638, -6200, 2489, 1825, -3280, 2302, 529, 808, -1079, -932, -7550, 308, 5501, -2490, -1262, -503, 2525, 5519, -1882, -1477, -86, -9414, -1875, 3709, 9345, 696, -580, -4114, 3784, -1469, -2308, -7687, 7726, -5358, 2180, 198, -4601, 6568, -846, -743, 602, 3768, -8464, -2305, 1505, 3102, -1882, 1882, 2084, -5905, 10953, 1874, 4433, -4212, 9862, 845, -1182, 2011, -3850, -3034, 1874, 4546, 4268, 481, 5882, 2178, -797, 636, 195, -2742, -6500, -172, 6924, -2807, 1402, 1809, 4814, -6196, -4112, -489, 4513, -788, -1141, -1066, 6471, -366, 3895, -7083, -2192, -936, -4171, -3834, -2427, 60, -2176, 1471, -7225, 1075, -4612, 2404, 923, -6865, 3175, -2994, 3791, 3837, 4112, -2837, -2407, -1790, -135, -2982, 756, 2905, -3754, 3142, 4695, -4753, 3775, -3668, 2878, 58, 1401, -6116, -3778, -835, -1237, 4451, -486, -5649, -2662, -1359, 2480, 764, 6716, 1520, -3423, 3565, 6528, -5598, -2577, -5838, 3809, 4273, -5191, -6151, 856, -3401, 1877, 181, -3391, 6397, 521, 2696, -729, 2447, -2357, 71, 393, -4286, -3678, -3804, 202, 2483, -1495, -567, -351, -5601, 4345, 727, 2205, -446, -1712, 4245, -555, 2319, -1229, -4391, 1198, 3343, 6352, -3041, 3530, 2555, -2491, 3267, 5197, 7241, -5418, -196, -6974, 4126, -6772, -1952, -1254, 4365, -856, -7301, 2039, -3488, -1819, -5129, -8144, 1046, 9050, -2252, 3089, 1116, -3244, 3722, -6500, -2682, 6899, 999, -6970, 4962, 1942, -155, 205, 1988, 2059, -7244, 8643, -2080, -11003, -3558, 6445, 4859, 5428, 2292, 67, -996, 6220, 3174, -276, -9762, -1324, 1566, 3728, -677, 3279, -2624, 2045, 2832, -6470, 1538, -1687, -3169, -2649, -7823, -1285, 4916, 1915, 8069, -955, 3076, 5247, 6909, -1496, 6131, -4841, 8632, 495, -755, -1478, -1746, -5553, 6564, -2779, -3504, 639, -5842, 1703, 1079, 2635, 2315, 1960, -9291, 531, -1071, -1838, -2918, -399, 2394, -8068, -720, 31, -1530, -1179, 65, -4719, 5641, -1551, 5440, -2457, 6268, -5913, 3913, -6646, 188, -6885, 2757, -3601, 3880, -3979, -1443, 1375, -2572, -1632, 2321, 5070, -2172, 731, 481, 1710, -5181, 8850, -931, -3332, 3141, -1414, -2568, -3533, 728, -1683, 206, 907, 5058, 2523, -158, -1465, 1969, -5960, -1139, -7207, 991, 2704, -8160, -2148, -4477, 4621, -5992, 2561, -2189, 5366, 2138, 2017, -2125, -844, -6806, 3850, 3987, 2856, 2990, -6767, -2315, -721, -205, -672, -2231, -617, 4268, 4988, -1234, -2918, 5121, 4651, -2067, 629, 655, 2305, 490, 990, 598, 4562, 3404, 3903, -5174, 7998, -8369, -7167, -1066, 5288, -2154, 5324, -1541, -620, -3439, -4516, 6180, -8012, -1858, 1175, -2675, -2835, -3610, -7460, 10522, 3595, -4464, 1727, 2719, -2989, -2425, 2312, 1535, -2001, -4046, 3982, -3749, -1536, 2144, -68, 284, 1545, -2459, -6920, -2683, 3627, -1356, -188, 2040, 3459, 33, 6605, -1418, 5162, 2430, -1030, 3098, }; +int32_t cls_token[16] = {1579, -8312, -1543, 5366, -5637, -2872, -787, 5773, -2441, 5560, -195, -1606, -1795, -6080, 1247, 219, }; +int32_t to_patch_embedding_layer_norm1_weight[400] = {4133, 4145, 3757, 3886, 3959, 4157, 3936, 3941, 4085, 3902, 4116, 4193, 4064, 4147, 4075, 4082, 4012, 4029, 4116, 3960, 4010, 3944, 4027, 4086, 3719, 3979, 4088, 4002, 4053, 3642, 3885, 3881, 4070, 3980, 3861, 4118, 3899, 4082, 4035, 3967, 3992, 3993, 3975, 3960, 4044, 4026, 3964, 4104, 4141, 4203, 4335, 3950, 4260, 4394, 4250, 4142, 4046, 4265, 4355, 4162, 4026, 3882, 4271, 4276, 4216, 3970, 3983, 3922, 4114, 3907, 4105, 3924, 3986, 4032, 4059, 4209, 3959, 4090, 4356, 3975, 4122, 3986, 4208, 4332, 3799, 4094, 4119, 4180, 3884, 4095, 4133, 4137, 3932, 4225, 4114, 4111, 4032, 3875, 4169, 4247, 4040, 4016, 3875, 4170, 3953, 4202, 3919, 4007, 4077, 4003, 4305, 3842, 4027, 4056, 4142, 4325, 4154, 4097, 3973, 4237, 4355, 4214, 3867, 4227, 3953, 4371, 4289, 3955, 4040, 4009, 4349, 4107, 4081, 3992, 4066, 4087, 4143, 3998, 4267, 4175, 4172, 4379, 4104, 3944, 4301, 4158, 4079, 4004, 4215, 3903, 3995, 4349, 4114, 4170, 4144, 3863, 4146, 4371, 4222, 4055, 3768, 4143, 4415, 4017, 3835, 3989, 4230, 4134, 3999, 4111, 4047, 4056, 4048, 3949, 4234, 3900, 4057, 3988, 4199, 4106, 4042, 3996, 4172, 3837, 4434, 3947, 4334, 4126, 3984, 4289, 4126, 4312, 4083, 4108, 4197, 4109, 4378, 4341, 4190, 4026, 4163, 4292, 4392, 4021, 4034, 4101, 4160, 4278, 4369, 3999, 3936, 4324, 4048, 4162, 4044, 3925, 4438, 3960, 4227, 3866, 4002, 4304, 4042, 4232, 4019, 4004, 4256, 4206, 4115, 4146, 4098, 4208, 4202, 4077, 4139, 3819, 4197, 4112, 4082, 4096, 4123, 4186, 4242, 3938, 3958, 3854, 4033, 3863, 4125, 3973, 4049, 4200, 4256, 4168, 3976, 4109, 3891, 4326, 3963, 4095, 3989, 4003, 3975, 4060, 3839, 4141, 4158, 3988, 4027, 3942, 4172, 3919, 3789, 4114, 3849, 4044, 4072, 4189, 4027, 3988, 4126, 4168, 4252, 3919, 4101, 4337, 4444, 4213, 4265, 4097, 4241, 4310, 4159, 3999, 3960, 4176, 4212, 4061, 4151, 4209, 3865, 4062, 4143, 4250, 4240, 3844, 3949, 4000, 4163, 3924, 4031, 4240, 3901, 4130, 4081, 3980, 4027, 4228, 4179, 4012, 4004, 4040, 4259, 3998, 4100, 4036, 4036, 4179, 3997, 4013, 3999, 4269, 3892, 4237, 3970, 4001, 4144, 3987, 4286, 4028, 3876, 4163, 4167, 4266, 4089, 3886, 3843, 4096, 4022, 4139, 3774, 3958, 4185, 3968, 3734, 3858, 3944, 3847, 3897, 4437, 3900, 4063, 4092, 4064, 4184, 4036, 3915, 4042, 4022, 4221, 4130, 3789, 4108, 4215, 4273, 3804, 3838, 3820, 4098, 4179, 3893, 4165, 3959, 4077, 4066, 3950, 4334, 4204, 3915, 3767, 4120, 4262, 4153, 3926, 4022, 3947, 4106, 4003, 3883, 3666, }; +int32_t to_patch_embedding_layer_norm1_bias[400] = {-181, -150, -345, -240, -156, -149, -228, -310, -125, -193, -139, -95, -144, -184, -125, -137, -225, -204, -98, -170, -13, -175, -169, -127, -341, -168, -8, -182, -261, -380, -104, -230, -161, -206, -269, -152, -96, -4, -246, -37, -138, -182, -33, -64, 9, -50, -201, 66, 108, 50, 51, -30, 117, 88, 32, 40, 5, 73, 92, 7, -126, -116, 87, 86, 78, -51, -135, 5, 48, -15, -3, -54, -132, 77, -78, 44, -12, -133, -116, -105, 60, -27, -108, -166, -119, -68, -6, -132, -102, -68, 29, 94, -23, 58, -51, -35, -61, -28, 4, -114, -232, 9, -89, 23, -29, 46, -44, -122, 78, -82, 53, -36, 47, 62, -86, 50, 35, 90, 5, -70, 69, 105, 3, 113, -38, 42, -69, 2, 131, -44, 53, -59, -18, -111, -97, -18, -91, 9, -97, -53, -121, -103, -6, 42, -30, -55, -39, -11, 121, 8, -32, -27, 20, -58, 54, -76, -13, -34, -80, 83, -37, -57, -59, -4, 42, 97, -90, -39, 19, -59, 44, -68, 115, 80, -65, 13, 54, -46, 109, -21, -47, 11, -23, 136, 56, -34, -30, -40, -29, 47, -71, -89, -16, 112, -95, -71, -114, -57, 79, -70, -81, -76, -106, -18, -53, -66, -53, -52, -116, -127, -50, -104, -70, -36, 41, -56, -110, 104, -62, 132, -40, -73, -54, -24, -21, 37, -40, -59, -3, -65, -28, -87, -69, -37, 83, 40, -38, -35, -61, 59, -59, -72, -92, 118, -4, 36, 29, 133, -64, 135, 9, -33, 69, -76, 74, -28, 52, 68, 108, 95, -77, 156, 191, 69, 130, -58, 88, 141, -12, 89, -39, 256, 158, -6, 61, -118, 75, -15, -21, 99, -115, 205, -21, 50, 121, -88, 110, -40, -19, -30, -57, 110, 140, 152, -37, -56, 123, 128, 151, 87, 53, 95, -35, 89, 98, 91, 154, 25, 83, 6, 145, 102, 99, 186, -14, 51, 39, 103, 124, 140, 114, 130, 81, 120, 157, 129, 160, 152, 169, 144, 111, 104, 51, 11, 43, 156, 74, 234, 13, 193, 130, -45, 159, -14, 102, 205, 125, 137, 43, 169, 306, 142, 87, 182, 136, 216, 166, 198, 142, 88, 233, 165, 195, 49, 192, 104, 37, 200, 17, 189, 36, 134, 192, 224, 76, 272, 170, 180, 146, 85, 130, 69, 189, 142, 163, 142, 111, 130, 251, 186, -30, 128, 149, 264, 144, 72, 200, 147, 131, 210, }; +int32_t to_patch_embedding_linear_weight[6400] = {-173, 179, -273, -237, 19, 323, 124, -8, -4, -42, 39, -70, -3, -226, 215, -34, -120, 218, -189, -275, 21, -86, 42, 92, 209, -149, 196, 180, 164, -87, 49, 54, -54, 66, -83, 102, 32, 118, 140, -60, -96, -33, -165, -97, -141, -163, 34, 208, -214, 108, 22, -126, 151, -120, -195, 88, 21, 35, 157, -22, -12, -191, 82, 89, 183, 252, 17, -22, 206, -29, 22, 57, 40, -82, -285, 98, 46, 52, -16, 165, -125, 181, -157, -105, -129, 329, -88, 193, 218, -133, -27, 85, 294, -133, -127, -40, 114, 68, 18, -162, -98, 166, -117, -18, 74, 59, 92, -40, 56, -200, 122, -163, 199, -62, -49, 106, -136, 184, 136, -64, 52, -164, -255, 115, -58, 162, 245, -40, 34, -19, -127, -342, -173, 220, -44, 171, 124, -198, -144, -127, 27, 219, 7, -176, 314, -18, -43, 69, 75, 138, -23, 118, 163, -35, 69, 100, 208, 65, 126, 149, 100, 210, -48, -106, 9, 41, 43, -3, 43, -297, -324, -96, -51, 47, 126, 5, 116, 360, -299, -36, -50, 148, -155, 242, 64, -130, 69, -48, 210, -165, 54, 142, -59, 101, -64, -264, 80, -13, -111, 223, -145, -159, 47, -87, 141, 196, 57, -183, -11, 300, -304, -50, -157, 122, 34, -19, -83, -170, 70, -41, 12, -44, -60, -122, -85, 69, 38, -107, -205, -58, -122, 100, 155, -300, -175, -11, 326, 120, 131, -174, 152, 104, -46, -72, 122, -19, -161, 138, 61, -76, -343, -88, 176, -103, 148, -188, -129, 282, 65, -34, -61, 91, 111, 38, 114, -19, 95, 50, 206, -33, -113, 81, 323, -45, -34, -164, -122, 253, 186, 102, -5, -244, 88, 181, -58, 195, -30, -18, 155, 107, -108, -267, 72, -23, 125, 65, -204, -254, -238, 96, 159, 228, 71, 13, 223, 3, -192, -176, -65, -151, -115, 213, 122, 8, -130, 66, 144, 208, 63, -140, 193, -90, 104, -189, -59, -146, -39, -185, 172, 138, -264, -217, -88, 39, 39, 42, -61, 194, 123, -57, 156, 0, -172, -132, -221, -197, -165, 80, 110, -95, 50, 52, 244, 41, -58, -107, 145, 203, 212, 204, 112, -91, 45, -22, -26, -51, 34, -152, -205, 239, -88, -122, 203, -85, -69, -43, -190, -202, -248, 7, 189, 103, 137, 133, -63, 42, -115, 68, 129, 184, -192, 176, -118, 86, -1, 90, 210, 37, -40, 135, -45, -164, -175, 70, 283, 232, -219, -81, 66, -85, -171, 40, -67, 310, 164, -66, 32, -64, -64, -52, 172, -128, -229, -156, -273, 208, -107, -196, -176, 355, 43, -19, 48, 155, 74, -145, -28, -83, -128, 15, -101, -37, -54, 103, 278, 194, 154, -161, -342, 8, -187, -34, -149, 175, -73, -153, -1, -303, -197, -180, -29, -75, 9, -157, -75, 157, -66, -130, 112, -68, -26, 10, 117, 138, -104, -189, -81, 38, 138, 149, -52, -30, 110, -93, 153, -62, -116, 189, -67, -67, -94, -94, 17, 45, 122, -158, 177, 166, 101, 105, 52, 140, -115, -7, -184, -85, -249, 98, 19, 233, -100, 198, -165, 6, -73, -183, -133, 196, -146, 231, 42, -266, 70, -104, 50, -80, 281, -171, -331, -9, 168, -98, 177, 201, -234, -103, 79, -96, 112, -38, 170, 36, -86, 201, -132, 137, -9, 34, 105, 75, -234, -69, -34, -193, 78, -236, 205, -169, 96, -48, -191, 55, -261, -52, -100, -15, -261, 24, -68, -304, -137, -296, 240, -164, 185, -182, -111, -93, 149, -194, 264, -46, -231, -16, 168, 36, -202, -47, -68, -22, 69, -129, -157, -118, 251, 40, 0, 89, -44, 117, -149, -10, -241, 89, -199, -124, -32, 146, -178, 157, 64, -285, 11, 38, -75, -46, -83, -75, 159, 32, -141, 42, 196, -159, 43, -164, -143, -6, 23, -149, -263, -75, -223, -44, 15, -220, 94, 86, -157, 104, -62, 74, -249, -46, -210, 4, -253, 126, 104, 32, 60, 64, 266, -67, -87, 149, -87, 222, 24, 66, -40, 215, -20, 143, -77, 1, -33, 165, -16, -109, 49, -142, -4, -9, 154, 163, 9, -198, -177, 40, -27, 102, 171, -158, 128, 122, 203, -8, -163, -18, -20, -102, 190, 137, 37, -143, -97, 71, 0, 49, -174, -31, -124, -165, 106, 93, 123, -117, 44, -250, -306, 72, -93, 193, -33, -62, -94, 208, 88, 271, -74, -127, 237, -187, -189, -22, 68, 219, -145, 54, 153, 185, -118, -157, 52, -40, -169, 107, -163, 117, 10, 109, -303, -33, 179, 35, 63, 2, 41, -167, -6, 46, -175, -94, 144, 195, 60, -2, -157, 185, -250, -49, -170, -204, -103, -32, -46, 163, -96, -232, -64, 206, 273, -166, -227, -127, -12, -14, -248, -98, -145, 440, -51, 48, 212, -426, 140, 275, 314, -190, -270, -342, -139, 95, -110, 298, -114, -93, 16, 253, 150, -110, 390, 282, 180, -162, 121, 90, -170, 72, -83, 150, -353, -119, -5, 341, -89, 100, 61, 58, 1, 58, -203, -85, -28, 174, -126, -44, -31, -18, 12, 170, -88, -354, 326, 19, -1, -223, -124, -175, -270, 43, -54, 73, -345, 90, 19, 171, -40, -251, 332, 245, 259, -14, -85, -418, -299, 125, -324, 123, -124, 475, 153, 349, 205, -154, 290, 37, 45, -230, -81, -178, -215, 335, 40, 230, -357, 310, -126, 269, 58, -334, 131, 101, 254, -141, -235, 7, -240, 30, 35, -22, -147, 183, -16, 22, -100, -138, 154, -4, -158, 46, 154, -301, -147, -85, 155, -97, -275, 68, 84, 160, 151, -319, 105, 230, -179, -41, -105, -23, -445, 463, -29, -24, -255, 53, -256, 349, -126, -481, 341, 224, 239, -322, -302, -98, -143, 170, -279, 78, -369, 124, 106, 379, -65, -202, 393, 148, -31, 25, -257, -260, -217, 80, 35, 119, 1, 191, -242, 87, 342, 19, -120, -80, 241, -29, -76, -314, 1, -125, -219, 76, -167, 65, 3, 281, 24, -17, 22, -131, 295, -81, 80, -116, -56, -51, 148, -231, 80, 232, 28, 74, -219, -231, 383, 165, 165, -122, -124, 66, -237, 357, 1, 318, -54, 391, -175, 353, -331, -405, 247, 40, -27, -38, 86, -286, -118, 306, -253, 235, -210, 153, -77, 158, -217, -229, 177, 345, 145, 66, 29, -100, 30, 78, -155, 115, -13, 193, -136, 250, -6, -98, -10, -90, 112, 25, -141, -107, 71, -27, -156, 101, -137, 5, 65, 45, 23, -100, -15, -24, 151, 161, 80, -155, 250, -107, 40, -82, 127, 201, -110, 26, -257, 22, 154, -109, -13, -108, 95, -81, 14, -46, -278, 45, -130, 132, 94, 205, -57, -65, -42, 120, 273, 174, -8, -103, -170, 201, -323, 24, -205, 274, 49, 151, 39, -38, 43, 139, -92, -239, -203, 160, -41, -99, -9, -33, 89, 311, 125, 136, 31, -311, 64, 44, 168, -124, -45, 97, 155, 131, 33, 90, 211, 229, 155, 51, -27, 61, -229, -16, -166, 13, 256, -85, -69, -208, -125, 31, -174, 134, 266, 51, -182, 87, 98, -266, -75, 140, -39, -21, -70, 52, -230, -159, -113, -47, -17, -114, -101, -52, 216, -70, 88, -134, -306, -153, -56, 27, -294, 195, -114, -30, 17, 167, -14, 154, -62, -187, -246, 256, -154, 116, 76, 62, -133, -302, 237, 212, -25, 55, -65, -402, -140, 271, -144, -256, -117, -135, -160, 174, -27, -30, 193, 6, -118, 217, -177, -111, -148, 80, -6, 259, 249, -190, 226, -5, -133, -272, 180, 218, -133, -196, 200, 226, -8, -30, -163, 76, 271, 195, 28, -218, 44, 77, 153, 74, 48, -100, -69, 501, -408, -465, 15, 212, -400, 14, 196, -245, -36, 65, 7, 236, 267, -91, 228, 215, -49, -24, -133, 233, -121, -180, 13, -63, -266, -171, 79, -208, 52, 177, -430, -222, 51, 204, -65, -151, -83, -96, -124, -120, -276, 54, 20, -160, 204, 288, -350, -181, 14, 63, 4, 167, 200, -82, -104, 226, 167, 58, -47, 82, 47, -166, -114, 227, -217, -307, -342, 222, 88, 57, -26, -61, -30, -53, -52, -155, -46, -169, -263, 489, -78, -174, -117, 383, -120, 50, 350, -197, 5, -40, 220, 18, 138, -250, 479, 66, 91, 121, 70, -38, -25, -30, -128, -78, 73, -39, 63, -19, 154, -88, -254, -90, 150, 1, 76, 259, -271, -83, -86, -10, -77, 83, 26, -49, 158, 224, 26, -21, 24, 17, 192, 107, 280, -337, 91, 375, -147, -155, -224, -165, -25, -18, -204, 212, -191, -97, -198, 85, 42, 76, 17, -292, -19, -2, 200, -220, -81, -147, -412, -87, -45, -146, -28, 143, -206, -67, -32, -85, 79, -225, -57, 76, -78, -115, 60, 154, -159, 163, 197, 167, 25, -344, 67, -24, -36, 85, -298, 166, -209, 124, 37, -245, 222, 171, 153, 54, -143, -48, -53, -84, -41, 16, -193, 74, 24, 219, -78, -13, 146, -6, 208, -32, 214, -190, 217, 162, -32, -131, -246, -68, -163, 222, -219, 165, 113, 174, -198, -126, -21, -27, 59, 124, -165, -183, 62, -260, 93, -123, -66, -362, 349, 167, -79, -255, -165, 16, -249, 33, 64, 43, -281, 10, -295, -2, 114, 271, -300, 76, 156, 292, -146, 162, 49, -186, -123, -62, 163, 73, 95, 59, 235, -148, 48, -140, 236, 97, -293, -12, 213, -230, -266, 156, 192, 276, 206, 31, -149, 29, -84, -82, -16, 49, 87, 135, 290, -181, -121, 63, 111, -260, -131, 101, 26, 74, 57, 72, -166, -134, 33, 39, -144, 0, 29, -231, -93, 87, 282, -4, -401, 100, 293, 217, 146, -40, -168, -61, -19, 226, 46, -57, 102, 333, -213, 181, -159, 239, -167, -189, 68, 373, -270, 205, 287, -244, 29, -164, 117, -246, 236, -212, 191, 133, -31, -190, -13, 239, -67, 220, 9, -57, -230, 85, 21, 102, 158, 50, 21, 90, 140, 147, 179, 182, -65, -162, 18, 153, -103, 49, 35, -204, -94, 168, -32, -55, -69, 91, 159, -65, 94, -53, 120, -176, 102, -170, -28, 133, 1, 56, -181, -32, 260, -114, 138, -22, -412, 55, -106, -82, -166, -37, -256, 34, -222, 168, -79, -8, -54, -122, 176, 189, -242, -8, 38, 64, -132, 33, 120, -83, -122, 99, -103, -323, 256, 184, 90, -276, 51, -46, -42, 340, -145, -1, -42, -80, 58, 125, -53, 105, 32, 89, 142, -101, 132, 125, 208, 193, 137, 56, -238, -12, -205, 13, -169, -97, -30, 51, -269, 97, -141, -90, 231, -266, 191, -113, 86, -21, -72, -97, 99, -110, 180, -232, 98, 177, -208, -84, -86, -46, -61, 148, -49, 320, -32, 227, -334, 98, 88, 35, 38, 46, -360, -176, 73, -91, -121, -146, 9, 22, 75, 256, -42, -285, 346, 241, 81, -69, -89, -5, -386, 219, 218, -77, -171, 98, -226, 204, 97, -33, -112, 152, 152, 34, 66, 119, -155, -199, 43, 130, -137, -44, -96, 82, -288, -136, 180, 67, 58, 240, -51, -101, 89, 76, -165, -18, 136, 163, 147, 207, -95, -269, 174, 176, -33, 7, -154, 34, 31, 75, -125, -131, 170, 93, -5, 4, -255, -115, 28, -94, -301, 115, -40, 222, 64, -253, 17, -361, 297, -179, 34, -122, -332, -498, 281, 146, 81, -278, -275, -391, -361, 191, 223, -101, -58, 252, -214, 112, 303, -63, 104, 77, 83, -6, 261, 69, -349, 239, 101, 17, -165, -216, -167, -42, 214, -158, 43, -76, 196, -192, -289, -128, -184, 198, -114, 185, -211, 175, 193, -2, 42, 261, -80, -165, 59, -100, -91, -102, -10, 96, -207, -315, -50, 122, 73, 68, 25, 283, 43, 53, -269, 315, -203, 78, 271, -252, 254, -237, 276, -168, -30, -139, 91, -524, 353, 229, 57, -60, -142, -120, -139, 219, -241, 245, -152, 68, 18, 123, -110, -320, 281, 100, 94, -293, 137, 79, -199, 243, -207, 369, -253, 46, -218, -91, -102, -115, -243, -60, 208, 198, -75, 57, 190, 198, -45, -201, -9, -41, 151, 98, -128, -259, 201, -44, 148, -109, 113, -111, 66, 174, -262, 215, -231, 232, -61, 174, -299, 182, -137, -75, 8, 164, 17, 133, -65, -230, -86, -109, 27, -206, 6, 41, 46, -317, 478, 341, 236, -222, 232, -178, -364, 430, -294, 250, -320, -201, -10, 23, 124, 308, 72, -229, -361, 21, 459, 86, -109, -87, 81, 121, -40, -47, -2, -456, 50, 43, -181, 18, 150, -103, -124, 83, -96, 62, 188, -96, 53, -207, -160, -115, -81, -9, 272, -59, -43, 28, -176, 19, 103, 20, -150, -92, -52, 106, -100, 250, 2, -92, -80, -190, -220, -14, 237, -166, -25, -163, 175, -183, 239, -42, -23, 4, 439, -583, 218, 202, 110, -80, 443, -129, -302, 113, 154, -186, -221, -109, 8, -34, 41, 227, -91, -144, -77, 59, 159, 269, -36, 78, 290, -352, 152, -351, -88, -82, 261, -65, -69, 73, -90, 173, 403, 191, 157, -55, -106, -167, -20, -267, 102, -97, -53, 276, -127, -53, -155, 159, -99, -71, 90, -168, 150, -247, -75, 80, -235, -60, -57, 24, 17, -178, 96, 71, 187, 101, -97, 66, 192, -313, 211, -257, -349, -104, 251, 110, 38, 214, 378, -169, 154, 88, 233, 114, 34, -13, 48, -105, -173, -229, 30, 70, -119, -12, -167, 240, 139, -86, 214, -45, 185, -14, 325, -8, 240, -272, 183, 148, -4, 8, -260, -30, 75, -113, 3, -142, 35, -289, 2, -163, -137, 0, -361, 155, 6, -194, -268, 359, 145, -108, 299, -257, 134, -44, 273, -23, -218, -84, 36, 385, -189, -269, -151, -45, 27, 114, 125, 148, 136, -150, 91, -251, -310, 188, -184, 115, -332, -88, -139, 89, 200, 274, 301, 15, 14, -16, 122, 6, -111, -399, -73, 356, -280, -103, -216, 119, -56, 158, 364, -175, 40, -239, 365, -225, 284, -136, 81, 12, 67, 9, 22, 157, -28, 240, 102, 167, -27, -290, 261, -138, 166, -265, -110, 114, 7, 252, -175, -84, 137, -44, -19, 41, -277, 21, 82, 209, 21, -140, -231, 378, -54, -203, -112, 365, 29, 221, 160, -320, 52, 3, 364, 115, -10, -74, -104, 274, -264, -235, -243, 104, -48, 357, 191, -34, -95, 98, -56, -223, -225, -131, -64, 69, -95, -44, -1, -155, -94, 0, 318, -249, -150, -84, -4, 4, -182, 109, -28, 162, 27, 105, -15, -50, -9, 50, 83, -335, 142, -197, 150, 11, -19, -5, 65, -415, 220, 342, 294, -116, 23, -71, -63, 87, -228, -17, 80, -44, -340, 242, 32, 191, 211, 127, -160, -160, 37, -133, 135, 88, 79, -59, -25, -39, -188, -78, -119, 0, 16, -201, -128, -22, 51, 205, 203, -251, 55, -68, 139, -213, 57, -194, 89, 143, -474, -147, -11, 215, -80, 10, 483, -289, -150, -102, 402, -64, 199, 92, 89, 74, -32, -19, -82, -39, 30, 315, 160, -190, 46, -287, -29, -401, -124, -363, 145, 379, -251, -80, -198, 123, 64, 200, 139, -314, 131, -168, 274, -175, -17, -56, 74, -237, 399, -4, 77, -194, -69, -225, -175, 220, 88, -68, -72, 189, -183, 57, -90, 104, 45, 77, 23, -30, 34, 245, 32, -195, -78, 9, -6, 126, -20, -48, 129, -4, -185, -77, -126, 106, 235, 104, 426, 31, 20, -284, -41, 172, -66, -98, 84, 373, -314, -14, -207, 90, -31, 359, 299, -430, -48, -280, 430, -229, 122, -257, 16, 360, -122, -226, -7, 332, 2, -61, 393, -208, 48, -257, -4, 70, -135, -152, 30, -188, -33, 162, 90, 24, 89, -147, 123, 221, -219, 105, -231, 67, -141, 68, -151, -95, 78, 152, -117, 5, 78, -312, 72, -86, 77, 102, 46, -7, 93, 209, -19, 123, -276, 218, 63, 184, -116, 13, 302, -95, -30, -169, 141, 71, -137, -58, 291, 356, -220, -165, -56, 144, 298, 156, 262, -250, -88, 33, 444, -421, 74, -504, 153, 59, -3, -20, -179, 58, -266, -160, 256, -217, -209, 60, -26, 64, 190, 11, -116, -36, 5, 18, 100, -111, -164, -197, 136, -5, 32, 19, -13, 28, -95, 201, -166, -177, -132, 273, 45, 60, 41, -72, -60, 64, -261, 165, 44, 86, 152, 205, 64, 371, -359, 1, 235, 109, 66, 54, 102, -121, 97, 71, 202, 22, -268, -198, 94, 123, -164, -106, -264, 18, 307, -108, -5, -209, 149, 279, -20, -235, 312, -34, -47, -77, 0, -136, -78, -73, 262, 133, 90, -191, 18, 17, 210, 84, 227, 0, -135, 138, -106, -124, -26, -125, 0, 123, 135, 60, 185, -230, 295, -524, -214, -158, -99, -137, 201, 84, -204, -170, 151, -142, -41, 94, -43, 135, -121, 274, -3, -114, 36, -194, -89, 140, 161, 3, 147, 38, 239, -238, -30, 91, 114, -197, 126, -186, -83, -100, 128, 198, 10, -154, 57, 48, -232, 155, -210, 348, 37, -83, -130, -85, 3, 15, -13, -307, -138, -28, 48, -28, 58, -26, 26, 177, -27, 61, -100, 91, -81, 434, -211, -47, -101, 42, -92, -68, -6, -324, 270, -162, 296, -227, -208, -115, 26, -97, 159, -142, -114, 60, 108, 189, 158, 109, -63, -39, -165, -80, -222, -97, -22, -105, 108, 83, 76, -43, 116, -48, 177, 195, 237, -73, -95, -361, 154, -186, 185, 38, -54, -88, 10, -34, 191, 225, 53, 14, -63, 183, 41, -166, -26, -154, 45, -300, 267, 65, 196, -13, -244, -54, 60, 221, 162, 1, -144, 358, 5, 242, -241, -56, 207, -172, 68, 226, -44, 24, -149, -174, 293, -346, 218, -298, -73, 68, 197, -24, -127, -47, -77, 65, 35, -150, 139, -218, -55, -267, -30, -107, 182, 166, 103, 121, -172, 160, -121, 90, 19, -86, 153, 210, -88, -188, 51, -277, -198, -20, 107, 23, -304, -154, -166, -35, -32, 35, 266, -42, -243, -176, 223, -282, -49, -382, 12, -90, 60, 228, 25, -65, 61, 113, -115, 55, -10, 54, -67, -20, -88, 110, 46, -367, 416, 400, -84, -2, 160, -258, -325, 301, -10, -93, -286, 42, -435, 8, -1, -31, 6, 241, 89, -97, 122, 81, 21, -3, -101, -77, -297, -110, 68, -92, -46, 317, -59, -308, -152, 72, 253, 332, 231, -370, 15, 13, 413, -143, -71, -169, -17, 15, -217, 82, -70, -75, 277, -13, -59, 68, 165, -80, 260, -12, 172, -332, -350, 72, -90, -24, -114, 169, 108, 121, 190, 57, -26, -83, 4, 24, -317, -132, -5, -94, 456, 278, 57, -108, 35, -43, -176, 158, 372, -98, -339, -270, -190, -220, 220, 290, -266, -206, -64, -41, -141, -117, -18, -327, 96, -117, 106, -8, 17, 100, -139, 105, -455, -354, -210, 78, 110, 56, 276, -312, 151, -78, 387, -14, -96, -422, -140, 133, -50, 140, -109, -171, -22, 50, 131, 101, -48, 310, -29, 42, 45, -193, -239, -20, 274, -98, 229, 16, 142, -100, 43, 119, 165, 73, -83, 11, -413, 54, 63, 211, -158, 59, -197, 63, 243, 88, -8, -228, 401, -273, 69, -212, -14, -167, 128, 104, -152, -365, -98, 67, -117, 348, 124, -12, -7, -115, 193, -123, 6, -279, -49, 371, -328, -340, -126, -28, 241, 98, 101, -317, 155, -108, 176, -166, 36, -494, 69, 296, -345, -282, 43, 121, 113, 189, 402, -338, -142, -49, 193, -279, 156, -75, -254, -118, 218, 151, 28, -95, 72, -197, -206, 52, 172, 363, -26, -153, 25, -257, 82, 293, -72, 128, -227, -135, 87, 50, -101, -80, 328, -90, 131, 54, 92, -325, 197, 148, -329, -25, 24, -202, 37, 94, 128, -156, -284, 189, 109, -138, -28, -158, 195, 389, -373, -160, -15, 81, 223, 308, 210, -183, 184, 31, 121, -50, -15, -287, 40, 178, -461, -201, -28, 359, 280, 143, 228, -155, -85, 10, 138, -297, 140, -414, 76, 121, 100, 132, -226, 53, 187, 41, -145, -142, 149, 124, 178, -328, -72, -207, 254, 117, -233, -1, -44, -131, 0, 91, 139, -113, 82, -35, 239, -93, 22, -172, 317, 107, 120, 29, -158, -129, -363, 110, 238, 111, 86, -159, 13, -36, 112, 67, 137, 271, -191, -127, -218, -76, 131, -7, 28, -30, -10, 143, -40, -217, -167, -362, -212, -35, -280, -203, 9, 221, 117, -52, 348, -83, -29, -257, 110, -330, 154, -171, -99, 372, -146, -231, -457, 200, 320, 151, 235, -105, 369, 82, 301, -280, 91, -390, -142, 178, 65, -95, 5, 228, 101, 162, 45, 51, 64, -12, 202, 1, -138, -181, 271, -188, -175, 102, 25, 92, -81, 132, -26, -217, 108, -95, 96, -115, -100, -88, -336, 221, -319, -213, -399, 80, 195, 165, 154, 110, 179, 17, 312, -418, -147, -353, 73, 104, -59, -130, -276, 197, 170, -42, 151, 65, 319, 122, 107, -27, 244, -101, -101, 165, -72, -248, -237, -230, 185, 263, 225, -225, 107, 175, 122, 234, -21, -6, -112, -116, 186, 66, -152, -70, -73, 59, -40, 77, -26, -228, -141, 197, -200, 22, 41, -17, -158, 162, -35, 75, 268, 198, 96, 15, 10, 19, 77, -156, 0, -277, -40, 486, -302, -359, -201, 349, 285, 301, 149, -104, 132, -256, 260, -178, -151, -475, -6, 14, -81, 39, -108, -159, 175, -164, 180, 242, -90, -30, 51, -215, 146, 225, 136, 305, -45, -111, -49, 18, 297, 122, 156, -326, -197, -3, 9, 112, 153, -334, 221, -196, -97, 19, -54, -199, -92, 28, -179, -105, -139, 230, -6, 115, -143, -102, -91, 214, -42, 27, -321, -40, 145, 39, -141, 114, -57, -287, 173, 67, -16, -158, -106, 130, -286, -393, -191, 211, 196, 80, 368, -338, -79, -141, 334, 200, 79, -316, -64, 140, -64, 39, -114, 115, 17, -46, 186, -127, 37, 16, -3, -230, 5, 38, 384, 210, -360, -255, 155, 28, 149, 289, 69, -72, -25, -139, 53, -119, 69, -83, 180, 164, -118, -107, -100, -55, 27, 150, 260, 75, 29, -262, -100, -193, -31, 12, 25, 5, 179, 100, 23, -3, 35, 160, 25, 192, 102, -65, -182, -234, 50, -113, 131, -24, -270, -163, 4, 88, 155, 223, 160, -171, 95, -280, 391, -28, -301, -172, -64, 275, -202, -35, -20, 356, -15, -35, 167, -57, 112, -197, 280, -325, -75, -119, 196, 110, -320, -116, 93, 130, -43, 67, 171, -38, 84, 61, 99, 22, 56, -33, -264, 362, -250, -96, 32, 139, -72, 209, 81, -76, 176, -76, 43, -213, -136, -201, -173, 126, -21, -62, -246, -105, 381, 339, 94, -111, 243, 153, 13, -227, -181, 159, 253, 200, -48, 0, -202, -34, 181, 196, 92, -296, 161, -256, 269, -277, 171, -192, 23, 301, -61, -135, -137, 291, 358, 303, 67, -183, 118, -82, 50, -280, -6, -223, 40, 206, -160, -160, -159, 85, 233, -9, 155, -173, 96, 165, 57, -149, 117, -173, 107, -33, 202, 202, 223, 95, 338, 73, -246, 264, 113, -75, -230, -321, -208, 168, 94, 74, -58, 105, -49, 220, 209, -154, 124, 15, 184, 50, -29, 0, -85, -54, -192, -93, -369, -252, -199, 30, 15, 9, -55, -229, 88, 334, 188, -104, 101, 53, 39, 215, -312, -153, -124, 8, 216, 67, 72, -13, 113, -342, 285, -68, 150, -222, -1, 209, 0, -58, -194, 187, 81, -62, 269, -203, 161, -5, 150, 77, 127, -46, 268, 90, -54, -4, -31, -275, 253, 69, -284, 149, -111, 81, -262, -212, -277, -111, 57, 242, -188, 55, -217, -20, 432, 154, 21, 69, 207, 94, 166, 78, -71, -181, 45, 64, -198, -40, -179, 71, 71, 28, 56, -262, 158, 358, -158, -103, 87, -199, -118, 284, -308, -174, 178, 155, 165, 13, 157, -88, 150, -139, 121, -132, 50, -151, -59, 4, 151, -14, -199, -174, 185, 94, -71, 24, 29, 117, 56, 354, -244, -10, 229, -70, -94, -13, 351, 202, -13, -128, 57, -77, -121, 6, 21, -139, 142, -159, 111, 73, 24, -14, -54, 78, 95, -85, 4, -64, -97, 97, -202, 87, 123, 190, -37, -172, 18, 51, -176, -335, 147, 66, 130, -1, 227, 143, -11, -2, 101, -187, 146, -114, 87, 39, -118, -8, 209, -37, 90, 231, 82, 73, -115, -153, 63, -179, -111, 83, -130, -356, 146, 181, 22, 119, 142, -15, 169, -225, -42, 233, 59, -204, 183, 59, -15, 36, 162, -141, 55, -29, -260, 33, -13, 144, -190, -27, -21, 120, 287, -74, 152, -86, 78, -42, 76, 138, -22, 8, 153, 300, -6, -67, 126, -88, 98, 312, -59, -312, -30, 25, 233, -18, 79, -263, -144, -15, 154, 203, 75, -291, 202, -62, 48, 117, 19, -274, 174, -188, -268, 298, 277, 209, -63, -146, -319, -5, -188, 126, -221, -115, 158, -140, 43, 85, -32, -154, 3, 213, 105, 308, 256, -119, 171, -236, -139, -171, 117, -19, -34, -168, 2, -23, -100, -250, -166, 41, -158, -119, -101, 82, -64, -256, -25, -53, 151, 224, -231, -47, 26, 66, 188, 58, 129, 122, -23, 91, -25, -150, -230, 208, 141, -34, 28, -50, 8, 117, 139, -77, 205, -213, 199, -122, 142, 344, -213, -477, 44, -117, -107, 351, 311, 112, -84, 274, -355, 80, 112, -149, -61, -85, 1, -15, -141, 38, 292, -82, -4, 155, 88, 132, -10, -35, -31, -260, 206, 62, 186, -90, 25, 79, -196, 204, -62, 173, -12, 208, -158, -21, -172, 49, 3, -109, -85, 230, -51, 28, 245, -202, 70, -349, 122, -185, -26, -309, -254, -66, -133, 221, 29, -225, -109, -199, 101, 93, 145, 26, -64, -161, -135, 181, -16, -49, 286, 177, 106, -210, 40, -241, 8, 169, -32, 25, -150, -5, 46, -62, 271, -250, 130, 143, 204, 43, 81, -49, -102, -63, -26, 247, -58, 200, 0, -27, 46, 30, 202, 169, -111, -164, 57, -53, -227, -117, -74, -93, -78, 77, 50, 201, -191, 68, -183, -165, -48, 124, 98, 306, 16, -177, 89, -181, -102, -204, 290, -186, -46, -93, 176, 314, 167, -110, -32, -194, 89, 145, 314, -154, -78, 292, -96, 93, -127, -128, 133, -108, -139, -44, 238, 53, -127, 126, 329, 116, 112, -173, -233, -124, 133, -1, -199, -60, 204, -55, 170, 168, -62, -45, 149, 129, 229, -75, -126, -154, 233, -119, 41, 44, 183, -121, 195, 149, 30, 61, -137, -69, 6, -264, 129, -98, 207, 172, -14, -390, -341, 199, 155, -71, -174, -121, 149, -37, 189, -1, -42, -122, -18, -104, 89, 103, -142, -89, 173, 146, -169, 136, -102, -165, 30, -106, -49, -108, -216, -81, 109, 6, -142, 203, 285, -38, -31, -183, 133, -3, -155, -158, -21, -24, 143, -108, -291, -209, -15, 87, 261, 215, 86, -236, -149, -38, -169, 1, -142, -216, 184, -155, -94, -141, 49, 77, 136, 66, 84, 159, -90, 176, -48, 0, -5, -87, 5, 104, -71, -335, -131, -157, -118, -98, 228, -164, 207, -202, -3, -5, 72, -256, -40, 22, 99, -172, -9, -471, 278, -10, -7, 19, 138, -242, -47, -152, -217, -51, -124, 422, -351, -51, -336, 146, 16, -11, 21, -222, 19, -233, -8, -186, 57, -116, 224, 16, -151, -174, -6, 155, -101, 320, 73, -71, -186, 145, 213, -120, 186, -234, 31, -97, -10, 225, -79, -265, 166, -133, -207, -18, -20, 122, -18, -246, 138, 90, 38, -4, -256, 27, -292, -134, -31, 45, 209, -245, 132, -374, 254, -310, -108, -247, 48, -23, 143, 116, -200, -177, 352, 144, 1, 262, 166, 50, -192, -14, -309, 47, -68, 289, -185, -5, -199, 240, 175, 231, 73, -280, 101, -464, 322, -410, 190, -127, 28, -21, 9, -92, 8, 117, -134, -10, 72, -263, -322, 74, -177, -134, 80, -199, 59, -81, 112, 49, 34, -46, -68, -201, -39, 337, -11, -98, -237, -155, 69, 89, -333, 338, 88, -36, -408, -90, -64, 91, 263, -41, 193, -123, -31, -338, -70, -49, 33, -535, 211, 351, 102, -468, 46, -232, -58, 603, 355, 330, -287, 270, -402, 232, 174, 223, -348, 66, 52, 5, 361, 139, 85, -128, 197, -240, -9, -195, 0, -370, 352, 178, -91, 6, 290, 156, -213, 184, 445, -149, -508, -32, 142, -21, -9, -368, 46, 240, 89, -16, -96, 169, -51, 242, -148, -153, 149, 49, 97, -294, 101, 18, -200, 216, -23, 155, -278, -197, 75, 155, -115, -147, 199, 143, 138, -185, 154, -178, 64, -236, 351, 223, -163, -474, 286, 61, -160, 161, -24, 413, -508, -102, -111, 255, -81, -263, 122, 266, -42, -109, 147, -176, -156, 309, -23, 41, -10, 118, -188, -95, 160, -249, -205, -155, 148, -239, -47, 169, 143, 114, -217, 144, -132, 6, 101, 105, 104, 90, 51, -93, 30, -100, -111, -83, 223, -182, 112, 26, -18, -151, -174, -44, -168, 214, 59, 35, -195, -253, 186, 13, 13, 8, 452, 348, 23, -141, -89, -192, -102, -455, 283, -57, -122, -35, -16, -157, -178, 15, -39, 224, -405, 78, -185, 215, 258, -256, -224, -13, 28, 123, 41, 25, 81, 139, 139, -1, -148, -34, 141, 211, 276, -139, 20, 78, 126, 46, -196, -120, 39, -114, -157, 46, -228, 355, 35, 148, 162, -305, 13, 362, -86, -141, 23, 23, -188, 286, -84, 209, -302, 171, -331, 135, -128, 81, 99, 146, -104, -97, 35, 108, 91, -62, 118, 133, 108, -69, 107, -57, 144, -371, 115, 132, -3, 19, 211, -46, -164, -57, -56, 9, 73, 97, -138, -29, 61, 169, -32, -116, -29, 106, 96, -12, 111, -295, -52, 102, 106, 110, -3, -126, -163, -326, 365, 11, -57, -93, 141, -364, -193, 297, -18, 1, -147, 23, -113, 142, 58, -274, 343, 86, 115, -225, 6, -86, -73, 158, 129, 8, -191, 179, -54, 316, -83, -168, -165, -108, -90, -24, 2, 212, -131, -37, 183, -117, 140, 89, 241, 143, 98, -50, 34, 215, -61, -267, 317, -118, -151, -110, -68, 201, -60, -254, 94, -87, -113, 126, -12, 113, -126, -55, -44, 79, 175, 92, 205, 193, 215, 22, 92, -128, -326, -261, 297, 293, -21, 78, -36, -259, -81, 53, 205, 1, 41, -102, -152, 44, -119, 85, -68, 0, 56, 144, -16, -35, 154, -25, 207, -124, -20, -170, 40, -56, -114, 139, 221, -108, 123, -230, -131, 125, -33, 142, 55, 314, -130, -70, 192, 31, 254, -414, 223, -26, 169, -202, 98, 168, -21, 216, 96, 191, -22, -98, 98, 117, 182, 105, 197, -9, -38, -157, 97, 193, 85, -125, -227, 55, -21, 109, 6, -56, -223, -219, 291, 246, -140, -205, 43, -24, -255, 85, -136, 141, -36, -17, 14, 294, -236, 179, -27, 46, 48, 115, 170, 106, -17, -186, 259, -150, 18, -157, 64, 121, -190, -60, -182, 80, -66, -73, -67, -171, 196, -168, 119, 297, -150, 168, 323, -29, 127, -139, 114, 19, -65, -288, 233, 7, -25, 161, 126, 27, 101, -57, -101, 11, 257, -331, 220, 163, 101, -9, 157, -14, -317, 189, 48, 43, -189, -128, 145, -172, -141, -59, 278, 296, -82, 135, -62, -137, 104, 300, -95, 145, -32, 32, -271, 134, -59, 9, -23, -151, 186, 0, -11, -156, 103, 174, 81, 87, -188, -14, -304, 155, 135, 50, -32, 254, -160, -256, -228, -248, 128, 147, 117, 105, -16, 100, -105, 119, 57, -171, 158, 0, 30, -189, 110, 40, -201, 171, -39, -65, -9, 184, 245, 35, -114, -273, 398, 211, 29, -41, 37, -116, -156, 137, 31, 121, -376, -98, -137, 123, -87, -168, 41, -41, 7, -76, -25, 45, -136, -184, -139, -3, -18, 127, 179, 152, 116, -164, 76, -46, 150, -120, 123, -192, -195, 67, 97, -211, -8, -72, -251, 188, -24, -163, -98, 136, 153, 95, 54, -181, -162, 303, -117, 277, -89, -84, 129, 147, 25, -116, 262, -29, -118, -235, 177, -107, -59, 51, 296, 122, -5, 81, 81, 119, -15, -168, 267, 344, 30, -162, -61, -303, -192, 225, -135, 173, -13, 220, -257, 239, 53, -12, -110, -89, 82, 27, -382, -33, -183, 10, -72, -272, -146, -26, 55, 188, -172, -230, 12, -136, 65, -32, -61, -276, -140, 243, 102, -5, -94, 88, -92, 31, 102, -77, -81, 267, -31, -29, 40, -300, -150, 3, 136, 74, -181, 66, -192, -61, 110, -323, 293, 262, -129, -224, 226, -302, -135, 263, 103, -115, -44, 297, 166, -109, -54, 82, -80, 129, 6, 34, 23, -4, 32, -25, -180, 18, 43, 213, -139, -41, -18, 26, -208, -216, -66, 206, -457, 169, 131, -224, -110, -229, 268, 12, 14, -281, -3, 93, 13, -8, -136, -119, 245, 106, -42, 152, 293, -42, 100, 44, -127, 133, 256, -130, 22, 55, -56, -70, -225, -196, -108, 23, -37, 90, -191, 71, -51, -27, -99, -164, 311, 313, -217, 154, 109, -142, -82, 0, 142, 188, -134, -126, 167, 82, 192, -110, -25, 1, -134, 25, 0, -218, -273, -49, 49, 375, -155, -103, 144, 222, 109, 84, -100, -521, -101, 41, -353, 472, 73, -210, -83, -350, 379, -96, 40, -206, 165, -145, 163, -129, 7, -116, 47, -244, -5, 125, -155, 49, 69, 92, -129, 83, -60, 13, -43, 194, 138, -143, -3, 4, -58, -195, 3, -59, -104, 166, -1, -119, -207, 62, -146, 129, -85, 127, 5, 136, 228, -143, 102, -154, 151, -237, 213, -213, 6, -349, 112, 279, 183, -199, 87, -13, 65, -22, 88, -14, -188, 23, -356, 185, -154, 357, -301, -398, -191, 45, -155, 38, 5, -377, 3, -139, 119, 59, -26, -162, -40, -92, 157, 59, 9, -106, 50, -42, -24, 113, 388, 113, -179, 10, -89, 193, -42, -78, 20, 226, 220, 45, 199, 104, 105, -42, -89, 292, 20, 78, -98, 37, -227, 100, 49, 131, -95, 197, 85, -21, -108, -68, -127, 128, -67, 78, 41, -44, 72, -176, 22, 368, 15, -280, 57, -113, -61, 254, 76, 222, 41, 212, 10, 68, -194, 57, -214, -27, -135, -49, -200, -65, 46, 2, -172, 219, -65, 116, 167, 24, -94, 39, 210, 310, -162, 19, 56, -79, 51, 305, 113, -152, -46, 76, -327, 171, -15, -46, 82, -153, 17, 10, 80, -164, -159, -18, -126, -4, 80, 94, 12, 197, -179, -54, 135, -147, -187, -108, -63, 136, -173, 116, 102, 219, 94, 159, 49, 89, -115, -140, 208, 324, 230, 9, 146, 3, -244, 84, 131, 114, -328, 122, 84, 96, -206, -253, -60, 26, 104, 124, 98, -142, 74, 83, -63, 160, -123, 21, 93, -93, -41, -29, 132, 61, 153, -47, -147, 9, 58, 35, 165, 112, 69, -13, -231, 171, -47, 90, 158, -25, 47, -132, 36, 214, -164, -224, -17, 9, 83, -82, 134, -153, -116, -48, 76, -173, -219, -106, -15, -77, -198, 21, -202, 161, -132, 28, -68, 137, -54, -76, 74, 63, 240, 1, -232, -229, 46, 226, -103, -190, -117, -85, 130, -71, -143, -89, 196, 99, 18, -169, -147, -114, -145, -85, -50, 48, -43, 115, 130, 48, -224, -402, 535, 529, 2, -64, 181, -160, -73, 488, 17, -69, -461, 52, -249, 389, -365, -89, 46, -233, -242, -119, -119, 199, -88, 16, 85, 0, -130, -156, -154, -198, -172, -192, 100, 13, 98, 149, -306, -18, -6, 197, 80, 105, 64, -71, 58, -1, -141, 8, -73, 111, 130, -260, 21, -95, -257, 161, 118, 9, -278, -96, 149, 148, 37, 87, 102, -225, 181, 13, -120, -272, 147, -90, -223, 290, 213, 258, -42, -4, 180, -434, 122, 56, 199, -340, -58, -184, -117, 145, 129, 42, -313, 220, -62, 89, -362, 1, -235, 26, -152, -19, -27, -207, 202, 11, 90, 130, 295, -18, -263, -320, 28, 97, -4, -97, -154, 169, -342, -102, -168, -75, 78, -8, 32, 181, -210, 26, -95, -149, 149, 240, 83, 76, 33, -212, -67, -9, 26, 2, -124, 151, 39, 231, -144, 104, 136, -110, 71, 145, -64, 86, 83, -177, 2, 152, 119, 226, 153, 113, 358, -183, 111, 366, 330, -70, -143, -87, -283, 245, -266, -142, -89, 270, -201, 357, -286, 219, 114, -164, -76, 210, -91, -1, 240, 105, 382, -164, -102, -142, -92, -171, -18, 79, -131, 66, -240, 55, -118, 24, 22, 85, 13, 64, 134, -64, -27, -85, 41, -102, 164, 114, 130, 24, 120, -212, -153, 29, -131, 0, -147, 42, -42, 269, 32, -288, -40, 239, 234, -172, 256, 22, -191, -103, -272, 230, -210, 377, 125, 340, 32, -193, 383, 220, 383, -47, -200, -121, -132, 269, -59, -42, -282, -3, 140, 217, 101, 70, 28, -168, -28, 45, 104, 83, -190, 69, -68, -58, 18, -4, 109, -61, -174, -80, 144, 12, 36, 69, 22, 155, 4, -63, 275, -151, 209, -6, -63, -72, -142, 49, -85, -34, 117, -82, -184, -134, -93, 7, -6, 159, -255, 73, 94, 138, 104, -87, 240, 193, 259, -108, 117, 111, -240, 193, -37, 105, -15, 172, 116, -98, 63, -296, 33, 21, 286, -122, -292, -353, -195, 323, -38, 170, -138, 95, 68, -39, -74, 185, 129, 133, 11, 70, -13, 180, -64, -74, -108, 173, -53, -11, 281, 77, -145, -39, 230, 270, 99, -44, -225, -166, -155, 334, 215, 120, -202, -159, -320, 77, -340, -148, 170, -1, -161, -125, -8, -56, -105, -90, 144, 73, -59, -259, 215, -76, -250, -212, 17, -117, 73, -63, -80, -167, -98, 101, 145, -73, -107, 294, -173, 111, -11, -271, 106, 206, 173, -130, -192, -95, -1, 85, -111, 123, -25, 12, 37, 105, -149, -89, 103, -43, 26, -252, 171, 31, -24, 21, -21, -111, -40, -39, -136, -68, 140, -260, 452, 305, 218, -366, -42, -236, -70, 404, 140, -51, -349, 21, -287, 334, -301, -308, 336, 227, -222, -231, -62, -208, -135, 153, 62, 34, -271, 17, 52, 163, -284, -154, -44, -182, -24, 245, 120, 64, -8, -98, -49, 307, -77, 233, -102, -102, -33, -42, -96, -12, -127, -108, 13, -66, -23, -55, 36, -298, -155, -13, -103, 3, 151, 107, -72, -44, -68, 177, 312, 197, 227, -248, 108, 86, 244, -299, -21, -300, 47, -414, 427, 291, 123, -82, 148, -185, -44, 114, 27, 141, -307, 73, -324, 200, -144, -72, 348, 10, -47, -80, 222, 154, -297, 54, 119, 40, -6, 54, -90, -16, -72, 83, 177, -138, 81, 0, 123, -277, 137, -185, 72, 167, -36, 153, 30, 23, 248, 249, 67, 48, 253, 189, -88, -143, 193, 52, -154, -143, -12, 122, 90, -152, -109, 83, -86, -94, -180, -31, 124, 146, -48, -123, 27, 123, -147, -128, -78, -139, -60, -236, 201, 30, -122, -84, -61, 79, -128, 194, 0, -6, -196, 0, -211, 360, -179, -128, 70, 44, -158, -109, -128, -10, -144, 176, -87, 132, 0, -49, 117, -225, -240, 117, -44, -5, 145, -8, -38, -158, 99, 57, 73, 32, 112, 70, 19, -186, 16, -107, 124, -48, 2, -143, -70, 5, 105, -94, -124, 99, 129, -76, -179, -88, }; +int32_t to_patch_embedding_linear_bias[16] = {227, -68, -2, -126, -99, -174, -84, 74, -6, 99, -139, 80, -62, -140, 83, -7, }; +int32_t to_patch_embedding_layer_norm2_weight[16] = {3971, 4588, 4419, 4328, 3995, 4153, 4080, 3987, 4099, 4443, 4075, 3864, 4214, 4134, 4104, 4276, }; +int32_t to_patch_embedding_layer_norm2_bias[16] = {132, -148, 57, 34, 72, -70, -116, -26, -76, 79, -190, 10, -46, 57, -30, 204, }; +int32_t transformer_layers_0_0_norm_weight[16] = {4052, 4657, 4613, 4245, 4042, 4415, 4086, 4275, 4240, 4498, 4285, 4081, 4387, 4184, 4302, 4580, }; +int32_t transformer_layers_0_0_norm_bias[16] = {80, -54, 40, 214, -203, -129, -101, 57, -177, 57, -56, -281, -36, 219, -182, 92, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H0[64] = {-568, -962, 189, -868, -562, 692, 858, 407, -818, -814, 262, -471, 1273, 623, -384, 338, -321, -114, -723, 913, -697, 294, -35, -123, -264, -331, 509, 129, 184, 595, 16, -677, -348, 313, -401, 679, -798, 378, -145, 190, 618, -246, 776, 801, 974, 570, 842, -29, -685, 721, 640, 87, -612, -939, 890, -225, 522, 70, -514, 927, 990, 825, 114, -893, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H1[64] = {640, 166, -336, 542, 491, -1105, -458, -497, 20, -292, 989, -578, -438, 699, -855, 724, 901, 119, -824, 607, 1135, 1478, -883, -673, -923, -897, 445, 395, -782, 260, 591, 327, 970, -1386, 631, 281, -121, -721, 109, 203, 74, 106, 593, 1065, 857, -728, 761, -620, -558, 765, -514, 587, -489, -144, 839, -142, -270, 415, -757, 288, 305, 1302, -249, 247, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H2[64] = {-1419, 962, -640, 252, -124, -585, -573, 363, 218, 537, 461, 201, -502, 636, 804, -1101, 434, 91, -595, -67, -209, -257, 132, 782, -55, -268, -36, -205, -1225, 1346, 648, -933, 360, 693, -726, -675, 1319, 324, -601, -707, 234, 687, 630, 769, 323, -334, -855, 135, -410, 330, -330, 739, -812, -33, -356, -471, 689, -841, 242, -763, -1304, 937, 743, -440, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H3[64] = {-1060, 1048, 444, 53, 299, -1202, -112, -899, 1136, 226, 103, -466, 653, 104, 151, -131, -910, 333, 104, -1167, -337, -744, -291, 445, -339, -916, 64, -170, -569, 334, -1016, 803, -782, -18, 583, -961, 304, -358, 725, 244, -567, -128, -370, 950, 536, -757, 290, -506, -365, -1083, 685, -1292, 555, -640, -304, 840, 919, -707, 665, -777, 781, 909, 869, 882, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H0[64] = {339, 84, 743, 513, 937, -490, 499, -304, 1092, 299, 522, -95, -850, -672, -565, 107, -47, -401, 196, 1062, -158, -507, 736, -381, -249, 768, -185, -849, -107, 483, 520, -997, -234, -945, 1008, -44, 674, -34, -388, -817, 289, 988, -652, -446, -603, 226, 427, 582, -422, 37, 474, -103, 561, 198, 113, 520, 150, 37, -857, 1162, -361, -122, -909, 596, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H1[64] = {587, -190, 215, -264, -1101, -633, 784, 643, 562, 794, -31, 134, -75, 572, -551, 233, -162, -1081, 780, -472, -588, 170, 1040, -1217, 805, 505, -961, -23, 457, 730, -77, 117, 771, -422, -811, -611, 622, 678, 554, -690, 435, 403, -904, 91, -350, -398, -563, -750, 352, -406, -22, 667, 468, -1362, 395, -764, 132, -553, -612, 61, -284, -933, -340, -561, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H2[64] = {399, -840, -111, -768, -787, 925, 1041, 579, -842, 1107, -195, -454, -1018, -673, 330, -1015, 554, 339, 389, 461, 579, -387, -826, 465, -1171, 274, -94, 518, 899, -878, -986, 258, -406, 199, -487, -577, -1264, 1126, -283, -1205, -1311, -101, 970, 79, 183, -108, -499, 980, 122, 110, -163, -25, 767, -718, -836, -838, 839, 120, -734, 789, -324, 119, -159, -411, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H3[64] = {585, 567, -262, -561, -166, 469, 155, -56, -512, 839, -519, 859, -225, 693, -983, -707, 395, -196, -574, 63, 3, -162, -1000, -962, 248, 335, 1235, -284, 994, 727, -475, -891, -428, -817, -598, -1159, 526, 715, -232, -742, -191, -21, 65, 1479, 84, 389, 658, 385, 674, 729, 169, 221, 7, -27, 811, 841, -1080, 645, 14, -1033, -1146, -472, -74, 265, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H0[64] = {356, -364, 862, -1113, -938, 408, 1437, 968, 987, 664, -411, -881, 756, 768, -795, 77, 326, 481, -714, 196, -110, -215, 106, 621, -812, 542, 213, 1043, -188, -725, -266, -114, 785, -690, 427, 627, 1001, 796, -752, -410, -760, -304, 129, 1112, 62, 805, -1030, 382, -1195, -1002, 855, 1261, 1026, -281, 57, -850, 763, 77, 738, -135, 1189, 65, -1168, 617, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H1[64] = {536, 374, 293, 992, -103, -576, -463, -1069, -605, 1261, 597, -599, 643, -622, 268, 603, 712, 373, -455, 8, 760, -1245, -460, 201, 1035, 731, 955, 626, -131, -759, 43, -722, -817, -398, 168, 999, 474, 150, 639, -148, -359, -493, -551, 339, -737, 825, -827, -86, -681, 474, 757, -1097, -858, -351, 372, -792, -44, -609, -879, 540, 286, 701, 875, 406, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H2[64] = {764, 345, -422, -624, 1231, 99, -640, -1501, -301, -900, 283, 1233, -1172, 202, 1417, -498, 544, 858, 106, 761, 381, -695, -1310, 63, 651, -635, 946, 848, 999, 198, 84, -923, 1050, 851, -766, -870, -854, -29, 999, 47, -538, -926, -208, 448, 898, 61, -418, 1075, 429, -731, -414, -264, -538, 892, 876, 667, 311, -928, -294, 449, -854, 53, 670, -212, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H3[64] = {-944, 62, 621, 124, -535, -149, 709, 95, 1129, 832, -644, 656, 547, 233, -187, 737, -793, 821, 16, -558, 129, -235, -896, 491, 753, 42, 343, 894, -531, -820, 518, -426, -787, 3, -398, -1120, 1170, 1063, -813, -105, -78, -135, 248, -263, -351, -172, 224, -430, -1072, -956, 331, -6, -221, -602, -34, 0, 913, -859, -110, -512, 1154, 657, -630, 8, }; +int32_t transformer_layers_0_0_fn_projection_weight[256] = {-402, -1077, -244, -103, 318, -176, 766, -1187, -866, 337, 1127, 451, -280, -1007, -185, -704, 654, 854, 369, -532, 565, -666, 1063, 433, 312, 232, 211, 846, 273, 115, -969, 847, -514, 236, -588, 549, -298, 759, -253, 1035, 6, -854, -445, -1030, -204, -85, -398, -307, 785, 142, -1233, -991, 496, 512, -675, -12, 172, 11, -1111, -633, 573, 502, -201, 322, -391, 248, -499, -56, -559, -305, -527, 629, 315, 130, -98, -248, 172, 148, 36, -337, 494, 353, 696, 517, 187, -1141, 985, -1041, -1095, 86, -29, 626, -1129, 678, -357, 67, 557, 291, -223, 493, -797, -561, 1218, -793, -542, 266, 275, 229, -637, -993, 965, 673, -884, 707, -19, -635, -663, -730, 87, 528, -179, 1047, -677, 1117, -854, -716, -700, 234, -970, 807, -180, -116, 1006, -13, -1029, -40, 182, 390, -1164, -858, 584, -453, 202, -765, 821, 362, -337, -572, 40, 20, -963, 525, -390, -743, 990, -432, 156, -54, 629, 666, -252, 461, 486, -5, 762, -728, 3, -742, -741, 1112, 1431, 1199, -676, -393, 403, -522, -474, -760, 508, -904, -265, 203, 78, -1096, -852, 587, 113, -680, 171, -308, -231, -484, -210, -463, 635, -561, -1093, 140, 509, -767, -329, 120, 518, 396, 280, -194, -414, 772, -697, -104, 218, 260, -105, 210, 1339, -369, -991, 856, 977, -735, 664, 306, 405, -156, -290, -772, -732, 594, -101, 930, -1060, 1133, 977, -515, -736, -390, 1010, 118, -351, -652, 74, -553, 216, -609, 289, -209, 1004, 930, 462, 171, 755, -914, -686, -185, -616, -648, }; +int32_t transformer_layers_0_0_fn_projection_bias[16] = {-840, -92, -107, 118, 323, -361, 278, -5, 135, 300, -784, 540, -15, 380, 771, 648, }; +int32_t transformer_layers_0_1_norm_weight[16] = {3913, 4457, 4086, 4198, 3935, 4065, 4044, 3934, 3956, 3983, 4205, 3852, 4319, 4076, 4119, 3967, }; +int32_t transformer_layers_0_1_norm_bias[16] = {-176, -178, -255, 86, 151, -163, -161, -8, 155, -133, -118, 180, -206, 30, -113, -222, }; +int32_t transformer_layers_0_1_fn_ff1_weight[64] = {-269, 879, 417, 125, -1042, 562, 825, 151, -22, 941, 340, 837, -99, -941, -81, -34, 779, -802, -170, 98, -331, -642, 898, 694, -266, 574, -677, 748, -770, -37, 501, -738, 539, -756, 846, -539, 380, 724, -628, 795, 1144, 372, 525, 499, -257, -2, -298, -356, -821, -8, 829, 852, 205, 290, -229, 201, -910, -991, -340, 841, -610, 961, 227, 151, }; +int32_t transformer_layers_0_1_fn_ff1_bias[4] = {-143, -827, -308, 129, }; +int32_t transformer_layers_0_1_fn_ff2_weight[64] = {305, -252, 1555, 1351, -1680, 1389, 1229, -741, -1475, 285, -203, -1095, -1407, -1403, -1965, 1256, -273, -533, -1, -1734, -417, 176, -253, 1055, -326, -525, -1, 343, -413, 309, -1034, -1608, -1219, -547, -472, -663, -1628, -1026, -56, -1330, 673, 451, -900, -1720, 2030, 607, 1103, -1915, 1853, 911, -939, 398, 21, 15, 1670, -409, 378, -1568, 1405, 1371, 933, -759, 545, -2014, }; +int32_t transformer_layers_0_1_fn_ff2_bias[16] = {837, -1010, 736, 2060, 1857, -1132, 728, -1052, 947, 1603, 1612, 1908, 1519, 508, -1745, -1202, }; +int32_t transformer_layers_1_0_norm_weight[16] = {3943, 4401, 4285, 4286, 4112, 4059, 4094, 4023, 4156, 4435, 4079, 4136, 4219, 4111, 4081, 4076, }; +int32_t transformer_layers_1_0_norm_bias[16] = {-44, -53, 85, 19, -34, -44, 71, -39, 40, 66, -63, 14, 27, -106, -87, -76, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H0[64] = {495, 600, -127, -357, 489, 355, 41, 97, 758, -317, 99, -403, 730, 452, -27, 354, -495, 997, 387, -732, -742, 475, 67, -193, 464, 305, -691, 995, 902, 1007, -985, -300, -608, 939, -555, 527, 454, -789, 77, 203, 550, 130, 912, 756, 104, 733, -477, -462, -25, 816, -253, -828, -407, 607, -1024, 458, -159, -75, -422, -327, 772, -845, 661, 673, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H1[64] = {-780, -895, 1016, -316, 1036, -767, 839, -289, -582, -1437, 46, -283, -830, 69, 661, 720, 925, -302, -908, -185, -771, 486, 460, -953, 327, -491, -209, -21, 210, -935, -445, 117, 541, -967, 810, -458, -985, -328, -38, 647, 456, 982, -64, -586, -155, 738, -358, 85, -536, 5, -210, 168, -628, 278, -280, 13, -793, 687, 18, -27, -340, 178, 258, -977, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H2[64] = {-397, -371, 571, 275, -30, 516, 642, 475, 831, 781, -398, -383, -510, 210, -543, 47, -637, 293, 625, -645, 40, -892, -734, 402, -172, -431, 7, -150, -549, 512, -208, 249, -527, -433, 922, 769, -788, -851, 328, 370, -51, 214, -971, -639, -809, 119, 54, 694, 746, -331, -515, 64, -894, 340, -713, -372, 540, -418, 924, 572, 1071, 882, 877, -633, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H3[64] = {476, -152, -876, 172, -361, -748, -636, -123, 162, -616, -504, 793, 661, 27, 626, 102, -518, 900, 891, -508, -848, -553, 519, 101, 122, -683, -204, 986, 44, 263, 421, -1069, 811, -302, 909, 942, 864, 478, -225, -1105, -470, 4, 387, 537, 133, 434, -6, -780, 301, 739, 1092, -834, -1072, 173, 106, 480, 981, -1, -672, 1039, -32, -769, -809, -673, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H0[64] = {-536, -105, 457, -372, -36, -789, 776, -669, 705, -386, -480, -493, -216, 652, -161, -285, 385, 1026, -222, 268, -761, -564, 815, 991, -417, -308, 967, -141, 950, -843, -774, 222, -9, -387, 466, 539, -385, 108, 569, 873, 607, 184, -627, -371, 92, 143, 355, 885, 141, 339, 397, 598, -574, 500, 226, 716, 449, 328, 820, -210, 614, -841, -650, -881, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H1[64] = {487, 12, -424, -75, 464, 210, 601, -479, 874, -114, 421, 630, 621, 563, 671, -886, 856, -783, 351, 676, 1263, -231, 1, -862, 609, 307, -259, -737, 649, -552, 811, -851, 764, -42, -780, -1011, -595, 521, -447, -604, -581, 286, -718, 184, -32, 81, -644, 927, -789, -145, 864, 638, -400, 675, -935, -786, 1144, -920, -702, 755, -341, -782, -596, 566, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H2[64] = {339, 539, 363, -56, -218, 918, 616, -856, -651, 992, -167, 175, 652, -456, -927, 539, -234, -846, -502, 924, 457, -677, -48, 41, -224, 685, -994, -17, -373, 766, 1014, -845, 509, -554, -878, 187, 824, 437, 871, 410, 1037, 18, 459, -666, 496, 360, -294, 407, 245, 266, -455, -167, -1086, -133, -739, 1113, 462, -910, 764, 1087, 238, -358, -725, -713, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H3[64] = {-909, -289, 660, -80, -802, 331, 600, 430, -889, 182, 205, -1121, 799, 211, 337, -537, 1094, -867, 396, 415, 806, 787, 683, 530, 240, -442, 73, -203, 433, 326, 802, 184, 1048, 362, 49, -755, 903, 970, 491, -289, -807, -123, -625, -826, -348, -711, 943, -872, 369, 459, -610, -780, -902, 865, -479, 952, 251, 723, 10, 137, 110, 432, 545, 827, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H0[64] = {-904, -972, 395, -281, 1346, 1215, 17, -994, -340, 936, -382, -125, -644, -779, -546, 815, 142, 820, 98, 552, -377, 959, 1113, 123, -221, -107, -964, -219, 206, 648, 834, -596, -35, 431, 658, 398, -1069, -140, -465, -39, 455, 824, -75, 420, -270, -55, 619, -394, -685, 548, 194, -23, 38, 815, -786, 474, 684, 318, -763, 593, -655, -618, -263, 251, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H1[64] = {550, 404, -867, -355, 1129, -344, -759, 403, 203, 811, 891, 674, 433, 812, 428, 68, -321, 344, -725, 560, 425, 801, 653, -328, 60, 269, 427, -15, -159, 367, 235, -599, 8, -1167, -239, -594, -544, 871, 675, 78, 607, 621, -244, -492, 415, 668, 1004, -170, 961, -1137, -717, 1007, 228, -242, 508, 511, -703, 429, 800, 807, 826, -723, 855, 790, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H2[64] = {137, -567, -524, -1077, -226, -320, -619, -639, -215, 351, 297, -193, 280, -282, 92, 700, 987, -271, 103, -408, 138, -763, -252, -592, 890, 463, 961, -740, -487, 323, 233, -639, -752, -186, 124, -984, -70, 996, 194, 663, 72, 109, 382, -590, 948, 98, -885, -1018, -411, -896, 847, 478, 16, 0, -861, 876, -875, -176, -784, 30, -797, -803, -906, 896, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H3[64] = {523, -54, 650, 319, 905, -162, 443, -845, -509, 320, -1008, -984, -99, 709, -64, -938, 175, -357, -351, 40, 777, 340, 1157, -867, -689, 733, 553, -237, 721, -1006, -476, -684, -446, -31, -974, 214, 469, -240, -1137, -233, 285, 528, 266, -798, 538, 786, 438, -717, 586, -872, -901, 1040, 137, -19, 215, -995, -446, -870, 675, 139, 103, -691, -115, -573, }; +int32_t transformer_layers_1_0_fn_projection_weight[256] = {-961, -497, -218, -462, -752, 764, 182, -416, 43, -295, -1317, -752, 990, 758, 595, 383, -297, 299, -272, -565, -953, -338, -303, 1186, 1256, 504, -455, 329, 353, -416, 202, 446, -869, 19, -776, -409, 959, 382, -5, 278, 503, 440, 209, 407, 410, 406, -331, 877, 463, 721, 65, -135, 293, -336, 674, -687, -1054, -331, -225, -675, -963, 710, 728, 790, -392, 108, -834, 300, -154, 767, 401, 421, -820, 246, -236, -957, 669, 358, 483, 60, 249, 66, 1149, -828, -539, 332, 57, -1235, 282, 268, 978, 216, -830, -553, -541, 279, -214, -340, 977, -249, 205, 70, -401, -502, 17, 1231, 634, 390, -937, 15, -798, -473, 50, -277, -825, 504, 79, 163, -647, -875, -860, 161, -256, -936, 594, -491, -403, -47, 643, 316, -778, 1075, -1066, -1276, -590, -713, 888, 114, 749, -78, -257, 103, -363, 247, -128, 40, 1004, 152, 639, 171, -485, -1083, 70, 342, 903, 569, -606, 472, -894, -585, -682, 488, -726, 169, 16, -905, -906, -734, 796, 697, -527, 807, -1091, -911, -320, -791, 718, 622, 475, -343, 853, 769, 884, 564, -1171, -59, 180, 14, 288, -1012, 1087, -518, -549, 777, 576, 765, -356, 945, 640, -174, 238, 281, -341, -889, 1007, 311, 40, -45, 633, -584, 1091, -101, -801, -483, -527, 411, 164, 457, 365, 19, 209, -542, 114, 352, -625, 590, 666, -706, 1037, -388, -993, -373, 240, -343, -914, 856, 956, 617, 982, -140, 371, -455, 208, 973, 133, 652, -646, 344, 297, -880, -97, 271, -380, -219, 827, 596, }; +int32_t transformer_layers_1_0_fn_projection_bias[16] = {-736, 309, -43, -180, -220, -446, 37, 54, 389, -788, 1114, -969, -17, 10, 286, 852, }; +int32_t transformer_layers_1_1_norm_weight[16] = {4083, 4051, 4008, 4127, 3974, 3860, 4095, 4052, 3996, 4005, 4114, 4195, 3983, 4097, 4071, 4004, }; +int32_t transformer_layers_1_1_norm_bias[16] = {137, -2, 135, 87, 127, -139, -134, -96, 67, 14, -108, -63, -78, 31, 15, 53, }; +int32_t transformer_layers_1_1_fn_ff1_weight[64] = {-127, -843, -176, -862, -255, -382, -561, 758, -943, -676, -585, -721, -737, -526, -519, -110, 481, 81, -122, -888, 358, 455, 170, 527, 336, 86, 266, 133, 896, 362, 806, -114, -894, -490, -7, 55, -544, 938, 456, -382, 987, -919, 127, 210, 427, -677, 788, -316, 776, -675, 152, 89, -813, -174, -14, 274, 317, -26, 399, -560, -367, -255, 649, -1004, }; +int32_t transformer_layers_1_1_fn_ff1_bias[4] = {90, -953, 421, -933, }; +int32_t transformer_layers_1_1_fn_ff2_weight[64] = {-1042, -1584, 1737, 504, -1780, 1348, 536, -1647, -1350, 839, -1377, 663, 455, -1985, -1640, 1642, 1730, -960, -1286, -54, -1541, 714, 971, 579, -69, 1795, -831, -1040, 1600, -382, -1386, 245, 1170, 1367, -210, 904, 1794, -1331, -524, -1304, 84, 743, 593, -621, -1397, -1482, 1047, -849, -1283, -1557, 911, 218, -1263, -1694, 1757, 1760, 812, 762, 1568, 1882, -1391, 1405, -244, 478, }; +int32_t transformer_layers_1_1_fn_ff2_bias[16] = {-1109, -350, -895, 2006, 686, -472, 1124, 1903, 1174, -405, -1500, -440, -422, -142, 1269, -836, }; +int32_t transformer_layers_2_0_norm_weight[16] = {4135, 4645, 4316, 4215, 4243, 4415, 4186, 4002, 4224, 4214, 4305, 4162, 4319, 4117, 4437, 4432, }; +int32_t transformer_layers_2_0_norm_bias[16] = {-10, -219, 118, -51, 66, -61, 16, 57, 4, 67, 27, 112, 24, -177, -70, 114, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H0[64] = {750, 642, 712, 102, -275, -314, 514, -1305, 48, 907, 72, -639, -859, -1227, -96, 131, -174, 771, 585, -694, 1109, -192, -60, -1356, 95, -133, -539, -295, -1002, 421, -649, 590, 403, 1025, -703, 311, 867, 275, -77, -759, 624, -841, -753, -297, -807, 129, 827, -804, -772, 63, 894, -59, -512, -206, 425, 657, 431, -1100, -646, 1259, -1036, -1045, 252, 1058, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H1[64] = {-101, 525, -497, -703, 267, -890, -574, 202, 304, -567, 1090, -181, -37, -245, -262, 545, -260, 686, -634, -882, 1059, -247, -562, -1061, -944, -143, 1018, -218, -608, -752, -127, 623, 467, -1114, -92, -355, -635, 947, 626, 710, -41, -864, -216, 275, -567, 834, -282, -558, -925, 848, 565, -826, 129, -724, 323, -1025, 681, 725, -81, -38, -463, -653, 1066, -210, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H2[64] = {-1000, -805, 417, -430, -467, 482, -643, 174, 646, -165, -599, 93, 65, -1101, 230, 546, -172, -758, -61, -837, 974, 408, -104, -727, -296, -456, -186, -148, -786, 216, -490, -825, 362, 932, -340, 816, 142, 20, -125, -1072, 390, -69, -839, 806, 830, -740, -407, -804, 1087, 182, 602, -206, -283, -331, -868, 454, 758, -753, -277, 266, -147, 297, -885, -669, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H3[64] = {890, -862, -125, -582, -1112, -1234, 52, -854, -742, -485, 26, -1324, 767, -304, 274, 490, 285, -878, -741, -904, -46, 536, -1020, -689, 33, 434, 481, -13, 67, -67, -28, 798, 162, 915, -629, 766, -1016, -907, 705, -1195, 1089, 399, -878, -55, -212, -838, -19, -777, 207, -357, -446, 28, 210, -1012, 500, 196, -409, 121, 470, 957, 885, -742, -227, 284, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H0[64] = {196, -857, -988, -250, 851, 1125, 256, 246, -13, -115, 43, 444, -62, 5, 196, 922, 603, 803, 7, -895, 225, 886, -688, 262, -355, -427, 167, 47, -220, -688, 373, -63, 36, 672, 524, -170, 675, 562, -1017, 662, -648, -36, -1136, 523, -305, 50, 303, 147, 246, -676, -142, 524, 327, 584, -688, -1043, 1089, -277, 414, -934, 798, 883, 1051, -572, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H1[64] = {893, 528, -509, -849, 255, -684, -717, 423, 113, -646, -210, -702, -66, 1028, -1014, -219, -40, -803, -291, 773, -187, 46, 954, 809, -872, 516, 833, -855, -848, 835, -481, 54, -295, 326, 904, 732, 338, 604, 78, -733, 129, 699, 498, 835, -949, 376, -955, -820, -618, 1033, 981, -643, 906, -534, -1152, 65, -322, 66, -274, 926, -558, -402, -926, -78, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H2[64] = {1036, 778, -513, 648, 42, 482, -147, 968, 12, -521, -380, 241, 982, 639, -959, -558, -511, 941, 56, -425, -745, 546, -937, 670, 819, -652, 739, -106, -552, -691, 445, -287, 30, -36, -715, -196, 884, -637, 0, 586, -230, 692, -169, -1036, 9, 548, 426, 797, 300, -356, -648, -432, 1287, -533, -110, -604, 835, 396, 466, -484, -443, 443, 421, -29, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H3[64] = {-1028, -82, 553, 856, -861, -129, 600, -637, 300, -239, 141, -296, 443, 358, 949, 498, -736, 977, 339, 225, -1016, -994, 330, -1120, 1007, 178, -78, 1380, -459, -932, 620, -454, -671, -885, -617, -1051, 1021, -378, 542, 1186, 512, 608, -809, 418, 153, -173, -46, -342, -1247, -413, 461, -858, 482, -234, 593, 168, -638, -919, -2, -734, -703, -717, 275, 1043, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H0[64] = {-569, -735, 276, 102, -180, 537, -520, 1212, 789, -363, 25, -565, 952, 177, 147, -941, -448, -1023, 433, -198, 197, 686, 450, 217, 498, 850, 455, -791, 992, 707, 544, -393, 914, 631, -407, -221, 131, 614, 619, 430, 710, -753, -270, 347, 115, 834, 648, -138, -386, -1090, -122, 758, 753, 488, -639, 843, 35, 193, -708, 1173, -499, -677, -894, -551, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H1[64] = {189, 384, -576, 584, 707, -516, -1085, 81, -652, 809, 849, 929, -834, 725, 256, -568, -77, 932, 4, 445, -174, -238, -718, -991, 539, -472, -577, -951, -1016, 229, 73, 838, 980, -710, -18, 111, -583, 916, 1046, -814, 551, 95, 777, -46, 975, 27, 252, 362, -772, -863, -803, 496, 855, 100, -481, 357, 577, 945, 630, 44, 712, -157, -147, 1142, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H2[64] = {668, -279, 884, 126, -1152, -408, 994, -84, 549, -356, -363, -365, 596, -513, 305, -212, 175, 181, -1146, -1, 588, 511, 147, 231, -751, -28, 129, 877, 385, 904, -362, -628, -290, -366, -1028, -102, 909, -942, 1006, 653, 454, -908, 1069, -462, 1201, -227, -847, -775, -1091, 75, -924, 178, 87, 519, 431, 287, -411, 100, 605, -926, 593, -438, -588, 618, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H3[64] = {496, 644, 748, 90, 519, 492, 816, -402, -44, -1013, -886, -581, 880, 744, -302, 821, -992, 729, -44, -493, -1191, -137, 352, 950, 342, -211, 347, -1036, 125, -31, 912, 313, -1230, 354, 356, -195, 220, -693, -1152, 538, 1248, -1006, 152, -822, -541, -813, 12, -269, -863, -739, -438, -650, -250, 770, 240, 195, -813, 411, 597, 1034, -114, -202, 777, -162, }; +int32_t transformer_layers_2_0_fn_projection_weight[256] = {-250, -616, -353, -787, 606, 329, 1043, 644, 827, -65, 841, 68, -804, -131, 515, 298, 594, 611, 284, -40, -72, -695, 564, -25, -141, -9, -936, 100, 318, 1101, -899, -442, 755, -919, -439, 111, -58, -1232, 34, 191, -666, 651, -416, -578, -160, -1101, 927, 786, -1151, 834, -830, 143, -180, 381, -887, 812, 755, -287, -1322, 98, 629, 499, 917, 957, 261, 509, -1001, -522, -102, -106, -48, -816, -161, -516, 345, 373, -881, 1022, -493, 648, 1124, -152, -542, -293, -708, -46, 779, -106, -1112, 1022, -634, 145, 401, -1117, -374, 775, -378, -672, 956, -497, 798, -1060, 359, -1384, -853, 802, 1090, -431, -391, -659, -931, 348, 565, 363, 395, -576, -696, 206, 157, 741, 253, -57, 848, -844, -828, -758, 621, -122, -565, 1162, 834, -754, -840, -883, 464, -1167, -816, 670, 613, 272, -459, -529, -585, -854, -559, 925, 240, 1169, -413, -69, -1001, 513, 571, -426, 359, 319, 612, -510, -580, -707, 391, 896, 354, -1138, 922, 943, 115, -252, 36, 225, -326, 598, -232, 828, -678, 621, 582, 930, -1020, 375, -504, -157, -669, -629, 577, -491, 312, 701, -909, -779, -159, 95, -738, 806, 1109, 64, -398, -15, 1345, -1061, -833, 827, 756, -223, 460, -359, -417, -114, 719, -1035, -180, -515, 124, 428, -975, 993, 533, -1178, 966, -308, 575, -908, -113, -656, -439, -547, -542, -343, 1116, -219, -704, 32, -184, -1065, -794, 784, 247, -762, -59, 35, -98, 387, 100, 593, 748, 564, 413, 453, -306, -254, 7, -255, -889, 814, -766, -481, }; +int32_t transformer_layers_2_0_fn_projection_bias[16] = {194, 93, 543, 448, -911, -445, 195, -40, 634, 876, 754, -1012, 50, 857, -446, -108, }; +int32_t transformer_layers_2_1_norm_weight[16] = {4070, 4054, 4113, 4250, 4054, 4081, 4083, 4181, 3917, 4167, 4225, 4116, 4074, 4125, 4118, 4086, }; +int32_t transformer_layers_2_1_norm_bias[16] = {42, 64, -32, 110, 137, -170, 140, 80, -43, -16, 168, -178, 100, 6, 44, -66, }; +int32_t transformer_layers_2_1_fn_ff1_weight[64] = {-874, -1079, -163, 736, -294, -562, -500, 987, 108, 568, -363, -934, -409, -573, -1048, -366, 277, -902, 259, 602, -45, 983, 366, 811, -394, -751, -662, -964, -400, -240, -967, -749, 166, 599, -648, -608, 618, 609, -928, -602, 56, -852, -818, -343, -398, 671, 187, 523, 906, -568, 602, 1123, 788, 123, 297, 817, -692, -732, -585, 704, 1029, 787, -902, 971, }; +int32_t transformer_layers_2_1_fn_ff1_bias[4] = {267, 470, -574, -399, }; +int32_t transformer_layers_2_1_fn_ff2_weight[64] = {1877, 1625, -992, -1629, -1178, -1784, 4, -1248, 905, 507, 1721, -4, 1659, 420, -527, 1624, -482, 1213, -223, 1858, -200, -1466, -160, 330, 1406, 396, -1566, 1945, -1635, 733, -1490, -1626, 404, -1409, -268, 1645, 1503, 1635, -1849, 1682, -1379, 1453, -465, 666, 593, -578, 1630, -747, -1665, -1625, 436, -1834, -1397, 1706, -1779, 42, -96, -1266, -1052, 1321, -1843, 128, -1722, 1636, }; +int32_t transformer_layers_2_1_fn_ff2_bias[16] = {-473, -1167, 1703, 46, 113, 609, -1347, 396, -303, -1647, -449, -372, 176, -1396, 1388, -966, }; +int32_t transformer_layers_3_0_norm_weight[16] = {4331, 4371, 4459, 4169, 4329, 4301, 4145, 4299, 4294, 4423, 4268, 4098, 4104, 4173, 4155, 3944, }; +int32_t transformer_layers_3_0_norm_bias[16] = {-9, -50, -35, -36, 149, -24, -70, 75, 0, 43, 35, -47, -72, 36, 13, 91, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H0[64] = {812, -991, -1033, 164, -795, 579, -348, 766, 1070, 162, 149, -447, 298, -560, 489, -455, -458, 1003, 28, 1178, -74, 572, 1063, -531, 288, -656, 52, -852, 268, -340, 554, 363, -261, 534, -24, -513, -736, 186, -265, -656, -131, -1131, 917, -628, -624, -829, 190, 508, -405, 31, 991, -533, 728, 1148, 761, -174, -792, -169, 356, 52, 950, 90, -723, 659, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H1[64] = {417, 44, -833, 344, 124, 505, 217, 114, -753, -223, 59, 506, 404, 796, 326, -824, 45, -937, -647, -1044, 367, 197, -42, 101, 914, -45, 768, 244, 988, 114, 388, 165, 502, -169, 880, 852, -46, -1099, -445, 420, 903, 508, 945, -334, 729, -605, 8, -69, 950, 0, 277, 227, -321, -251, 636, 393, 441, 75, 269, -270, -713, 662, -916, -227, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H2[64] = {-625, -372, 134, 911, -887, 1167, -760, 713, -72, 576, 108, -1107, -353, -550, 605, -319, -229, 136, 335, 688, 221, -610, 366, 98, -380, -125, -61, -205, -432, 389, 110, 286, 1046, 550, -314, -243, 626, -699, -397, -950, 806, 553, -298, -1018, 713, 74, 860, 746, 348, -952, -293, 440, 797, -396, -340, -810, 182, 1001, 47, 626, 734, 45, -284, -563, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H3[64] = {1082, 533, -719, 574, 747, -378, 72, -655, 244, -372, -790, -465, -449, -305, 970, 536, 218, -626, 396, -1083, -413, -840, 679, -186, -650, 865, 721, -883, 882, -1084, 614, -783, -846, 623, 94, 490, 1052, -340, -1226, -483, -16, -382, 717, 491, -780, -723, -848, -613, 345, 648, -319, -34, -72, -347, 989, -457, 377, -805, -29, 734, 973, 791, 861, -764, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H0[64] = {-521, 858, 454, -495, 916, 442, -168, 604, 411, -89, 999, 1, -96, 421, 95, 197, -129, -822, 103, 866, -480, 714, -342, 656, -813, -974, 231, -1000, 783, -582, -154, -1051, -942, -760, 788, -81, -396, -102, 270, 72, 1116, -755, -832, 101, 1, -476, 195, 308, -144, -1003, -811, 813, -853, 1089, -738, -198, -100, 252, 935, 526, 115, 513, 18, 735, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H1[64] = {-918, -29, 832, 896, -778, 564, -148, 730, -237, 85, 834, 823, -836, 820, 575, 638, 661, 140, -132, 629, -1014, 82, -486, -571, 994, -457, 1027, 346, 445, -634, -202, 487, 587, 25, 580, 854, -154, -265, -46, 733, 728, 507, -780, -448, -367, -229, 937, 305, 293, -1028, 445, -37, -608, -867, 512, 240, 230, -243, -412, -676, 930, 645, -19, -602, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H2[64] = {-77, -1040, 122, 316, -714, 687, -1048, -1038, 982, -600, -161, 541, -937, -978, 541, 656, 134, -443, -314, -18, 239, 44, 138, -596, -403, 588, 715, 958, 812, -651, -300, 441, -765, 319, -127, -1081, 385, -228, -45, -405, 134, -655, 949, -141, -850, 513, -829, 466, -601, -76, 280, 217, 155, -150, 1085, 409, -572, 165, 818, 548, -504, -663, -25, -151, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H3[64] = {-822, -987, 500, 498, -380, 118, 296, -875, -428, 525, 721, -948, -96, -220, 952, -534, -1220, -182, -802, -290, 53, 825, -687, -910, 930, -42, -265, -297, 1184, -688, -121, -414, 524, -856, -476, 496, 631, 134, 1193, -132, 486, -166, 691, 1058, 274, -1097, -921, 388, 993, -9, -933, 525, -20, -405, -604, -828, 207, -280, -1049, 406, 872, -153, 134, -7, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H0[64] = {883, 284, 1094, -584, -1043, 1291, -1017, 538, 1181, -826, 537, -743, 1056, -1051, 1065, -347, 947, -152, -36, -529, -394, -532, 143, -447, 819, 768, 375, -626, 107, 1032, -154, 691, 845, 1047, -224, 931, 1173, -396, -983, -455, 16, -1076, -83, 121, -988, 816, -291, 72, -1167, -783, 823, -605, 196, -86, -857, 738, -495, 625, -374, -571, 128, -985, 844, 796, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H1[64] = {-121, -695, 45, -12, 29, 145, 226, 781, -515, 970, 780, 1133, -311, -960, 447, 445, 896, -274, 519, -1066, -274, -909, 923, 193, 246, 733, -661, 1113, -95, -1037, -874, -375, 807, -375, 333, -1144, 290, -112, -464, 1003, -578, -207, 751, 1000, 582, -342, 641, 775, -672, 604, -283, 834, 8, -312, -856, -454, 326, -226, -11, -959, 70, 1098, -225, -777, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H2[64] = {800, -780, 659, 436, 608, 983, -692, -810, 1055, 209, -284, 989, 203, -579, -376, 84, -312, -39, 309, 272, -631, -387, 500, -413, 866, 99, 322, -723, -751, 811, 635, 257, -571, 521, 454, -915, 239, -332, 381, -897, 1141, 265, 813, 83, 105, 243, -431, -597, -886, -987, -1014, -252, -271, -94, -218, -324, -948, 846, 376, -282, -851, 724, -920, 601, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H3[64] = {-539, 136, 319, -1137, 523, -281, -164, 890, -243, -237, -195, 331, 203, 862, -165, 188, 480, -509, 632, -963, 98, -30, -1019, 1024, -732, -486, -843, -480, -458, -729, 528, 728, -402, -495, -697, 1208, 689, -417, 308, -1250, 809, -878, 772, -534, 648, -420, -677, -614, 230, 167, -953, 828, -357, 801, 752, 1045, -868, 305, 622, 1084, -482, 809, 990, 825, }; +int32_t transformer_layers_3_0_fn_projection_weight[256] = {342, 5, -248, -706, 551, -1138, -335, -803, -1059, -259, 550, -227, -212, -948, 336, -347, 724, 0, -258, -610, 104, 853, -1145, 801, 45, -122, -296, -960, 979, -164, 227, -633, 291, -29, 331, -570, -899, 539, 166, -885, 666, -86, 227, -209, 44, -1134, 439, 556, 428, -932, 165, 517, 13, 135, -735, 917, 412, 6, -317, -426, 450, 310, 11, 70, -476, -749, -107, 792, -254, 818, -650, 707, -400, 687, 222, 431, -284, -826, 120, 150, -819, -614, -974, -859, 345, 367, -32, -770, -762, 372, 1068, 352, -201, 500, 166, -592, 665, -217, 231, 366, 564, 47, -268, -925, 1011, -851, 371, 688, -1137, 740, 918, -1041, 971, 42, 914, -1073, -248, 73, 271, -1088, 335, 392, -633, 626, 233, 825, 398, -790, 157, 1155, 441, -655, 356, -920, 699, -145, -525, 955, 180, -23, 97, 817, -420, -964, 1096, -19, -195, -12, 843, 359, -504, 273, 655, -269, 438, 373, -546, -25, 663, -717, -136, -276, 938, 78, -921, -687, 740, -459, -1038, -826, 965, -535, 352, 804, 894, 293, -451, 707, 613, 768, -1007, -1111, 410, -671, -224, 418, 773, 388, -242, -517, 908, 3, -794, 179, -520, 518, -565, -638, -300, 55, 888, 790, 754, -689, -561, 358, 723, -21, -528, 557, 1065, -476, -312, -544, -658, 803, -328, -464, -309, -778, -558, 298, 299, 445, -143, 526, 1111, -49, -762, -721, -224, -158, 529, 1242, -545, -287, -974, -391, 603, 743, -589, -1132, 55, 661, 757, 273, -1212, 1374, 396, -276, -975, -866, -192, -78, 168, -164, }; +int32_t transformer_layers_3_0_fn_projection_bias[16] = {-513, 807, 27, 109, 381, 633, 651, -345, -188, -948, -40, -1119, 69, -344, 610, -562, }; +int32_t transformer_layers_3_1_norm_weight[16] = {4014, 4033, 3946, 3968, 4029, 3985, 4117, 4068, 4052, 4005, 4190, 4268, 4082, 4047, 4155, 3996, }; +int32_t transformer_layers_3_1_norm_bias[16] = {114, -8, 39, -134, -76, -28, -5, -45, -16, 95, 69, -148, 162, 32, 143, -74, }; +int32_t transformer_layers_3_1_fn_ff1_weight[64] = {45, -294, -338, -514, 405, -861, -371, 974, 831, 195, -815, 159, -8, -783, 753, 635, -125, 722, 314, 472, -678, 633, 911, -906, 948, -593, -502, 602, 482, 1182, 18, -479, -804, 954, 458, 242, -300, 779, -731, 989, 108, -1102, -456, -82, 914, -716, 923, 673, -451, 517, -480, -898, -279, 521, -213, 1045, -1039, 728, -1044, -504, 824, -374, -136, 480, }; +int32_t transformer_layers_3_1_fn_ff1_bias[4] = {420, -528, 708, 556, }; +int32_t transformer_layers_3_1_fn_ff2_weight[64] = {-1264, -245, -243, -1258, -1099, -1898, -832, -1786, -91, -535, 338, 531, 99, 47, 1132, -293, 1776, -1641, 1705, -1170, 1156, 1020, -187, -1538, -652, 147, -962, -721, 748, -398, -1670, -84, 1373, 389, -1031, -329, 520, -615, -769, 1458, 1650, 1183, 1178, -137, -775, -271, -1281, -1755, 1191, -1755, -561, -1893, -104, 833, 1300, 1269, 1925, 1248, -225, 316, 1618, -1789, 479, -958, }; +int32_t transformer_layers_3_1_fn_ff2_bias[16] = {170, -517, 322, 1989, -502, 37, -357, 766, 1958, -45, 1673, -1260, 1175, -1481, -1355, 818, }; +int32_t mlp_head_layer_norm_weight[16] = {4039, 4009, 3972, 4135, 3957, 4168, 4133, 4187, 4009, 4196, 4210, 4267, 4051, 4053, 4018, 3976, }; +int32_t mlp_head_layer_norm_bias[16] = {-17, 24, 34, 16, -13, -23, -17, 16, 1, -62, 29, -4, 6, 46, 47, -28, }; +int32_t mlp_head_linear_weight[256] = {-400, 764, -464, -564, 75, -317, 351, -609, -341, -736, 55, 467, -747, 464, -536, 11, -341, 380, 479, -292, 53, 351, -332, 245, 155, -579, 630, 827, 727, 483, -86, 108, 213, 752, -431, 437, 649, -37, 685, 776, 793, -899, 934, 175, 432, -808, -868, 652, 337, 186, -967, -417, 839, -193, -764, 361, -577, 497, 103, 29, 709, 472, 390, -606, -656, -616, -69, -770, 191, -494, 187, 355, 687, -821, -806, 283, 407, -555, -704, -244, 293, -970, -991, 380, 67, 390, 291, 35, 677, 337, -688, -817, 332, 688, 115, -779, 759, 534, 1055, 544, -116, -636, -247, -774, -784, -208, -659, 704, 557, 19, -829, 373, -758, -1026, -1167, 763, 885, -721, -593, -330, 864, 108, -561, 49, 217, -543, 154, -191, 121, -393, 365, 39, 803, 558, -218, 55, 207, 304, -657, -35, -421, 416, 483, 446, 703, 943, 692, -200, -8, 13, 895, -533, 740, -906, -911, -388, 582, -75, -1053, 767, 540, -323, 452, -414, -781, 723, 942, 1029, -920, 937, 884, 1034, 698, 554, -1068, 265, 816, 549, -8, -511, -490, -485, 385, 399, 523, -225, -770, 248, -263, 463, -796, 920, 392, -447, 302, -81, 528, -831, 62, 885, 86, -591, -37, -233, -211, -441, 837, 72, -598, 370, 45, -481, 671, 651, 781, -823, -731, 754, -199, -540, -639, -364, -318, 723, 485, 423, -650, -648, -909, 197, -795, 824, 336, 546, 837, 201, -398, -653, 219, -537, 809, -402, -652, -289, -437, 160, 122, -485, -203, -50, 731, -353, 805, -87, 878, -517, }; +int32_t mlp_head_linear_bias[16] = {-54, 918, 756, -770, 1018, -2, -846, 44, 784, -104, -384, -203, 212, -628, -94, -97, }; + +// Total 14512 parameters \ No newline at end of file diff --git a/sw/applications/transformer/data_cpp/signal.cpp b/sw/applications/transformer/data_cpp/signal.cpp new file mode 100644 index 00000000..0f18a419 --- /dev/null +++ b/sw/applications/transformer/data_cpp/signal.cpp @@ -0,0 +1,5 @@ +#include "stdint-gcc.h" +//int32_t STFT_out[48000] ={15022, 16390, 15545, 7388, 9791, 14435, 15910, 14934, 8889, 9029, 12589, 14368, 13003, 9548, 6344, 9857, 11479, 9461, 8476, -1914, 9560, 7842, 5972, 6077, 3300, 9683, 6443, 5918, 4306, 3938, 8512, 3724, 5741, 5023, 2931, 7275, 3649, 5604, 5232, 3039, 7640, 5448, 5155, 3191, 4248, 7282, 5707, 3886, -1395, 4874, 5392, 5566, 307, 3140, 5102, 5513, 5713, 2597, 3891, 5867, 6802, 5914, 4893, 3388, 6861, 6592, 6289, 5121, 3314, 7333, 4961, 6907, 3998, 3581, 7119, 1288, 7340, 1455, 3347, 6134, -4195, 7221, -649, 2575, 4133, 1906, 6413, 1158, 1360, 639, 3608, 4810, 1664, -862, -2161, 4537, 2477, 1308, -3721, -2389, 5307, 903, -4, -555, -6878, 5826, 1113, -906, 1167, -1543, 5776, 1199, 1884, 1762, 149, 4966, 11, 3047, 1390, -386, 3716, -5616, 2671, -203, 74, 2832, -1861, 1678, -2604, 1596, 1292, 161, 1333, -2384, 1575, -3881, 818, 667, -1833, -390, -1812, 1707, -740, -1805, -3086, -694, 1426, -453, -1980, -790, -124, -648, 361, -3457, 42, 1155, -1014, 791, -13091, -656, 812, 379, 1297, -3332, -2853, -1853, -235, 1618, -420, -3919, -2006, -4401, 1689, 1044, -2273, 275, -565, 1635, 1800, -2376, 792, 2138, 1102, 1969, -2561, 237, 2818, -543, 1624, -310, -1249, 2136, -4400, 904, 920, -3606, 71, -6615, -81, 501, -2837, -1532, -4246, -1490, -2411, -879, -159, -3977, -4394, -7388, -319, -37, -4141, -10580, -1874, -1163, -1711, -3155, -3770, -1572, -3881, -5011, -826, -3183, -2875, -10316, -4701, 956, -4547, -3369, -6280, -4795, 1932, -4555, -2151, -4832, -7088, 2278, -4062, -1050, -4362, -9139, 2188, -5250, -628, -4430, -6307, 1816, -7122, -665, -4281, -3722, 1238, -4499, -856, -3217, -2790, 465, -2960, -1433, -2147, -3077, -434, -3195, -2783, -1981, -2941, -1212, -5049, -5353, -3217, -1690, -1498, -5065, -11050, -3855, -942, -1402, -2999, -6061, -1383, -1013, -1582, -2083, -3332, -275, -1903, -2508, -2036, -2211, -841, -4324, -4298, -2542, -2304, -3922, -6944, -6426, -3393, -3771, -7282, -2375, -9088, -4619, -7090, -2152, -895, -13285, -6205, -9679, -953, -1090, -7111, -6943, -7333, -1160, -2657, -5178, -6399, -4361, -2748, -5439, -4401, -5331, -2684, -7849, -7725, -4121, -4253, -2323, -6348, -6897, -3765, -3744, -2985, -4222, -5344, -3340, -3952, -4292, -6316, -3943, -3635, -5099, -5501, -6581, -3258, -5395, -8104, -6121, -2890, -3694, -8349, -8938, -7267, -2405, -5253, -6570, -6183, -8317, -3901, -6728, -6160, -6023, -6129, -6730, -5623, -7081, -8065, -5117, -7618, -3654, -5993, -12612, -5517, -6372, -2633, -5248, -9541, -6669, -4810, -2844, -6076, -6778, -7488, -5029, -4130, -6289, -5302, -5846, -9132, -5152, -5290, -5980, -4321, -6877, -5027, -5471, -8488, -3290, 10948, 5340, 9881, -583, -1529, 10281, 3184, 9400, 6255, -1363, 7983, 1790, 7839, 8319, -1213, 2985, 5766, 4578, 8716, -1201, 5806, 5972, -7468, 8093, 239, 7278, 3992, 2631, 6914, 2658, 7007, 3013, 4259, 6183, 4335, 5657, 4920, 4879, 6103, 5026, 5172, 5662, 5285, 5893, 4883, 5509, 5524, 5613, 5378, 4402, 4184, 4538, 5872, 4553, 4309, 3084, 2519, 6053, 4412, 4533, 5541, 2182, 5884, 5410, 4304, 6269, 3345, 4957, 5653, 3045, 5565, 3276, 3046, 4418, 1028, 4272, 2407, 595, 1213, 734, 3636, 1612, -1021, -9, 1479, 3416, 1031, -324, 1364, 1998, 3255, 94, 588, 973, 1467, 3470, -317, 408, -256, -1566, 3966, 176, -148, -1555, -5910, 4403, -381, 149, -3399, -1218, 4406, -3162, 1043, -3706, -2034, 3699, -6969, 1255, 13, -2967, 2095, -928, 675, 2541, -309, -742, 1059, -55, 3772, 276, -5152, 1483, -1167, 3918, -918, -2310, 600, -2456, 3234, -4253, -629, -1699, -803, 2143, -8360, -748, -4480, 187, 920, -4510, -2796, -5722, -657, -732, -2852, -6555, -8562, -5101, -1617, -1578, -3238, -2751, -2692, -76, -473, -1770, -1006, 672, 1164, 146, -1307, -1054, 1972, 1728, -76, -1108, -747, 2401, 1777, -1105, -617, 737, 2292, 1237, -496, 491, 1494, 1811, -216, 1202, 1623, 1157, 1162, -1153, 1656, 2217, -332, 552, 898, 776, 2074, -3098, -150, 2083, -258, 1096, -4664, -1276, 2076, 269, -817, -3732, -2660, 1252, 403, -3595, -2332, -3627, 139, -804, -5568, -652, -4610, -491, -4906, -5112, 12, -5653, -40, -5243, -4091, -766, -6220, 444, -1562, -3606, -3645, -7870, -40, -1055, -4503, -10695, -8347, -1875, -1973, -6634, -7025, -5321, -3534, -3721, -6422, -10405, -3470, -2072, -5833, -8296, -6307, -2409, -1348, -8634, -8763, -3250, -1734, -1712, -13134, -3935, -2113, -1132, -2943, -10088, -2782, -1927, -552, -3587, -7851, -3207, -2420, -210, -2134, -5907, -4824, -3031, -288, -1175, -4432, -6584, -2800, -678, -1292, -3739, -5705, -2132, -1039, -2508, -3901, -3854, -1624, -1437, -5728, -4955, -2528, -1266, -2274, -7524, -5831, -2232, -1272, -3370, -2624, -5012, -3195, -2200, -3783, -947, -4277, -4836, -4802, -3420, -488, -3943, -4317, -5543, -2886, -691, -4040, -4122, -3597, -2892, -1142, -4925, -6452, -3758, -4002, -1519, -5252, -10060, -5054, -4808, -1904, -3326, -4930, -4535, -2874, -2275, -1642, -3491, -3392, -1585, -2128, -765, -3125, -2599, -1366, -1867, -687, -3101, -1848, -2227, -2471, -1521, -3092, -1584, -4873, -5110, -4002, -3221, -2450, -8948, -5746, -11796, -3989, -5450, -4673, -2300, -3014, -6275, -6993, -3629, -1265, -1233, -13060, -3994, -3325, -1129, -1401, -6473, -2795, -2634, -856, -3122, -4984, -1852, -2143, -668, -4531, -4954, -1543, -2277, -1158, -4444, 8135, 6088, 8626, -4024, 9938, 7329, 6317, 8147, 3034, 9253, 4904, 6099, 7090, 5534, 7062, 4788, 5168, 5821, 5756, 2868, 6323, 4576, 3219, 3312, 1833, 6494, 3735, 3133, -3194, 4473, 5760, 1781, 5247, 3503, 5033, 4322, 154, 5491, 4139, 2895, 2112, -1883, 5106, 3344, 1160, 567, -8604, 5398, 2834, 5248, 2441, -1097, 6168, 3530, 5936, 4900, 904, 6690, 4608, 5104, 6129, 2446, 6590, 5040, 5192, 6005, 3385, 5551, 4266, 6075, 4500, 3096, 3111, 1873, 6379, 1400, 1015, -337, -2432, 6535, -3148, -6312, 1153, -3379, 6387, -4178, -2431, 1960, -3097, 5323, -2846, -282, 1735, -1790, 2714, -1477, 1123, 1114, 483, -5178, -288, 2408, 349, 2279, -962, 828, 2867, -310, 3205, 602, 1651, 2089, 248, 3324, 1195, 1919, -836, 1723, 2724, 2721, 1435, -8160, 2498, 1506, 3795, -83, -1480, 2126, 141, 3702, -2304, -1676, 632, -186, 2139, -1688, -2840, -452, 758, 749, -1085, -1050, 84, 1955, 2587, -1448, -667, 47, 2776, 3314, -1334, -1973, -584, 3074, 2871, -1128, -4037, -927, 2914, 2029, -1831, -4223, -893, 2430, 1750, -3735, -1903, -725, 1721, 2124, -4438, 91, -814, 695, 2326, -1846, 1159, -718, -1112, 1779, -605, 1229, 953, -4285, 161, -1077, 226, 2278, -2549, -3196, -1597, -1233, 2448, -61, -10037, 1326, -207, 1631, 1238, -5459, 2800, 1173, 597, 1719, -2662, 2475, 1064, 234, 1395, -1008, 22, -931, 85, 225, -520, -10125, -1692, -101, -2013, -1056, -3239, -169, -365, -5623, -1918, -2721, -886, -713, -4148, -1070, -4144, -4883, -992, -3366, -504, -5371, -7334, -1451, -4299, -1722, -5860, -5572, -2058, -2407, -3307, -5420, -9669, -1902, -626, -800, -3278, -4000, -1470, -465, 514, -2492, -1965, -1758, -2323, 435, -3628, -1768, -2921, -5922, -956, -9229, -2309, -4942, -927, -4084, -4407, -2502, -9038, 836, -8231, -2095, -2284, -5389, 1066, -5365, -1906, -1985, -2756, 264, -3891, -3017, -2226, -2262, -1447, -4557, -4960, -3502, -3466, -3976, -11280, -5981, -3511, -5119, -4299, -3848, -5230, -2657, -3228, -2919, -1482, -4701, -3847, -1903, -2750, -1004, -4962, -9136, -1535, -4156, -1487, -5918, -5496, -1578, -9790, -2332, -7666, -4300, -1746, -6635, -2932, -11718, -5430, -1928, -3956, -3045, -13570, -7603, -2016, -3785, -2822, -9656, -7021, -2159, -4384, -2470, -5004, -4553, -2859, -3625, -2045, -2525, -3046, -5049, -2807, -1748, -1425, -2589, -10651, -3267, -2273, -1223, -2394, -5327, -4768, -4832, -1712, -1883, -4089, -3759, -6611, -2592, -1631, -4451, -2098, -3778, -2317, -1688, -4707, -1511, -4370, -1104, -1674, -5347, -1880, -7616, -511, -1990, -8962, -3392, -5659, -637, -3117, -7329, -6851, -5500, -1134, -4374, -4297, -12628, -9453, -1507, -3914, -3602, -7923, -7498, -4224, -5554, -4353, -4133, -2129, -3878, -7270, -2473, -2452, -1737, -3507, -7586, -2008, -2512, -2831, -2846, -5254, -3025, -3418, -5986, -2821, -3714, -5611, -3744, -7985, -2808, -3010, -13840, -2935, -6763, -2277, -2991, -6283, -2459, -7017, -2183, -3789, -3468, -3366, -5831, -3055, -6182, -2980, -5755, -4109, -5251, -13347, -4226, -3284, -3689, -9905, -6728, -7062, -1040, -4341, -6515, -5290, -10547, -88, -4173, -4287, -5037, -9538, 15, -3219, -3665, -4580, -5533, -670, -3366, -3725, -4293, -3755, -2433, -5426, -3616, -4979, -3342, -5897, -10483, -3418, -6809, -4226, -5644, -6907, -3888, -7436, -6950, -4348, -6768, -4698, -5425, -7290, -5661, -11547, -4637, -4024, -4705, -7820, -7789, -5294, -3717, -3606, -4001, -4241, -7811, -4602, -2791, -2423, -2364, -6255, -6510, -1775, -2276, -1164, -5607, -6340, -1017, -3077, -580, -7866, -4238, -901, -4310, -652, -11726, -3115, -1541, -5083, -1309, -10766, -3063, -2977, -5072, -2160, -5334, -3219, -5153, -4673, -2549, -2761, -2681, -5813, -4537, -2539, -1887, -2418, -4519, -5214, -2776, -1955, -2947, -4445, -6446, -3623, -2344, -4213, -5961, -6591, -5118, -2949, -6336, -7215, -6457, -7136, -4560, -9194, -6317, -7439, -9810, -7339, -9647, -7399, -9089, -8084, -5084, -8196, -10603, -8142, -4773, -4006, -6529, -5264, -6082, -3144, -4962, -5245, -3482, -4467, -2991, -7160, -4667, -3534, -3485, -4536, -5624, -4729, -5032, -3222, -8808, -4191, -5173, -6219, -3555, -16024, -4330, -5943, -5030, -4186, -8660, -6684, -6669, -4314, -4229, -3671, -7971, -6376, -4176, -3187, -1670, -3458, -5898, -4030, -2731, -1236, -1895, -5622, -3478, -3836, -1952, -1883, -5111, -2565, -7553, -3555, -3115, -4399, -1740, -7056, -5274, -5062, -4108, -1482, -5186, -5586, -5718, -5093, -2065, -5623, -4664, -4970, -9301, -3493, -7925, -3350, -3927, -8207, -4928, -13647, -2286, -3205, -5647, -5288, -11389, -1695, -3351, -5048, -5436, -10277, -1476, -4273, -3759, -5299, -11084, -1462, -3966, -2469, -4478, -12156, -1510, -2701, -2149, -3377, -9283, -1412, -2234, -3086, -2832, -6406, -1068, -2636, -6186, -3387, -5200, -747, -3812, -10087, -5553, -4196, -911, -5894, -5260, -12137, -2698, -2137, -8129, -4371, -9214, -1973, -5654, -7221, -4905, -7118, -2635, -11761, -6359, -5793, -7149, -5285, -7383, -5904, -6008, -8398, -8178, -8107, -5657, -6536, -9448, -5544, -5874, -6363, -8914, -8639, -5672, -4566, -8413, -10223, -8665, -9040, -4611, -8140, -6790, -7995, -9845, -5443, -6600, -5701, -5196, -5562, -6064, -6901, -5391, -3432, -4047, -5589, -10634, -4751, -2899, -3579, -5435, -9912, -4255, -3442, -3902, -5816, -6228, -4453, -4620, -5031, -6518, -5566, -5374, -5341, -6901, -8805, -6416, -7360, -5643, -8714, -17696, -8138, -11290, -6006, -9255, -12064, -8799, -7964, -6673, -10575, -9542, -7865, -5755, -8615, -10922, -5114, -7102, -4998, -11781, -6158, -3484, -4628, -2421, -3126, -2497, -6789, -5250, -4794, -4449, -4410, -7477, -9881, -6436, -5064, -3607, -3449, -4608, -4046, -5613, -2139, -2217, -2871, -2510, -6822, -1828, -2235, -3843, -2185, -5537, -2152, -3064, -6329, -3289, -4432, -2550, -4718, -4122, -6236, -4556, -2730, -8599, -3320, -6537, -4686, -2432, -7789, -4202, -4618, -4608, -2175, -3777, -6026, -3566, -6205, -2668, -2263, -7801, -2576, -13093, -4308, -2029, -9251, -1785, -4928, -7375, -3049, -8052, -1709, -2944, -9674, -6259, -5386, -2760, -2434, -9137, -6066, -4239, -5655, -2581, -6472, -3521, -4001, -10908, -3366, -5255, -3280, -3305, -4920, -6014, -6907, -4092, -2406, -3021, -9081, -10022, -4709, -2289, -2635, -3189, -5011, -4448, -3296, -3604, -1475, -4570, -4321, -5646, -6025, -1196, -5631, -5608, -5570, -5345, -1726, -3948, -8925, -3247, -3919, -2528, -2846, -4629, -2085, -3725, -3203, -2884, -1340, -1892, -3501, -3959, -2956, 213, -2570, -3436, -5344, -3247, 385, -3672, -4179, -7922, -4596, -782, -4517, -4623, -10663, -5247, -3613, -5710, -4269, -7357, -3805, -8204, -7537, -4200, -4774, -3261, -3386, -9210, -3521, -3260, -4029, -1266, -10245, -2801, -2777, -6779, -618, -8283, -3242, -3408, -5810, -806, -5770, -5696, -4816, -2843, -1404, -3474, -12002, -4835, -2324, -2230, -1947, -5336, -3635, -4445, -3446, -1253, -3757, -2754, -9328, -5841, -1357, -3536, -2539, -2725, -13317, -2351, -3881, -3123, -1220, -7147, -4485, -4898, -4220, -1221, -5824, -7862, -8392, -5317, -2285, -6768, -11502, -7970, -6846, -4558, -7862, -6879, -3544, -8386, -8920, -5639, -3193, -1802, -5582, -16426, -4403, -1478, -1162, -3322, -11213, -4289, -1030, -1320, -2236, -7203, -4753, -1637, -2259, -2066, -5910, -5082, -3287, -4154, -2592, -7050, -4526, -5607, -7379, -3425, -5504, -4246, -5552, -9774, -4065, -2373, -5163, -4380, -8617, -4242, -1009, -7160, -3989, -7901, -3963, -876, -8081, -4222, -6692, -3726, -1778, -6391, -4630, -5593, -4172, -3764, -4734, -4670, -5500, -5797, -7407, -4288, -4354, -7442, -8769, -8786, -5317, -4301, -11498, -6984, -5990, -8221, -4744, -5009, -4564, -5757, -9903, -4512, -3263, -3106, -7633, -8076, -3552, -3447, -2234, -11771, -6541, -3325, -5117, -1930, -12667, -4415, -4296, -5804, -2117, -11981, -2877, -7575, -5708, -2684, -12463, -2311, -10012, -7172, -3786, -17520, -2856, -5074, -5329, -5509, -11698, -4665, -4276, -3556, -6559, -7320, -4445, -5423, -3139, -6032, -4982, -2432, -6815, -3515, -5233, -3675, -1834, -5983, -4451, -4885, -3100, -2452, -6053, -5609, -4813, -3412, -3794, -7398, -6187, -4484, -5126, -5070, -8555, -5637, -4332, -8942, -6059, -7890, -4903, -4780, -8156, -5664, -6966, -5044, -5826, -7445, -4759, -6094, -6121, -7366, -8944, -5258, -4845, -7107, -8586, -12286, -7313, -4354, -6859, -8099, -16158, -6273, -5653, -6242, -7236, -8803, -5182, -11020, -6046, -6956, -5479, -6656, -1536, -2950, -4414, -6079, -3604, -1428, -2411, -7541, -5139, -1848, -1324, -2361, -9913, -4836, -1486, -1298, -2802, -4591, -3959, -2406, -1573, -3744, -2758, -1712, -4194, -2495, -5418, -2422, -42, -5054, -4591, -9189, -3442, 459, -3980, -9195, -8925, -4492, -230, -2899, -11097, -5822, -3678, -2121, -2792, -12465, -5374, -3936, -5487, -3382, -10965, -6491, -4860, -13201, -3897, -6980, -8176, -4223, -4575, -4537, -5943, -7331, -4482, -2722, -5484, -5427, -5826, -5564, -2821, -5674, -5105, -4386, -3766, -4394, -4608, -5164, -2664, -1603, -5443, -3593, -4710, -1555, -639, -4933, -2796, -3042, -1221, -1098, -6719, -1430, -1246, -1225, -3395, -11421, -447, -162, -1211, -8133, -7246, -627, 167, -1171, -4891, -10083, -2175, -139, -1219, -3020, -7058, -4571, -1084, -1635, -2768, -4466, -3412, -2470, -2518, -4109, -4079, -1188, -3285, -3544, -6015, -4011, 137, -3802, -3376, -4381, -3608, 518, -4965, -1353, -3572, -3037, -126, -7139, 168, -4533, -3447, -1934, -13471, 690, -7204, -6408, -3553, -5680, 417, -9220, -8269, -2607, -3936, -222, -8050, -5319, -2079, -4119, -761, -4771, -4550, -1746, -4482, -1413, -3437, -3790, -1023, -3611, -2864, -3832, -3177, -620, -2645, -4979, -5815, -2643, -652, -2136, -4731, -10493, -2648, -695, -2344, -4163, -10081, -3430, -880, -3418, -4701, -6001, -2792, -1648, -5340, -4910, -4263, -1434, -2959, -6768, -3486, -3360, -1291, -4215, -5259, -2557, -2870, -2715, -5327, -4127, -2717, -2591, -6908, -7188, -3928, -3565, -2566, -9345, -9250, -4424, -3837, -3153, -6026, -6089, -5596, -3329, -4823, -4115, -4029, -5332, -3093, -7403, -2244, -3228, -3730, -3423, -6394, -1321, -3169, -3120, -4030, -4822, -1391, -3856, -3352, -4019, -4452, -2389, -6223, -4162, -3507, -5531, -3885, -11595, -5537, -3763, -9584, -4454, -7117, -6049, -5539, -11492, -4732, -8537, -4404, -6531, -8904, -4400, -6582, -2673, -5208, -8826, -2727, -2659, -1747, -5819, -5655, -2061, -1277, -1705, -9453, -4239, -3059, -1187, -2241, -10353, -4868, -6682, -1802, -3158, -5447, -8286, -8509, -2649, -4713, -3619, -12757, -5460, -3539, -4764, -3014, -12636, -4901, -4068, -3348, -2840, -8742, -5394, -4270, -3392, -2768, -4667, -6856, -5074, -5305, -2984, -3324, -7579, -6296, -6783, -3459, -3532, -4949, -5979, -5328, -4029, -5532, -2721, -5319, -5970, -4667, -14849, -1369, -6133, -10401, -5585, -6837, -790, -12638, -8761, -7334, -5777, -937, -6287, -6741, -9955, -8368, -1808, -3420, -7326, -12278, -8497, -3363, -2912, -8770, -16695, -5559, -4951, -4095, -8610, -13416, -4846, -5025, -7435, -7926, -11937, -3580, -4428, -9001, -6381, -11803, -2464, -4303, -6744, -4580, -13182, -2617, -4979, -6343, -3508, -14602, -4359, -6610, -6657, -3260, -15423, -8127, -8838, -6860, -3720, -14890, -7968, -8299, -6477, -4389, -9173, -6467, -6679, -6249, -4327, -7138, -6132, -6455, -6392, 992, 7886, 7836, 5707, 2952, 5763, 7674, 7512, 5744, 3131, 7257, 7047, 6697, 5594, 2840, 6944, 6137, 5861, 5029, 1656, 6387, 5254, 5171, 4191, 1669, 6716, 4499, 4157, 3252, 2364, 6445, 3756, 2809, 2540, 1949, 4670, 3162, 2233, 3092, 910, 3710, 3344, 2679, 4147, 410, 5517, 4146, 3327, 4671, 452, 6178, 4380, 3727, 4620, 2149, 6053, 3711, 3627, 3805, 4693, 5401, 2486, 3007, 1193, 6237, 3584, 1501, 2138, -2809, 6624, -1377, 1312, 1430, 1631, 5874, -740, 1336, 1335, 2278, 3788, 1232, 544, 1760, 1376, -797, 984, -1787, 1610, 858, -4456, -16, -4421, 402, 1445, -841, -510, -1344, -1367, 1905, -616, -34, -459, -2302, 2253, -1120, 504, -1942, -2912, 2376, -1730, 720, -3838, -5891, 1875, -2627, 388, -695, -5800, 806, -4711, -673, 741, -1852, 50, -11015, -2310, 1308, -789, -233, -8245, -3429, 1893, -426, -743, -6045, -3855, 2501, -212, -1327, -3983, -5484, 2535, -521, -2006, -2393, -6745, 1562, -1584, -3385, -1364, -4140, -858, -3071, -6674, -598, -3454, -2410, -4007, -10510, -171, -4255, -203, -4907, -4974, -243, -6219, 582, -5832, -3180, -1018, -8783, -28, -4707, -1608, -2965, -5414, -2510, -3392, -581, -7330, -3019, -3582, -2700, -677, -6955, -1847, 35, -2277, -1773, -3219, -1611, 1252, -2376, -2733, -1083, -2530, 694, -4002, -2387, -716, -5145, -2053, -9433, -1461, -2429, -5676, -2719, -10283, -1021, -1831, -3878, -761, -5449, -1362, 475, -3664, -1287, -2617, -1862, 915, -3556, -2383, -2085, -1446, 149, -2817, -670, -4159, -375, -472, -2112, 394, -5643, 323, -35, -1757, 248, -2140, 192, 320, -1983, -1029, -1086, -983, -22, -2932, -3865, -1238, -3894, -1474, -4558, -9183, -1959, -7920, -3368, -5977, -7833, -2767, -2841, -1495, -4291, -6174, -3929, -1107, -176, -2147, -2464, -4110, -851, -181, -1039, -299, -2417, -2003, -1071, -1016, 578, -2123, -5311, -1919, -1861, 617, -3951, -4696, -2089, -1896, 235, -9294, -2333, -2652, -733, -288, -6439, -1996, -4479, -339, -1155, -4501, -2973, -7503, -1126, -2682, -2749, -3114, -5895, -3277, -4758, -822, -1788, -4046, -8511, -7487, 437, -1922, -3277, -7813, -5958, 551, -5066, -3319, -4848, -2147, -756, -6046, -3552, -4780, 106, -3455, -2730, -2710, -5057, 1332, -4293, -3013, -1523, -5034, 1646, -4528, -6230, -887, -6935, 891, -6414, -9181, -812, -4640, -1659, -7119, -6210, -1117, -2365, -14029, -5370, -6259, -1621, -1609, -3314, -5115, -7142, -1958, -1108, -2256, -7398, -7089, -1758, -994, -2106, -4836, -5489, -1371, -1982, -2098, -2545, -3927, -1402, -4561, -3066, -2233, -3486, -2416, -7078, -4875, -3155, -4911, -5524, -4643, -4758, -5020, -7861, -12217, -3992, -3582, -9911, -4628, -6038, -4259, -2813, -6597, -3333, -5671, 4431, 6956, 4647, 3404, 3214, 3330, 6394, 4445, 4636, 4919, -2018, 4626, 3869, 5670, 6749, 174, 1203, 3186, 5540, 7498, 1979, -3313, 3158, 4216, 7309, 89, 504, 3878, 1072, 6525, -7332, 2160, 4371, 83, 5384, -1885, 2720, 4121, 2851, 3793, -2387, 2886, 3245, 3140, 2596, -131, 3575, 2615, 2064, 2369, 2750, 4385, 2649, 2541, 1643, 4474, 4335, 2717, 3876, 2216, 5069, 3125, 2641, 4261, 3761, 4424, 1483, 2251, 3750, 4483, 2485, 1454, 1283, 2464, 4432, 1067, 1443, 85, 569, 3826, 2180, 401, 47, -1340, 3066, 2822, -1339, 182, -2231, 2563, 2587, -1558, -920, -2301, 1920, 1218, 336, -3313, -1700, 683, -1842, 1950, -4908, -599, -386, -1289, 2887, -5087, -836, 463, 149, 3227, -887, -4338, 1261, -594, 3167, 1502, -1816, 1038, -2955, 2939, 2548, 680, 327, -2472, 2629, 2745, 1043, 51, -1627, 2053, 2212, 948, -302, -2321, 933, 785, 1074, -1594, -3706, -838, -1956, 601, -3409, -3084, -3032, -6554, -656, -3464, -1611, -4914, -7763, -1656, -4244, -1174, -4880, -6737, -1234, -2011, -1233, -4355, -3618, -340, 526, 47, -5364, -1510, -318, 1544, 1463, -7198, -750, -1860, 1727, 1828, -5679, -1416, -7268, 1307, 931, -6528, -3862, -4626, 11, -1518, -4014, -6626, -1510, -2411, -4306, -437, -6696, -397, -3961, -3760, 1004, -6606, -513, -3297, -2746, 1013, -5990, -1930, -2778, -663, -172, -11236, -2111, -3063, 473, -2169, -4851, -144, -4907, 464, -3009, -1982, 781, -8275, -439, -1982, -1424, 776, -9936, -1390, -912, -1763, 71, -6078, -531, -87, -1362, -1265, -4817, 709, 402, -298, -2933, -7191, 1147, 411, 464, -3762, -5416, 641, -36, 858, -3242, -3244, -878, -725, 974, -2772, -4068, -3062, -1369, 786, -3532, -4200, -3880, -2030, 165, -5898, -1956, -3455, -3426, -1106, -5290, -1439, -3346, -6797, -3430, -3721, -2194, -3895, -5475, -7296, -2447, -2540, -5088, -2472, -7216, -1279, -1260, -6922, -1288, -5455, -683, -66, -6827, -1382, -4648, -376, 376, -4007, -2543, -4856, -190, 93, -2386, -3378, -5880, -477, -515, -2070, -2682, -4918, -1273, -1178, -3491, -2129, -3087, -1615, -2334, -12014, -1948, -2105, -1411, -4243, -2991, -1997, -1792, -1734, -8766, -470, -2496, -1876, -2784, -5016, 104, -3838, -1877, -4591, -1105, -731, -6301, -1746, -9082, 199, -3223, -8534, -2817, -6844, -58, -8548, -7309, -10561, -3983, -1936, -10120, -5995, -3376, -3673, -4603, -20985, -4612, -1454, -2665, -1776, -7189, -3343, -2512, -930, -299, -4932, -3211, -7404, -583, -305, -4692, -4774, -3010, -1973, -1335, -5472, -5595, -369, -4883, -2031, -6404, -3584, 783, -3635, -1048, -6310, -2819, 852, -2206, -154, -5323, -1834, -93, -1718, 30, -4480, -626, -1947, -1728, -541, 4174, 4649, 8112, 4717, 10466, 5280, 6423, 7948, 6862, 10222, 6501, 8002, 7664, 8295, 9563, 6769, 8408, 7456, 8429, 8561, 6127, 7730, 6905, 7644, 7034, 5048, 5903, 5514, 5941, 4594, 4185, 2543, 3305, 2660, 982, 3149, -888, 1426, -2564, -1865, 1011, 1471, 735, 1166, -1159, -5527, 2616, -306, 1632, 314, -106, 3024, -43, -844, 734, 2930, 3341, 2467, -2478, 2614, 3788, 3719, 3345, 2597, 4789, 2812, 3667, 2827, 4269, 5884, -511, 3317, 2219, 4869, 6290, 1704, 3473, 2860, 4963, 6365, 3274, 3591, 3308, 4690, 6044, 2644, 2936, 2953, 4056, 5092, -557, 1584, 1968, 2995, 3317, -4360, 179, 891, 1167, 815, 452, -215, 513, -2135, 86, 1319, 299, 907, -1288, 765, 870, 155, 1373, 1199, 403, 686, -2036, 1276, 2295, -1164, 1208, -6659, 115, 2607, -2310, 701, -1110, -2708, 2307, -1258, -1150, -328, -2530, 1467, -1410, -736, -1907, -296, 883, -2029, -52, -5263, 495, 1564, 553, -1306, -5543, 797, 2156, 1991, -3684, -3848, 1128, 1951, 1912, -3782, -1034, 1249, 1359, 895, -5389, 388, 952, 1349, 218, -6377, 657, 576, 1456, 759, -2880, 335, 729, 494, 1309, -1657, 478, 1458, -2099, 866, -473, 1422, 2292, -1460, -620, -50, 1993, 2768, -94, -1113, -2239, 1399, 2583, -751, -410, -4992, -1336, 1481, -2172, -510, -476, -3462, -839, -1211, -841, -618, -17, -2638, -555, 273, -3499, 496, -876, -1009, 1572, -1315, -297, 196, -2170, 2027, -228, -1264, 454, -3745, 1439, -1464, -2322, 81, -4717, -381, -5409, -4077, -907, -4231, -3575, -11310, -5445, -2337, -2910, -8052, -6921, -5310, -4192, -1845, -13976, -4606, -4917, -4348, -2024, -8954, -3415, -5146, -1546, -3490, -8070, -3267, -5532, -149, -4645, -5821, -3369, -4589, 86, -4673, -3846, -4033, -4557, -413, -2522, -2014, -7275, -7793, -1331, -262, -1161, -6355, -4242, -2505, 707, -1661, -2821, -1515, -4093, 563, -3620, -1675, -1146, -6469, -473, -6858, -1510, -2831, -7219, -1769, -5947, -1635, -7801, -5863, -2385, -4331, -2407, -5390, -5883, -3613, -4909, -5852, -2773, -7221, -9159, -8695, -6468, -1251, -7432, -3003, -8598, -3055, -955, -3342, -265, -7250, -2386, -2007, -710, 612, -7422, -1428, -3766, 347, 364, -4521, -496, -3947, -144, -697, -1507, -547, -3434, -2881, -2096, 292, -1598, -3256, -5414, -2594, 965, -3239, -3247, -2169, -2317, 652, -4359, -2603, -1742, -3337, -557, -4459, -1171, -2509, -10715, -2786, -4692, -227, -3927, -3425, -7108, -6957, -226, -4770, -818, -4731, -6172, -1041, -2897, -248, -2449, -1775, -2384, -1771, -697, -2684, -90, -5076, -1110, -1802, -6855, 99, -9796, -337, -4902, -5453, -1061, -2976, -36, -5415, -2246, -3853, -1317, -549, -918, -1705, -3747, -2112, -4001, -3034, -4635, -4213, -1260, -3727, -2473, -2438, -6982, -367, -3185, -1593, -982, -4534, 264, -2079, -1182, -222, -2747, 483, -2456, -1750, 35, -2512, 388, -5304, -3164, -88, -2206, 140, -4527, -3982, -532, -1428, -144, -2873, -3008, -1346, -1345, -365, -3984, -1784, -2639, -2397, -697, -6265, -1517, -3277, -2307, -1651, -4134, -2354, -1553, -288, -3640, -3791, -3550, 65, 652, -3861, -4141, -3568, 950, 228, -2067, -2900, -2781, 1302, -1954, -1289, -2053, -2108, 1342, -6273, -1345, -1988, -2096, 1204, -4779, -1906, -1653, -3694, 637, -5027, -1988, 82, -10105, -1492, -629, -486, 2110, -1648, -3002, 1882, 1459, 3378, 657, 1358, 2660, 2603, 3623, 1185, 2820, 2130, 2627, 2740, 637, 2565, 365, 1434, 560, -235, 841, -2650, -1067, -3141, -370, -1308, -5821, -3575, -5607, 47, -1692, -6442, -2726, -5532, -168, -2738, -4904, -1480, -7712, -1903, -4340, -3564, -672, -11754, -6389, -3800, -3243, -417, -5924, -5494, -2953, -3758, -816, -4087, -4188, -2255, -4726, -1998, -3790, -4542, -1674, -5694, -3952, -5810, -5381, -1442, -6169, -5589, -7299, -5101, -1910, -5950, -4971, -2468, -4109, -3935, -6223, -3510, -1109, -4084, -12610, -7526, -2798, -1748, -4875, -2691, -6655, -3009, -5180, -3571, -299, -4560, -3222, -5909, -1531, 345, -3402, -2278, -3277, -663, -382, -2929, -1166, -3916, -1028, -2305, -2012, -494, -7351, -2594, -3089, -610, -250, -8475, -5069, -3070, -48, -487, -5563, -7464, -4932, -943, -1479, -3054, -7030, -5903, -3367, -3876, -1946, -5475, -4377, -2021, -7366, -2306, -4082, -4492, -563, -4662, -4219, -2805, -3707, -1053, -3735, -9693, -2621, -1912, -4055, -3845, -8011, -3894, -912, -8948, -3433, -5298, -6418, -661, -3656, -2446, -5489, -10928, -1071, -2590, -1764, -7680, -8049, -2208, -2121, -1662, -6862, -3920, -4199, -1926, -2121, -4885, -2611, -7311, -2486, -3145, -4183, -2502, -6901, -3554, -5151, -3631, -2937, -4649, -4186, -7162, -2699, -4051, -3461, -4742, -5468, -2078, -6172, -2738, -5050, -5448, -2188, -5573, -2471, -5332, -7820, -3023, -4144, -2849, -8141, -9531, -4575, -4189, -3847, -6521, -7025, -4941, -5784, -4681, -3328, -4626, -2908, -10587, -4944, -2513, -3434, -1903, -8857, -6083, -3079, -3631, -2184, -6619, -7385, -4605, -4939, -3503, -7520, -4832, -5781, -5437, -4992, -16740, -3000, -5635, -4065, -5684, -7742, -2005, -6065, -2885, -6214, -5278, -1464, -7700, -2155, -7036, -4340, -1287, -9068, -1918, -8916, -4106, -1409, -10187, -2433, -8882, -4859, -1646, -9359, -4090, -7672, -7479, -1849, -6429, -6578, -10293, -11893, -2146, -5860, -5821, -9577, -9527, -2889, -7698, -5002, -5400, -10978, -4290, -10471, -5225, -4621, -9688, -5863, -8450, -5468, -6029, -7785, -7006, -10558, -5211, -9458, -7926, -8354, -10826, -5036, -5769, -9321, -8951, -3863, -401, -4910, -2323, -2099, -3046, -1484, -5082, -3636, -4300, -1990, -3768, -3293, -6039, -2892, -1020, -3385, -4360, -10286, -1381, -255, -1195, -8361, -4200, -844, 278, 114, -2769, -1775, -811, 435, 634, -894, -1206, -1477, -8, 381, -142, -2189, -3598, -1427, -717, 335, -4704, -8123, -5223, -2835, 417, -4946, -7597, -6079, -6358, -351, -3272, -5801, -2029, -7051, -2202, -2890, -3212, -1142, -3754, -3082, -3662, -1664, -2077, -2099, -2011, -3470, -1050, -5634, -1766, -1891, -1794, -940, -8934, -2247, -2760, -858, -1262, -3438, -2825, -4027, -444, -2366, -964, -2952, -3780, -62, -4754, 1092, -744, -1225, 785, -3777, 2671, 1289, 547, 1815, -1385, 3401, 2002, 1037, 2102, -919, 3093, 1419, 302, 1159, -2604, 1611, -615, -1667, -1151, -6590, -1305, -4651, -4417, -2579, -2497, -5931, -3787, -3795, -2262, -1112, -6328, -1578, -2133, -2192, -1282, -5249, -492, -1608, -1433, -1872, -5463, 56, -2829, -1033, -1877, -6735, 108, -8921, -1287, -2722, -7527, -461, -2687, -1650, -8005, -5833, -1891, -802, -2093, -3565, -4344, -4628, -1311, -2714, -996, -3912, -7108, -4596, -2647, -767, -3612, -5606, -7922, -2412, -2013, -1807, -5153, -3394, -3264, -3955, -187, -5528, -2571, -5326, -4593, 284, -4498, -2853, -4618, -4179, -632, -2208, -3530, -2875, -3441, -3109, -724, -4099, -2419, -2947, -2721, -181, -4229, -3471, -2999, -1022, -361, -3709, -7384, -3834, -599, -967, -3015, -8685, -5134, -711, -1899, -2887, -5903, -3554, -765, -3358, -3166, -5754, -1923, -714, -3785, -2993, -5364, -1627, -914, -2953, -2677, -4464, -2332, -1681, -3383, -2699, -3035, -3388, -3309, -3892, -3248, -1738, -3700, -6108, -2633, -5378, -1179, -2604, -4500, -2448, -6191, -1404, -1393, -2437, -4005, -3079, -2358, -977, -2288, -5299, -2310, -4056, -1572, -3908, -3726, -3124, -5777, -3196, -5321, -2909, -5437, -4515, -4846, -3710, -2791, -11497, -2689, -5536, -3021, -3005, -9364, -1774, -7165, -3170, -3541, -5741, -2088, -5895, -4048, -4716, -2782, -4370, -4907, -6604, -7144, -759, -6454, -7052, -7518, -8122, 162, -3555, -4903, -4158, -5895, 171, -3090, -2152, -3245, -5270, -458, -3873, -1626, -3560, -5052, -1399, -4831, -2721, -3192, -3680, -2242, -6011, -5172, -1962, -2520, -2037, -8181, -5573, -1320, -2241, -1316, -8217, -4278, -1378, -2414, -1338, -6014, -3858, -2009, -2515, -2295, -5196, -4232, -3320, -2881, -3690, -5759, -4847, -5692, -3846, -4289, -8306, -4073, -8223, -5282, -3679, -16164, -3100, -6849, -6858, -3166, -9936, -3173, -6371, -6714, -3424, -8925, -4364, -5933, -6648, -3920, -7339, -6037, -4464, -9019, -3779, -6133, -6647, -3996, -10396, -3640, -6068, -6735, -5136, -8205, -3995, -6796, -7047, -8061, -8816, -4599, -6902, -7482, -10407, -11258, -4973, -5821, -7887, -7805, -11952, -5019, -5191, -8094, -3997, -1225, -1726, 455, -2235, -1923, -1850, -2943, 550, -3777, -1445, -2087, -3342, -100, -5814, -1953, -2336, -3153, -1103, -4142, -2632, -4684, -3320, -1695, -2613, -2901, -8141, -4337, -1264, -1490, -2999, -2810, -6058, -562, -465, -3671, -2464, -7398, -133, 2, -5802, -5233, -7651, 29, -553, -6365, -4151, -6733, -20, -2718, -6204, -1790, -5319, -477, -5304, -14004, -1346, -5160, -1726, -2391, -5560, -1932, -7949, -4745, -808, -3556, -3041, -3434, -9599, -338, -2007, -3100, -831, -3094, -916, -500, -1744, -360, -1619, -2268, -816, -956, -1394, -1788, -2899, -8095, -2464, -3479, -2063, -2920, -96, -6021, -2134, -158, -528, 2698, 497, 628, 1616, 1838, 3059, 2030, 1896, 2141, 2847, 1232, 1605, 1912, 1225, 2745, -8986, -425, 926, -1296, 1901, -483, -2512, -753, -2453, 956, 843, -1462, -2673, -1688, 9, 95, -537, -4408, -2272, -2437, -1608, -347, -5766, -2994, -5430, -3559, -711, -6027, -2730, -1048, -6876, -1160, -5132, -2448, -191, -9054, -1174, -3723, -2641, -1234, -7680, -999, -2339, -3458, -3787, -4533, -1345, -1551, -4958, -4962, -1365, -2678, -1656, -4757, -4839, -255, -4576, -3032, -2895, -6716, -603, -5046, -6251, -2278, -6261, -1986, -4877, -5405, -3344, -5445, -3752, -4363, -3169, -7274, -8626, -5077, -4816, -2093, -8234, -4423, -6048, -8315, -1521, -5655, -2150, -7367, -4908, -1421, -4987, -2215, -8890, -2915, -1900, -3782, -4512, -8844, -3645, -2610, -2110, -11768, -7070, -6387, -2648, -642, -5088, -5925, -2978, -2638, 160, -3597, -6593, -1333, -4099, 112, -3402, -10426, -1467, -8395, -890, -3571, -6303, -2852, -3149, -3120, -4245, -3113, -4508, -964, -7471, -4544, -1674, -5138, -434, -8217, -3670, -1793, -6248, -1070, -7179, -3860, -3207, -11460, -2975, -7530, -5558, -2942, -8060, -6450, -4451, -7461, -2403, -5962, -4914, -1935, -10274, -3799, -6274, -3149, -605, -5873, -6762, -4510, -3147, -166, -3850, -6233, -2935, -4624, -373, -4159, -5653, -2806, -7555, -1092, -5467, -7347, -3662, -11322, -2169, -5232, -6273, -4987, -12250, -1931, -6186, -3310, -6732, -12012, -704, -11559, -2685, -8575, -6899, -460, -3157, -3793, -10286, -3554, -1608, -737, -6339, -9748, -1825, -4462, -94, -7832, -6802, -1348, -6603, -749, -7260, -7043, -2270, -5405, -2259, -6798, -13103, -5551, -4543, -3056, -6387, -5503, -8667, -4196, -3570, -6220, -3738, -5031, -5614, -4747, -6335, -4764, -4838, -14754, -2743, -6782, -10976, -6079, -6492, -839, -8010, -3814, -6350, -4274, -270, -10839, -1667, -4784, -3521, -885, -8579, -1418, -3388, -3149, -2850, -6281, -2455, -2546, -3133, -7300, -6330, -4263, -2585, -3700, -11042, -7839, -5477, -3646, -4679, -6705, -5640, -5430, -5216, -5187, -4908, -3996, -4950, -5622, -5062, -3597, -3962, -5171, -5520, -5080, -3056, -5109, -6746, -6170, -4909, -3343, 12256, 8004, 12464, 10904, 8416, 11661, 8838, 11745, 10292, 7837, 9829, 9223, 9416, 8226, 5859, 6696, 8767, 5290, 3434, 1111, 2977, 8757, 4969, 1397, -464, 2108, 8772, 5794, 2522, 410, 3623, 7901, 5356, 2679, -1019, 5245, 5907, 2704, 4437, 2837, 6340, 1941, -1646, 4585, 4770, 6369, -1679, 2483, 2553, 5902, 5187, 2214, 1437, -1825, 6887, 4304, 3741, 84, 2872, 7698, 4748, 5084, 4322, 4584, 8097, 3880, 6081, 5659, 4890, 7818, 404, 6185, 5249, 4249, 6527, -7291, 5006, 2951, 2881, 3497, -5240, 2206, -4488, 1561, -9294, -62, 927, -185, 1006, 283, 2058, 2088, 1229, 656, 1421, 2252, 1775, 1014, 258, 2453, 1699, 199, 430, -287, 3213, 2191, -2181, -57, -1054, 2911, 3325, -3151, -687, -1903, 1542, 3738, -1571, -2331, -1605, -940, 3089, 510, -6440, -368, -8987, 1177, 1854, -1607, -59, -1887, -1725, 2033, 1828, -1407, 592, -2381, 864, 3501, -5873, 1064, -2537, -1580, 3845, -3362, 542, -1505, -2445, 2886, -229, -405, 220, -2483, 444, 1400, -1286, 1392, -3217, -2656, 2135, -1229, 2661, -1199, -1080, 1981, -101, 3840, 256, 738, 747, 983, 4422, 182, 1386, -1648, 1393, 4214, -1355, 859, -838, 572, 3078, -2979, -575, 1179, -2779, 1287, -2136, -2727, 2186, -603, 978, -480, -6706, 2734, 2007, 1252, 808, -2298, 2885, 2142, 482, 891, -647, 2223, -222, -882, 48, -1264, 701, -928, -1442, -453, -2690, 1267, 2068, -781, -1361, -3028, 2620, 2817, -385, -2744, -5865, 2610, 2421, -936, -733, -3840, 1366, 1544, -2087, 10, -1101, -272, 683, -2789, -693, -877, -801, 163, -3096, -1309, -2391, -582, 299, -3274, -1850, -6029, 58, 616, -2384, -4761, -7028, 879, 179, -883, -6516, -4411, 1277, -1468, 34, -2535, -2780, 952, -4018, -129, -857, -2165, 261, -4386, -1751, 839, -3254, 107, -2568, -3835, 2081, -8946, 80, -1732, -2107, 2452, -4218, -605, -3095, -1867, 1838, -2078, -1614, -6924, -5828, -12, -2580, -2200, -2167, -3131, -2820, -2926, -3767, -1126, 719, -1176, 479, -6279, -2542, 2094, 49, 2495, -2044, -5879, 2347, -592, 3243, -1135, -5126, 1748, -3047, 3057, -3205, -4156, 138, -1356, 2208, -7246, -1605, -2387, 720, 1134, -3015, 104, -1286, 1267, 413, -3284, 616, 176, 843, 110, -6889, 398, 697, -193, -436, -11669, -33, 829, -1605, -2037, -10863, -448, 101, -2500, -5866, -5674, -1045, -2758, -2960, -12132, -2950, -1885, -5134, -5512, -10490, -2075, -2092, -2006, -4752, -10492, -2218, -1038, -1937, -3669, -4559, -1907, 129, -3237, -4189, -2470, -812, 589, -2988, -1045, -2067, -276, -42, -1464, 325, -2838, 109, -2212, -1060, 380, -3663, 1003, -7791, -1896, 621, -2976, 1814, -2913, -403, -258, 8045, 9550, 7186, 501, 120, 7325, 8675, 6888, 1718, -160, 4903, 5702, 5722, 2833, -1728, 3467, 5928, 3912, 3925, -1514, 5284, 7940, 4257, 4699, 1072, 4933, 8041, 4843, 5014, 3906, 1122, 6909, 4358, 5019, 5623, 1005, 5540, 3590, 4792, 6091, 4076, 4906, 3947, 3907, 5549, 3769, 3762, 4786, 890, 4882, 741, 1371, 5631, -291, 4994, 728, 1159, 6304, 4450, 4886, 3321, 2554, 6345, 5797, 3780, 3904, 2829, 5709, 5579, 1185, 3568, 1699, 4629, 4263, -2447, 2989, -2181, 3142, 3186, 129, 2449, -5138, 1168, 3525, 1168, 1787, -1819, 195, 3274, 742, 1218, -663, 1042, 1324, -866, 1954, 1364, 1572, 1662, -4443, 3379, 2084, 1684, 4019, -8671, 4064, 1194, 1955, 4407, -4026, 3688, 230, 2287, 3023, -2688, 2463, 1878, 2236, 1119, -1896, 1342, 2899, 2547, 2351, -1459, 192, 2690, 3911, 2889, -558, -3703, 1611, 4897, 2077, 1155, -4453, 1426, 4812, 253, 2535, -1286, 2192, 3359, -1729, 3156, -1705, 2219, -457, -1692, 2994, -4273, 1368, -6251, -398, 2085, -4517, -325, -1626, 744, 1019, -1348, -3731, -2295, 1545, 1093, 732, -3623, -5882, 1875, 1617, 2194, -270, -4617, 1827, 2031, 3166, 506, -916, 1703, 1981, 3615, -387, 1276, 1579, 173, 3603, -2179, 2473, 1186, -3435, 3314, -2054, 2724, 140, 1652, 3011, 491, 2149, 1076, 2844, 2872, 2244, 1128, 3283, 1936, 2805, 2588, 349, 3957, -821, 2510, 1202, -190, 2950, -1257, 1734, -4619, -1319, 204, -250, 544, -1348, -2007, 294, -875, -352, 1091, -997, 1688, -2024, -425, 1248, -1371, 1668, -855, -262, 382, -5691, 956, 510, -302, -817, -2914, 1049, 907, -595, -1920, 502, 1943, 448, -821, -2724, 1601, 2352, -661, -746, -3330, 1475, 2140, -2026, -671, -4629, 392, 1396, -2031, -648, -7270, -1545, -146, -264, -553, -5524, -5040, -3276, 1055, -589, -3499, -9133, -5950, 1530, -979, -2698, -4207, -2716, 1158, -1913, -2031, -4130, -1612, -210, -3641, -1409, -6419, -2059, -2883, -5326, -565, -1954, -4178, -5976, -4314, 748, 198, -8769, -5558, -2953, 1516, 195, -7740, -4682, -1797, 1192, -2740, -4010, -3483, -331, -413, -5649, -2104, -2098, 1117, -2120, -1314, -1318, -954, 2108, -357, -1250, -1381, -306, 2503, 958, -537, -1893, -644, 2144, 961, 741, -1843, -2192, 590, -137, 519, -1748, -1145, -2490, -1252, -1332, -2488, 606, -797, -2951, -2477, -3125, 1038, 190, -3824, -112, -2300, 779, -1038, 313, 1460, -1318, 19, -3384, 1074, 2146, -964, -1678, -3315, -616, 2249, -1141, -4332, 867, -1709, 1865, -1088, -9021, 3321, 629, 1195, -654, -782, 4100, 1998, 1048, -939, 2199, 3533, 2857, 1285, -2908, 3349, 1691, 3051, 932, 8460, 8764, 11352, 9229, 2753, 7994, 8949, 10816, 8749, 4209, 6432, 8797, 9288, 7514, 4087, 3028, 7763, 7221, 6280, 2883, 4307, 6429, 6286, 6063, 5151, 7170, 5960, 7057, 6742, 5915, 7885, 5807, 7424, 7641, 5033, 6634, 4701, 7023, 8459, 3040, 2317, 292, 6300, 8670, 1377, 4805, 1482, 5279, 7906, 2178, 6627, 4124, 3261, 6187, 1619, 6761, 5003, 2385, 4000, -1840, 6090, 5749, 4444, 149, 435, 4690, 5625, 4623, 68, 1056, 2124, 4213, 2140, 3875, -22, -3026, 2354, -1857, 4641, 1532, -8310, 1683, 2757, 4313, 3311, -7519, 872, 3382, 3707, 4183, -6729, -44, 2501, 2651, 4306, -3805, -1024, 1050, 4, 4095, -3055, -2232, 319, -2462, 4125, -2696, -1606, 834, 1370, 4268, -2410, -1369, 1480, 2791, 4182, -2101, -3471, 1399, 2977, 3828, -1520, -10223, 1, 2121, 3192, -775, -2869, -4311, -529, 2125, -186, -1618, -5470, -6680, 279, -352, -75, -2436, 917, -2823, -2656, 1519, -1145, 3016, -804, -4637, 1827, 182, 3785, 2504, 898, 1495, 964, 3725, 4232, 2812, 2149, 1390, 2948, 4710, 3434, 2418, 1520, 1436, 4089, 3316, 1374, 1283, -1088, 2899, 2824, 1657, 994, -7632, 2226, 2433, 2951, -5, -3054, 1144, 2270, 2699, -55, 100, -2935, 1379, 725, 3089, 1043, -1725, -2073, -2755, 4658, 399, 1008, -1394, -4091, 4839, -2461, 1439, 629, -1411, 3963, -2723, 695, -1442, -2145, 2462, 299, -1740, -1715, -2818, 1113, 1355, -2852, 2143, 2129, 732, 1797, 736, 2904, 3268, 1169, 2289, 1744, 1974, 1867, 1005, 2571, 1211, -754, -5190, -349, 2287, -231, -8360, 810, -1871, 1834, -1632, -3091, 2122, -1322, 2495, -2923, -1269, 1075, -755, 3536, -2198, -695, -2012, -865, 3776, -238, -991, -3860, -1450, 2933, 160, -2163, -644, -2220, 1230, -1354, -3734, 1575, -2364, 379, -5293, -4967, 2724, -1855, 144, -3369, -5844, 2915, -1599, -1240, -2022, -5521, 2148, -1625, -2487, -1109, -3257, 70, -1427, -1644, 471, -1981, -5198, -595, -705, 1684, -2131, -6811, 346, -443, 2197, -3951, -6458, 798, -2139, 1940, -8099, -3504, 634, -5089, 805, -6176, 47, 469, 671, -1372, -7883, 1266, 1254, 2689, -5451, -5118, 975, 2109, 3192, -9195, -643, -664, 2208, 2548, -3472, 822, -3077, 1423, 640, -719, 902, -5188, 621, -3357, 1233, 509, -7465, 1372, -8998, 2263, 412, -1372, 1921, -3528, 2170, 457, 1163, 1371, -1897, 689, 419, 2608, 199, -990, -2223, 406, 3461, -518, -285, -1417, 524, 3722, -721, -471, -59, 846, 3468, -3, -2518, -219, 1216, 2950, 769, -6634, -1664, 1267, 2254, 1212, -4126, -3522, 954, 1146, 1796, -4887, -2688, 562, -252, 2150, -5063, -1078, 15, -607, 1798, -1354, 64, -2422, 1217, -1222, 2356, -549, -826, 1359, 46, 2528, 77, 703, 1093, 540, 2047, 385, 1584, 810, 575, 906, 905, 1793, 607, -30, -280, 928, 1335, 127, -2231, -579, 524, 372, -1104, -3372, -1242, 594, -759, -2885, -1276, -2669, 1271, -2051, -1787, -2151, 731, 1607, -3941, -142, -2902, 2755, 1031, -2410, 257, 526, 3356, 338, 368, -416, 1648, 3127, 1169, 1554, -883, 1187, 2447, 1919, 1349, 35, -355, 1505, 2010, -49, 491, -1493, 290, 1885, -1012, -189, -706, -1402, 1835, -653, -1342, 414, -4049, 1445, -1380, -835, 1399, -2753, -656, -1061, 407, 2389, 328, -5594, 1578, 1699, 3256, 1557, 1803, 3104, 2721, 3595, 1262, 3600, 3538, 2988, 3157, -425, 3530, 3049, 2241, 2007, -2748, 1807, 1702, 292, 913, -2749, -1753, -271, -1737, 416, -410, -2780, -2211, -796, -825, 738, -3053, -3166, 224, -4159, 388, -6781, -1350, 778, -7538, -684, -6021, 40, 794, -8075, -1196, -2613, 194, 186, -5381, -1710, -796, -846, -876, -3076, -2264, 450, -3535, -2173, -2795, -2610, 1111, -3248, -2985, -3229, -2763, 942, -1127, -3091, -2968, -2029, -564, -957, -3445, -2602, -2077, -4367, -1931, -2600, -3586, -4953, -599, -2966, -1270, -6257, -3913, 1906, -3599, -1194, -3077, -125, 2630, -4263, -2647, -1461, 1024, 1879, -4804, -1485, -2161, 636, -401, -5464, 880, -7517, -1091, -1523, -7686, 1802, -3875, -3391, -522, -10960, 1715, -893, -3458, 65, -4600, 963, 83, -1659, 494, -638, -385, 426, -37, 215, 1234, -2347, 531, 777, -961, 1538, -3032, 550, 806, -2996, 382, -1489, 670, 104, -6353, -2430, -72, 764, -1070, -7499, -7218, 711, 512, -2166, -6543, -16015, 894, -116, -4145, -8256, -4972, 799, -1035, -9862, -3472, -1895, 662, -2096, -2376, -442, -683, 312, -2580, -257, 980, -586, -284, -2829, 219, 1468, -997, -665, -3893, -358, 1381, -1313, -924, -5072, -1739, 1043, -1979, -2041, -4316, -4271, 900, -3999, -5376, -3714, -10667, 1246, -9268, -12061, -4294, -2703, 1723, -5847, -6724, -5843, -451, 1670, -3115, -8155, -5466, -5, 553, -2213, -8196, -3675, -928, -2179, -2481, -5031, -2801, -2871, -5236, -2656, -4252, -2905, -3313, -4565, -1879, -5726, -3708, -2167, -4952, -1631, -9692, -4346, -1480, -4648, -2599, -3388, -4863, -1423, -3280, -5618, -1103, -6256, -2118, -2033, -7619, -369, -4822, -3878, -1391, -3919, -476, -2701, -7312, -1380, -2864, -804, -2024, -5814, -1760, -2468, -1219, -2327, -3750, -2191, -2058, -2263, -2831, -3560, -2300, -2160, -4133, -2731, -4973, -1943, -3298, -4746, -2163, -8332, -1633, -5245, -3793, -1897, -9267, -2145, -4547, -3877, -2678, -7678, -4342, -3610, -5656, -5583, -6145, -6009, -4297, -9752, -11844, -3874, -3231, -9564, 3317, -1712, 2495, -249, -4231, 2333, -4860, 1441, -2319, 472, 214, -2134, 332, -6326, 2920, -5387, -2290, -772, -1964, 3892, -958, -9231, -1652, 802, 3680, 1596, -2025, -1339, 1828, 2542, 1900, 188, -1396, 1656, 1022, 311, 218, -2450, 361, -494, -5238, -143, -2696, -2148, -2685, -3968, 428, -2002, -5779, -3974, -1723, 596, -1375, -7355, -2275, -1966, -382, -1209, -4313, -1981, -1460, -2295, -2147, -1661, -4310, -181, -3322, -3900, 111, -7570, -182, -3673, -3565, 1099, -2872, -1643, -4352, -1997, 1367, -1554, -2401, -4965, -514, 875, -433, -1869, -6022, 566, -330, 1229, -3502, -2602, 1703, -1157, 2667, -3167, -378, 2998, -711, 3240, 137, 101, 3765, -609, 2728, 1359, -902, 3624, -1976, 1083, 1316, -2345, 2389, -8600, -1322, 389, -1026, -309, -758, -3238, -266, 437, -6312, 2126, -4703, 816, 1101, -3475, 3235, -5948, 1770, 967, -999, 3122, -5564, 1828, -395, -227, 1573, -3359, 1194, -5735, 255, -3600, -2273, 303, -2483, 1032, -1824, -2752, -632, 326, 1326, 840, -5005, -1329, 466, 820, 941, -4284, -1794, -1498, -222, -125, -1421, -2664, -5865, -1489, -924, 146, -2813, -1618, -2149, -70, 669, -2351, 367, -1519, 961, -46, -1477, 1177, -1038, 1226, -1699, 628, 1361, -486, 532, -76, 2150, 963, 527, -1000, 1627, 2592, 101, 1346, -1927, 2020, 1908, -700, 1647, -1514, 1653, -332, -1236, 1406, -1411, 1325, -10068, -989, 667, -924, 1690, -1303, 515, -409, -10, 2410, 1293, 1728, -1478, -109, 2706, 2163, 2160, -2210, -2149, 2184, 1921, 1908, -2428, -9430, 658, 573, 1130, -1598, -8966, -2020, -2038, -112, -240, -6766, -3364, -3674, -1602, 690, -1499, -2217, -1771, -1832, 920, 140, -2417, -677, -1264, 421, -87, -4587, -576, -1291, -567, -1831, -8048, -1305, -1898, -875, -4965, -3671, -2780, -2956, 215, -9928, -2334, -4840, -3151, 960, -8429, -2557, -4926, -2364, 391, -4029, -3040, -2353, -2119, -1905, -2826, -2297, -703, -1551, -2284, -3370, -806, -431, -283, -701, -2411, 257, -1976, 712, -781, -110, 523, -5822, 1049, -1996, 1024, 18, -2396, 621, -3525, 1091, -1011, -1452, -564, -4353, 241, -1537, -3027, -1276, -3894, -1498, -1273, -1980, -230, -3036, -4200, -1669, 593, 335, -2142, -8792, -3426, 1475, -195, -1508, -9505, -5679, 1171, -1675, -1465, -6397, -4053, 5, -4040, -2016, -6187, -2771, -1603, -8102, -3353, -6786, -2667, -2941, -7881, -5242, -6067, -3708, -3427, -6175, -3917, -4149, -5051, -3540, -5787, -2668, -2366, -3368, -4009, -4915, -2502, -1633, -1766, -4810, -3513, -2509, -2258, -1212, -5520, -2392, -2325, -4518, -1430, -6411, -2023, -2446, -5615, -2144, -7517, -2545, -2686, -4291, -2848, -6527, -3844, -1880, -4841, -1145, -145, 628, 475, 457, -2957, -10, -1570, 1391, -133, -4206, 52, -6385, 1664, -1805, -3079, 145, -4327, 1253, -3114, -1486, -819, -975, 374, -2454, -1235, -5610, 467, -293, -1797, -3162, -3606, 815, -758, -304, -3796, -1578, 354, -1073, 797, -583, -2625, -499, -771, 551, 92, -2287, -1511, -778, -390, -1734, -786, -2860, -1886, 191, -5805, -598, -3619, -3831, 690, -130, -1444, -1214, -2643, 209, 1606, -3083, 1408, -614, -1114, 2381, -4094, 2906, 633, -6743, 2871, -2164, 3295, 1471, -1532, 2341, -551, 2600, 1803, 1710, -254, -1350, 670, 852, 2520, 1150, -2959, -1344, -3412, 1716, 3180, 1734, 1280, -675, -265, 2878, 3379, 3075, 1577, 593, 564, 3251, 3563, 1385, 2170, 651, 1874, 3033, -583, 2850, 2123, 884, 1686, -4414, 3101, 1837, 1719, -398, -9515, 2822, 99, 2401, -3167, -4597, 1589, -2826, 2676, -4771, -1401, -138, -5814, 2910, -6350, -610, -104, -6063, 3013, -8985, -1488, -619, -3875, 2957, -8283, -2294, -2217, -1501, 3230, -2237, -1782, -1127, 361, 3596, 688, -1570, -753, 1476, 3297, 1530, -1263, -1992, 1754, 1762, 584, -332, -3281, 1156, -2419, -2802, 614, -2246, -349, -3108, -5652, 727, -1032, -2545, -441, -2741, -363, -1151, -3433, -692, -2244, -2517, -3094, -2801, -2605, -2152, -2148, -5145, -2558, -3874, -1905, -258, -4390, -2293, -3149, -1464, 888, -6111, -1497, -3126, -774, 1634, -5495, -650, -2098, -295, 1935, -2774, -379, 67, -790, 1403, -1358, -1010, 1457, -3443, -11, -51, -2306, 1889, -3109, -284, 1057, -4607, 1583, 263, 789, 1584, -6906, 976, 1375, 1056, 1371, -1678, 582, 1247, 544, 460, -635, 136, 304, -188, -774, -1331, -1029, -952, -1160, -2151, -918, -1051, -1310, -2378, -3368, 140, 174, -419, -310, -2190, 673, -106, 227, 1558, -1586, 1039, -2416, -134, 2027, -2991, 893, -6580, -1703, 1269, -6484, -115, -5723, -4105, -856, -2971, -2238, -3554, -6704, -5229, -939, -6743, -2910, -7597, -3618, -429, -10337, -4056, -6796, -1566, -1561, -6673, -4428, -12669, -1216, -7896, -6061, -3668, -2993, -1485, -2882, -5866, -4362, -584, -1137, -280, -6184, -5742, -232, -590, 311, -7151, -6190, -1667, -693, 372, -10047, -5120, -7048, -1029, 73, -10798, -3369, -4997, -1002, -1285, -5770, -2927, -2547, -1148, -2374, -4233, -4789, -2791, -1988, -447, -4173, -8613, -4557, -3999, 457, -4995, -3105, -6255, -7731, -100, -6188, -1730, -7142, -5266, -2370, -6593, -2111, -11767, -3767, -5091, -5145, -3803, -7493, -3824, -2533, -4008, -6733, -4307, -4295, -1719, -4287, -10252, -3294, -4072, -2339, -5571, -8014, -3507, -3417, -3899, -3474, -6660, -4456, -2442, -6205, -1628, -7007, -4803, -1214, -10809, -1319, -8609, -4288, -465, -10738, 11098, 5212, 12300, 10731, -13274, 10442, 6685, 11667, 10185, -5310, 8302, 7186, 9625, 8459, -3020, 3785, 5776, 5462, 5253, -2244, 1023, 3996, -1424, 287, -1736, 2976, 4149, 407, -1784, -605, 3079, 3114, -722, 661, 89, 2958, 784, -5, 1303, 325, 3135, 1756, -86, -672, 1340, 3989, 2726, 137, -26, 2416, 4821, 2709, 1082, 3029, 3017, 4752, 3030, 538, 4385, 3491, 3277, 4047, -3489, 4673, 3810, -348, 4441, -1135, 3980, 3758, 216, 3628, 293, 2357, 3336, 1802, 1749, -2091, 829, 2509, 1505, 768, -891, 395, 811, 631, 636, 1899, 109, -4455, 226, -296, 2648, 168, -1596, -540, -1523, 2391, 272, 1368, -1774, -3220, 1437, 265, 1752, -1880, -5949, -332, 528, 741, -1641, -3799, -3154, 1030, -656, -1690, -2449, -3611, 1340, -1832, -1245, -2534, -2997, 1490, -4817, -374, -2040, -4587, 1682, -2789, -169, -908, -9040, 1674, -187, -1274, -1075, -8328, 1255, 257, -3880, -3698, -4611, 584, -873, -5979, -5615, -2235, 163, -3707, -9433, -1926, -1347, 160, -9210, -7969, -1200, -1870, 103, -12453, -4893, -2052, -4712, -220, -7170, -5432, -4455, -7397, -715, -3549, -7741, -7953, -2554, -1232, -1773, -5242, -5832, -1528, -1503, -1547, -2831, -3492, -2060, -1501, -3042, -1437, -1902, -3381, -1917, -4839, -896, -1487, -4409, -3751, -2231, -1335, -2925, -5361, -9173, -752, -2493, -11578, -7925, -5094, -347, -2519, -3585, -18176, -3398, -604, -1625, -1877, -10374, -3873, -1355, -1285, -2854, -12016, -6563, -2503, -1518, -6327, -12043, -7376, -3559, -2105, -3820, -7938, -4767, -3599, -2760, -2402, -6678, -4353, -3201, -3089, -2845, -6013, -5385, -3098, -2942, -4488, -4418, -8138, -3288, -2847, -6622, -2408, -14394, -3652, -3416, -8079, -1161, -5638, -4190, -4624, -8116, -831, -2668, -4954, -5222, -6976, -1189, -1206, -5770, -5339, -5479, -1860, -828, -5995, -6444, -4132, -2620, -1298, -5463, -7908, -3071, -3510, -2244, -4449, -6470, -2511, -4811, -3266, -3517, -4756, -2817, -6980, -3990, -3400, -4214, -4423, -6924, -3501, -4595, -5061, -7353, -5594, -2586, -6687, -5601, -7305, -5826, -2433, -5014, -4189, -6156, -7004, -3291, -3297, -3931, -4989, -7679, -4740, -2520, -5206, -4326, -7732, -5585, -2025, -5975, -4052, -6323, -7057, -1360, -4578, -2613, -4732, -12016, -683, -3435, -1212, -4410, -7504, -294, -2585, -828, -5621, -6556, -375, -2187, -1415, -5592, -8070, -1032, -2424, -2718, -3489, -9643, -1973, -3028, -4759, -3094, -7536, -2619, -3475, -9114, -5000, -4308, -3469, -3501, -6100, -6687, -2197, -4270, -3029, -3362, -3660, -1111, -3131, -3031, -2650, -3297, -786, -2407, -4677, -3325, -5145, -1064, -3122, -10750, -5078, -6277, -1863, -5590, -9095, -6716, -4257, -3437, -10057, -8470, -7109, -3506, -7310, -10609, -11511, -6290, -2969, -8178, -5305, 1585, 3305, 8481, 3947, -7373, 857, 2438, 7871, 4483, -5163, -1996, -93, 5893, 4989, -1325, -1659, 841, 2403, 4908, 1273, 2099, 2461, 2031, 4779, 2616, 3751, 2638, 2640, 5051, 3061, 4361, 2355, 1685, 5346, 2837, 4441, 2016, 406, 5189, 2082, 4328, 247, 1849, 4410, 1080, 4039, -3195, 3468, 3163, -336, 4027, 2040, 4662, 1497, -3365, 4988, 3859, 5658, -982, 38, 5693, 4172, 5994, -1242, 3006, 5278, 3567, 5174, -822, 4260, 3458, 2747, 2548, -2184, 4354, 706, 2516, 58, -2813, 3520, 445, 2291, 2562, -2896, 2005, 192, 1550, 2941, -4081, 194, -869, 734, 1859, -4434, -1360, -785, 930, 155, -3206, -2027, 300, 1899, -530, -2885, -1699, 1254, 2444, 93, -5182, -1408, 1767, 2207, 423, -10119, -1961, 1778, 1408, -459, -6219, -2644, 1226, 771, -1880, -1894, -2940, 111, 722, -634, 805, -3221, -589, 873, 577, 1830, -1550, 239, 766, 783, 1632, -334, 995, 95, 209, 354, -388, 892, -717, -877, -2339, -1423, -500, -449, -1883, -4972, -3426, -5195, -1, -1938, -2367, -8461, -3421, -187, -1485, -1279, -4852, -866, -240, -1510, -1196, -1826, -1293, 206, -2200, -1447, -684, -4666, -29, -3118, -1524, -475, -6737, -1703, -3556, -973, -677, -4775, -4770, -3481, -59, -841, -4117, -4457, -3387, 502, -1063, -2478, -3343, -3405, 513, -1847, -1872, -2763, -3513, 216, -3158, -1954, -3293, -3491, 6, -1841, -2078, -6307, -3108, -39, -34, -2676, -4200, -3202, -70, 295, -4143, -1613, -4699, 133, -1057, -5056, -933, -8726, 735, -5222, -4775, -1032, -7064, 1143, -6540, -5723, -1051, -4089, 856, -4798, -7549, -1215, -2400, -195, -7213, -5635, -2425, -1542, -1435, -6176, -4819, -4529, -1232, -2289, -3326, -6213, -3064, -863, -4036, -3085, -8323, -2295, -451, -4993, -4715, -5061, -4020, -749, -2752, -3877, -3576, -6565, -1875, -2479, -2051, -3764, -3560, -2217, -3992, -1880, -5381, -3341, -1708, -5812, -3022, -4445, -4321, -1992, -6653, -5129, -2650, -3498, -3241, -5129, -7028, -2528, -2897, -4728, -3051, -5802, -4167, -3519, -5969, -2871, -4319, -7325, -4670, -9996, -4331, -3595, -4791, -4604, -7482, -4786, -3318, -3351, -3509, -5488, -4479, -3763, -3662, -3008, -6282, -6129, -6270, -5514, -3122, -7904, -5156, -9061, -7791, -2629, -5439, -3320, -3932, -5454, -1852, -3039, -2650, -2778, -3742, -1820, -1611, -1754, -3548, -3505, -2607, -1143, -1164, -7063, -4740, -3944, -1745, -1874, -6602, -7379, -5275, -3118, -4641, -2947, -5731, -4220, -3162, -4582, -1783, -3739, -2276, -2644, -2088, -1782, -3252, -1601, -3260, -1424, -2322, -3649, -2494, -4660, -1975, -3063, -4196, -5663, -5993, -3845, -3228, -4619, -8550, -9567, -6095, -2124, -4831, -5158, -8780, -3685, -1638, -4736, -3700, -5019, -2600, -2706, 3707, 2638, 6935, 2367, -409, 2736, 2365, 6486, 3751, 2168, 1377, 1343, 5470, 4876, 3115, 3163, -681, 4488, 4624, 1773, 4089, -697, 2993, 2655, -2576, 3762, 1709, 329, -2962, -906, 2292, 2976, 233, -1112, 746, -870, 3029, 587, -145, 458, -5764, 1947, 2, -1787, -2017, -2262, -4, 430, -2562, -3108, -14, -1930, 1231, -1716, 1821, 1788, -2410, 1649, -1517, 3826, 2804, -1236, 1710, -143, 4544, 3057, -441, 1395, 1775, 4359, 2635, 418, 578, 2847, 3582, 1434, 1425, -1172, 2693, 2857, -1028, 1644, -3601, 1070, 2653, -6563, 865, -687, -76, 2631, -10669, -513, 830, 1328, 2475, -6428, -1739, 525, 1282, 2073, -2958, -2828, -1301, -1020, 1441, -2750, -4133, -3430, -16441, 646, -4168, -2603, -3920, -2047, 242, -486, -225, -4235, -270, 624, 1024, 1000, -3784, 359, 546, 493, 1237, -3623, 640, -679, -2010, 381, -3130, 969, -2732, -3305, -2278, -1646, 1447, -3567, -2123, -7752, -834, 1559, -1510, -2701, -3584, -997, 908, 148, -4190, -2956, -1853, -521, 587, -4177, -3973, -2802, -2053, 103, -3373, -5826, -3259, -2014, -1133, -3022, -7751, -3502, -801, -3851, -2864, -7128, -4058, 12, -6858, -2197, -5368, -4733, -156, -2515, -1500, -4914, -3531, -1289, -1601, -2129, -5401, -1761, -934, -3359, -5833, -5855, -929, 961, -7624, -2855, -4490, -885, 1960, -1611, -733, -2348, -960, 2037, 345, -1164, -1348, -729, 1452, 1044, -3845, -1594, -613, 382, 974, -4552, -3003, -778, -1558, 95, -3389, -5396, -859, -5068, -1692, -3932, -3957, -712, -2859, -2906, -4352, -1844, -920, -1314, -2445, -3971, -1383, -2114, -710, -2151, -3884, -2316, -5126, 123, -1625, -4171, -3896, -7733, 660, -1102, -4685, -3933, -2734, 588, -702, -5475, -3649, -655, 67, -528, -6936, -4077, -101, -1149, -1218, -10007, -4253, -984, -4323, -3259, -7527, -2958, -3909, -5933, -3525, -3866, -1383, -6203, -2006, -1102, -2139, -615, -2993, -907, 107, -2018, -870, -1857, -1267, 143, -3948, -1987, -1685, -2792, -1038, -8334, -3092, -2154, -4408, -3392, -4299, -3602, -3363, -4114, -3630, -3513, -4155, -6059, -3263, -2461, -5321, -4200, -9254, -2273, -2403, -14087, -3900, -5744, -1227, -3193, -4042, -4117, -5267, -476, -3996, -1661, -4803, -7994, -240, -3732, -892, -5842, -10145, -634, -3205, -1265, -7545, -5716, -1846, -2950, -2523, -9839, -4877, -4653, -3034, -3705, -7522, -4084, -5418, -3877, -4613, -4659, -3178, -2218, -5807, -7387, -3785, -3515, -1403, -8260, -11497, -4984, -6182, -2172, -9360, -6346, -6504, -6892, -4239, -7743, -4428, -4122, -4123, -6879, -7008, -3190, -3511, -4579, -10967, -6432, -2575, -3400, -5683, -7842, -4646, -2471, -1945, -3157, -3757, -4293, -2553, -1025, -2473, -2903, -5273, -2585, -1288, -3610, -4283, -4097, -9523, -5943, -2164, -5581, -2444, -7776, -7923, -2002, -6584, -1324, -6893, -10160, -3126, -8249, -1242, -5853, -5730, -6185, -7069, -1318, -4999, -4494, -11606, -4761, -1033, -4625, -4512, -9209, -2764, -895, -4675, -5093, -5432, -2392, -906, -5316, -6753, -2629, -4217, -506, -7343, -12258, -1117, -18640, -111, -9723, -7977, -691, -4660, -501, -6642, -6882, -1346, -3457, -2156, -5205, -9530, -3231, -4659, -6435, -3930, -12152, -6519, -8626, -5634, -3154, -7490, -9589, -6737, -2102, -3723, -7020, -9157, -4072, -731, -5013, -8657, -9415, -2941, -398, -4607, -10880, -9679, -2876, -754, -5311, -14843, -9054, -4567, -1638, -14356, -6364, -8733, -13294, -3056, -4994, -2996, -4463, -5328, -4725, -2286, -1904, -2246, -4056, -4127, -1121, -2429, -1557, -5177, -2582, -734, -4504, -1938, -7300, -2004, -1035, -7966, -3344, -7584, -2366, -1927, -7388, -7014, -5819, -3508, -3280, -5943, -7778, -3259, -5056, -4883, -5403, -3711, -1761, -6577, -5724, -3812, -2815, -1334, -10214, -6432, -2134, -3513, -1800, -7198, -8335, -1299, -5112, -3064, -4323, -6722, -1216, -6206, -5131, -3659, -5068, -1666, -8050, -8021, -4004, -4996, -2605, -8072, -11208, -4015, -6186, -4652, -4438, -10588, -3273, -8792, -9297, -3155, -7707, -2889, -9015, -5467, -3343, -5270, -3625, -6067, -3545, -4613, -3311, -6748, -5065, -2944, -6260, -2057, -9865, -6187, -2925, -7114, -1475, -5008, -6917, -3686, -7323, -1268, -4218, -3167, -5852, -7615, -1271, -4439, -1312, -6944, -8678, -1771, -3908, -680, -4782, -8846, -3161, -3446, -825, -4036, -8856, -5418, -4445, -1466, -4437, -10779, -6813, -5622, -2382, -5802, -4930, -7126, -3128, -3724, -7505, -1874, -8631, -1671, -6449, -8103, -453, -13228, -1267, -9744, -7564, -269, -10195, -1356, -6865, -6983, -1270, -7884, -1598, -7550, -8264, -3377, -6582, -1809, -13209, -10664, -5900, -4933, -2029, -6603, -7333, -6637, -3141, -2649, -4805, -5579, -4607, -2065, -3786, -4159, -4530, -3556, -1958, -4434, -4021, -3946, -3579, -2653, -4115, -5443, -4218, -3204, -3892, -4038, -9143, -6128, -2134, -4915, -5295, -4613, -13797, -1494, -3796, -8152, -2934, -8834, -1618, -2501, -3860, -2776, -7296, -2660, -1837, -2081, -3349, -6771, -4973, -1725, -2184, -4176, -7035, -10012, -2470, -3850, -4867, -10270, -8530, -4484, -7644, -4945, -11567, -5452, -7947, -13246, -4593, -7648, -4465, -13331, -8972, -4690, -7031, -4486, -11865, -9795, -5755, -7391, -4672, -9503, -9418, -6950, -7780, -4682, -16058, -7030, -6089, -6621, -4720, -7791, -5977, -5453, -5265, -4802, -5117, -5921, -6064, -4721, -5110, -5085, -8222, -8408, -4431, -5728, -7469, -7815, -12098, -3763, -6161, -10741, -3895, -8584, -3051, -5790, -8524, -2729, -7566, -2674, -5077, -9058, -3014, -8564, -2654, -4944, -7027, -4310, -8408, -2854, -6054, -5405, -6337, -6067, -3169, -7725, -5604, -8646, -5427, -3730, -6045, -7173, -9349, -5644, -2745, -4435, -3255, -5100, -10319, -2409, -5707, -5709, -3217, -4289, -2904, -8567, -10219, -1759, -1428, -4532, -10403, -10345, -2067, -360, -8814, -11601, -8343, -3550, -360, -6021, -10113, -5433, -2952, -1047, -2621, -6476, -3020, -2146, -2014, -1286, -3590, -1799, -3138, -3347, -1293, -2157, -2028, -4382, -6207, -2485, -2222, -3986, -3157, -6363, -4376, -3953, -6302, -2993, -3178, -4933, -8381, -5066, -4482, -2127, -4846, -12400, -4240, -7919, -2555, -6214, -8454, -3503, -7013, -4322, -5684, -6272, -2668, -4389, -4535, -3199, -3959, -1933, -3414, -2477, -2617, -2243, -1718, -3123, -1327, -3827, -1305, -2294, -2093, -1066, -7001, -1076, -3850, -801, -1632, -8388, -1685, -6329, -498, -2998, -7507, -3648, -5368, -1515, -4982, -7466, -7383, -3325, -2655, -7653, -7390, -5273, -2413, -1555, -14324, -6261, -3707, -2532, -1035, -9651, -4787, -3281, -3732, -1629, -5854, -4420, -3728, -5714, -2317, -4014, -5483, -5742, -5663, -2378, -3529, -7319, -8604, -4638, -3085, -4334, -6198, -5104, -4462, -5674, -6502, -5078, -3689, -4555, -14132, -11050, -5171, -3450, -4259, -13545, -9341, -5933, -3294, -3862, -8457, -5184, -6151, -2572, -4167, -4497, -3611, -5143, -1653, -5473, -3356, -3468, -3974, -1278, -6098, -3895, -4212, -3747, -2331, -4030, -5500, -5145, -5045, -7589, -2336, -6391, -5749, -7203, -4400, -1870, -5463, -6348, -6143, -2208, -2193, -4082, -7322, -4906, -2997, -1735, -2751, -4971, -3830, -7372, -806, -1731, -2704, -3698, -7334, -695, -1307, -1781, -5715, -4778, -1785, -1633, -1760, -9078, -4864, -4826, -2603, -2323, -4936, -5444, -10881, -3398, -3460, -4051, -6080, -4726, -3330, -5913, -4514, -9708, -2940, -3278, -9419, -5049, -7931, -2193, -3486, -4353, -4575, -4653, -2333, -3719, -1933, -3317, -4288, -3790, -4057, -585, -2619, -6018, -6452, -4951, -5, -3009, -13340, -4646, -7322, -224, -4531, -8298, -3373, -11910, -1415, -6536, -5687, -3711, -8413, -4246, -7867, -4259, -5131, -4938, -8504, -10451, -3386, -6804, -2993, -4161, -10671, -3469, -9349, -2556, -2815, -8378, -5085, -9094, -3620, -2359, -9030, -9748, -5670, -6663, -1707, -10671, -5964, -4925, -6982, -1238, -6904, -4084, -6098, -4870, -1593, -4780, -4367, -8449, -4262, -3044, -3837, -7028, -7802, -3321, -5930, -3460, -13684, -7987, -2254, -10288, -3088, -6700, -13398, -1980, -7907, -2537, -5443, -5852, -2529, -5309, -2281, -5477, -3144, -3454, -3354, -2779, -6270, -2284, -3982, -2010, -4131, -8456, -2577, -3993, -1443, -5248, -14405, -3869, -3884, -1780, -5301, -7072, -6484, -3667, -3182, -6687, -4773, -11855, -3411, -6299, -13380, -4030, -9727, -3625, -13249, -6993, -4150, -8273, -5127, -5833, -5646, -4561, -7768, -9798, -3523, -7344, -4823, -7563, -9133, -2409, -13634, -5072, -8797, -8460, -2152, -6157, -5646, -14285, -14051, -2812, -4474, -6838, -10685, -8765, -4529, -4371, -9026, -8921, -7190, -2538, -2793, -5336, -3947, -3232, -2447, -6203, -5527, -1346, -4646, -2657, -11648, -5577, -289, -7774, -3120, -5916, -4942, -409, -4535, -2327, -3789, -3437, -1664, -3652, -1306, -2676, -2158, -4312, -5043, -1433, -2688, -1550, -4704, -12021, -2924, -4046, -1718, -2938, -6369, -5811, -5486, -2140, -2456, -4418, -9238, -4771, -1672, -2623, -5173, -7536, -5012, -1027, -2916, -7563, -5388, -6455, -1047, -3534, -5747, -3857, -6470, -1762, -6188, -4386, -2362, -5764, -3270, -7302, -3486, -1317, -5339, -5938, -2043, -2596, -977, -5002, -5752, -567, -2031, -1364, -5686, -4356, -871, -1595, -2485, -9444, -4559, -3048, -1263, -4310, -9670, -4284, -9537, -1203, -5912, -6224, -3258, -4981, -1598, -5220, -6752, -3456, -3016, -2725, -4270, -13093, -3992, -2290, -3813, -4408, -7856, -1929, -1810, -2808, -6610, -6766, -300, -1490, -1837, -12281, -9620, 182, -1437, -1396, -4540, -5758, -268, -1434, -1067, -2260, -3563, -1245, -1335, -1237, -1190, -3551, -1476, -1500, -2333, -991, -4916, -812, -2049, -2009, -1888, -4600, -483, -2455, -390, -4537, -3079, -788, -2471, -38, -8360, -2618, -1859, -2379, -449, -5758, -2959, -4411, -2219, -90, -6016, -3160, -7765, -2225, 307, -9508, -2980, -4024, -2636, -255, -5505, -3532, -2875, -3524, -1276, -2591, -5988, -3067, -5231, -1555, -1350, -8221, -4186, -8034, -1763, -1154, -3675, -7696, -8156, -2892, -1762, -1783, -8195, -7268, -4659, -2969, -1119, -3649, -6626, -3255, -4262, -1365, -2163, -6289, -1846, -4546, -1670, -1498, -6156, -1979, -4453, -425, -943, -4181, -3783, -5071, 723, -488, -2102, -7526, -5890, 759, -454, -991, -7736, -5490, -412, -1108, -886, -9249, -5507, -2500, -2611, -1753, -11330, -8110, -3541, -4951, -3085, -6498, -11560, -2818, -6163, -3838, -5476, -7744, -1613, -4473, -4503, -4895, -10538, -787, -3815, -4152, -4471, -9289, -772, -5325, -2438, -4617, -7042, -1681, -12156, -1011, -4078, -11124, -3652, -4463, -221, -3429, -6484, -6516, -2117, -224, -4362, -3413, -8298, -1303, -1142, -8465, -2652, -10619, -1620, -3147, -4694, -2958, -9320, -3078, -5244, -2625, -3493, -7538, -4728, -4215, -2782, -3538, -7417, -5557, -4010, -5181, -3169, -3829, -6440, -6266, -8421, -2777, -1878, -4202, -11497, -4542, -2452, -1751, -2812, -4234, -3385, -2148, -2715, -2843, -2160, -3604, -1954, -2837, -3958, -1415, -4855, -2031, -2412, -5695, -1431, -6987, -2535, -2219, -6285, -1866, -8006, -3450, -1908, -5988, -2553, -5303, -4148, -2209, -7158, -3775, -2744, -4606, -3348, -12623, -6204, -1360, -6610, -3959, -7071, -11644, -1069, -13710, -4590, -5496, -9894, -1583, -5968, -8329, -6387, -6163, -2172, -4522, -6894, -9424, -4457, -2212, -4798, -3904, -7938, -4179, -2202, -6264, -3431, -5745, -5168, -2666, -9482, -4409, -5407, -7155, -4061, -10419, -6791, -6801, -8847, -7855, -5501, -8849, -10972, -7787, -7849, 11195, 15123, 10025, 6099, 8571, 11019, 14694, 9644, 5733, 7741, 10391, 13372, 8577, 4369, 4786, 9563, 11038, 6931, 1192, -2344, 9374, 7356, 4436, -3542, 1962, 9099, 3349, 1630, -2046, 1944, 7586, 6115, 2811, -531, 935, 5291, 7372, 2914, 1121, 1036, 6408, 7321, 1143, 1454, 2072, 7296, 6291, 1497, 1177, 3087, 6928, 5468, 3598, 1443, 4050, 5664, 5714, 4290, 2105, 4939, 3856, 6142, 3746, 2319, 5591, 727, 6849, 1885, 1557, 5915, -7395, 7137, -2519, -389, 5801, -1126, 6483, -4415, -2680, 5201, -1921, 4721, -769, -2403, 4188, -739, 1647, -162, -594, 2599, 794, 821, -656, 91, -466, 1178, 2644, -1822, -1098, -11217, 1390, 3262, -1618, -5779, -4820, 1147, 2935, 896, -7053, -5800, -464, 1555, 2522, -6062, -6045, -5268, -1479, 3020, -9656, -3864, -1743, 964, 2638, -5107, -3853, -203, 3374, 1760, -4036, -6396, -1279, 3921, 776, -4029, -16551, -3809, 2968, -236, -3220, -8143, -3589, 368, -1465, -2442, -7889, -10233, -2711, -3780, -2795, -5569, -709, -936, -8300, -5686, -3273, 2446, 737, -3423, -7181, -2279, 3543, 1442, -1155, -2180, -1762, 3392, 861, 137, -815, -746, 2232, -1795, 961, -896, 52, 239, -5979, 1433, -1863, -189, -2099, -897, 1622, -3121, -1718, -3985, 551, 1557, -3537, -2905, -5520, 686, 1261, -2232, -1677, -7394, 27, 715, -885, -1237, -8488, -1059, -213, -377, -2039, -4980, -2121, -1747, -830, -4073, -2595, -3249, -4097, -2325, -6630, -1691, -4229, -7405, -4772, -5486, -2005, -3586, -7187, -7279, -4017, -3260, -3248, -4533, -7752, -3357, -5022, -4191, -3047, -4702, -3228, -5988, -5489, -2174, -3104, -3376, -4316, -6122, -1603, -2904, -3414, -2785, -8958, -1317, -3641, -3062, -2009, -8828, -1351, -4858, -2576, -1824, -4507, -1595, -6319, -2447, -2153, -3322, -1869, -7238, -2943, -2892, -4009, -2192, -6063, -3927, -4048, -7471, -2810, -5060, -5006, -6336, -7996, -4013, -5153, -6513, -12027, -5008, -6226, -6290, -9703, -6730, -4456, -10684, -7420, -12876, -5063, -4618, -8828, -6957, -13355, -4465, -4695, -6007, -6580, -10569, -3031, -4757, -4748, -6951, -6650, -1852, -5345, -4392, -8115, -5484, -1897, -6110, -5073, -11001, -5880, -3632, -5574, -7318, -9674, -5604, -9235, -5218, -9011, -7118, -4163, -8010, -6298, -7697, -7118, -3950, -7467, -7900, -8856, -9572, -5670, -9525, -7093, -9777, -8870, -11966, -4224, -6722, -7543, -6720, -9695, -2019, -7078, -7268, -6368, -8813, -1415, -6884, -7908, -6644, -10736, -2124, -5611, -8390, -6536, -9810, -4488, -4537, -9472, -6533, -7881, -9121, -4070, -12403, -7430, -6232, -5549, -3898, -14521, -8280, -5120, -4089, -3925, -8328, -6393, -5058, -4425, -4379, -6126, -4521, -6278, -5827, -5537, -5533, -3452, -9027, -5927, -8372, -6073, -3144, -11883, -5083, -12795, -7374, -3693, -10706, 7471, 1317, 4615, -14033, 6451, 6761, -946, 3861, 2250, 6218, 4361, 2064, 1361, 3975, 5565, 1245, 4653, -2752, 3802, 4901, 3821, 4949, -1612, 2915, 4689, 5122, 3530, -928, 2833, 4410, 5379, 619, -784, 3273, 3654, 5126, 1850, -228, 3372, 2809, 4595, 4245, 1260, 3195, 2679, 3317, 5555, 3236, 3066, 3585, 2570, 6007, 4835, 3199, 5060, 5802, 5615, 5821, 3574, 6185, 7650, 4281, 6151, 3833, 6600, 8050, 1836, 5719, 3310, 6301, 7191, -1342, 4359, 947, 5430, 4988, -2155, 1953, -4581, 4275, 1230, -1996, -855, 1888, 3139, -1090, -3080, -2669, 3627, 1920, -848, -2718, -4740, 3998, -120, -600, -370, -6840, 3703, -4798, 942, 482, -5468, 3139, -1418, 2099, 270, -1744, 2580, 254, 2134, 83, 206, 1939, -599, 1174, 971, 901, 592, -4386, -109, 2158, 709, -1687, -3201, -668, 2771, -56, -1057, -2015, -653, 2568, -1020, 370, -4131, -1203, 1562, -1873, 813, -8413, -3746, 260, -2548, 481, -4924, -3734, 66, -3146, -998, -6771, -975, 696, -3602, -5177, -5184, -1115, 1081, -3284, -2797, -2198, -5771, 1062, -1997, 6, -1363, -1954, 769, -720, 941, -1541, 928, 396, -202, 718, -2197, 1581, 51, -822, -701, -3020, 1164, -226, -3019, -3831, -3029, 261, -275, -7997, -4819, -2221, -863, -369, -19659, -2074, -2177, -2305, -1211, -8690, -561, -3244, -3692, -3153, -4836, 423, -3537, -3659, -4844, -3733, 1030, -1982, -2668, -3175, -3808, 1179, -958, -1967, -1121, -3089, 819, -892, -1758, -304, -2016, 0, -1850, -1648, -1034, -1839, -1084, -3559, -1352, -3952, -2599, -2187, -4248, -1182, -6726, -3883, -3331, -3728, -1352, -4597, -5022, -4866, -3655, -1972, -5668, -6061, -5979, -4598, -3524, -7075, -7941, -4363, -6821, -7352, -4790, -10153, -3141, -8647, -7694, -4560, -8181, -3059, -8163, -5139, -5967, -6999, -3522, -7499, -4662, -4430, -7789, -3323, -7236, -5095, -2678, -13015, -2370, -8770, -6402, -2326, -8020, -1428, -15172, -5738, -2779, -5912, -718, -6714, -3872, -3293, -6246, -269, -4852, -3756, -3844, -8584, -248, -5726, -6181, -5197, -8974, -895, -9090, -9187, -7961, -7599, -2222, -3604, -4499, -7550, -8094, -3415, -1637, -3358, -5196, -9103, -3766, -1415, -3280, -4638, -8634, -4531, -2375, -3022, -6155, -8514, -6723, -3882, -2388, -12957, -8294, -10702, -4611, -2183, -6208, -6294, -8596, -4624, -3030, -4294, -4482, -6502, -4505, -5533, -4369, -3588, -5140, -4437, -9778, -5678, -3492, -4094, -5129, -8125, -5901, -3924, -3454, -7825, -6824, -5268, -4546, -3504, -13669, -6096, -6415, -5086, -4449, -6758, -6129, -8657, -5754, -5507, -5122, -6649, -5868, -7418, -4495, -4525, -6668, -4849, -10128, -3423, -4501, -6654, -5680, -9210, -3299, -5553, -7664, -8110, -9114, -4008, -9971, -8777, -8515, -9887, -5323, -8213, 2153, 1795, 3912, 3587, 5834, -1016, 1537, 4466, 5109, 5613, 2066, 1108, 5719, 6749, 5662, 4755, 1217, 6345, 7241, 5840, 4602, 781, 5804, 6512, 5032, 2445, -1165, 4060, 4580, 2896, 1283, -330, 1412, 1818, 314, 2223, 989, -1502, -594, 801, 1915, 805, -2466, -1993, 3264, 2110, 52, 1217, -2491, 4804, 3837, -370, 3461, 1191, 5229, 5129, 1590, 4442, 3359, 5230, 5439, 3535, 4021, 3458, 5420, 4640, 4053, 1234, 1504, 5143, 2771, 2996, -656, -252, 3689, 1434, 58, 2848, 505, 725, 1598, -723, 3135, -993, -1702, 1350, 456, 1419, -4105, -508, 626, 15, -3113, -8520, -826, -156, -918, -6508, -1488, -4348, -47, -1237, -2357, 1393, -258, 649, -1318, -869, 2277, 2002, 1054, -1786, 235, 2361, 2321, 970, -2298, 985, 2258, 1436, 338, -2189, 1162, 1883, 110, -861, -1995, 521, 926, -600, -2784, -1977, -1188, -663, -1187, -5786, -2009, -2750, -2117, -1153, -5734, -2331, -1468, -1559, -424, -3789, -3391, -846, -124, -271, -2616, -5094, -1425, 568, -635, -1514, -7855, -2307, 193, -1079, -957, -6199, -1955, -1183, -242, -1688, -1225, -674, -3158, 874, -4361, 557, 144, -2714, 775, -2997, 622, 45, -932, -462, -885, -746, -456, -966, -1615, -916, -3384, 16, -3805, -3124, -3523, -8639, 1030, -4263, -9598, -4733, -6012, 1482, -1416, -4817, -1442, -2525, 1284, -727, -3537, -1493, -2039, 938, -420, -4252, -4997, -2887, 726, -354, -6085, -5058, -2260, 126, -945, -11731, -2710, -1154, -1202, -1769, -7325, -3777, -1094, -2891, -2222, -4635, -9826, -1999, -3706, -3273, -3883, -7014, -3719, -3379, -6908, -5244, -4869, -5933, -2992, -7082, -10324, -5168, -7420, -3277, -4263, -5530, -7436, -7158, -4667, -4579, -4126, -15350, -6271, -7759, -7094, -4505, -11147, -6313, -8923, -7329, -4495, -10853, -8293, -6150, -3947, -3008, -9408, -7699, -4367, -1877, -2408, -9026, -4849, -2898, -1183, -3101, -12385, -3941, -1949, -1875, -4788, -11231, -4544, -1903, -3954, -6879, -9517, -6720, -3039, -5178, -8548, -9850, -8467, -5021, -4193, -7323, -13018, -5354, -5141, -3844, -6560, -9112, -2811, -4752, -4008, -7486, -4419, -1606, -4762, -4680, -7503, -2441, -1777, -4502, -5971, -6081, -1754, -3403, -4646, -6904, -7030, -1869, -5849, -5379, -6375, -17535, -2471, -5899, -5749, -5793, -5734, -3495, -5789, -5025, -5445, -3960, -5428, -6367, -4398, -4889, -4138, -9359, -7064, -5009, -4619, -5597, -7328, -7851, -7654, -5160, -7970, -5438, -9383, -9530, -6483, -9446, -5387, -12105, -8456, -7893, -9236, -6564, -11607, -10606, -7852, -10832, -7544, -11498, -9134, -6662, -15210, -6070, -8433, -6344, -5589, -10395, -4950, -6170, -5338, -4885, -8898, -5055, -5460, -5829, -4232, -8021, -6466, -5481, -9062, -3557, -8159, -9262, -5154, -10191, -3290, -10077, -5350, -5843, -8811, -5320, -9128, -7464, -3738, -10143, -7960, -8100, -9496, -3235, -12739, -9271, -7889, -5974, -4061, -12627, -9218, -7999, -4389, -6014, -9309, -7709, -7663, -4306, -6351, -8323, -6228, -6876, -6256, -4848, -8023, -5981, -6369, -22941, -3874, -7185, -6829, -7207, -7048, -3467, -7086, -8196, -10378, -6642, -3479, -9258, -9857, -7156, -11084, -3651, -9220, -14935, -5104, -7677, -3819, -5829, -12594, -4775, -5058, -4090, -4704, -10755, -5069, -4478, -4545, -4855, -12465, -4925, -4561, -5231, -5501, -8389, -4510, -4559, -6212, -5288, -5943, -4715, -4564, -6756, -4783, -5362, -6670, -5045, -5267, -4956, -6155, -12391, -5872, -3268, -5009, -7774, -4679, -6195, -2051, -4210, -7952, -2658, -5427, -1662, -3561, -6643, -2372, -4257, -1872, -3409, -5854, -3374, -3473, -2318, -3894, -6110, -5644, -3255, -2620, -5374, -7144, -8270, -3633, -2712, -6792, -7214, -7604, -4796, -2792, -5905, -6319, -6949, -7097, -2972, -6274, -5927, -6965, -8726, -3185, -10383, -6426, -6650, -7111, -3338, -7288, -8155, -5905, -6216, -3604, -4812, -10773, -5450, -6311, -4407, -4748, -8935, -5538, -7599, -6173, -6452, -7096, -5857, -10204, -9091, -10233, -5895, -5855, -9265, -11213, -18393, -4744, -5604, -7013, -10177, -15188, -3829, -5427, -5872, -8567, -13044, -3467, -5386, -5846, -7906, -14226, -3806, -5568, -7225, -8231, -15640, -4867, -6064, -7962, -8570, -15315, -6491, -6603, -5666, -8093, -12325, -8361, -6551, -4535, -7626, -8564, -10203, -5893, -4544, -7566, -6681, -10950, -5123, -5408, -7591, -5847, -10538, -4421, -7186, -7343, -5592, -11590, -3902, -11545, -6836, -5673, -13925, -3799, -10239, -6406, -6118, -7636, -4267, -5771, -6545, -7258, -5346, -5225, -3950, -7375, -9963, -4827, -6336, -3422, -8649, -19154, -5777, -7520, -3945, -11323, -9199, -8682, -8992, -5413, -13915, -6826, -13591, -9162, -7564, -8499, -5978, -9332, -7473, -9923, -7084, -6291, -8315, -6112, -12872, -7505, -7801, -8927, -5640, -20680, -9918, -9336, -11811, -6077, -12715, -18131, -8541, -12484, -7082, -9311, -15387, -8505, -8095, -7985, -7318, -16632, -10172, -6551, -8789, -6129, -15036, -11625, -6071, -10040, -5623, -14149, -10038, -5712, -12652, -5786, -8795, -8596, -5150, -17093, -6398, -6442, -7428, -4844, -10921, -6799, -6098, -6908, -5106, -9167, -6896, -7377, -7247, -5934, -9277, -6995, -10019, -8436, -7206, -11837, -6677, -11714, -9005, -8900, -14474, -6423, -10326, -7606, -10715, -8786, -7193, -9644, -7153, -10266, -6949, -9861, -9951, -8611, -9436, -6413, -15358, -10963, -12247, -10379, -6633, -11458, -15410, -11217, -13295, -7154, -11108, -12643, -12588, -9742, -7396, -11499, -9731, -11903, -7479, -7161, -11064, -10301, -8998, -6598, -6914, -11898, -16542, -9630, -6623, -7180, -13601, -11254, -10157, -7547, -8109, -9983, -8363, -6865, -9548, -8945, -8289, -6601, -5682, -12160, -8646, -8391, -5706, -5913, -11865, -8276, -10447, -5925, -6935, -9121, -8354, -7604, -6798, -9462, -6838, -4716, -6822, -6549, -8462, -7693, -4000, -6594, -7895, -6769, -7586, -4973, -6013, -8419, -5617, -7780, -7360, -5270, -5937, -5635, -9492, -7264, -4908, -4523, -7270, -15655, -6850, -5062, -4234, -9884, -13528, -8888, -5614, -4852, -7523, -10928, -7270, -6215, -5311, -6747, -7114, -4923, -6566, -4600, -7739, -4724, -4564, -7040, -4242, -8549, -3727, -5943, -8435, -4850, -7798, -3812, -9394, -9503, -6331, -8229, -4845, -8458, -8618, -8332, -10959, -6702, -8161, -9438, -10704, -9777, -8455, -12745, -8288, -18293, -7542, -8917, -6757, -5409, -10329, -7475, -8013, -4059, -4109, -6316, -7180, -5499, -2730, -3871, -4034, -4328, -3872, -1852, -4352, -2859, -2390, -3590, -1313, -5337, -2758, -1733, -4776, -1285, -6561, -3900, -2343, -8214, -2047, -8071, -6182, -4479, -13300, -4172, -9847, -5768, -6314, -8925, -10777, -7609, -4552, -4439, -8330, -7203, -5519, -4559, -3779, -8590, -5127, -4699, -4959, -4239, -9071, -5260, -4944, -4503, -5149, -10096, -6423, -6439, -3922, -5556, -12913, -7777, -9690, -4341, -5107, -11462, -9815, -12056, -6622, -4521, -7703, -10977, -13298, -11830, -4439, -5979, -7696, -10712, -5605, -5086, -5555, -6830, -6915, -3485, -6244, -6340, -8277, -5108, -2779, -6934, -8530, -14756, -4508, -3014, -6373, -12795, -8122, -4962, -3946, -5447, -20497, -5840, -6385, -5337, -5108, -16593, -5327, -8387, -7255, -5739, -11819, -6191, -10161, -7649, -7019, -10547, -9152, -10066, -5847, -6470, -14486, -10060, -8501, -5217, -5286, -9341, -5770, -7874, -5880, -5256, -5970, -3900, -8430, -7759, -6395, -5144, -3241, -9640, -11092, -7933, -6040, -3405, -10804, -14053, -8638, -9004, -4054, -13237, -11551, -9299, -12484, -5009, -14033, -10711, -9999, -8460, -6175, -9999, -11959, -10288, -7217, -6379, -8146, -14966, -9243, -7447, -6123, -7424, -10787, -8123, -8228, -7030, -7654, -9525, -8109, -7544, -8848, -8383, -10883, -8998, -5887, -8280, -8208, -19806, -10114, -4968, -7492, -8023, -12012, -11740, -5422, -7524, -9341, -8940, -12506, -8279, -6865, -13448, -6894, -7999, -13915, -5800, -15544, -6065, -5780, -8611, -5322, -10285, -6815, -5080, -9507, -5177, -8316, -10562, -5325, -9006, -5229, -8222, -10018, -6044, -6886, -5836, -10249, -6882, -7736, -7052, -6820, -14958, -6880, -13252, -7863, -7128, -11928, -9877, -7676, -7032, -6802, -11699, -13657, -5602, -7377, -6714, -12093, -8943, -5430, -10822, -6575, -10612, -8469, -6471, -9368, -5754, -10230, -9748, -8396, -7060, -5243, -10757, -16112, -9310, -7211, -5730, -10197, -11386, -7731, -8958, -7499, -9370, -9610, -6667, -10252, -10601, -8998, -11204, -6622, -9982, -9833, -8612, -10396, -7354, -10764, -8613, -8016, -8505, -7972, -13083, -8838, -7443, -9133, -7421, -22329, -9933, -7356, -13400, -6717, -12747, -10748, -8053, -11388, -6577, -9403, -10115, -9711, -8863, -6951, -8050, -9368, -13137, -8426, -7709, -8026, -9329, -16157, -9241, -8961, -9285, -10204, -10665, -4364, -6294, -3836, -7219, -9365, -3929, -6002, -5580, -4914, -8936, -4243, -7687, -8215, -4495, -10010, -5284, -8697, -7519, -5838, -12775, -6430, -8266, -7565, -10654, -11040, -7006, -10283, -10751, -9930, -10448, -7897, -13324, -7606, -7022, -9663, -9744, -8958, -4818, -6295, -6927, -10911, -7584, -3691, -5889, -5940, -10517, -7192, -3582, -5363, -7219, -9895, -7168, -4360, -5180, -9619, -8691, -7961, -5198, -5803, -5978, -7237, -10391, -4804, -7380, -4833, -6109, -10396, -4192, -9450, -5547, -5263, -9089, -3209, -10289, -6763, -4585, -6318, -1948, -8639, -6093, -4576, -4159, -1231, -6172, -5231, -5832, -3620, -1236, -4528, -3804, -6468, -4263, -1849, -3621, -2225, -4256, -4723, -2965, -2791, -1475, -3322, -4411, -4578, -1826, -1700, -3905, -4468, -6272, -1273, -2831, -6034, -4816, -5906, -1430, -4717, -8818, -4714, -4902, -2262, -6920, -8330, -4036, -4736, -3635, -8333, -7975, -3348, -5249, -4955, -8431, -7728, -2994, -6889, -5195, -8476, -6570, -3102, -13434, -5928, -9587, -5214, -3852, -6093, -7567, -11295, -4506, -5399, -3752, -5774, -9771, -4808, -6523, -3233, -4852, -8863, -5962, -6095, -3654, -5989, -8809, -6196, -6473, -4103, -7589, -9073, -5738, -7981, -4108, -5257, -8939, -6148, -8299, -4780, -3803, -6527, -6477, -6990, -7861, -3288, -4499, -6232, -6105, -10866, -3259, -3479, -6646, -5314, -6065, -3503, -3374, -7567, -4174, -5087, -3853, -4226, -8037, -3362, -5254, -4256, -6220, -8814, -3278, -6154, -5008, -9116, -10928, -3834, -7891, -6764, -9195, -9869, -4800, -10372, -11778, -8982, -7745, -6119, -11778, -10249, -10527, -7539, -7762, -9666, -7519, -11275, -9557, -9285, -7147, -7933, -10382, -14017, -13071, -6178, -12286, -10424, -9186, -10255, -7514, -11687, -8993, -7492, -6503, -9128, -10698, -7872, -7326, -5508, -4999, -16246, -7830, -8372, -6157, -3467, -8183, -8341, -9524, -8154, -3266, -6474, -8933, -10035, -9500, -3579, -6851, -9384, -10592, -9732, -3931, -8966, -10573, -9352, -10725, -4621, -8411, -12677, -8166, -8141, -5573, -6177, -10671, -6396, -7005, -5019, -5664, -8539, -4903, -7998, -4353, -6129, -7154, -4439, -8108, -5015, -6479, -6239, -4922, -6675, -6239, -7302, -5595, -5903, -7161, -5943, -9650, -5466, -6010, -10543, -6084, -7520, -6087, -5225, -15220, -7054, -5292, -6691, -4902, -11189, -6657, -4647, -6504, -5288, -11743, -5961, -5358, -6616, -6282, -13219, -6286, -7658, -6664, -7806, -14203, -7961, -9002, -6051, -8918, -12693, -12553, -6606, -6071, -8136, -9552, -11452, -5097, -7414, -7769, -7945, -8942, -4260, -9978, -9190, -7114, -9340, -4201, -10764, -13846, -5954, -15349, -5477, -9096, -10039, -4706, -9028, -10172, -7495, -8385, -4112, -5674, -7674, -6897, -8848, -4367, -4294, -4688, -7419, -10627, -5427, -3950, -3679, -8725, -9351, -7109, -4392, -3577, -9706, -6925, -9179, -5632, -4123, -9339, -5498, -11658, -7746, -5061, -8542, -4782, -13051, -8615, -5995, 10207, 11289, 9083, 11137, 8447, 9430, 10944, 8381, 10592, 8026, 7216, 9886, 6198, 8985, 6673, 6633, 8129, 4138, 6584, 4431, 7475, 6153, 5042, 4490, 3804, 6993, 5102, 5109, 3740, 4357, 5154, 4561, 3913, 3153, 3361, 3044, 3469, 1068, 2251, 46, 5734, 1797, -3758, 2245, -1866, 7030, 564, 1773, 1725, 1478, 6789, 625, 3127, -1614, 3713, 6222, 488, 3036, -562, 5623, 5979, 1255, 3515, 3295, 6951, 4547, 3822, 4257, 4597, 7390, -822, 4900, 3891, 4550, 6732, 826, 4401, 2104, 3719, 4627, 2534, 2473, -938, 2962, -219, 1731, -34, -1834, 2546, -1652, 296, -325, -1352, 2012, -161, 110, -52, -1516, 1491, -1138, 1025, -483, -1726, 1399, -1913, 1741, -1410, -987, 1403, -1115, 1689, -1125, -40, 831, -211, 353, 543, -80, -702, -268, -1854, 1470, -1423, -4196, -1443, 1014, 1393, -2236, -3751, -2075, 2777, 588, -92, 156, -1659, 3229, -489, 1328, 1353, -2081, 2877, -1334, 1669, 744, -1109, 1810, -1551, 1024, -2013, 743, 890, -1334, -573, -3908, 1664, 2001, -1130, -2663, -2071, 1890, 2865, -872, -2943, -3700, 1837, 2831, -270, -1210, -6507, 1574, 2720, -90, 239, -577, 784, 2899, -1803, 1098, 983, -818, 2646, -5786, 1519, 789, -3360, 1812, -615, 1551, -667, -9003, 940, 404, 1184, -1470, -3667, 193, -742, 497, -1471, -710, -601, -2693, -262, -4084, 478, -929, -1549, -687, -2203, 1135, -674, -381, -561, 895, 1537, -720, -271, -731, 1593, 1380, -1903, -1418, -2215, 596, 488, -5180, -3958, -6036, -2502, -1253, -8537, -4943, -11206, -5160, -4763, -5640, -3247, -5166, -1946, -7933, -5692, -1330, -1766, -398, -2854, -7819, -79, -219, 665, -1759, -10432, 51, -41, 1234, -2617, -5774, -1231, -1204, 1088, -5262, -3406, -5013, -4180, 88, -4682, -2510, -7221, -6368, -1986, -2630, -2390, -4973, -4483, -5984, -1756, -2469, -4899, -4610, -6454, -1856, -2687, -3228, -6005, -3629, -3222, -3783, -2565, -6734, -2752, -7600, -6444, -3639, -5262, -2601, -7169, -2645, -4663, -2591, -2349, -4601, -60, -3248, -847, -1804, -5712, 1000, -2539, -362, -1421, -7959, 1097, -3055, -943, -1731, -5327, 408, -4410, -1942, -2930, -5813, -1139, -4321, -2170, -3867, -7668, -4112, -3678, -1571, -3272, -4025, -6533, -4260, -973, -2701, -2626, -3591, -6282, -1033, -2514, -2780, -2551, -9603, -1826, -2444, -3987, -2360, -8058, -2500, -2464, -5667, -2311, -6635, -2500, -3015, -6611, -2884, -7232, -2174, -4393, -6850, -3689, -11287, -1442, -5914, -7380, -1876, -8607, -1157, -5547, -5864, -537, -7727, -2009, -4643, -3494, -603, -8298, -4132, -4745, -2530, -1954, -3908, -5005, -6482, -3294, -4320, -2201, -3564, -8216, -7161, -5690, -2257, -2733, -6127, -9394, -4781, -2998, -2583, -3481, -7349, 5426, 7847, 9313, 7297, 4636, 5085, 7058, 8906, 6891, 6119, 4043, 4658, 7771, 5909, 7459, 2156, 2417, 6234, 5217, 7788, -1435, 1624, 5049, 5095, 7408, -7233, -3838, 4569, 4327, 6644, -901, -94, 3901, 1247, 5628, 546, 2292, 3526, -2961, 4485, 1089, 2669, 4078, 1769, 4119, 257, 2406, 3876, 672, 4579, -46, 2191, 2664, 96, 5252, 4383, 2794, 2833, 4355, 5809, 6437, 3970, 3823, 5731, 5659, 6971, 4748, 3719, 5315, 4453, 6348, 4851, 2532, 2791, 2260, 4618, 4379, 1086, -8967, 813, 1747, 3504, 474, 1170, 1665, 656, 2502, -629, 2487, 2435, 1586, 1424, -1338, 2665, 2198, 903, -639, 1323, 2723, 670, -3224, -1740, 2583, 2562, -3183, -2303, 757, 2232, 1425, -3889, 1318, 1349, 528, -629, -666, 2355, 216, -310, 590, -34, 2543, -2223, 1015, 1222, -286, 2181, -3519, 1729, -234, -448, 874, -4004, 1344, -1421, -769, -2573, -5363, -1150, -254, -1731, -6367, -5754, -2257, -787, -1895, -884, -4020, 1781, -3247, -481, 896, -1826, 2605, -3712, -117, 1559, -668, 1196, -2059, -1999, 1519, -1375, -2616, -1751, -10551, 1487, -6260, -456, -2258, -1066, 1966, -3019, 589, -2636, 819, 2356, -1004, 39, -3487, 1438, 2445, -993, -1235, -4447, 1845, 2441, -462, -2703, -3742, 2280, 2201, 496, -1995, -2080, 2322, 1166, 981, -201, 444, 1756, -1499, 868, 431, 1756, 806, -3667, -112, -238, 1637, -78, -1968, -1412, -2136, 109, -646, -3260, -733, -5007, -2825, -1485, -9342, 109, -10058, -5639, -4041, -4338, 254, -9527, -5977, -12869, -2969, 285, -5502, -5068, -4607, -1379, 469, -3507, -3972, -3367, -219, 405, -2348, -2465, -3265, -347, -173, -1863, -1051, -3589, -1807, -931, -1612, -414, -4401, -4781, -861, -1242, -673, -5615, -13421, -194, -944, -1880, -6549, -7062, 327, -1004, -4253, -7672, -4454, 748, -1496, -5510, -13924, -3132, 923, -2578, -3646, -7889, -2116, 404, -5211, -3170, -5116, -1094, -1253, -7590, -3962, -4729, -190, -4422, -3925, -4724, -5366, 176, -4380, -3646, -4135, -5588, -196, -2938, -6095, -2935, -4876, -1312, -2734, -8116, -2162, -4472, -3171, -3102, -10162, -2307, -5976, -5890, -3760, -5903, -3491, -9974, -7713, -4368, -1577, -6112, -5954, -5608, -3784, 30, -7232, -4160, -3885, -2656, 375, -4147, -1974, -3448, -2591, -104, -2696, -669, -4437, -3507, -1342, -2292, -787, -6889, -3156, -3878, -2933, -2172, -8951, -2564, -14786, -4893, -3482, -6806, -3435, -5097, -4805, -2796, -4327, -5656, -3335, -3204, -1890, -3247, -6490, -4428, -3529, -1462, -2997, -4216, -10286, -6461, -1467, -2295, -3052, -2273, -15047, -1709, -1113, -4487, -3, -7242, -1887, -336, -7340, 491, -3356, -2034, -380, -1820, -228, -857, -2469, -1405, -209, -1899, 295, -2879, 9652, 7124, -6527, 7067, 8584, 9372, 7627, 4321, 7288, 8635, 8507, 8128, 6618, 7542, 8691, 6993, 7912, 7318, 7372, 8450, 5156, 7030, 7061, 6655, 7534, 4824, 5754, 6076, 5354, 5562, 5020, 4152, 4597, 3849, 2168, 3748, 1157, 3080, 3905, -862, -888, -4556, 1962, 4386, 440, 1776, 1834, -482, 3628, 2068, 4814, 2591, -2346, 2446, 1044, 6083, 3325, 3300, 3420, -8072, 6245, 4934, 4483, 3509, 1315, 5062, 5033, 2977, 2414, 1922, 1231, 2650, -7803, 3735, 4001, -994, -396, 3097, 4750, 6221, 2117, 3058, 4447, 4182, 6836, 1332, 3289, 3808, 2267, 6175, -2967, 1953, 2041, -705, 4531, -3984, 268, 555, -6472, 2323, -252, -245, 1111, -3071, 1547, 589, 90, 2149, 168, 2513, -158, -521, 2545, 1469, 3099, -3443, -3551, 2239, 1852, 3305, -5347, -5659, 1439, 1681, 3407, -1643, -2718, 664, 1044, 3140, -836, -3775, 451, -421, 1750, -909, -8705, 356, -2317, -2939, -1755, -3895, 55, 313, -1306, -2954, -3244, 290, 2307, 1473, -2253, -2582, 1121, 2993, 1894, -1241, -812, 1586, 2776, 1418, -694, -196, 1431, 1897, 301, -354, -91, 871, 447, -2935, -300, 497, 132, -1759, -1713, -692, 664, -1077, -5634, 1413, -1322, -130, -2534, -9987, 2011, -1774, -1518, 21, -4793, 692, -783, -4924, 2058, -2960, -3722, 1082, -4365, 2653, -2402, -2916, 1796, -616, 2184, -3321, -672, 892, -837, 1125, -5352, -197, -2158, -4373, -104, -2044, -116, -4696, -799, -1885, 108, -455, -3788, 609, -3943, 912, -1172, -5821, -365, -3853, 922, -1494, -10726, -3632, -4144, 351, -1992, -13746, -7281, -6012, -870, -4088, -7003, -8955, -9928, -2215, -10930, -4801, -4130, -9607, -1677, -6667, -4013, -2026, -7841, -1256, -4379, -3478, -2305, -7516, -2244, -2726, -3069, -5169, -7457, -3927, -1566, -3072, -5952, -8071, -4662, -1407, -3683, -3284, -12012, -6466, -2627, -5559, -2466, -8503, -8260, -7049, -12068, -1939, -6263, -5644, -5535, -5532, -1498, -8145, -3326, -1547, -2922, -1460, -8897, -1785, -83, -2035, -1681, -3586, -1615, 262, -2335, -1801, -1720, -3506, 34, -3925, -1776, -1105, -7138, -351, -7320, -2071, -1136, -2049, -1030, -13759, -3510, -1246, -409, -2428, -11366, -7703, -1434, -345, -3435, -6548, -4630, -2223, -1301, -2075, -4725, -2506, -3777, -3015, -810, -3991, -2467, -5095, -5961, -163, -3725, -3751, -5199, -6350, -106, -4025, -4216, -6003, -3078, -822, -4461, -2049, -9318, -1990, -2599, -3994, -206, -8426, -2517, -5395, -3002, 684, -5990, -5066, -4987, -2271, 701, -4272, -9414, -2754, -1898, 125, -2779, -4829, -1562, -1654, -710, -2591, -4261, -1492, -1627, -1909, -3583, -5441, -2417, -2053, -3650, -2863, -2625, -3523, -2894, -4334, -1597, -473, -3340, -4067, -3633, -1699, 232, -2580, -4067, -2308, -3084, -1180, -6092, -4239, -1293, -4354, -36, -2800, -3728, -1102, -5333, 72, -1672, -1911, -1753, -4297, -556, -1852, -986, -3200, -4189, -1704, -2067, -1346, -5424, -6356, -3116, -1528, -2690, -6495, -5987, -3808, -981, -3077, -4233, -4180, -3316, -640, -2510, -2383, -6287, -2277, -429, -2864, -1384, -5192, -1512, -475, -3355, -1349, -966, -1403, -881, -2271, -2630, 389, -1847, -1543, -1237, -4508, 338, -2645, -1930, -979, -2698, -646, -3822, -1645, -1614, -1494, -1975, -5789, -1433, -3747, -1685, -2633, -8070, -1757, -8432, -3345, -3061, -5691, -1998, -3004, -8269, -4698, -4254, -1247, -599, -4812, -2980, -4254, -336, 249, -2421, -411, -4544, -81, -145, -2301, 396, -4487, -860, -1777, -4124, -241, -4998, -3200, -3160, -8355, -2338, -5146, -7469, -2295, -9141, -5032, -3662, -5895, -1874, -5905, -5154, -2514, -5081, -2382, -4328, -6181, -2148, -4711, -4073, -4849, -8862, -2655, -3913, -8250, -4878, -8104, -4369, -3010, -6854, -3375, -5052, -6610, -2190, -4762, -2965, -3345, -5969, -1668, -5101, -3189, -3193, -5337, -1630, -7802, -3245, -4524, -4370, -2125, -8453, -3168, -6898, -3635, -3126, -6650, -3888, -6152, -4153, -4874, -7013, -7049, -4643, -6797, -8176, -7959, -7043, -4792, -14044, -4507, -7943, -3770, -7443, -6466, -1643, -7323, -3277, -7378, -5406, -580, -7269, -4736, -4354, -6025, -960, -8876, -6648, -4096, -7668, -2995, -12681, -3646, -6702, -9556, -6765, -12470, -1753, -6742, -7613, -4703, -9559, -975, -2850, -4852, -3019, -7457, -1062, -1342, -2897, -2641, -6713, -1993, -831, -1659, -2941, -6644, -3833, -972, -1070, -3118, -6411, -6991, -1778, -1119, -3081, -6290, -8705, -2943, -1677, -3203, -7092, -5220, -2945, -2155, -3704, -7188, -3990, -2399, -2346, -4409, -5589, -4399, -2796, -3158, -4166, -5033, -6164, -4740, -5073, -3487, -5275, -8020, -9252, -5519, -3013, -5280, -7049, -6241, -4112, -2602, -5002, -4342, -4485, -3499, -2209, -5353, -2726, -3989, -3586, -1779, -7542, -2447, -3624, -4131, -1538, -10178, -3316, -3414, -4716, -1680, -6510, -4780, -3717, -4943, -1959, -5807, -5592, -4417, -5193, -2187, -6896, -5312, -4970, -5971, -2826, -9528, -4553, -5374, -7619, -4631, -11720, -4032, -6466, -10981, -9776, -9626, -3596, -7883, -7643, -7926, -9450, -3189, -6556, -4514, -5081, -10063, -3555, -5838, -3001, -4330, -5326, -5705, -6934, -2437, -4379, -3222, -13828, -8629, -2534, -4638, -3081, -6308, -7829, -3122, -4884, -4988, -4575, -8347, -4172, -5425, -12266, -3980, -12652, -5641, -6592, -8644, -3517, -9681, -6087, -8262, -6792, -3360, -7437, -5156, -9033, -6179, -3928, -7239, -4846, -7804, -6242, -5451, -7585, -5468, -6124, -7393, -7578, -6948, -6962, -4992, -10180, -8464, -5689, -10150, -5007, -9271, -9298, -5037, -12223, -7211, -6436, -12225, -5674, -6543, -12220, -5783, -11803, -8592, -4992, -5941, -3157, -170, -3957, 419, -2841, -3929, -1142, -4620, -314, -3270, -2281, -2919, -3992, -1859, -5558, -532, -5426, -4294, -4450, -10597, 248, -5391, -4548, -9407, -3583, -35, -3340, -3159, -7880, -1402, -1515, -2693, -2726, -6853, -692, -4796, -3774, -3899, -7827, -1072, -6084, -8339, -5251, -6331, -2497, -3400, -7077, -4072, -4268, -4882, -2502, -4276, -3589, -3245, -7636, -2608, -3600, -4090, -3282, -9546, -3455, -3308, -4841, -4708, -8275, -4656, -2979, -5731, -9120, -5274, -5088, -2714, -6845, -9933, -3065, -4837, -2564, -7328, -5654, -1960, -4820, -2365, -6734, -3859, -2256, -5088, -1539, -5890, -4024, -4679, -4334, -322, -4506, -10133, -2871, -2397, 300, -2445, -3656, -186, -1113, -244, -1247, -620, 543, -552, -2311, -1136, 177, -4, -276, -3337, -1706, -466, -1231, -500, -2301, -2313, -2774, -2075, -2132, -3227, -2650, -6498, -2054, -7939, -3448, -2781, -5073, -1721, -3973, -1305, -3086, -6035, -1765, -1945, -533, -4356, -16899, -2541, -1818, -706, -6369, -5265, -4491, -2578, -1216, -4346, -3699, -10344, -3971, -1983, -3044, -4514, -7241, -6979, -2824, -3433, -10366, -5372, -9833, -3742, -6117, -5688, -5513, -3639, -6728, -9176, -3372, -5632, -1562, -6172, -3954, -3871, -4747, -992, -3247, -2446, -7278, -3462, -1548, -3282, -1876, -5573, -2696, -2417, -4861, -1604, -2894, -2699, -1627, -3137, -1879, -1806, -3529, -636, -1494, -2835, -1315, -5640, -629, -1268, -3994, -1102, -7340, -1609, -2153, -4626, -1179, -3667, -3165, -4117, -4095, -1683, -1811, -4122, -7872, -3229, -2724, -1385, -3690, -10671, -2923, -4360, -2363, -2690, -6183, -3171, -6327, -5682, -2145, -4540, -3834, -6881, -12452, -2398, -4211, -4850, -5589, -7662, -2900, -5063, -5796, -4179, -7179, -2366, -6936, -5940, -3622, -3547, -1541, -6389, -6049, -4282, -2157, -1368, -4364, -7178, -6198, -2702, -2154, -3233, -9029, -6981, -5334, -4461, -2787, -7655, -3614, -9777, -7026, -2835, -5070, -1319, -8361, -4223, -3253, -3094, -448, -9863, -3240, -3538, -2131, -806, -18134, -3532, -2913, -2198, -1992, -9332, -4367, -2200, -3003, -2578, -7431, -5050, -2440, -3693, -2335, -6507, -5188, -4258, -3720, -2648, -5348, -4864, -6207, -3824, -3727, -4056, -4372, -4311, -4385, -5038, -3425, -3762, -4365, -5165, -6263, -3861, -2949, -5523, -5803, -7267, -5535, -2440, -3450, -6491, -6583, -7471, -2905, -2155, -7149, -5838, -7255, -5139, -2232, -6117, -5664, -7448, -9986, -3195, -5670, -6103, -9060, -5480, -4686, -7828, -7515, -11807, -4176, -6412, -10395, -8694, -8353, -4366, -7673, -6264, -7269, -4235, -5007, -7954, -5487, -5539, -2070, -5206, -7984, -5717, -4639, -1338, -5335, -9191, -5433, -4683, -1827, -6415, -13691, -4209, -5045, -3519, -8156, -12743, -3118, -4772, -6756, -6671, -9288, -2765, -4329, -8963, -6039, -8329, -3145, -4475, -6576, -7427, -8702, -3934, -5309, -6314, -5477, -3410, -3167, -66, -2262, -5855, -3498, -5408, -1286, -2858, -5521, -3041, -5328, -4032, -4533, -6361, -2287, -3867, -20243, -4777, -10200, -2155, -2661, -5044, -3543, -9783, -3018, -1798, -4161, -3724, -4886, -4616, -1429, -7303, -5895, -2396, -4869, -1700, -6545, -6492, -949, -3431, -2717, -2493, -2300, -565, -2311, -4681, -1593, -456, -1694, -1798, -8494, -2401, -264, -6883, -1563, -11681, -4056, -1761, -3721, -1230, -5505, -3650, -5053, -947, -821, -2387, -3506, -3741, -358, -624, -405, -3536, -2328, -642, -790, 472, -970, -2018, -1064, -1438, 77, 912, -1657, -583, -2990, -2015, 1734, -664, 340, -4616, -3717, 1779, 565, 722, -2975, -1722, 1200, 1446, 669, -2045, -1682, 17, 1739, 477, -2367, -3931, -1958, 1421, -69, -3265, -7861, -5522, 510, -1234, -3364, -5265, -17262, -914, -2866, -2765, -4489, -7162, -2282, -3834, -2555, -3742, -5362, -3331, -3263, -2447, -3105, -3817, -6616, -3147, -1883, -3630, -2625, -6406, -4667, -1269, -5446, -2050, -2187, -9455, -626, -7359, -1879, -1076, -5427, 148, -6831, -1534, -1283, -2948, 483, -4340, -944, -2099, -2338, -155, -3232, -947, -2821, -3413, -2428, -3920, -2179, -3242, -7184, -12341, -7016, -4100, -3160, -5233, -3558, -14145, -3318, -2490, -3249, -1710, -7597, -2832, -2170, -3325, -1787, -6355, -3936, -2602, -4810, -2898, -5908, -5624, -3795, -8726, -3745, -5841, -3629, -5146, -8145, -4212, -6266, -1858, -3569, -3990, -6194, -5008, -1244, -2718, -2468, -10348, -2920, -1426, -4559, -2215, -7165, -2210, -2518, -10184, -2919, -6182, -3111, -6181, -2783, -4790, -6442, -3864, -3545, -859, -16235, -6619, -1850, -595, -2, -3783, -5489, -641, 56, 310, -930, -3593, -440, -895, -13, -139, -2242, -907, -3589, -963, -691, -2010, -1697, -8947, -1732, -1890, -2865, -1927, -12190, -1474, -2324, -3764, -1104, -6571, -1214, -2128, -3762, -508, -5101, -1675, -1924, -4087, -850, -5613, -2976, -2142, -5175, -2255, -4302, -4548, -3586, -6211, -4518, -3139, -4060, -8390, -5934, -6325, -4610, -2357, -7488, -5683, -6163, -7341, -1213, -4894, -4927, -6371, -2692, -1206, -5002, -3591, -9952, -1444, -3129, -5790, -2942, -8019, -1823, -13260, -5479, -3063, -4223, -3022, -3420, -5042, -3514, -3078, -3803, -1685, -5575, -3754, -3408, -4172, -1592, -8212, -3633, -5294, -4751, -2493, -10080, -3281, -8064, -4468, -4490, -5562, -2984, -6170, -3963, -7899, -4475, -3326, -5320, -4466, -5433, -4894, -5054, -5898, -6387, -3080, -5548, -10698, -6944, -9742, -2464, -5787, -7323, -7028, -11875, -3031, -6788, -4895, -6152, -15868, -3168, -8866, -4532, -5277, -7629, -2080, -10652, -5437, -4903, -5330, -1388, -10577, -7358, -5212, -4795, -1010, -9603, -9015, -6117, -5454, -606, -8182, -9363, -6617, -7009, -517, -6436, -9368, -6261, -6469, -1053, -6020, -8244, -6454, -4848, -2195, 6928, 7161, 7582, 9663, 3009, 6574, 6930, 7288, 8942, 2336, 5736, 5959, 6643, 6362, 551, 4880, 4033, 6077, -2389, 1134, 4115, 3344, 5678, 3457, 2681, 3483, 3649, 5306, 3935, 2660, 2102, 2126, 4541, 2237, 516, -2154, -289, 2802, 3058, -1716, 3671, 2723, 322, 4541, 2205, 5567, 3995, -57, 4703, 3907, 5418, 4148, -1085, 3697, 5001, 3807, 4239, -3546, 1478, 6029, 1668, 4889, 818, -144, 6718, 1282, 5574, 2393, 1204, 6736, 1982, 5516, 2036, 1773, 5835, 1456, 4272, -5, 1474, 3807, -453, 1723, -367, 723, 1272, 1176, 589, 1470, -87, -532, 1951, 1410, 2149, -182, -2145, 820, 1516, 1956, 714, 1835, 1723, 1139, 1227, 1601, 3241, 4201, 697, 407, 1961, 2985, 5495, 625, 86, 1831, 1753, 5665, 644, 258, 1375, 101, 4633, 408, 428, 591, 101, 1964, 73, 586, -1114, 1791, -3599, 341, 1153, -5101, 2327, -3064, 1556, 1648, -5711, 1436, -3218, 2393, 1225, -6239, -1028, -2614, 2159, -112, -3314, -6108, -490, 634, -104, -935, -7254, 1131, -2714, 266, -725, -2490, 2436, -5403, -995, -1625, 141, 3343, -2207, -1860, -1732, 1613, 3657, -1396, -380, -920, 2091, 3269, -2605, -115, -694, 1471, 2147, -8207, -1260, -1161, -634, 487, -5559, -2514, -1353, -5645, -720, -3252, -1475, -1312, -5870, -873, -3397, -1416, -2092, -3917, -921, -4442, -3653, -3683, -3276, -1468, -2817, -6368, -4562, -2547, -2602, -945, -5453, -3824, -2102, -3643, -496, -10197, -3446, -2567, -3957, -1277, -5898, -4932, -4097, -3617, -2940, -3369, -12484, -5700, -3037, -4624, -2317, -5191, -6881, -2797, -4694, -1040, -3485, -9315, -3042, -3857, -200, -3721, -8256, -3425, -3250, -339, -3769, -6949, -3035, -2842, -1585, -1973, -5703, -2145, -2747, -3759, -602, -4099, -1649, -3167, -5274, -249, -3214, -1890, -4350, -6286, -1009, -3009, -3173, -7507, -6186, -3358, -3037, -6044, -9712, -3886, -9717, -2858, -4379, -4317, -3178, -6481, -2575, -1477, -2575, -4203, -5782, -2697, -165, -2142, -5758, -7880, -3698, -55, -2516, -4626, -9078, -6360, -1198, -3214, -4071, -7936, -8296, -3909, -3814, -5051, -7098, -4863, -6324, -4723, -6959, -5957, -3596, -5381, -6863, -5569, -4869, -3771, -5398, -9812, -3639, -3449, -5759, -6330, -7022, -2587, -2509, -9998, -7825, -5322, -2124, -2606, -5872, -7187, -4567, -1959, -3973, -4872, -7178, -4412, -1840, -7693, -6145, -8514, -5065, -1816, -10338, -9791, -6354, -6935, -2090, -5574, -7507, -5249, -10146, -2684, -4477, -6408, -5846, -8380, -3063, -4549, -7633, -7512, -6250, -2611, -4874, -9968, -9417, -5461, -2196, -5033, -10329, -9230, -5494, -2565, -5050, -7495, -7770, -5990, -3404, -4994, -5494, -7295, -6686, -3496, -5244, -5669, -7175, -7101, -3513, -5959, -9259, -6859, -6415, -4417, -6444, -6359, -1981, 7876, 7695, 8495, 8237, -2844, 7481, 7270, 7862, 7545, 1019, 6019, 5665, 6034, 5202, 3039, 2185, 2306, 5340, -953, 3467, -1751, 3379, 6516, -117, 3658, 2522, 4529, 6607, 2003, 4490, 2914, 3987, 5438, 1648, 5270, 2903, 3379, 3369, -873, 5512, 2931, 3175, 1822, -2892, 5008, 2496, 1168, 220, -3019, 3421, 1830, -4198, -2965, -1917, 2406, 1767, 2827, 1174, 509, 4688, 2281, 4282, 2522, -37, 5930, 2738, 4040, 2101, -5544, 6003, 2823, 2793, 766, -3529, 5412, 2160, 1395, -503, -2334, 4763, 194, 657, -1395, -5836, 4156, -4541, -263, -2714, -6537, 2816, -3596, -1707, -728, -2451, -1709, -784, 231, 1996, -855, -251, 214, 1987, 2531, 152, 3082, 342, 2359, 300, 813, 3486, 164, 1775, -2561, 1035, 2136, 271, 621, 2147, 408, -696, 702, -1360, 3150, -1099, -2018, 944, -8521, 3171, 847, -1162, 473, -2446, 3282, 2751, 143, -1128, 31, 3279, 2878, 1415, -2750, 35, 2765, 1139, 2366, 390, -2352, 1736, -3317, 2803, 2860, -7559, 611, -4770, 2225, 4179, -3502, -87, -5472, -484, 4644, -5787, -1006, -3457, -4922, 4405, -4343, -2748, -1305, 943, 3514, -212, -2991, -843, 2521, 2064, 748, -836, -1403, 3056, 516, 233, 886, -1366, 2921, -400, -794, 2005, -3, 1891, -1284, -1647, 2547, 456, -449, -3947, -3161, 2391, -251, -4949, -10357, -2631, 1181, -1484, -7207, -6178, -821, -2308, -2560, -5659, -11313, -580, -5646, -2848, -3473, -2267, -1680, -967, -2630, -2106, 56, -3239, -401, -3008, -2384, 407, -4374, -1663, -3304, -4877, -627, -4487, -4751, -4659, -9247, -2585, -2020, -9640, -8211, -5383, -3012, -327, -11648, -2926, -5704, -2565, 378, -6753, -1507, -7532, -3347, 483, -4807, -2080, -3945, -4303, 264, -4548, -4391, -2012, -3684, -187, -4851, -6521, -1326, -3289, -980, -4349, -5678, -1515, -2131, -2063, -3427, -6038, -2768, -864, -2668, -2829, -7045, -6107, -792, -2995, -2743, -6596, -12351, -2175, -3964, -3177, -5050, -7948, -4977, -3998, -3949, -3822, -7796, -6941, -3381, -4913, -3246, -4481, -7580, -4051, -6255, -3220, -2724, -7102, -5431, -6488, -3589, -2407, -5400, -5885, -4847, -4463, -2929, -4341, -6888, -4257, -6679, -3643, -3892, -5181, -5014, -18357, -3975, -4023, -3273, -6397, -5969, -4322, -4631, -3067, -6547, -3801, -5631, -4851, -4139, -5174, -3317, -8692, -4473, -5120, -3951, -3770, -9338, -4609, -5421, -3673, -4699, -8021, -5558, -6945, -4439, -5838, -9140, -6951, -8590, -6337, -7444, -14789, -8155, -6678, -9408, -9408, -12676, -8249, -5398, -12206, -9098, -11849, -6063, -4893, -14348, -8102, -14796, -3920, -5688, -8043, -8041, -11395, -3023, -9351, -5778, -8808, -9526, -3716, -11085, -4731, -10442, -9287, -7182, -8530, -3985, -15913, -9585, -9185, -10307, -3460, -10567, 6844, 8184, 3420, 5950, 6590, 5716, 7520, 2915, 5650, 5578, 1323, 5655, 1526, 4481, 1420, 2109, 4602, 938, 2294, 15, 4468, 5518, 3231, 2469, 3187, 5793, 5964, 4592, 3694, 3339, 6224, 5655, 4528, 4454, 2352, 5057, 4221, 3430, 5324, 971, 1833, -301, 2190, 5579, 373, 2644, 850, 1098, 4721, 980, 4056, 3616, -1585, 2925, 537, 4012, 4156, -3087, 1117, -3988, 3210, 4093, 1451, -2670, -2487, 1519, 3634, 2380, -613, -810, -2387, 2590, 568, 2761, -6471, -488, 1010, -5312, 3534, 340, 1823, -1565, 1888, 3010, 3257, 1775, -3382, 3422, 2002, 4252, -685, -951, 3397, 1173, 4308, -3154, 168, 2609, -479, 3921, 1052, 588, 1830, -3238, 3553, 2378, 610, 1794, -208, 3373, 2364, 113, 2254, 1288, 3176, 1322, -1241, 2383, 1270, 2722, -950, -4485, 1628, 102, 1826, -5666, -8227, -513, -1899, 410, -4133, -3782, -6552, -905, -1388, -2513, -747, -3604, 1420, -3010, -3860, 972, -216, 2714, -628, -2463, 1139, 963, 3132, 1691, 105, 357, 731, 2731, 2376, 650, 659, -968, 1401, 1577, -86, 1151, -5024, -280, -273, -1284, 615, -7242, 329, -1523, -2322, -285, -1319, 1239, -3131, -4030, -1557, 1273, 1204, -2623, -4930, -4765, 2533, 382, 31, -3846, -2702, 2810, -1149, 1031, -2436, -2306, 2244, -3404, 1046, 817, -8994, 1047, -4395, 638, 2113, -1506, 182, -2293, 232, 1249, 408, 245, -443, 303, -2615, -457, 2, 388, 1146, -1225, -3270, -964, 114, 1823, 69, -1130, -1849, -1146, 1661, -1202, -555, -1365, -2727, 687, -4664, -2784, -860, -4224, -719, -8293, -6623, -1237, -5927, -2521, -5505, -3504, -1674, -4074, -4433, -3443, -3662, -1029, -1584, -4872, -3436, -5480, -604, 87, -4061, -6831, -6373, -954, 895, -2930, -4665, -5970, -1481, 869, -3005, -1678, -6194, -1725, 102, -4007, -1213, -7330, -2515, -1336, -4220, -2492, -4365, -4748, -3634, -3468, -6231, -2036, -8618, -7015, -2416, -10932, -1345, -8476, -5322, -2055, -7350, -2131, -10709, -3277, -3007, -7164, -4938, -10398, -2347, -5087, -6032, -11826, -6451, -1985, -5375, -5476, -6386, -5870, -1782, -5321, -6190, -5095, -7148, -1297, -6906, -7337, -4828, -9918, -793, -7903, -6343, -5432, -7696, -862, -6090, -4809, -7046, -5531, -1731, -4551, -4415, -5858, -5221, -3339, -4088, -5435, -4033, -6463, -4688, -4882, -8282, -4049, -8560, -3891, -6749, -9165, -6707, -8658, -2887, -8564, -7138, -10402, -6502, -2670, -9858, -6370, -4903, -4838, -3343, -10015, -6338, -3947, -4444, -5240, -7141, -7775, -4739, -5188, -6116, -4346, -12681, -6528, -6728, -3824, -2500, -6372, -8095, -9228, -2730, -1680, -4190, -7241, -11071, -2502, -1914, -3767, -4542, -8579, -2851, -3341, -4537, -3365, -7100, -4257, -5807, -6160, -3938, -6677, -8386, -5363, -6487, -5417, -4831, -5399, -3595, -6606, -5220, -4098, -3955, -2996, -6791, -5518, -4339, -2958, -3813, -5029, -4855, -6573, -2456, -5830, -3627, -3990, -10242, -2583, -6572, -3503, -3955, -5694, -3498, -5733, -4531, -4720, -4080, -4973, -6642, -6336, -5565, -3660, -5397, -11244, -7572, -5403, -3796, -4399, -9624, -6943, -4976, -4501, -3341, -7751, -6284, -4998, -6524, -2623, -7953, -6400, -5125, -13720, -2499, -7962, -6581, -4922, -9675, -3201, -6947, -6428, -4554, -8044, -5125, -5239, -7512, -4496, -6154, -8552, -3600, -12902, -5097, -3938, -6733, -2506, -12785, -7219, -2296, -6245, -2448, -8098, -6875, -793, -7453, -4342, -2270, -1398, 579, -2516, -2953, 237, 929, 1489, 27, 266, 986, 1584, 1656, 936, 1345, 322, 829, 893, 681, 786, -1675, -1400, -934, -484, -1650, -4605, -5233, -3661, -2148, -8273, -7098, -7983, -5542, -3463, -6495, -9317, -6325, -6176, -3798, -6445, -10349, -4891, -7107, -3570, -7094, -11108, -4375, -7870, -3322, -4857, -10823, -4363, -8390, -3422, -3691, -7608, -4723, -10417, -4252, -3535, -5257, -5565, -11499, -5773, -3891, -4566, -6740, -9103, -6320, -4558, -5707, -7907, -7989, -6022, -5807, -10570, -8858, -6677, -6372, -7130, -8773, -8440, -6381, -6672, -7034, -6078, -8636, -9076, -6136, -7177, -5651, -8736, -9553, -5450, -7590, -6840, -7336, -5381, -5011, -6630, -14294, -7488, -4801, -4871, -5848, -6136, -10098, -6286, -5008, -6046, -3235, -11529, -8986, -5317, -6412, -2186, -7462, -8587, -5614, -5608, -2127, -5546, -5993, -5602, -4895, -2768, -4953, -3879, -5369, -5200, -4091, -5580, -3164, -5477, -6772, -6470, -7886, -3903, -6183, -9649, -11308, -9200, -6437, -7719, -8945, -10678, -6182, -9302, -11853, -7614, -9572, -5189, -7009, -10482, -7855, -10849, -5754, -6670, -7654, -7960, -10133, -8021, -8450, -7492, -6982, -9424, -10234, -15495, -8411, -6733, -10228, -7509, -11577, -8767, -7567, -9477, -6263, -9487, -9857, -8789, -7763, -6036, -8615, -16894, -9219, -6594, -6453, -7945, -10252, -9583, -5649, -7061, -7302, -7813, -10419, -4963, -7236, -6595, -7004, -10903, -4924, -7947, -6179, -6655, -10453, -5878, -10923, -6142, -6372, -9527, -7202, -14480, -6401, -6149, -9032, -6310, -9481, -6657, -5984, -9602, -5378, -7495, -6427, -5769, -9697, -5650, -6850, -6403, -5592, -7339, -7131, -7150, -7731, -5749, -5664, -8298, -6849, -11449, -6429, -4910, -7086, -6298, -10534, -7720, -4908, -6514, -6999, -10839, -9769, -5924, -6860, -9561, -13612, -11400, -9204, -6920, -14357, -8162, -11150, -11068, -6493, -12766, -6878, -13047, -6942, -6884, -9274, -7453, -15660, -5989, -8558, -7535, -9432, -9547, -6401, -9898, -7434, -14187, -7718, -7893, -9707, -8867, -13166, -7538, -10498, -11141, -10755, -9815, -8900, -12875, -16967, -9262, -9781, -12291, -11937, -15404, -8060, -13327, -13354, -9920, -12630, -7888, -12745, -11948, -8216, -10002, -7989, -8788, -11573, -7404, -9210, -6686, -15004, -3289, -6328, -7919, -10176, -10887, -3489, -4414, -6566, -8259, -9697, -4196, -4142, -5503, -5290, -11864, -5981, -5954, -4598, -5677, -11430, -11060, -14555, -3737, -8789, -6780, -7117, -8086, -3108, -8413, -5414, -4226, -8755, -3056, -6295, -5370, -2921, -10658, -3642, -5938, -5817, -2362, -5959, -4464, -6230, -6351, -2305, -4802, -5318, -5661, -7355, -2605, -4648, -6030, -4788, -8877, -3153, -4318, -5904, -4916, -9187, -3968, -3807, -6158, -6283, -7416, -4581, -3478, -7312, -8938, -5776, -4128, -3614, -8987, -8870, -4994, -3576, -4325, -11480, -8343, -4380, -3152, -4685, -5002, -9948, -2766, -2348, -3502, -1091, -2435, -586, -914, -1095, 924, 162, 874, 420, 766, 1496, 868, 1184, 908, 1411, 666, 95, 131, 390, 762, -1920, -2085, -2922, -845, -1280, -7756, -4454, -16110, -1966, -4698, -6715, -3873, -5983, -2930, -5724, -6404, -2975, -5321, -4831, -4148, -8149, -2771, -6242, -8405, -2985, -11642, -3082, -7557, -10505, -2280, -10096, -3383, -5472, -15643, -2315, -5910, -3512, -4542, -9302, -3544, -4161, -4119, -5871, -6931, -7014, -3807, -6345, -9365, -7016, -10307, -4311, -9961, -7929, -7821, -5691, -5163, -6055, -8191, -8082, -4467, -6171, -4793, -9507, -9009, -4679, -7184, -4796, -7642, -11541, -6390, -7723, -5518, -7267, -10546, -7902, -8212, -6977, -8316, -7941, -5667, -8984, -8527, -8988, -6911, -4411, -8643, -6370, -8980, -7105, -3989, -8007, -4233, -8228, -7891, -4022, -8794, -3315, -6300, -7934, -4546, -11341, -3481, -5193, -7635, -5755, -12427, -4738, -5205, -8025, -8019, -10792, -7259, -5891, -8796, -13258, -7564, -11530, -6159, -9580, -11920, -5757, -17389, -5882, -11718, -8114, -5523, -15594, -6008, -10143, -6180, -6780, -17090, -6855, -7510, -5038, -8817, -11814, -7704, -6483, -4638, -7888, -8637, -7401, -6001, -5064, -6890, -6993, -7147, -5609, -6385, -7082, -6207, -7481, -5691, -7961, -8353, -5988, -7837, -6738, -7876, -11189, -5943, -7604, -9331, -7787, -19199, -5825, -7175, -12307, -8505, -11676, -5962, -6404, -9173, -8273, -9909, -6757, -5111, -8220, -8439, -9529, -8310, -4397, -8781, -9601, -10027, -9518, -4853, -9488, -6396, -11585, -8235, -6822, -10060, -4537, -9577, -6889, -10416, -8115, -4244, -7183, -6916, -8712, -5559, -5065, -6404, -7819, -6786, -4732, -6745, -6723, -6229, -6014, -5754, -8068, -7727, -4706, -6080, -9574, -6889, -9382, -4416, -6628, -7227, -5957, -10909, -4928, -6618, -5124, -6000, -10310, -5733, -5841, -5155, -6098, -9824, -6774, -5344, -7076, -5466, -9382, -8830, -5583, -13008, -5116, -9364, -14598, -6627, -10457, -5703, -10925, -13134, -7897, -9338, -7078, -17766, -11047, -8228, -10926, -7312, -12329, -10043, -8854, -14096, -6377, -9246, -8903, -12360, -12308, -6179, -7824, -7904, -11876, -9138, -6918, -7406, -6685, -7622, -7962, -8100, -8250, -5658, -6581, -8677, -8669, -11653, -5213, -7600, -11726, -9502, -6275, -7459, -7000, -6470, -3903, -4611, -8854, -5266, -3553, -3567, -3870, -4951, -3609, -2416, -4242, -4366, -4804, -3320, -2270, -5967, -6275, -6972, -4166, -3256, -8507, -10171, -12115, -5676, -6261, -8439, -11299, -12043, -7006, -8492, -5927, -10517, -10697, -7794, -4872, -3723, -11855, -6608, -8993, -3744, -2358, -13710, -4703, -11678, -3516, -1921, -10297, -4260, -14057, -3549, -2336, -7447, -5051, -12593, -3527, -3366, -6283, -7371, -9834, -3390, -4634, -6581, -9859, -7409, -3297, -5936, -8880, -6768, -5974, -3285, -6690, -13443, -5505, -5455, -2978, -6634, -11797, -7806, -6402, -2254, -6693, -7806, -5050, -6959, -1229, -6141, -2174, -264, -2380, 89, -2592, 260, 1781, 74, 1016, -20, 921, 2414, 1007, 941, 1072, 9, 1957, 705, -553, 924, -2636, 564, -799, -4597, -202, -5387, -1546, -3587, -7025, -1771, -6066, -3644, -7205, -3911, -3331, -9450, -4568, -8048, -3349, -4854, -7175, -5245, -7936, -3646, -6327, -6008, -6570, -8861, -4621, -11767, -7183, -7459, -9946, -5893, -6739, -11369, -7622, -9559, -5931, -3608, -13936, -8468, -8911, -4742, -2750, -10183, -10097, -8682, -4374, -2987, -9181, -8548, -8794, -5678, -3069, -8990, -5410, -10167, -9059, -2481, -10011, -3681, -11519, -7713, -2240, -12961, -3158, -7402, -7225, -2629, -14315, -3664, -4975, -8061, -3591, -8715, -5158, -3513, -6182, -5211, -6693, -7881, -2674, -4835, -7763, -6634, -13779, -2476, -4538, -10107, -9065, -12637, -3083, -4685, -6531, -13953, -9700, -4730, -4943, -4833, -7463, -8389, -7154, -5426, -5212, -5979, -7985, -7362, -6888, -8907, -5809, -8836, -7039, -10232, -9569, -6110, -10164, -7723, -6606, -5848, -6181, -8551, -9132, -4796, -5085, -5711, -7127, -12411, -5076, -5321, -5106, -7060, -8607, -7079, -7071, -4767, -8634, -5752, -7579, -8468, -4796, -9544, -5016, -6526, -4435, -5263, -7770, -5677, -6851, -2722, -6394, -7830, -5973, -6828, -2351, -7826, -8200, -4993, -5965, -2867, -7129, -6373, -4708, -5973, -3666, -6375, -5292, -5314, -6838, -3734, -7316, -5384, -6269, -7531, -3386, -10330, -6284, -7143, -7886, -3446, -9316, -7264, -8282, -7969, -3961, -8354, -7454, -9326, -7048, -4575, -9967, -6846, -9308, -6015, -5682, -12094, -6182, -9574, -5562, -8455, -10098, -6251, -8823, -5788, -7933, -10115, -7438, -7179, -5798, -6256, -12729, -9670, -6641, -4424, -6670, -16869, -11702, -7349, -3136, -8626, -11379, -12571, -8894, -2706, -10776, -9858, -12632, -10360, -3202, -9852, -9656, -14351, -11892, -4516, -8120, -10112, -9196, -14718, -6029, -7326, -11073, -6167, -20010, -7015, -7571, -13288, -4933, -16628, -8164, -8158, -15866, -4808, -13887, -8859, -8671, -13006, -5320, -12181, -7866, -10275, -11071, -5975, -11702, -6915, -13457, -9700, -6806, -12271, -6528, -11149, -8831, -8396, -13721, -6934, -8250, -8454, -9442, -13972, -9042, -6740, -8719, -7705, -11615, -17335, -6696, -9993, -6648, -9134, -8087, -7929, 11499, 9653, 11787, 11865, 10918, 10750, 9748, 11068, 11240, 10364, 8109, 9531, 8698, 9336, 8658, -392, 8420, 3495, 6224, 6048, 4468, 6188, -2829, 2992, 4944, 4836, 2886, -1034, 852, 4834, 3423, -314, 929, -354, 3400, 2873, -1496, 1653, 65, -323, 689, -2183, 2935, 767, -6658, -226, -1673, 3889, 816, -6654, 5189, 544, 3523, 1694, 727, 7001, 1280, 3374, 3183, 4394, 7543, 2819, 4609, 4414, 6201, 7338, 5335, 5343, 5008, 6784, 6524, 6594, 5248, 4727, 6186, 4964, 6532, 4685, 3373, 4034, 2635, 5338, 4042, 439, -1698, 1519, 3675, 3143, -3463, -868, 1737, 2813, 1237, 612, 987, 1363, 2305, -3363, 2166, 1556, 1643, 2080, -5536, 2433, 1979, 2425, 2309, -3356, 2424, 956, 2375, 2323, -5877, 2676, -9137, 1643, 1847, -2948, 2781, 1636, 1445, 565, -278, 2290, 4161, 1827, -51, 118, 1184, 4603, 2057, 2119, -766, 999, 3517, 1918, 3192, -1961, 1741, 351, 1084, 2772, -5075, 1823, -9009, -3, 1315, -3513, 1715, -3156, 754, 666, -1, 2060, -6758, 1223, 3, 894, 2448, -4417, -629, -2904, 789, 2644, -1501, -4193, -1362, 779, 2463, -342, 741, -280, 657, 1614, 444, 1940, -2432, -386, 302, 300, 1661, -5600, -2648, -116, -1426, 728, -517, -5816, 42, -8691, -478, 1020, -5590, -492, -2680, -2624, 1193, -3778, -1788, 222, -9612, 248, -3523, -2310, 1328, -4828, -1791, -4731, -1546, 1500, -3774, -4803, -6916, -1462, 950, -6641, -4848, -8218, -1770, 222, -7771, -1963, -6686, -921, 557, -3923, -756, -4622, 123, 1229, -2846, -872, -3909, 554, 1169, -2433, -1846, -5745, 413, 243, -2080, -2755, -6614, -278, -1394, -1921, -2331, -1802, -1389, -2957, -2013, -1209, -272, -2419, -2893, -1213, -627, -236, -2201, -2356, -14, -707, -987, -752, -2093, 439, -940, -1989, 234, -1770, 82, -885, -3121, 317, -1690, -747, -680, -4513, -297, -2330, -1287, -546, -7327, -631, -3621, -1505, -658, -4254, -147, -4817, -2767, -1298, -1704, 213, -5047, -6312, -2616, -1171, 99, -4591, -4520, -3856, -2233, -602, -4570, -3047, -4603, -5501, -2062, -4365, -3248, -5468, -13943, -3893, -2743, -3891, -4549, -8014, -5236, -1218, -3439, -4507, -10182, -5271, -339, -2017, -6499, -6396, -3095, 51, -1278, -5234, -4433, -1926, 180, -1582, -4112, -5251, -1997, 117, -3012, -4723, -5486, -2358, -140, -6067, -5077, -2875, -2262, -540, -4332, -4377, -2761, -2777, -1175, -1347, -4245, -6137, -3431, -2252, 198, -5646, -2423, -1844, -3110, 896, -10059, 0, -490, -2063, 662, -7959, 293, -39, -1037, -1028, -5465, -943, -84, -1061, -5569, -3676, -3524, -278, -2353, -4143, -3071, -6214, -1188, -5856, -2726, -4220, -11237, -4123, -9832, -3171, -6078, -4947, -2949, -10897, 1986, 7534, 7994, 8395, 5655, 1586, 6803, 7469, 7696, 4993, 986, 4683, 6042, 5302, 3663, 1176, 4020, 4165, -290, 3540, 1354, 5071, 1972, 1624, 3711, 1165, 4944, -498, 2650, 3436, 1305, 3929, -780, 2245, 3125, 2022, 2784, 1021, 1914, 2896, 2842, 2606, 2544, 1909, 2503, 3458, 2577, 3509, 1162, 2278, 4319, 2777, 4320, -1679, 3341, 5631, 4337, 5485, 591, 4894, 6571, 5188, 6487, 2665, 5846, 6695, 4848, 6546, 2448, 6016, 6031, 3962, 5257, 374, 5518, 4941, 3891, 1946, -1263, 4519, 4092, 3892, -9767, -732, 3047, 3742, 2274, -3403, 28, 1256, 3246, -4496, -6805, 1456, 9, 2179, -172, -5004, 2240, -1027, 1634, -109, -3777, 2227, -2661, 1529, -2955, -4061, 1781, -4333, -54, 227, -4123, 1286, -2738, -3606, 548, -7285, 702, 202, -2746, -36, -1668, -116, 2048, -502, 1178, -760, 320, 3206, 1792, 1855, -4693, 1439, 3944, 3000, 1660, -2152, 1418, 4259, 3060, 927, -29, -23, 4053, 2125, -517, -1139, -1610, 3269, 301, -1313, -3676, -661, 1878, -2420, 858, -3865, 454, -397, -6488, 1913, -3258, 1317, -4907, -6205, 1205, -992, 1933, -2414, -2780, -2487, 70, 2028, 163, -680, -3970, 142, 1003, 843, 334, -195, -40, -3085, 301, 112, -43, -188, -1548, -1011, -1459, -1898, -666, 1611, -2204, -1343, -6526, -1699, 2298, -2599, 591, -7144, -2901, 1715, -1844, 1237, -4046, -3598, 179, -140, 759, -2406, -3075, -2445, 1180, -335, -1952, -1899, -5612, 1415, -1094, -2214, -1360, -1893, 203, -1459, -1069, -1757, 481, -3330, -2097, 752, -2767, 1624, -7473, -1792, 1782, -2900, 1889, -7712, -101, 1912, -2068, 1430, -5585, 1149, 1283, -1498, 397, -866, 1524, 568, -963, -1106, 495, 954, 497, -188, -3461, -19, -412, 139, 324, -10632, -2949, -900, -1303, -35, -4678, -7384, -163, -3549, -1866, -2417, -2039, -90, -4801, -7138, -2238, -767, -899, -3789, -5957, -2726, -570, -2445, -1632, -2991, -2995, -898, -4903, -717, -1806, -1742, -1512, -8493, -1379, -1798, 585, -1549, -5539, -3625, -3504, 1770, -763, -3517, -3105, -8456, 1591, -119, -3114, -1345, -7055, 92, -21, -4398, -782, -9520, -2433, -808, -6538, -902, -6864, -4298, -3229, -2854, -1191, -3592, -3995, -7376, -1294, -667, -3069, -3510, -3439, -1592, -26, -2002, -4369, -1857, -2227, -397, -443, -3309, -1476, -1091, -2056, 221, -1094, -2369, -668, -4218, -5, -716, -6260, -1626, -3114, -970, -2628, -5218, -2561, -1129, -2134, -2523, -2555, -2529, 148, -2205, 324, -2183, -3484, 433, -2391, 994, -2104, -4388, -687, -4433, -147, -1845, -2974, -4487, -13025, -4452, -1215, -1607, -5702, -5079, -4621, -8, -769, -2473, -2682, -1284, 552, -657, -1852, -1952, -775, -338, 3403, 4132, 7641, 778, 5289, 2552, 4145, 7421, 2383, 6068, 4670, 4212, 7130, 4931, 6997, 6328, 4373, 6985, 5898, 7176, 6003, 4155, 6359, 5214, 6490, 3584, 2785, 4682, 2921, 4968, -3986, -778, 1301, -742, 3260, -539, -3989, -6344, -2274, 2502, -875, -1955, -2882, -434, 1798, -3591, -1851, -1994, 1043, 958, 3027, -70, 38, 2360, 1125, 5424, 2700, 1757, 2968, 1329, 6100, 4469, 1807, 2654, 1037, 5305, 4858, -175, 2820, 2749, 2728, 3599, 755, 3658, 4815, -3318, 76, 2620, 3579, 5670, -6116, 599, 2350, 2258, 5308, -2952, 1593, -76, 344, 3740, -1295, 197, -7631, -293, 1431, -414, -2083, -4705, -32, 454, 1193, -1037, -2916, 140, -87, 2307, -23, -1998, -320, -18, 2491, 240, -1222, -2065, 924, 1975, -38, -567, -6414, 1177, 977, -812, -86, -2158, 1569, -272, -2074, 62, 217, 2576, -712, -3867, -198, 1022, 2926, -117, -3578, -924, 905, 2160, -125, -1289, -2054, 12, 982, -1563, -215, -2503, -1765, 993, -6099, -47, -1659, -4728, 1308, -6373, -203, -670, -5335, 1637, -2661, -739, 229, -3261, 1850, -1322, -2303, 947, -1527, 1748, -928, -5554, 1239, 616, 2135, -1827, -11079, 834, 2152, 2999, -5832, -6189, -473, 2630, 3320, -3403, -2728, -1400, 2094, 2477, -572, -1483, -13, 1139, -474, 25, -1786, 1043, 931, -2991, -845, -3318, 1407, 776, 1042, -2630, -4489, 1405, -256, 2424, -987, -2810, 1333, -2287, 2747, 512, -1553, 1549, -5824, 2282, 279, -2049, 1871, -3869, 900, -1724, -5113, 1702, -1201, -1600, -2784, -3388, 568, -172, -2220, -895, -1663, -2290, 292, -362, -418, -2568, -9930, 580, 503, -1227, -7070, -2603, 429, 437, -2729, -5947, -436, -295, -560, -2611, -3597, 571, -1311, -2955, -1634, -2500, 779, -2367, -6798, -1580, -1228, 83, -3626, -2730, -1961, -159, -1607, -4533, -689, -1789, 222, -2814, -4019, 358, -1588, -452, -1013, -4088, 995, -2319, -2726, 767, -6820, 974, -4507, -8398, 1631, -11130, -303, -2578, -6953, 1518, -6724, -3262, -327, -6716, 421, -8780, -1524, 193, -8230, -1594, -5833, 225, -690, -4076, -3241, -2524, 550, -3379, -1911, -2869, -975, 320, -6486, -1262, -3444, -392, -71, -2338, -1737, -7273, -902, -761, -805, -3112, -5322, -3132, -1739, -753, -4756, -3052, -3407, -2524, -1795, -7989, -2173, -957, -2388, -3114, -6050, -1001, -97, -1763, -3563, -1277, -227, -19, -1780, -4053, 280, -333, -629, -3246, -5652, -96, -1690, -2562, -4260, -11515, -3068, -6057, -6844, -1570, -6403, -7864, -5955, -5304, -902, -3614, -3309, -3410, -4326, -2882, -2501, -2023, -1490, -3336, -7164, -1740, -36, 312, -1321, -2026, -1151, 996, 668, -883, -890, -1372, 643, -586, -3064, -910, -3402, -4482, -2190, -1270, -4262, -3070, -4590, -2040, -2520, -946, -3274, -9669, -4249, -9697, -56, -3661, -5978, -4859, -3848, -493, -3439, -3542, -2771, -1509, -504, -3120, -3970, -2516, -560, 163, -2938, -6862, -2398, -958, 411, -2723, -11590, -1025, -3975, 1108, -3014, -6531, 310, -5335, 1975, -3553, -4511, 957, -1340, 1873, -3638, -4597, 887, -704, 258, -5787, -7724, 248, -1979, -4020, -5723, -4889, -576, -6030, -5557, -1752, -1896, -1048, -5583, -3021, -961, -879, -994, -2977, -1828, -2324, -1161, -756, -2567, -894, -8329, -3006, -890, -3048, -336, -2419, -12398, -1434, -2230, 342, 771, -2734, -174, 527, 1344, 2390, -223, 1634, 2317, 2073, 3055, 210, 2246, 2721, 1891, 2870, -912, 1627, 1673, 245, 1928, -3573, -115, -1050, -3564, 507, -6432, -3262, -4038, -2351, -1054, -6372, -8754, -4753, -938, -2769, -7193, -2761, -4473, -1032, -3845, -10328, -1095, -2632, -1692, -3653, -2631, -1126, -2259, -2446, -3893, -256, -2771, -3310, -2791, -4961, 361, -8126, -5707, -2611, -5749, -245, -7360, -6102, -2940, -5490, -1830, -6736, -4501, -4546, -5568, -4055, -6866, -4259, -6523, -5735, -6537, -2456, -3944, -4694, -5152, -6281, -791, -2729, -3326, -5147, -4384, -636, -1952, -3614, -6397, -3150, -1511, -1616, -7073, -4951, -2081, -2980, -1332, -7338, -2755, -1670, -4406, -1259, -3640, -1452, -2662, -5710, -1451, -3615, -261, -5548, -7769, -1585, -5654, 706, -3476, -12844, -1737, -4974, 1109, -1569, -10018, -2414, -4155, 931, -1372, -8834, -4007, -7511, 348, -2417, -19835, -6770, -5193, -391, -4759, -5253, -7132, -1173, -1144, -7689, -1769, -4823, 228, -1928, -6624, -170, -3580, 522, -2723, -5276, 133, -3197, 312, -3832, -5133, -786, -3275, 86, -6741, -5275, -2979, -3246, -15, -9085, -3240, -6076, -2781, -346, -4076, -2116, -6898, -1822, -1476, -2444, -2481, -5099, -863, -3556, -1673, -3676, -3843, -402, -3266, -1569, -4468, -2131, -551, -2215, -3039, -4968, -340, -1284, -2389, -8551, -5841, 652, -2084, -3633, -3304, -6153, 803, -1768, -9006, -1361, -4735, 202, -833, -4478, -1044, -3627, -1151, -16, -1493, -1415, -3147, -3442, 294, -1194, -2076, -3305, -6063, -281, -2926, -2664, -4702, -3915, -1898, -6565, -2405, -6927, -2282, -3991, -4178, -1692, -5166, -2072, -5567, -3102, -1571, -4346, -2848, -8095, -4080, -2244, -5297, -3728, -11771, -6981, -3029, -8705, -3791, -10247, -6713, -3057, -9979, -3672, -6229, -4608, -3131, -5419, -4169, -4738, -3996, -4066, -3853, -5631, -5869, -5689, -6247, -3266, -7684, -20323, -11907, -7206, -2894, -8001, -5255, -3943, -5052, -2472, -5833, -3593, -2379, -3961, -2063, -4117, -4113, -2539, -3763, -1759, -4145, -4780, -3799, -3579, -1678, -7482, -3796, -5995, -3003, -2008, -6027, -3836, -9554, -3075, -3017, -2896, -5702, -14625, -1504, -2360, -3044, -1487, -4265, -3225, -3986, -9075, -3210, -4127, -2464, -6521, -5388, -6423, -916, -408, -6156, -3486, -9355, -571, 552, -4207, -4319, -8203, -1147, 569, -2249, -4905, -6750, -937, -72, -543, -2242, -4041, -863, -1216, 432, 114, -2699, -2014, -3629, 418, 1352, -3433, -2727, -10814, -681, 1366, -6282, -1958, -2590, -2952, -6, -3716, -2224, -513, -6937, -3433, -2625, -4043, -163, -7808, -13572, -3488, -9508, -1117, -3808, -5312, -4816, -6499, -2760, -1250, -3357, -2952, -2767, -2385, 163, -1731, -865, -1248, -1202, 216, -691, -552, -359, -1048, -1285, -1002, -3070, 1192, -999, -682, -3304, -1531, 2877, 478, 1448, -1240, 1840, 3908, 1324, 1752, 1094, 2880, 4142, 771, 68, 1497, 2483, 3577, -1142, -4927, 401, 872, 2279, -3574, -4789, -1818, -1422, 578, -4474, -4161, -2381, -2721, -792, -3274, -4035, -1915, -2841, -1498, -1655, -3202, -2845, -1530, -2122, -731, -4220, -4852, -346, -3911, -488, -8410, -3948, 17, -11601, -1054, -6930, -2428, -223, -4265, -3181, -5540, -1608, -827, -2590, -7168, -6787, -955, -1883, -2828, -1763, -8574, -293, -4050, -3295, 197, -4504, 297, -6437, -3468, 640, -2015, 398, -3753, -4356, 188, -1034, -732, -2281, -6113, -672, -1381, -4975, -1556, -7557, -1508, -2985, -3857, -829, -5404, -2414, -5159, -1358, 231, -3005, -3667, -5494, -1721, 1210, -1657, -2840, -4258, -4395, 1572, -946, -1003, -4242, -6830, 1068, -494, -228, -7851, -4250, -530, -338, -381, -6428, -3621, -3439, -768, -1361, -3066, -4154, -4575, -2020, -3706, -2565, -5873, -4091, -3450, -8764, -3454, -11360, -3994, -2473, -2757, -5121, -9430, -2536, -1171, -226, -6409, -6764, -1856, -666, 1078, -4370, -4805, -2973, -793, 1676, -2813, -3727, -5223, -1648, 1649, -2899, -4746, -2938, -3744, 960, -4358, -6558, -1958, -7719, -587, -4615, -3112, -2844, -8827, -3886, -3787, -1491, -5185, -4575, -6683, -4287, -1159, -6972, -1822, -2712, -6079, -1790, -7969, -556, -1786, -7156, -3885, -6150, -504, -1647, -6708, -10546, -3778, -1648, -662, -6693, -4053, -3151, -2948, 216, -6619, -2100, -4161, -2211, 7, -6241, -2150, -7819, -1901, -1619, -5625, -4201, -9236, -2125, -5359, -4772, -20035, -6203, -1695, -8961, -3936, -4620, -8137, -1423, -7771, -3168, -2625, -7866, -1884, -10407, -2637, -2134, -3678, -2511, -4562, -2875, -2186, -2574, -2759, -1385, -4470, -2603, -2829, -2964, -151, -5713, -3902, -4024, -2960, -285, -4488, -7391, -6273, -2378, -1600, -5924, -6123, -8840, -1575, -4013, -10024, -3258, -8351, -1241, -8567, -3585, -2348, -6904, -2097, -7621, -2694, -2456, -5419, -5432, -2881, -4705, -3130, -4781, -9225, -949, -11217, -3993, -5228, -5395, -421, -3792, -4698, -6520, -6366, -1110, -2417, -5091, -7604, -8282, -3182, -2698, -5569, -7999, -6149, -3058, -1149, -2782, -5494, -1655, -5423, -4878, -2823, -425, -4758, -4616, -5470, -3528, 1229, -4878, -3694, -2318, -7757, 1559, -807, -1796, -428, -3529, 926, 319, -670, 610, -1132, -507, -59, -806, 775, -582, -1285, -1894, -1604, -11, -1141, -280, -4756, -2209, -1942, -1683, 395, -4392, -3263, -5611, -859, 232, -5596, -6205, -10941, 8, -890, -9871, -9277, -6377, 262, -3581, -4485, -3242, -3582, -180, -7947, -3244, -492, -2391, -1929, -2648, -2125, 1089, -2467, -7535, -184, -1467, 1949, -3488, -1853, 927, -1118, 2048, -5434, -232, 1105, 12, 1109, -8568, -1789, 588, 134, -54, -1893, -2458, 90, -2350, 1154, 1134, 1625, 861, -2206, 1874, 2340, 2891, 1827, 813, 1064, 2174, 2645, 2115, 1368, -1399, 752, 1734, 1801, 465, -4924, -1875, 1555, 987, -998, -3232, -5678, 1800, -332, -737, -1065, -4665, 1480, -1490, 7, -36, -2542, 608, -1714, -508, 265, -2403, -86, -2104, -2181, 70, -4109, 53, -2358, -179, -995, -5926, 423, -1358, 1566, -3229, -3574, 424, -385, 1563, -2794, -2277, -289, 57, 211, -1662, -1919, -2226, 214, -608, -2548, -1864, -5770, 128, -489, -5510, -1845, -4538, -522, -1573, -2361, -2327, -3159, -2097, -2126, -19, -3712, -2801, -5200, -529, 895, -4192, -3067, -14878, 331, 844, -2237, -4676, -5338, 164, -106, -889, -10372, -2762, -871, -1700, -574, -4661, -1659, -1252, -2037, -1288, -1745, -1741, -415, -1122, -1881, -221, -2879, -431, -795, -27, 586, -2664, -1936, -1383, 1453, 760, -877, -5747, -3279, 1713, 230, 48, -9848, -6121, 743, -1223, 33, -6267, -4083, -1491, -4338, -683, -3873, -3319, -3890, -10951, -1470, -2171, -4353, -4587, -6234, -1877, -1456, -6665, -4400, -6122, -2562, -1490, -9262, -2215, -8824, -2936, -2028, -5486, -970, -12518, -1587, -2449, -3870, -1006, -5513, -81, -1884, -5070, -1852, -2270, 846, -1583, -9725, -2673, -446, 1035, -2785, -3642, -3626, 299, 384, -4071, -1697, -5615, 0, -845, -1718, -1073, -7410, -1367, -1028, -814, -935, -6894, -3471, -398, -1648, -916, -3548, -6133, -728, -4499, -965, -830, -6958, -2693, -7097, -1111, 409, -3086, -6713, -4160, -1165, 298, -1895, -3881, -2976, -907, -1067, -2241, -1851, -2797, -502, -2215, -3381, -910, -3517, -345, -1448, -4587, -507, -4985, -745, -742, -5417, -460, -4953, -1722, -290, -5442, -719, -2865, -2546, -433, -6672, -1408, -930, -2768, -1687, -15512, -2698, 113, -3871, -4079, -5756, -4240, 71, -8233, -6080, -4337, -4508, -951, -6482, -6111, -5045, -3690, -1837, -3879, -3679, -6100, -3119, -1430, -3633, -2205, -5399, -3187, -1123, -4720, -2134, -4594, -3773, -1525, -7034, -3457, -4808, -4327, -2954, -13724, -6477, -6667, -4058, -6774, -6851, -6498, -11831, -3388, -5873, 4533, 15493, 7130, 11099, 10872, 8971, 15079, 7409, 10372, 10215, 10477, 13792, 7275, 7939, 8110, 10115, 11471, 5974, 2071, 4093, 8807, 7904, 3893, -401, 596, 7640, 6406, 2632, 291, 246, 6353, 7830, 1705, 498, -2133, 5933, 8178, -99, 1669, -1466, 7015, 7495, -3209, 1380, 906, 6642, 5809, -2085, 420, 2649, 3011, 3101, 467, 890, 4060, 2610, 1239, 3134, 2438, 5095, 6134, 4168, 4923, 3666, 5672, 6390, 6574, 5504, 4339, 5666, 5175, 7432, 4771, 4364, 4716, 3611, 6811, 2487, 3671, 2068, 2734, 4441, 897, 2214, -1551, 1422, -1480, 1980, 145, 404, -1713, -829, 1479, -1429, -400, -2830, -620, -980, -1508, -4595, -937, -4509, -5950, -843, -3942, -436, -956, -3109, -86, -2002, -692, 253, -1534, 309, -1370, -1942, -1167, -2427, 197, -874, -4390, -7899, -2739, -461, -450, -4445, -2005, 564, -1706, -673, -4643, 937, 1953, -3334, -2247, -9197, 2447, 1896, -3203, -7384, -2865, 3140, 702, -1405, -4796, -1206, 3044, -1300, -192, -2152, -1597, 2136, -2908, 125, -1193, -3364, 442, -2540, -592, -655, -6300, -1686, -1452, -2733, -319, -2385, -3504, -1146, -6747, -114, 418, -6151, -1916, -7425, -50, 1525, -8056, -3061, -8010, -273, 1413, -4908, -3606, -8036, -740, 45, -4499, -3707, -9333, -1100, -3493, -4605, -2349, -7706, -1075, -5940, -4116, -1488, -4490, -1074, -2420, -4716, -2222, -4322, -1688, -1937, -7574, -5472, -7708, -3210, -2954, -9068, -8547, -8071, -5093, -4749, -6216, -4839, -4324, -4994, -4740, -5370, -4755, -3714, -4619, -3586, -5709, -6445, -4542, -5527, -3203, -6705, -7296, -6022, -7614, -3491, -7190, -5463, -5318, -7737, -3294, -6641, -3769, -3574, -6598, -2733, -6292, -2699, -2511, -6223, -3322, -7125, -2528, -1985, -6367, -6489, -9032, -3192, -1758, -6932, -10492, -10363, -3831, -1862, -7547, -5582, -7436, -3718, -2684, -7591, -4955, -4703, -3850, -5169, -7156, -5282, -3324, -4932, -15759, -6365, -5603, -2636, -7772, -5235, -5242, -5591, -2536, -7604, -3910, -4440, -5019, -3328, -4982, -4552, -4531, -4227, -5154, -4938, -6666, -5498, -4315, -7384, -6805, -10403, -6424, -6270, -8430, -6066, -14886, -5957, -8237, -9381, -4709, -7991, -4773, -6516, -15946, -5086, -4770, -4046, -7510, -8213, -7473, -3115, -3811, -5936, -6036, -13292, -2612, -3598, -3212, -6093, -7140, -2970, -3330, -2197, -7069, -5339, -3798, -3249, -2596, -7484, -4894, -4503, -3658, -4898, -7717, -5436, -4681, -5182, -7703, -9217, -6569, -4421, -10267, -4587, -15266, -5999, -3847, -8154, -4051, -14168, -5103, -3525, -4809, -5255, -9670, -5175, -3853, -3862, -7668, -5919, -5897, -4642, -4121, -8586, -4629, -7287, -5715, -5258, -7177, -5460, -9161, -7852, -7043, -6614, -7702, -10597, -16619, -8897, -6982, -6417, -13152, -8491, -8037, -7590, -5676, -7926, -5771, -7079, 8378, 264, 6883, 11011, 8143, 7556, 1695, 6137, 10467, 7604, 4780, 3511, 3566, 8760, 5905, -1905, 4481, 1645, 5576, 3317, -5876, 4662, 3831, 483, 3090, -657, 4234, 4030, 917, 3836, 2385, 3349, 2513, 2198, 3803, 3375, 2196, -346, 2695, 3488, 3584, 819, -176, 2702, 3452, 2746, 335, -412, 2651, 3857, 1787, 2832, 1422, 3444, 4373, 5252, 4678, 5194, 4458, 4573, 7185, 5288, 6970, 4627, 4164, 7558, 4889, 7263, 3451, 2960, 6666, 3846, 6129, 1351, 758, 4646, 2817, 2960, 2364, -3368, 1865, 2292, -15868, 3155, -5752, -564, 1822, -116, 2577, -2844, -2178, 610, -161, 1399, -2842, -3605, -1454, -690, 520, -2531, -955, -1400, -539, -353, -1441, 1152, -124, -2240, -2051, -868, 1843, 464, -11447, -4585, -824, 1495, 678, -1738, -5301, -1185, 281, 745, -280, -5586, -1797, -1825, 459, -992, -6544, -2607, -5670, -649, -4226, -6437, -4093, -9434, -2416, -5874, -4257, -7643, -4370, -1347, -2625, -2606, -5330, -3094, 283, -2130, -1978, -2963, -3396, 824, -3189, -1573, -2398, -5621, 448, -5830, -798, -2397, -12478, -642, -10395, -161, -1970, -5002, -2176, -11549, -242, -785, -3316, -4916, -7381, -1520, 502, -2597, -9442, -4302, -5125, 1082, -1579, -3107, -2656, -2112, 665, -1043, -2269, -1962, 1021, -494, -1698, -4389, -2045, 2453, -1441, -4094, -4653, -3063, 2833, -2423, -13200, -2195, -5171, 2263, -4770, -6279, -2685, -4206, 699, -11234, -4126, -5226, -2200, -889, -6141, -3336, -2471, -1746, -560, -3305, -3339, -1170, -2899, -506, -3067, -4504, -2083, -7249, -1161, -4422, -7364, -6452, -7606, -1149, -5031, -7721, -5413, -4786, -466, -5029, -5662, -2999, -6071, -230, -5115, -4645, -3330, -11883, -811, -4326, -4105, -5245, -6769, -2428, -3992, -4199, -6936, -6518, -5211, -4770, -5177, -5351, -9277, -5506, -7365, -5638, -2906, -9850, -3555, -18071, -4137, -2140, -6688, -2506, -11084, -3154, -3833, -4152, -2146, -9314, -3232, -7623, -2662, -2270, -6701, -4756, -2688, -2446, -2726, -5357, -10055, -1806, -3670, -3392, -5184, -7186, -3235, -6329, -4180, -5034, -5349, -8245, -7533, -4973, -4501, -5329, -6564, -8702, -5175, -4938, -4572, -3817, -13587, -3909, -6498, -3654, -2700, -8833, -2464, -4797, -3378, -2376, -7217, -1812, -3428, -3628, -2944, -6491, -2063, -3960, -3761, -4608, -6658, -3034, -6518, -2849, -6431, -8580, -3801, -7431, -2009, -6121, -16045, -3344, -5560, -2096, -5897, -10675, -2850, -5160, -3323, -6165, -8817, -3093, -5969, -6089, -6663, -8860, -4081, -8848, -13227, -7866, -10554, -5060, -9306, -10594, -9882, -12794, -4854, -5107, -7765, -7546, -9109, -4704, -3508, -6253, -4799, -6608, -5836, -3334, -5350, -3322, -5327, -9282, -4326, -4660, -2846, -5363, -7109, -5836, -3927, -3251, -7120, -4339, -5865, -3254, -4504, -9555, -3564, -5144, 1256, 8194, 9051, 8438, 6129, 650, 7937, 8480, 7806, 6110, 593, 6913, 6782, 5746, 5680, 1396, 4326, 4193, 1459, 4087, 699, -3885, 2269, -3077, 178, -1300, 2669, 2316, -3257, 1229, -395, 4207, 1878, -348, 2806, -745, 3878, -490, 2326, 2043, -6821, 2190, -9079, 2726, -404, 2215, 355, -1577, 2680, 1752, 5378, 1813, 1864, 4276, 4284, 6994, 4431, 3807, 5208, 5306, 7530, 5770, 4359, 4429, 4896, 6988, 5456, 3166, 388, 2751, 5161, 2708, -623, -360, 3728, 1734, -3842, 1396, 2724, 6103, -350, 2628, 2636, 1996, 6816, -647, 3185, 1600, -2459, 6482, -3023, 2185, -1368, -3164, 5709, -7149, 372, -6559, -756, 4888, -5411, -2287, -12196, -1359, 3713, -2871, -4511, -9419, -3677, 1748, -2653, -5209, -5848, -5567, -924, -4604, -8946, -3825, -3525, -2421, -15332, -4285, -2637, -2461, -1599, -5356, -2543, -1760, -1539, -2080, -2989, -3332, -1242, -553, -7473, -2254, -4298, -1333, 51, -966, -2558, -1966, -1802, 158, 1360, -3677, -1343, -2179, -240, 1463, -4227, -2395, -2938, -1199, -487, -3520, -3483, -4805, -2796, -7193, -2827, -3956, -7252, -5226, -2860, -2057, -5333, -12403, -8461, -1370, -1333, -4898, -4867, -4416, -1209, -1339, -4761, -1651, -1420, -763, -2458, -3962, -610, 30, -99, -4593, -2531, -997, 341, -220, -6698, -3370, -2282, -267, -1783, -5861, -10912, -1765, -1616, -2858, -4350, -3667, -232, -3596, -457, -4035, -2491, -17, -4169, 839, -4041, -4380, -1642, -2772, 1037, -3197, -3931, -6408, -1924, 423, -1948, -1864, -4142, -621, -571, -1301, -2064, -2997, 731, -961, -1589, -4497, -4267, 1250, -926, -2992, -8958, -8864, 917, -1474, -7457, -6750, -7896, 44, -2788, -5957, -6933, -5080, -899, -4510, -2528, -7146, -4167, -1538, -5667, -2113, -6172, -3159, -2182, -5590, -3646, -5813, -2198, -3796, -5537, -7502, -5014, -1999, -8334, -5487, -8382, -4255, -2704, -10080, -4584, -7250, -4315, -4114, -7922, -3508, -7169, -4759, -5307, -12536, -2807, -5831, -4859, -4921, -8245, -2569, -4107, -4743, -4018, -5103, -3040, -3088, -5043, -3730, -3963, -4918, -2810, -6461, -4368, -3629, -10136, -2912, -10574, -6007, -3890, -5810, -3042, -11332, -8360, -4947, -3876, -3399, -7554, -10480, -6989, -3516, -4362, -5965, -12544, -6735, -3533, -5859, -5315, -14505, -4827, -3209, -7345, -5893, -14616, -4171, -3017, -9808, -8271, -13590, -4636, -3677, -14120, -9644, -9215, -6100, -5605, -12666, -8331, -6548, -8048, -7381, -10863, -10016, -5139, -7709, -5938, -6204, -15211, -4551, -6454, -4807, -4875, -8887, -4491, -6128, -3721, -5659, -7500, -4682, -6747, -2556, -7675, -6139, -4864, -7890, -1964, -6667, -4402, -5188, -8256, -2320, -4996, -3710, -6703, -7762, -3806, -4001, -4335, -11670, -7648, -6396, -3930, -6030, -5334, -8387, -8283, -5021, -7927, -3020, -9673, -7495, -8041, -6548, -6351, -4577, -6923, -7329, -8284, -6631, -4061, -7063, -5307, -8390, -6378, -4222, -7515, -4424, -7435, -5524, -5190, -6242, -5340, -6891, -6092, -6443, -4482, -9412, -6512, -8504, -7151, -3780, -6509, -6541, -7944, -7748, -4030, -3881, -7323, -6572, -8041, -5028, -3184, -8845, -7005, -7553, -6481, -3803, -8940, -8206, -6558, -7744, -6040, -6500, -8761, -6037, -7925, -10519, -5080, -9533, -6506, -7240, -9368, -4760, -9287, -8232, -7063, -10010, -4792, -7236, -12589, -7486, -9919, -5057, -5658, -8648, -7374, -7534, -6010, -4564, -5838, -5932, -5664, -6665, -3232, -6002, -4453, -3240, -4373, -1650, -13290, -3202, -865, -1386, -185, -2610, -1208, 688, 185, 948, 143, 530, 1179, 389, 1454, 963, 1243, 482, -607, 1088, 355, 836, -1785, -2522, -295, -1720, -758, -8318, -4503, -2747, -4915, -3800, -5798, -5229, -5997, -5149, -7227, -3822, -5190, -8891, -5027, -5935, -4036, -5501, -11012, -5751, -5296, -5407, -5933, -14699, -6245, -5838, -7147, -5933, -7333, -6323, -7869, -6831, -5364, -5247, -6471, -12393, -6155, -4895, -4878, -6556, -8509, -6499, -4992, -5571, -6484, -6755, -7576, -5429, -6747, -6782, -6913, -8912, -5640, -6000, -7704, -8167, -8864, -5128, -4469, -8921, -8017, -6624, -4493, -4273, -9640, -7406, -5049, -4473, -5991, -9343, -7561, -4418, -5066, -13268, -8643, -6815, -4450, -5720, -8838, -8074, -5190, -4799, -5812, -7425, -8578, -3930, -4919, -5457, -8368, -10504, -3413, -4635, -5151, -10434, -8473, -3847, -4677, -5001, -14928, -6745, -5601, -5846, -4794, -13557, -6224, -9763, -9292, -4507, -10355, -6021, -7168, -9656, -4467, -9557, -6503, -4641, -8241, -5059, -8694, -8687, -3764, -11422, -6437, -8146, -8778, -3950, -7103, -7453, -9133, -6146, -5314, -4463, -7307, -13477, -5448, -8279, -4093, -8118, -10718, -6447, -8181, -5475, -10931, -8180, -10001, -7192, -8322, -15204, -7878, -10771, -9099, -7508, -16281, -8573, -8246, -11432, -6265, -15411, -7892, -8576, -7119, -6237, -10841, -6883, -9984, -5696, -6866, -8892, -7123, -7987, -5549, -7763, -7957, -8032, -6305, -6345, -8954, -7489, -7324, -5799, -7600, -10486, -7290, -6169, -5854, -7392, -9232, -7372, -5691, -6019, -6508, -7284, -7752, -5822, -6340, -6327, -6590, -8314, -6392, -7067, -6831, -6989, -8911, -6713, -8579, -7890, -7869, -9445, -6372, -10999, -9800, -7776, -9341, -6414, -10052, -11851, -7401, -8415, -7597, -8164, -10261, -8170, -7870, -9737, -7401, -10459, -10877, -8278, -9718, -7889, -16067, -13568, -9071, -9638, -9811, -10978, -12213, -8858, -12121, -9877, -8305, -12370, -8594, -13135, -9242, -7339, -8537, -8928, -9409, -11784, -6960, -6211, -9573, -8126, -11065, -7114, -5472, -10652, -8225, -8324, -8287, -5949, -10635, -9908, -8492, -11586, -7270, -8860, -15514, -11024, -18718, -8410, -7806, -11134, -12072, -14639, -8466, -7747, -8489, -10385, -18810, -8197, -8742, -7493, -9563, -13499, -2908, -6699, -7247, -4378, -5073, -3327, -10845, -5664, -6704, -5999, -5316, -12007, -4681, -6668, -8456, -11358, -7040, -4423, -5286, -14984, -5540, -5199, -5265, -5211, -8728, -3696, -4677, -7107, -6611, -6682, -3638, -5055, -7761, -13025, -6529, -4707, -5934, -7805, -8128, -7618, -5980, -6600, -9058, -5764, -8213, -6226, -6227, -8087, -6096, -7454, -6407, -5201, -6920, -7532, -7107, -6511, -4581, -7163, -6288, -7064, -6532, -4870, -6736, -5605, -7004, -7435, -6602, -5552, -6552, -6745, -7886, -12200, -5388, -7769, -6227, -6979, -6980, -5654, -7796, -5688, -6463, -4928, -6064, -6473, -4840, -4803, -5437, -11898, -3453, -2951, -2292, -4249, -3831, -573, -738, -575, -1265, -669, 1261, 600, -18, -52, 336, 1930, 743, -753, -352, -12, 1425, -450, -3087, -2171, -1392, -310, -3143, -7103, -6068, -3344, -3185, -5780, -7571, -8065, -5057, -5027, -6312, -6455, -6798, -6420, -4856, -6105, -4670, -7252, -9081, -4674, -4671, -4106, -7864, -13386, -4465, -4086, -5220, -8621, -10281, -4309, -4242, -8559, -9005, -10797, -4498, -4461, -7752, -8497, -7325, -5414, -4277, -5370, -7797, -5059, -7937, -3897, -4982, -6640, -4296, -11752, -3836, -6238, -6072, -4338, -6354, -4438, -6660, -6407, -4700, -4666, -5675, -4453, -7390, -5256, -4511, -6533, -3547, -8897, -6522, -4832, -6306, -4020, -11184, -10382, -4960, -6389, -5959, -13516, -10335, -6209, -7820, -11066, -12590, -6437, -14322, -12986, -10320, -10129, -5207, -6874, -10885, -6944, -7587, -4943, -4813, -8883, -5362, -5973, -5279, -5283, -7056, -4170, -5508, -6155, -8576, -4767, -3337, -6284, -7542, -11029, -3905, -3103, -7915, -10062, -6884, -4627, -3659, -6884, -16473, -5993, -7170, -5101, -5139, -8567, -5852, -10715, -7398, -4371, -6536, -5670, -11270, -10348, -4382, -5992, -5626, -18778, -9143, -5134, -5752, -6121, -9399, -6596, -6755, -5309, -7402, -6917, -5445, -8929, -5428, -9935, -6312, -5132, -10054, -7106, -10118, -6658, -5255, -9667, -13075, -7099, -6394, -5653, -7872, -8792, -5678, -5288, -6438, -6763, -7146, -5493, -4663, -7384, -6729, -7684, -6347, -4530, -7160, -7379, -9507, -7291, -4559, -6680, -8148, -11206, -6599, -4802, -7142, -8712, -10361, -5839, -5422, -8417, -9661, -8222, -5888, -6181, -9920, -13604, -6597, -6609, -6751, -11337, -11829, -5824, -7493, -7258, -12042, -7840, -5990, -8131, -7717, -10880, -6602, -7278, -8949, -8032, -9651, -6747, -10059, -10509, -8548, -9624, -8103, -13261, -12531, -9616, -10733, -10395, -12730, -10939, -9319, -11676, -10460, -12527, -9983, -8093, -10785, -9309, -12955, -10411, -7973, -9245, -8938, -13295, -9574, -8281, -8789, -9000, -9805, -9090, -8248, -9757, -9125, -7776, -10044, -8898, -9633, -9117, -7390, -9505, -10617, -8342, -8800, -8461, -8786, -12609, -8822, -8115, -10808, -10312, -19216, -11882, -7526, -10971, -18444, -11727, -11604, -7828, -9439, -10460, -9691, -10746, -10399, -8907, -8269, -10319, -6878, -9851, -2641, -8407, -6705, -6866, -10729, -3982, -6529, -7147, -5880, -8550, -8117, -5432, -9053, -5592, -6433, -7111, -4552, -9303, -5849, -4964, -5221, -3781, -6290, -6387, -3769, -5732, -3360, -4621, -6109, -2878, -8342, -3383, -4350, -4191, -2694, -9240, -3989, -5223, -3001, -3438, -6009, -5375, -6996, -3143, -5046, -4195, -6291, -10745, -4699, -6768, -3080, -5204, -10279, -7260, -7703, -2416, -4464, -6950, -7035, -7753, -2151, -4372, -6527, -6596, -7208, -2333, -4532, -8309, -8248, -6634, -3117, -4632, -15361, -9623, -5373, -4999, -4484, -9217, -6905, -4820, -12682, -4436, -6508, -6933, -4762, -5006, -3898, -3783, -3713, -1910, -1481, -1738, -1064, -643, 227, 177, -122, 543, 585, 909, 595, 257, 852, 386, 309, -314, -640, -275, -1112, -1534, -3212, -2963, -3566, -3883, -4501, -7127, -6597, -9483, -7485, -7128, -4571, -7375, -4444, -11865, -7870, -5313, -7155, -3428, -11077, -7770, -9125, -8310, -3381, -7399, -6912, -8765, -11503, -3966, -6346, -6521, -7168, -11360, -5531, -7257, -7706, -7116, -7068, -7660, -12054, -10682, -8340, -5558, -7006, -8854, -9587, -9526, -6069, -6389, -7118, -9337, -5638, -9274, -6453, -8845, -12604, -3441, -10968, -6227, -14733, -10009, -2529, -10137, -5697, -8539, -7247, -2413, -12264, -5425, -8522, -6545, -2854, -6333, -5646, -12419, -7328, -3787, -4279, -6259, -8824, -9771, -4800, -3838, -6481, -7261, -8563, -4664, -4541, -6203, -7890, -6232, -4045, -6420, -6541, -6816, -5547, -3955, -9842, -7972, -5009, -5959, -4435, -10213, -10475, -4682, -6963, -5504, -7886, -11744, -5499, -7792, -7511, -7102, -11514, -5834, -7854, -9814, -7475, -13256, -4957, -7573, -8841, -7927, -13400, -4683, -7644, -7727, -7390, -9887, -5684, -8306, -7013, -6861, -7521, -8562, -10015, -6961, -6447, -5779, -15776, -10543, -8142, -6028, -4576, -14903, -7085, -10275, -5988, -4022, -9449, -6034, -10182, -6406, -4355, -7039, -7576, -10481, -6594, -5971, -6042, -10735, -12139, -6102, -10077, -5147, -6540, -9336, -5684, -13039, -4449, -5644, -7173, -5861, -10946, -4710, -6404, -6152, -6929, -12656, -6287, -6600, -5901, -9247, -8756, -9140, -5629, -6384, -11170, -6098, -9513, -5078, -7412, -10098, -4956, -7975, -4866, -7864, -9491, -4904, -7755, -4930, -7681, -8716, -5856, -9063, -5549, -8024, -7235, -7838, -10883, -6812, -8157, -5775, -11198, -10213, -8346, -7342, -5226, -16470, -8954, -9620, -7158, -5899, -10835, -8071, -10983, -8544, -7222, -10022, -7876, -13422, -12045, -7091, -14439, -8548, -15395, -10606, -6787, -10761, -10332, -12884, -8817, -7185, -8085, -10652, -10287, -8365, -7504, -8403, -8478, -8341, -8698, -7538, -8349, -7415, -7562, -8799, -7687, -6477, -7272, -7897, -8144, -8004, -5823, -7833, -8661, -8029, -8453, -6541, -9320, -8159, -8876, -9742, -9087, -11904, -7116, -10415, -10815, -14632, -10865, -6658, -11041, -7507, -8806, -9105, -6804, -9543, -5818, -7707, 10155, 12746, 13112, 9384, 6364, 9425, 12279, 12488, 8807, 5785, 6856, 10838, 10468, 7169, 4021, -1794, 8320, 6370, 5113, 1089, 3338, 4773, 2049, 3570, -2031, 4578, 1878, 3081, 2124, -3039, 4190, 2224, 1344, 426, -4825, 2790, 3118, -1476, -3958, -4895, 1593, 3326, -3336, -3215, -40, 1441, 2672, -2582, -63, 2254, -2078, 622, -2736, 1020, 3521, -1089, -6869, -1708, 2853, 4154, 1811, 1747, 62, 4384, 4192, 1339, 4130, -49, 4952, 3521, 776, 4507, -2725, 4560, 2308, 2035, 3068, -3883, 3154, 2592, 2099, -2045, -1190, 368, 3919, 780, -955, -1675, -4758, 4235, -493, 1643, -5914, -2613, 3299, -102, 2175, -3555, -576, 1433, 323, 1824, -2409, 554, -344, 524, 616, -3957, 1226, -3936, 628, -124, -3020, 1340, -3346, 361, 1304, -944, 997, 114, -405, 2360, 69, 317, 418, -1152, 2405, 535, -1268, -1198, -1069, 1531, 603, -5980, -5265, -577, -49, 269, -6258, -4021, -918, -1856, -616, -3713, -1023, -2786, -3457, -2425, -4304, 609, -1514, -5701, -4607, -6379, 1493, 253, -5339, -5188, -10266, 1581, 28, -1870, -4916, -5895, 550, -2190, -734, -3085, -3294, -2146, -4314, -1378, -3039, -1655, -2526, -1846, -3501, -6895, -253, -421, -642, -5841, -5964, 766, 65, -417, -6885, -2925, 1104, -557, -677, -3422, -2869, 680, -2226, -977, -1882, -4846, -307, -5870, -1316, -2482, -7492, -1746, -5986, -1963, -3896, -4590, -4094, -2960, -2495, -1718, -4834, -5027, -2262, -2106, -268, -14176, -4192, -2772, -1617, -161, -4262, -5206, -3131, -1845, -1199, -2457, -5959, -2018, -2950, -3579, -2876, -5138, -300, -4511, -8852, -4098, -5770, 1085, -5111, -8511, -4172, -8071, 1678, -4856, -3797, -3774, -9588, 1229, -5366, -1471, -3627, -6087, -643, -7686, -479, -3710, -3453, -3701, -5377, -581, -3755, -2312, -1745, -2660, -1705, -3430, -2398, -620, -1427, -4016, -2901, -3232, -1016, -1039, -7903, -2776, -4205, -2516, -1344, -7185, -3750, -5736, -4869, -2431, -5456, -6694, -7873, -7378, -4341, -5246, -10595, -12277, -6725, -5936, -6069, -6533, -6152, -4723, -5557, -6075, -3954, -2296, -3849, -4801, -4137, -2590, -1009, -4258, -4566, -2724, -2469, -1338, -5936, -5982, -2265, -3786, -3074, -8221, -11402, -2912, -6822, -5872, -8258, -4370, -5367, -4966, -7581, -7360, -2243, -6281, -3751, -6287, -7066, -1808, -2884, -5122, -5047, -6901, -2359, -1531, -9857, -5059, -5925, -3686, -1311, -7128, -6167, -4822, -6161, -1804, -6896, -5863, -4475, -6151, -2600, -9974, -4072, -5347, -3663, -2725, -15938, -3560, -8575, -2717, -1770, -10213, -4551, -7879, -2768, -787, -9373, -4406, -4310, -3255, -205, -9962, -2890, -2963, -3422, 1, -6661, -3392, -2844, -3029, -170, -4916, -8209, -3539, -3108, -942, -4675, -3966, -3962, -3867, -2982, -4586, -1818, -3373, -4092, 7465, 10363, 10751, 7892, -896, 6569, 9725, 10121, 7108, 489, 3261, 7811, 8164, 4473, -38, 1488, 4891, 4774, -1000, -2812, 3807, 1945, 981, -1314, -4478, 3427, -937, 259, -2409, -518, 2267, -4716, 342, -3855, 954, 2702, -1194, -894, -4800, 1416, 3355, 2541, -24, -4117, 1331, 3433, 3956, 950, -5606, 1135, 2957, 4417, -231, -2425, 1451, 1445, 4334, -740, -4, 1960, -2938, 3566, 1676, -36, 2061, -443, 1518, 2270, -1102, 1814, 2329, -4486, 1457, -1257, 1751, 3119, -2316, 873, -678, 2230, 2757, -404, 1232, 550, 2768, 1250, -906, 1095, 1159, 2764, -1686, -2178, 629, 491, 1950, -1012, -2263, 502, -1620, 151, 803, -1032, 320, -5347, -2789, 1188, -332, -302, -9984, -2968, 1024, -469, -936, -8802, -1426, 921, -1322, -874, -4464, -1272, 774, -3355, -300, -1727, -1962, 407, -4289, 192, -290, -2721, -63, -741, 414, -45, -2883, -413, 1133, 417, -1107, -2659, -597, 1776, 49, -3274, -3075, -661, 1373, -1110, -2215, -5329, -642, -89, -3609, -769, -10998, -851, -2524, -9132, -735, -5260, -666, -4873, -5634, -1800, -3680, 670, -5591, -1939, -3299, -4235, 1397, -7483, -350, -4024, -6442, 682, -10761, 74, -5944, -1923, -2142, -4543, 208, -6266, 39, -12373, -2914, 956, -2055, -71, -3681, -2241, 2248, -784, -2158, -2380, -1894, 3287, -867, -2712, -2920, -1889, 3491, -1740, -699, -3844, -2384, 2524, -3659, -485, -2494, -3500, 9, -4356, -2160, -1864, -3123, -1755, -2585, -8293, -2174, -1722, -256, -2470, -4448, -2638, -1516, -185, -4057, -2350, -3833, -3287, -1331, -7535, -2298, -6043, -7242, -2531, -11586, -3140, -4751, -2519, -1968, -9226, -3707, -3978, -1185, -1044, -6128, -3021, -5076, -1576, -888, -4336, -2184, -6571, -3061, -1757, -3834, -2065, -5168, -5343, -3763, -4201, -2827, -3367, -9239, -5769, -4884, -4592, -2241, -8583, -5319, -6652, -7865, -1871, -5208, -5235, -6257, -10939, -1962, -4412, -6054, -2774, -7764, -2222, -5460, -5720, -1289, -4814, -2796, -6417, -5008, -886, -3633, -4235, -4891, -5366, -1022, -4116, -7967, -4810, -6575, -1521, -4923, -11224, -7129, -7925, -2409, -3956, -6990, -17269, -8064, -3622, -3433, -5957, -8662, -6873, -4986, -3865, -5455, -5338, -6159, -7519, -4616, -5257, -3224, -7325, -9523, -4790, -5156, -2448, -9371, -3567, -4489, -5697, -2821, -5314, -1640, -4708, -8441, -3770, -3707, -1381, -6199, -8236, -3921, -3471, -2251, -8708, -4559, -3491, -3836, -3328, -8789, -3216, -3637, -4449, -3813, -9644, -3129, -4424, -5738, -4748, -7124, -3965, -4513, -6723, -5711, -4060, -5275, -3835, -4397, -3995, -2311, -5990, -4048, -3026, -2356, -1567, -5673, -5713, -2770, -1660, -1904, -5196, -10226, -2655, -1716, -3442, -3897, -6594, -1813, -2358, -5478, -2519, -3534, -912, -3236, 2816, 10853, 11130, 7971, 5305, 2639, 10384, 10551, 7334, 5102, 1951, 8983, 8721, 5502, 4500, 472, 6733, 5317, 2994, 3652, -2632, 4136, 846, -685, 2731, -942, 2498, 250, -2235, 1608, 1547, 2032, -817, 2360, 1113, 2142, 1255, -1477, 3248, 2007, 2181, -258, -1515, 2199, 2816, 2574, -934, -2617, -551, 3123, 3037, -17, -2686, 1598, 2910, 3264, 1765, 319, 3044, 1515, 3095, 3165, 1646, 2554, -4918, 2191, 3454, 1129, 531, 1550, 591, 2469, -2124, -1176, 4667, 243, 798, -3351, -1221, 6207, 202, 977, -39, -1104, 6777, -1813, 1461, 366, -318, 6336, -1875, 1209, -607, -15, 4776, 1149, 936, -2417, -791, 2440, 2332, 1056, -3948, -2974, 1560, 2195, 1417, -3292, -8100, 1569, 929, 1661, -1614, -3619, 997, -930, 1448, -901, -1155, -156, -1963, 846, -2205, -348, -1919, -2811, 257, -8398, -214, -3453, -4946, -206, -1537, -170, -7124, -10364, -164, 402, 115, -4540, -12621, 588, 652, 896, -1195, -16424, 900, 60, 1597, -1237, -7107, 278, -1201, 1633, -3867, -3272, -858, -4112, 939, -2844, -900, -1321, -10210, -263, -1175, 454, -1039, -4481, -2017, -716, 561, -736, -6075, -5001, -71, -1380, -522, -4911, -1851, 211, -5301, -51, -100, 645, -415, -538, 199, 1670, 1488, -1398, 29, -730, 1896, 1173, -1821, -2739, -3889, 487, -216, -2279, -6894, -6878, -3666, -2184, -3296, -2486, -6489, -1177, -1264, -4863, -3892, -11466, 696, 258, -4590, -6984, -3988, 744, 570, -2274, -3033, -2936, -16, -459, -1090, -1224, -4081, -1101, -2535, -1339, 120, -7075, -3108, -1752, -3254, 546, -14394, -7204, -355, -3727, -306, -8928, -4062, 58, -1666, -2335, -5461, -2334, 28, -982, -2879, -4177, -2322, -84, -990, -2306, -3866, -3444, -366, -908, -3226, -3878, -5506, -1203, -564, -6448, -4126, -11451, -2910, -152, -8746, -4208, -6954, -3861, 100, -5412, -3887, -4327, -2458, 36, -4128, -4020, -4759, -1580, -462, -3551, -4817, -5465, -1384, -1518, -3568, -5537, -2972, -1548, -2904, -4034, -5937, -1743, -2046, -3334, -4066, -7162, -1717, -2720, -2923, -3738, -10740, -2582, -2337, -2918, -4108, -10690, -4479, -1383, -3176, -5674, -9109, -8246, -1332, -2751, -8263, -9485, -10896, -2741, -2023, -8803, -4645, -7508, -5089, -2009, -7045, -2053, -5038, -2886, -2801, -4004, -1291, -3449, -1253, -3022, -2556, -2207, -3232, -859, -2392, -2889, -4765, -5100, -1269, -2410, -4490, -4375, -12314, -2208, -3197, -4435, -3202, -5109, -3341, -4380, -3450, -3109, -3996, -4346, -6059, -1620, -2968, -4817, -5390, -7471, 117, -2499, -5740, -6338, -5152, 752, -2173, -6120, -6169, -4065, 257, -2365, -8440, -4260, -4972, -1232, -3283, -8427, -2650, -7703, -3235, -5008, -4629, -2540, -7609, -4511, -5536, -3071, -5195, -7715, -2229, -7725, -3696, -1743, -3123, -402, -3041, -2461, -2227, -3511, 82, -1098, -1439, -2126, -3625, -604, -1073, -1291, -1826, -3226, -2174, -2719, -2504, -1520, -3114, -3895, -6905, -3542, -946, -4190, -5272, -7702, -2073, -304, -9118, -7403, -5800, -2159, -127, -4725, -6445, -6421, -5627, -774, -2103, -3377, -9635, -5046, -2299, -1817, -1608, -11314, -1802, -3645, -3641, -607, -7169, -1155, -3617, -5895, -97, -5934, -1594, -3750, -2787, -76, -5338, -2697, -4602, -1917, -767, -3873, -3565, -4736, -2394, -2683, -2203, -2411, -3080, -3139, -8290, -1188, -1566, -2246, -3717, -6051, -1043, -2144, -2269, -4135, -3166, -1736, -4665, -1541, -3420, -2445, -2807, -5714, -428, -1720, -2671, -3901, -3742, -133, -304, -3534, -6730, -4461, -635, 196, -4999, -9280, -10084, -1368, -461, -6250, -3601, -7678, -1850, -2531, -4963, -1718, -6610, -2500, -5824, -3788, -911, -10839, -4332, -5219, -3619, -707, -7788, -9632, -2921, -4230, -945, -5913, -8131, -1636, -5498, -1431, -6064, -7834, -1339, -7316, -1910, -6401, -7193, -1225, -7706, -2012, -5833, -4882, -998, -6730, -1463, -4220, -3883, -1552, -7327, -1007, -3446, -3715, -3291, -9721, -1335, -4379, -4961, -4267, -8177, -2680, -8030, -7886, -4251, -8146, -4898, -11524, -5527, -6364, -9818, -4962, -9179, -4559, -12750, -7549, -3475, -7716, -5543, -10002, -6633, -2922, -5897, -8312, -16142, -5658, -3029, -4932, -15307, -9516, -4894, -3818, -4216, -12433, -8084, -5217, -6432, -3736, -10402, -5130, -4942, -11180, -3459, -8452, -2451, -4563, -6610, -3042, -5685, -1321, -6302, -7019, -2659, -3931, -1369, -14280, -10820, -2711, -3088, -2285, -9053, -9099, -3352, -2633, -3749, -11980, -9436, -4253, -2509, -5009, -8102, -13941, -4320, -3419, -4522, -5168, -12003, -4059, -7399, -3655, -4747, -14360, -4608, -6510, -3954, -5312, -8539, -5475, -3113, -6467, -5601, -6161, -5400, -2508, -12457, -6038, -5294, -5312, -3169, -5293, -7629, -4882, -5578, -4175, -3787, -8540, -4697, -6554, -3984, -4043, -7789, -5165, -8141, -2751, -6578, -7592, -7204, -6154, -2242, -11739, -5629, -15877, -4579, -3361, -5185, -3711, -7014, -3568, -8555, -3553, -2900, -4905, -2461, -5455, -2903, -3147, -4420, -1824, -2925, -2480, -4606, -4717, -2029, -2581, -2166, -8433, -5083, -3066, -3064, -2108, -11378, -5143, -4636, -3586, -2551, -7590, -5327, -5433, -4131, -3709, -8176, -6163, -4356, -4980, -5464, -13694, -8437, -3324, -5727, -7051, -11130, -12397, -3008, -6211, -8993, -9184, -8892, -3231, -7306, -7476, -9969, -7742, -3573, -10203, -4634, -12684, -7927, -3684, -16659, -3624, -17243, -8584, -3813, -9568, -3837, -13002, -8983, -4193, -7514, -4636, -10462, -8864, -4036, -5969, -5485, -8704, -8689, -3081, -4683, -6535, -7310, -7888, -2436, -3996, -7866, -6560, -7437, -2539, -3992, -9937, -6985, -9075, -3531, -4695, -11614, -9521, -14498, -5769, -6377, -8750, -6250, -2388, -2382, -792, -3844, -5568, -4195, -2097, -1896, -4692, -3336, -7965, -2214, -4281, -6960, -2085, -4817, -2960, -4738, -14538, -2011, -4251, -4964, -4203, -9271, -2839, -6000, -9238, -3609, -8753, -4399, -4727, -9798, -2251, -8970, -7127, -2190, -7635, -1894, -5336, -4922, -1187, -6424, -3022, -3667, -2114, -1209, -5803, -5445, -3153, -1059, -1714, -5782, -6155, -2981, -1207, -1976, -6663, -6096, -2844, -2311, -2135, -7195, -8362, -2705, -4110, -3132, -3972, -14535, -2467, -5510, -5792, -1921, -7078, -2310, -4635, -4818, -1135, -5387, -2569, -3822, -2402, -1269, -4121, -3458, -4663, -1609, -2134, -2080, -5044, -10175, -1910, -3693, -420, -7921, -5837, -3250, -6267, 390, -11087, -2919, -5527, -11392, 354, -4261, -2479, -5466, -12193, -474, -1930, -3810, -4357, -7850, -1864, -1383, -4977, -4058, -6027, -2994, -2375, -3743, -3166, -5115, -2870, -4993, -4345, -2099, -4091, -1980, -7257, -8726, -2171, -3207, -1416, -4962, -7049, -4404, -3282, -1581, -2328, -4625, -11970, -4971, -2512, -957, -4192, -3732, -8884, -3966, -954, -4571, -2315, -4916, -3980, -2717, -4787, -2467, -2751, -2466, -10008, -4276, -3237, -1999, -1585, -3612, -3781, -3062, -2151, -1621, -1599, -3895, -2077, -3195, -2708, -1552, -4783, -1739, -5405, -5519, -2732, -5996, -2242, -6747, -8327, -4793, -6178, -3120, -5205, -4868, -6877, -5084, -3574, -4568, -3278, -8116, -4178, -3346, -3155, -2751, -9489, -3357, -2974, -1424, -3687, -8878, -2607, -3122, -724, -7232, -7028, -2531, -4177, -1287, -8077, -4775, -3380, -6154, -3483, -8296, -2786, -5279, -7446, -9742, -7717, -2005, -6688, -8091, -7778, -4203, -2509, -3835, -9854, -6041, -3579, -3402, -2103, -5315, -6127, -4537, -3127, -1887, -2927, -7252, -5946, -3274, -3282, -2280, -8381, -6652, -4967, -7575, -3073, -6001, -7409, -8732, -10256, -5786, -4500, -10375, -14838, -7218, -12124, -4221, -8848, -10338, -7181, -5745, -4837, -5972, -6104, -7131, -3726, -6107, -5315, -4291, -6432, -3057, -7145, -5953, -4118, -5286, -3563, -7131, -7803, -4913, -4846, -5573, -7630, -12685, -4135, -5862, -5860, -8251, -10917, -2629, -9106, -3478, -5686, -7278, -1934, -6210, -2447, -3660, -6232, -1807, -4019, -2351, -2685, -6934, -1713, -3831, -2811, -2361, -10394, -1327, -5543, -3893, -2399, -11271, -924, -12006, -6556, -2697, -8086, -980, -6260, -8052, -3147, -7675, -1867, -3905, -4646, -3523, -8270, -4120, -3468, -3723, -3978, -8272, -9603, -4622, -4360, -5092, -6699, -5698, -8289, -6575, -7691, -4966, -3395, -7250, -13723, -9388, -3800, -2684, -5014, -8438, -5655, -3298, -2890, -4606, -5398, -3834, -3409, -3617, -4354, -4354, -3106, -3951, -4212, -3430, -4542, -3071, -4575, -4677, -2538, -5841, -3489, -4923, -5681, -2124, -8023, -4274, -4900, -7264, -2333, -8982, -5708, -4813, -8796, -3313, -8289, -8689, -5138, -7854, -5175, -8156, -10859, -6117, -5752, -5528, -4471, -2652, -6196, -11727, -8669, -4997, -2925, -1220, -9177, -4889, -4601, -3001, 373, -6932, -2599, -2013, -2167, 571, -6367, -2479, -1175, -1324, -277, -4778, -3825, -2284, -1048, -2049, -2983, -3926, -5524, -1465, -4418, -2204, -2113, -3979, -2658, -6428, -2456, -1106, -2602, -4177, -8465, -3291, -1040, -2746, -4047, -10954, -3643, -1595, -3662, -3529, -5062, -3396, -2253, -5660, -4050, -2701, -3635, -3181, -7993, -5894, -1968, -5269, -5613, -4906, -11586, -2387, -6787, -19755, -3199, -7378, -3991, -3393, -7052, -2632, -4643, -7713, -1496, -6389, -2867, -3961, -5292, -933, -8342, -3994, -3450, -2399, -1669, -13083, -6695, -1822, -1225, -4265, -6013, -7647, -205, -1037, -6638, -3330, -5317, 707, -1597, -4335, -2858, -4621, 846, -2926, -4878, -4668, -4337, 262, -4596, -10910, -8174, -5034, -934, -3779, -6660, -4125, -9053, -2616, -2219, -4445, -2773, -8275, -4516, -1280, -4806, -2834, -5603, -5921, -916, -7097, -3696, -5307, -7555, -1364, -9936, -4798, -5744, -9207, -3079, -8646, -5690, -7252, -5003, -6585, -8770, -6410, -10935, -3488, -5610, -8659, -6744, -9245, -4543, -3736, -6559, -7362, -6667, -9999, -3573, -4302, -8965, -5489, -3734, -5494, -2963, -5703, -5456, -1880, -11408, -2594, -2907, -6858, -1770, -4699, -2890, -1549, -6535, -2640, -2857, -3453, -1154, -4094, -4328, -2189, -4074, -1541, -3391, -7130, -2055, -4605, -2792, -4375, -8446, -2633, -4459, -5634, -6677, -6922, -3739, -4190, -16075, -7423, -5863, -3600, -4931, -5658, -5893, -4679, -3076, -6630, -3613, -3718, -3507, -3927, -7514, -2568, -2615, -2837, -7290, -8002, -1719, -2934, -2845, -6953, -8216, -1143, -4435, -3538, -4074, -8730, -1125, -4456, -5120, -3464, -9807, -1668, -3324, -8996, -4488, -7542, -2334, -3513, -9803, -7113, -5666, -2808, -5626, -6177, -5883, -4286, -3672, -12648, -5514, -4407, -3453, -5572, -8244, -5411, -5150, -3455, -8737, -7283, -4425, -10922, -4379, -13654, -5561, -3741, -5647, -6222, -14264, -3558, -4234, -2762, -6842, -13732, -2974, -6441, -1961, -4929, -7858, -3630, -11656, -2401, -3825, -4479, -4823, -8689, -3994, -3620, -2891, -5125, -7594, -6922, -3746, -2095, -4262, -6938, -10203, -3831, -1822, -3487, -5721, -7810, -4420, -2297, -3764, -5273, -5157, -6377, -3705, -5866, -5856, -3896, -8346, -5827, -11724, -7327, -3817, -6118, -6657, -5614, -9996, -4462, -5188, -5069, -3567, -23608, -5227, -5446, -3785, -2982, -9908, -6383, -6470, -3373, -2828, -7664, -9051, -7122, -3856, -2319, -7283, -14350, -6048, -5148, -1901, -7891, -10559, -5218, -6995, -2190, -8009, -8803, -5223, -9427, -3309, -6301, -8108, -5472, -11170, -5393, -4919, -7391, -5316, -14433, -7828, -4693, -6097, -5145, -7918, -5216, -5792, -4923, -5350, -4639, -3623, -8660, -4158, -5483, -3482, -3677, -8145, -3554, -4932, -3589, -5313, -5483, -2925, -4456, -4440, -9515, -4467, -2589, -4890, 3118, 146, 1330, 6913, -8593, 2225, -2169, 4462, 6442, -5307, 12, -2240, 6211, 5121, -3754, 1312, 1078, 6366, 3616, -3143, 2963, 2155, 5076, 3021, -2276, 3466, 3005, 1414, 2465, -1894, 3025, 3214, -157, 740, -4887, 1293, 2110, 3189, -4219, -2132, -4556, -1005, 3860, -2021, 2117, -988, -6969, 3108, 306, 3776, 2001, -3941, 546, -137, 4468, 2875, -3603, -7925, -958, 4940, 2381, -2086, -131, 1799, 5298, -257, -19, 1104, 3233, 5130, -1436, 755, 202, 3141, 3946, 2103, -996, -1421, 1700, 660, 2879, -1924, -391, -73, -827, 1894, 2690, 319, 1207, 2394, -865, 4090, 511, 2256, 2674, -2225, 3748, 735, 2067, 1310, -805, 1920, 526, 1172, -336, 316, 162, -206, 561, -4199, 1989, 568, -1159, 654, 72, 3204, 150, -3201, 1390, 3714, 3505, -472, -9209, 1725, 4733, 2879, -171, -1469, 729, 4091, 1390, -691, 396, -2601, 1674, -810, -2626, 295, -7749, -4042, -3765, -4460, -1820, -3734, -3146, -8464, -6383, -8245, -1372, -2356, -3271, -5291, -2978, 733, -1947, -1560, -1302, -1978, 1491, -432, -2768, 154, -3479, 940, 126, -7540, 9, -7941, -284, -776, -2313, -1679, -4676, -294, -3182, -1244, -3582, -2537, -44, -2447, -1635, -2579, -1208, -961, -777, -1382, -3078, -74, -3733, -602, -943, -3659, 674, -12982, -1533, -1950, -926, 812, -5139, -3127, -3137, 55, 385, -4789, -4648, -987, -234, 565, -5526, -5624, -483, -47, 1504, -2684, -7560, -1628, 61, 1754, -738, -8574, -1004, -1997, 1217, 92, -2497, 756, -4957, 887, 251, -78, 1558, -1276, 1105, -37, 864, 1478, -1042, 1072, -963, 840, 515, -1753, 612, -3097, 141, -1088, -1256, -163, -5478, -1065, -2240, -1733, -901, -2319, -3035, -2699, -4870, -1569, -198, -5528, -3643, -3113, -3722, 748, -2815, -6049, -748, -8112, 813, -1249, -10768, -477, -1404, 223, -1639, -9965, -1843, 436, -587, -4400, -7743, -5307, 600, -1048, -9887, -4784, -6827, -371, -1397, -3433, -2408, -4764, -1549, -3179, -1722, -763, -4034, -1054, -5471, -2083, 41, -3624, 844, -613, -5535, -199, -3123, 2355, 787, -6442, -1793, -3035, 2846, 197, -1717, -5117, -4639, 2196, -2325, 310, -4472, -17536, 255, -7013, 1172, -1994, -3928, -3289, -9853, 1038, -379, -1702, -10583, -4825, 59, 694, -786, -4575, -2715, -1504, 1229, -290, -574, -2738, -2659, 1129, -455, 1086, -4577, -2561, 147, -1698, 1292, -6912, -2028, -2223, -3573, 147, -4034, -1176, -6949, -4009, -2647, -2021, -691, -7117, -1952, -4681, -1034, -173, -5394, 544, -2675, -487, 966, -1670, 2086, -1898, -583, 1526, 1029, 2718, -1984, -2698, 884, 2329, 2530, -2503, -3246, -933, 2231, 1490, -2589, 810, -2167, 188, -256, -1535, 1951, -1852, 4277, 8809, 8073, 8894, 6117, 3705, 8169, 7263, 8200, 5739, 2140, 6120, 4511, 5897, 4409, 220, 2412, -1604, 1340, 1445, 146, 481, -1372, 1083, -3380, 1598, 78, -303, 1172, -534, 1779, 437, 2339, -180, 102, -96, 3588, 3941, 1896, -338, -7107, 5326, 4951, 4069, -568, -1001, 5674, 5616, 4464, 116, 533, 4623, 5794, 2535, 2085, -90, 2337, 5337, -650, 3534, -2172, 3173, 4030, 3689, 3828, -2848, 4564, 1813, 4696, 3088, -83, 4455, 1995, 3875, 1675, 2758, 3043, 3189, 1410, 215, 4450, 479, 2920, -1555, -385, 4934, -2987, 1382, 245, 524, 4125, -3666, -1159, 1789, 2241, 2386, -582, -2739, 2611, 3599, 3106, 367, 503, 3170, 3851, 4087, -163, 2224, 3834, 2505, 3466, -1465, 2628, 4288, -600, 1277, -2497, 2187, 3945, 1691, 460, -1772, 1456, 2627, 3462, 1714, 507, 977, 1390, 4027, 1833, 2274, 325, 1221, 3987, 747, 3308, -1273, 328, 3319, -1813, 3771, -4158, -1971, 1860, -2041, 3738, -8238, -6137, 140, 549, 3185, -8916, -8056, -245, 1533, 1988, -3807, -2856, 8, 1112, 86, -2567, -1311, 257, -1158, -625, -4053, -884, 724, -8202, 204, -5880, -549, 1493, -3115, -338, -1423, -598, 2289, -2715, -2811, 211, -2133, 2723, -5070, -3071, 611, -8399, 2597, -3161, -2561, 692, -3892, 1767, -1189, -3756, 1144, -1831, -48, -728, -3358, 1838, -1321, -3653, -891, -2556, 2279, -818, -5325, -1002, -2309, 2273, -755, -1921, -970, -3974, 1745, -2182, -462, -1343, -6567, 595, -4975, -109, -2688, -712, 98, -2412, -786, -4322, 515, 930, -1467, -2608, -3287, -363, 881, -3112, -5276, -1939, -1794, -198, -6744, -6453, -1216, -868, -1136, -1844, -4225, -1144, -463, -2293, -40, -2040, -1808, -1214, -5789, 735, -1162, -4271, -3008, -8304, 1061, -1156, -6402, -4590, -6784, 835, -1738, -1396, -3877, -4845, -72, -3918, -375, -3647, -2302, -1608, -8159, -1533, -3457, -957, -3636, -2085, -3981, -2984, -393, -6563, -454, -4316, -2912, -391, -7770, -154, -8634, -3245, -852, -4968, -428, -2861, -3898, -1510, -4373, -1559, 310, -5401, -2226, -5840, -5442, 1388, -5982, -3498, -12001, -6296, 1478, -2471, -6107, -5912, -2775, 1040, -626, -5956, -2526, -2580, 37, -222, -3260, -729, -3968, -2029, -982, -2254, 52, -7660, -4143, -1877, -1721, 0, -9829, -3081, -1249, -993, -278, -7732, -3697, -1019, -611, -13, -9038, -9054, -2074, -485, 538, -3289, -6787, -3741, -897, 1122, -1718, -5178, -3493, -3183, 1177, -2659, -4875, -1197, -3555, -370, -7024, -2896, 359, -1109, -10480, -3403, -1167, 750, -742, -682, -1152, -273, 631, -359, 1694, -417, -631, 967, 650, 2436, -396, -3188, 1408, 1224, 2455, -890, -4362, 1385, 1311, 1974, -2045, 6241, 8127, 8154, 3329, 3450, 5414, 7353, 7504, 4539, 2359, 2893, 4853, 5406, 5810, 1415, -1407, 256, 1137, 6393, 2869, -4026, -1018, -3143, 6315, 2155, 1049, 1256, -932, 5055, -2328, 1888, 2348, -688, 522, 392, 1371, 1929, -161, 1861, -383, 1944, 436, 605, 4813, 1599, 2704, -665, 78, 5335, 4973, 2879, 316, -4132, 4860, 5703, 2508, 552, -2180, 3700, 5143, 1233, -840, 1420, 1344, 4776, -241, -3382, 2340, -973, 4692, 1402, -6939, 1903, 1856, 4098, 2648, -7534, 271, 2871, 3474, 2561, -2175, -3392, 2245, 3982, 1263, 431, -5024, -271, 5016, -803, 2239, -404, -4052, 5332, -1549, 3452, 1413, 285, 4676, -1912, 4399, 2200, 1950, 4041, -4243, 5284, 2722, 2343, 5254, -7932, 5851, 3446, 2058, 6540, -3096, 5792, 3984, 1509, 7012, -79, 5012, 3853, 851, 6625, 1757, 3676, 2829, -245, 5303, 2223, 2010, 665, -2602, 2883, 1032, -577, -3711, -5186, -375, -2619, -5703, -5238, -928, -593, -1219, -2876, -1840, 1076, 1431, 735, -2153, -756, 1646, 2671, 1002, -3381, -237, 951, 2829, 384, -4943, 284, -1173, 1765, -810, -2245, 794, -1385, -1118, -718, -879, 1043, 812, -1580, 712, -1844, 617, 1873, 391, 1316, -2229, -997, 2264, -60, 984, 724, -1524, 2405, -3089, 20, 2026, 1053, 2434, -4403, -739, 2167, 2422, 2259, -839, -659, 1578, 2632, 1650, 247, -828, 419, 1795, 319, -694, -1902, -798, -256, -1868, -4354, -3589, -864, -1973, -3668, -3444, -3657, -939, -447, -4164, -3165, -2500, -2023, 36, -5331, -7651, -2047, -2187, -969, -5920, -3386, -2484, -1053, -2807, -5063, -1625, -3744, -1227, -2107, -4562, -1828, -5324, -3535, -728, -5042, -2414, -4339, -4821, -435, -5803, -1451, -1994, -2642, -1112, -3598, 21, -334, -3353, -2078, -1599, 842, 223, -10118, -2764, -810, 845, -733, -5822, -4143, -1101, -5, -3691, -6578, -4775, -1730, -1606, -2260, -4415, -2597, -1198, -2413, -567, -414, -1047, -116, -1646, -993, 475, -162, 1059, -1526, -3779, -725, 354, 1978, -2684, -12033, -4345, 581, 2077, -5734, -6570, -7242, 245, 967, -9861, -2620, -13415, -1008, -2056, -3860, -341, -4412, -3183, -16484, -1046, 515, -1713, -3196, -5242, 290, 709, -847, -1213, -3672, 196, 859, -581, 130, -2007, -1415, 1056, -926, 842, -1128, -1339, 832, -1558, 1039, -1686, 429, -331, -120, 936, -4188, 662, -2454, 1262, 705, -4660, -622, -3390, 1469, -124, -3031, -3537, -1024, 687, -2587, -4361, -8373, 1268, -716, -3647, -8348, -7906, 2426, -1858, -1745, -2939, -3338, 2563, -1919, -2562, -1240, -1319, 1873, -1528, -8172, -740, -557, 537, -905, -5316, -928, -343, -1343, -382, -3196, -2312, -285, -3772, -710, -2727, -4046, -461, -2665, -536, -163, 1395, -2433, 1451, 700, 744, 289, -3430, 3049, 1103, 669, 769, -1953, 3410, 273, -1166, 1312, 104, 3125, -2569, -3797, 1211, 1460, 2553, -9160, 187, 970, 1832, 1920, -2243, 1512, 854, 1220, 1268, -1188, 946, 536, 262, 486, -2287, -1878, -373, -200, -702, -7091, -6246, -1769, -1183, -2357, -3416, -2110, -2397, -3818, -3072, -1011, -1305, -1881, -3042, -1255, -866, -1461, -1339, -1058, 828, -1576, -1817, -975, -769, 1895, -384, -1716, -768, -1761, 1759, 840, -483, -1031, -4489, 255, 635, 564, -2962, -4338, -2924, -1584, 561, -6641, -1145, -3653, -8057, -1020, -37, -382, -2246, -1516, -6472, 2152, -2088, -1904, 192, -4472, 2868, -3651, -1567, -85, -2669, 2764, 450, -990, -2113, -2535, 2310, 1626, -728, -874, -1695, 1779, 891, -1428, 971, -1296, 972, -2200, -4166, 1114, -1924, -589, -5780, -7825, 221, -2285, -3323, -1691, -3487, -433, -1145, -6073, -230, -2525, 154, -513, -7508, 585, -2832, 982, -1242, -6886, 1164, -3535, 1293, -3821, -2967, 1527, -2951, 1074, -3743, -1304, 1347, -1822, 720, -957, -1811, 494, -1426, 611, -92, -6989, -125, -2038, 500, -931, -3428, -303, -4554, -223, -4165, -768, -1666, -8290, -1602, -9042, -497, -5360, -2436, -1486, -5364, -1441, -9835, -372, -324, -4806, -3517, -7210, 429, -68, -4413, -9929, -2532, 63, -987, -4720, -4172, -1231, -2332, -2607, -7687, -1449, -1587, -10531, -2300, -6691, -997, -1616, -2487, -1538, -2714, -1635, -947, -2399, -1748, -1546, -1794, -870, -4803, -2651, -1760, -1825, -737, -1535, -4039, -2533, -1711, 154, -150, -5934, -2753, -484, 1019, -933, -7073, -2866, 5, 1070, -3637, -5680, -4080, -1145, -109, -2894, -3903, -7681, -5198, -2927, -1149, -3309, -13945, -4640, -7076, -712, -4112, -8977, -2381, -8465, -1063, -5929, -6661, -2103, -10346, -2170, -6951, -5306, -1922, -8416, -3844, -6126, -3923, -918, -6938, -3284, -5098, -1641, 232, -4789, -1976, -5542, -320, 584, -2403, -1930, -9068, -89, -478, -1271, -3167, -8062, -453, -3539, -1173, -4139, -5769, -675, -2442, -1128, -3323, -5757, -424, -655, -992, -3463, -5377, -141, -554, -1804, -4584, -4849, -221, -1415, -3947, -3942, -5664, -758, -2821, -5311, -2857, -7407, -1807, -4706, -4203, -2952, -7839, -3364, -7523, -2643, -4658, -7175, -4285, -10408, -1974, -8684, -5055, -3850, -10031, -3020, -4467, -3341, -3543, -10283, -8030, -2506, -2501, -3456, -9502, -4641, -2462, -2508, -3156, -8393, -1826, -4311, -3506, -2583, -6880, -1017, -10471, -5698, -1943, -5264, -1200, -6114, -8872, -1308, -3958, -2024, -3779, -9555, -714, -3006, -3196, -2756, -7642, -318, -2665, -4451, -2181, -7800, -232, -3248, -5932, -1995, -9862, -387, -5214, -7985, -2473, -5118, -634, -10596, -6671, -590, 828, 1140, 897, -4455, 836, -453, 1020, -805, -8201, 1240, -3314, 1013, -1857, -4285, 878, -10100, 575, -1714, -2248, -534, -4527, -1053, -2108, -1398, -3738, -3428, -5782, -2540, -1106, -8967, -1979, -7322, -2507, -1225, -4764, -375, -5824, -3301, -1909, -188, 210, -5874, -5913, -2966, 2004, 13, -2887, -11871, -3077, 2628, -182, -2256, -7499, -2382, 1941, -20, -2963, -6365, -2134, -214, 85, -3343, -6950, -2664, -5440, -97, -2891, -9609, -4111, -6051, -512, -1859, -6414, -4387, -2835, -991, -1289, -3253, -1811, -2261, -1819, -1961, -2581, -154, -3716, -3708, -4248, -2866, 428, -5957, -4586, -5717, -1388, 250, -1362, -2812, -4076, -46, -232, 202, -2495, -3994, 145, -473, -293, -2952, -5457, -607, -394, -2999, -2029, -5329, -1868, -402, -1902, -730, -2852, -2581, -860, 88, 94, -1471, -1763, -1976, 154, 599, -1287, -409, -3449, -1277, 655, -2383, 311, -2279, -4613, -296, -5104, -67, -199, -7294, -3867, -8220, -1944, 800, -3967, -4647, -7273, -3447, 759, -2999, -810, -6999, -836, -375, -3924, 91, -6887, 602, -3578, -9585, 263, -6229, 989, -4598, -5303, 443, -5622, 594, -814, -1778, 190, -5693, -602, 161, -20, -1138, -6369, -3280, -345, 693, -4110, -7452, -10517, -2039, 522, -6520, -10090, -1877, -3949, -111, -3046, -10215, 153, -3469, -1228, -858, -4303, 197, -3005, -4583, 20, -1881, -1980, -3873, -6635, -204, -969, -12129, -6634, -2248, -1165, -1067, -3411, -14424, -1216, -2162, -1806, -3472, -10512, -1015, -3433, -2713, -8785, -8797, -1523, -4765, -3220, -6674, -6629, -2753, -1521, -3010, -5032, -4341, -2046, 556, -2567, -5564, -2743, -961, 1157, -2728, -4715, -2157, -1369, 577, -3680, -2853, -2554, -3246, -935, -4763, -1830, -3949, -5571, -2846, -4939, -2357, -7216, -5189, -5632, -5028, -5879, -6176, -3218, -5355, -6656, -7252, -2515, -2071, -1519, -8773, -3268, -1159, -1901, 43, -6697, -2751, -1582, -2470, 251, -5832, -3593, -4347, -3784, -472, -4930, -4996, -2333, -5359, -1016, -3163, -5633, 387, -3609, -360, -1554, -4434, 1352, -1620, 357, -653, -2786, 1356, -955, 589, -304, -1947, 814, -1709, 232, -331, -2133, -95, -4579, -960, -981, -3216, -1523, -9511, -3151, -2752, -5009, -4028, -4287, -3325, -6326, -7580, -8835, -2825, -1915, -12577, -9888, -6154, -2438, -1518, -16095, -8728, -4523, -2806, -1754, -12740, -4331, -4205, -4441, -2262, -10771, -1767, -4063, -7782, -2945, -5524, -579, -3885, -4925, -3475, -2923, -415, -3872, -3641, -3227, -1621, -1265, -3880, -3911, -2963, -1030, -3607, -3291, -2867, -3751, -882, -10713, -2529, -1312, -6123, -944, -7948, -2416, -1050, -9084, -1181, -7284, -3032, -2472, -8240, -1961, -10394, -3808, -7257, -8586, -3656, -7317, -4037, -6884, -10044, -5869, -5150, -3836, -5947, -2580, -1817, -63, -1113, -9139, -3509, -732, 2203, -2243, -7660, -666, -399, 3078, -3463, -3819, 709, -1157, 2992, -3260, -3360, 978, -3220, 2087, -1007, -5895, 413, -6009, 198, 468, -7010, -938, -5300, -2032, 601, -3241, -3022, -4062, -1096, -266, -2400, -3961, -3889, -541, -976, -2954, -2619, -4510, -1088, -1482, -3296, -1694, -3411, -1747, -2278, -2002, -1510, -1566, -1565, -2514, -1351, -1842, -731, -667, -2777, -2532, -1939, -895, -195, -2897, -6893, -1062, -1717, -852, -4150, -2542, -28, -2440, -3422, -5473, -890, 332, -3761, -6847, -2396, -1703, -569, -8831, -1617, -2322, -6028, -4802, -1462, 155, -5542, -3449, -3114, 1202, 196, -3242, -1460, 157, 2223, -1741, -982, -1798, 999, 2258, -4027, -504, -2424, 1102, 1597, -309, -858, -1269, 835, 568, 1041, -1503, -573, 96, -538, 860, -2239, -1024, -476, -2009, -584, -3420, -2146, -1219, -4215, -3154, -5719, -2372, -4291, -5754, -5190, -10646, -2435, -8020, -6840, -4674, -10945, -3730, -3218, -7367, -2206, -6945, -6626, -2250, -5292, -295, -4357, -7260, -2140, -4918, 608, -2141, -4577, -3272, -6137, 700, -806, -4059, -8068, -7767, 67, -862, -2626, -6891, -9693, -1233, -2828, -190, -4005, -13823, -3004, -7741, 1078, -2999, -7404, -4510, -6447, 1406, -1940, -6131, -1874, -7410, 1286, -1144, -5664, 323, -9777, 931, -869, -4100, 1027, -5152, 3, -929, -3232, 550, -2988, -2172, -960, -3351, -688, -2065, -5764, -756, -3666, -2056, -1780, -2930, -674, -3646, -3854, -1655, -605, -1363, -3738, -5948, -1755, 749, -3931, -4082, -4189, -2218, 1260, -7893, -3659, -2275, -2730, 775, -2651, -2921, -1098, -2917, -955, -1833, -3719, -945, -3060, -4225, -3916, -10150, -1887, -3949, -4420, -7190, -3920, -2446, -6648, -3020, -2013, -1590, -1372, -9080, -3407, -786, -1784, -739, -6573, -5994, -1196, -4625, -954, -5556, -5302, -2991, -6013, -1596, -3238, -2435, -6571, -2527, -1443, -1401, -1446, -12956, -1688, -623, -692, -1449, -9256, -1925, -434, -936, -2392, -6646, -2804, -1317, -1929, -6513, -7742, -4992, -3521, -3534, -4806, -5703, -11473, -7166, -5587, -1267, -2751, -6370, -6135, -5950, -694, -2614, -5122, -3782, -4633, -1739, -4493, -4723, -2648, -3777, -4008, -2574, -3483, -2485, -3100, -5203, -825, -2691, -3275, -2515, -3061, -688, -2771, -4995, -2296, -1519, -1502, -3411, -4819, -2533, -989, -1955, -4571, -3057, -3199, -1354, -1337, -6963, -2599, -4289, -2705, -1162, -9032, -3603, -5197, -5798, -2242, -8257, -6241, -4827, -14563, -5396, -9561, -8319, -4668, -6812, -10119, -13471, -6541, -5009, -7422, -5365, -9996, -4516, -3651, -8204, -3802, -6835, -2656, -2308, -3295, -3198, -5994, -1602, -2187, -1432, -3289, -6904, -1313, -3172, -1048, -4012, -7904, -1301, -4601, -1706, -5041, -7724, -1318, -5221, 9893, 6950, 9734, 7998, -3265, 9282, 6868, 9246, 7306, -879, 7376, 6226, 7886, 5027, 487, 4021, 4447, 6120, 1103, 1111, 198, 1432, 4432, 1914, 1731, -41, 270, 2231, 2670, 2032, 765, 1266, -1073, 2285, 1999, 57, 2064, -1174, 1420, 1713, -4, 2528, 18, 208, 1011, 2531, 2550, -774, -987, 247, 4302, 2273, -1992, -512, 1069, 5292, 2765, 601, 259, 2656, 5511, 3997, 1922, 615, 3785, 4756, 4676, 1487, 1453, 4497, 2866, 4353, -1937, 1953, 5063, 1640, 2681, -406, 1008, 5555, 2238, -1792, 3028, -2156, 5709, 1660, -707, 4037, -1697, 5139, 1333, 1563, 3710, 144, 3461, 2740, 1301, 2213, 216, 279, 3573, -1012, -915, -575, -2572, 4101, -6155, -5955, -974, 776, 4613, -6417, -2489, -160, 3507, 4596, -3033, -2042, 376, 4807, 3740, -543, -3313, -291, 4973, 2331, 90, -4669, -1893, 4219, 1493, -1212, -3760, -962, 2868, 1060, -4321, -2394, 350, 1828, 136, -1545, -2829, 486, 1568, -150, 91, -6332, -233, 1223, 791, 955, -972, -1221, 404, 1432, 1927, 1262, -538, -576, 1452, 2499, 1585, 1448, -604, 990, 2197, 668, 2686, -106, 401, 527, -548, 2888, -561, 375, -5179, -647, 2015, -2836, 934, -1038, -715, -143, -6899, 1233, 1224, -2034, -4156, -4439, 707, 970, -5586, -6884, -3377, -790, -1534, -10400, -6638, -2846, -2670, -2224, -4720, -4488, -2764, -3121, -458, -2227, -2505, -3033, -2467, -895, -1393, -2155, -2927, -2708, -2651, -2073, -2826, -2188, -5623, -2440, -4684, -3015, -1380, -7691, -1396, -8090, -3008, -1330, -2732, -1107, -4133, -4632, -2552, -1529, -1286, -2098, -8551, -5014, -1830, -1746, -1218, -6037, -4872, -2835, -2461, -1528, -5820, -4374, -3178, -3227, -2825, -7996, -6427, -3596, -3601, -3179, -7516, -5452, -5289, -4098, -2506, -5674, -2494, -6585, -5832, -2239, -5129, -1965, -6739, -7895, -2245, -6075, -3593, -12704, -6431, -2473, -5989, -8011, -5722, -6393, -2616, -3421, -7615, -2983, -6584, -2418, -2383, -7676, -2490, -4175, -2544, -2873, -5523, -3387, -2302, -3566, -4987, -4964, -5383, -1518, -5393, -9860, -6669, -8023, -1758, -6861, -8351, -5303, -8833, -3061, -5485, -5551, -3952, -6464, -5607, -3324, -4449, -4393, -4230, -9981, -2401, -4229, -6714, -2955, -12310, -2517, -4169, -5225, -2739, -8967, -3045, -3946, -2176, -3315, -6666, -3395, -4325, -1027, -3142, -4725, -3617, -6432, -1090, -1997, -3373, -3991, -8417, -1858, -1347, -2983, -4736, -5653, -2642, -1435, -3830, -5918, -4329, -3166, -2324, -6439, -7517, -2801, -3681, -4403, -7189, -8238, -1590, -3374, -9389, -3213, -5115, -866, -2799, -9122, -880, -2473, -394, -3240, -5616, 298, -980, -554, -4377, -4575, 393, -443, -1834, -4171, -5295, -725, -757, -4530, -2532, -10057, -2845, -1725, -8647, -698, 3683, 4463, 1825, -124, 2917, 3531, 4227, 4240, 35, 2671, 2782, 3483, 5662, 524, 2710, 504, 2319, 5436, 1115, 3175, -3508, 963, 3424, 1254, 3130, 543, -871, -2756, 521, 2540, 1362, -2417, 1540, 422, 1314, 82, -1317, 3275, 2037, -1669, -2950, 414, 3145, 2608, -6893, -6719, 2433, 1962, 1679, -5415, -244, 4197, -253, -665, -1236, 3013, 5400, -2164, -3883, 1545, 4445, 5907, -791, -4302, 2164, 4659, 5654, -2012, -1539, 953, 4030, 4641, -1671, 1948, -2540, 3135, 2907, 2284, 4142, -1780, 2362, 508, 3697, 5003, -104, 1246, -2934, 3750, 4673, -57, -356, -7216, 2959, 2988, 324, -1990, -788, 1999, -1190, 1584, -6384, 1481, 1711, -875, 2793, -3376, 1938, 1773, 816, 3392, -910, 903, 1359, -1253, 2831, -1619, 1642, -188, -731, 255, -5239, 3956, -4493, 2828, -8619, -2533, 4856, -4998, 3833, -1001, -1084, 4393, -3073, 3923, 618, -1142, 2651, -4611, 4240, 1265, -881, 210, -5301, 4501, 1122, -499, 193, -4510, 3983, 262, -1048, 1801, -4984, 2540, -291, -2398, 2929, -4414, 757, 537, -2886, 3307, -4481, 103, 1723, -996, 2971, -4340, -56, 2378, 779, 1931, -1460, -617, 2165, 1457, 356, 324, -1165, 1014, 957, -219, 749, -1223, -80, -772, 268, -53, -1566, 7, -3643, 100, -2097, -3244, -380, -5296, -443, -5329, -3409, -1484, -4828, -764, -7308, -397, -2607, -4755, -1428, -5650, 1043, -4558, -3782, -2276, -4608, 1365, -4631, -3248, -2331, -4564, 937, -3603, -4689, -1848, -5570, -114, -4942, -6652, -1041, -8989, -1444, -4558, -4670, -768, -8841, -1623, -2698, -3964, -1574, -4905, -1545, -2709, -3772, -1889, -3496, -2481, -4800, -3080, -487, -3199, -2491, -6607, -2057, -99, -3860, -956, -4339, -1413, -1421, -5906, -119, -5179, -1661, -4126, -6756, -18, -9412, -2886, -3466, -4567, -490, -4385, -3190, -3539, -4647, -1720, -3269, -2601, -6575, -8530, -4143, -4104, -3705, -7531, -6789, -4666, -5399, -6984, -4920, -3645, -2381, -3745, -4689, -3534, -2175, -1047, -1526, -3752, -2596, -1387, -478, -439, -5222, -2893, -1772, -690, -638, -9504, -5060, -3742, -1752, -2606, -5450, -5338, -4699, -3223, -8253, -2526, -2665, -3154, -3203, -3882, -1171, -1418, -2852, -1799, -2719, -769, -956, -3830, -592, -3001, -893, -876, -6593, -122, -2411, -1366, -712, -6676, -453, -1599, -2241, -174, -5179, -1158, -1393, -3593, 190, -8457, -1606, -1738, -5732, -191, -5409, -1791, -2832, -8734, -1571, -1648, -1687, -4201, -8852, -4170, -527, -1602, -4051, -5823, -9139, -730, -1987, -3716, -3907, -11209, -1602, -2843, -3955, -3356, -8787, -2174, -3993, -4651, -3786, -10514, -2840, -4097, -4885, -5179, -7967, -4623, -2429, -3972, -9638, -4419, -2540, -1185, -3861, -8437, -2446, -244, -882, -5374, 2071, 5274, 358, 3097, 2901, 3087, 5290, 179, 2440, 4240, 4286, 5227, 2071, 2279, 5543, 4640, 4868, 3722, 3871, 5615, 4256, 4036, 3915, 4598, 4038, 3599, 2603, 2792, 4107, -820, 2694, 333, 669, 2386, 1352, 545, -2228, -1132, -297, 2616, -4617, 66, -478, 928, 1899, -3609, 2059, 1131, 3144, 3561, -2802, 2953, 1802, 4341, 5646, 176, 3275, 1193, 4703, 6660, 1689, 3389, -406, 4168, 6646, 1494, 3245, -202, 2362, 5312, 546, 2550, 672, -1315, 1314, 539, 1039, 99, -305, -1380, 537, -1736, -2001, 1107, 2170, -629, -4142, -3126, 824, 2788, -3120, -323, -1983, -1179, 3342, -5279, 1431, -1203, -15504, 3500, -8644, 1589, -289, -1264, 2896, -1443, 1085, 870, 683, 1977, 1646, 1753, 1766, 762, 1584, 2523, 2441, 2014, -410, 1828, 1733, 2143, 1665, -2458, 1779, -580, 1122, 1333, -2289, 443, -2330, -694, 1141, -851, -5301, -1406, -4307, 201, -240, -704, -1220, -1759, -349, -231, 1902, -3224, -1091, 1012, -494, 2122, -3760, -3942, 1430, -685, 606, -911, -2434, 572, -741, -1792, -827, 187, -959, -812, -1344, -3080, 1182, -2765, -1219, -396, -2854, 1454, -6097, -2278, 349, -346, 984, -5858, -1832, 586, 208, 185, -3048, -159, 35, -1482, 5, -482, 323, -1365, -9304, -245, 965, -492, -2805, -809, -578, 1008, -2378, -2286, 462, 348, 162, -3310, -1562, -1082, 1163, 61, -1521, -886, -10256, 1089, 201, -321, -304, -1749, 651, -802, -186, -472, -786, 487, -3197, -700, -1998, -2250, 30, -5741, -1330, -5332, -5894, -1304, -5224, -2301, -5321, -7508, -3500, -4848, -4435, -5400, -4138, -5353, -5387, -4648, -5943, -2636, -4929, -5749, -2260, -5960, -2548, -4522, -5910, -1570, -11322, -3391, -4287, -4582, -2262, -5475, -4224, -5056, -2469, -3304, -3208, -5285, -15497, -1671, -2481, -3233, -7761, -3302, -2240, -1290, -4304, -7305, -748, -3313, -959, -4685, -8587, -138, -2873, -1691, -5040, -9775, -750, -2175, -3745, -8771, -4605, -2461, -1900, -7811, -6671, -3613, -5205, -1659, -16669, -3382, -4566, -5873, -1742, -7431, -2962, -7979, -4609, -2757, -3770, -4067, -8369, -3708, -5023, -1628, -5470, -4799, -3005, -7284, -787, -4821, -3364, -3245, -8660, -1205, -3282, -2386, -5394, -21635, -2749, -3176, -1431, -9820, -6374, -4620, -5153, -994, -7799, -3404, -5608, -4621, -1549, -4089, -1986, -5269, -2318, -3083, -733, -1068, -3624, -1497, -3572, 905, -463, -2247, -1346, -2685, 1208, -663, -1894, -1327, -2314, 308, -1739, -2844, -1368, -2315, -1855, -2198, -5478, -1863, -2681, -4685, -2098, -9135, -3094, -4042, -6115, -3475, -7313, -4275, -7120, -11604, -4665, -5881, -3958, -4008, -5829, -2099, -5042, -3526, -1499, -3020, -955, -4614, -3889, -628, -2335, -978, -5090, -5198, -6693, -2397, -2436, -6940, 413, -3124, -1150, -1766, -4277, 569, -1716, -1089, -821, -3726, -133, -1335, -2118, -574, -4771, -1118, -1788, -4533, -1089, -6483, -1203, -3295, -7803, -1687, -7666, -782, -7035, -5120, -1532, -8367, -640, -8173, -3809, -1042, -5039, -758, -4992, -2834, -766, -2795, -1257, -4148, -1562, -1042, -1781, -2915, -3268, -924, -2126, -1678, -6465, -2094, -1358, -3889, -2569, -2978, -1369, -2705, -4702, -4670, -1376, -1192, -2399, -4298, -3541, -1823, -1405, -688, -4292, -1129, -4441, -1744, 165, -4909, -83, -8700, -2234, 64, -6111, -44, -5034, -3463, -1129, -8544, -933, -3916, -5216, -4297, -9496, -3055, -4060, -5058, -6889, -5530, -6880, -5043, -5511, -3563, -3947, -5509, -4620, -9826, -3077, -3703, -4110, -2473, -9109, -3073, -4321, -4340, -1237, -6172, -2252, -4721, -5560, -1206, -4919, -1714, -3427, -5315, -2540, -3081, -2010, -2043, -3547, -5688, -1806, -3034, -1653, -2336, -6185, -1448, -4324, -2606, -1612, -4627, -1750, -5049, -5608, -1617, -4301, -2017, -4837, -10434, -3121, -3926, -1761, -4320, -6408, -8827, -3809, -1742, -3933, -5517, -7753, -4951, -2753, -3445, -5975, -8179, -10358, -5800, -2992, -6739, -8190, -6338, -11959, -2968, -4780, -3609, -3461, -5121, -3250, -2908, -2881, -3423, -3601, -3812, -2465, -4197, -6068, -3341, -5352, -3239, -7876, -8982, -3038, -5348, -4535, -9111, -5954, -1789, -3284, -4922, -5043, -5908, -801, -2898, -4112, -2754, -6412, -731, -4210, -3444, -1365, -6418, -1557, -7601, -3078, -1010, -6761, -2828, -12376, -2903, -2004, -8207, -3801, -7601, -3812, -5223, -8936, -4466, -7246, -7516, -7407, -6897, -5080, -11590, -5389, -3402, -4261, -6361, -6756, -2689, -1936, -2229, -7673, -4149, -1919, -1751, -1495, -5312, -3567, -2082, -2883, -2053, -4058, -3840, -2715, -6105, -3758, -4086, -4213, -3681, -9655, -7278, -5025, -4966, -5049, -5135, -8523, -6913, -6019, -5251, -3028, -3299, -7882, -4942, -4176, -1766, -1731, -6423, -4198, -3960, -1243, -1617, -6221, -5419, -4669, -1382, -2249, -7777, -9966, -5818, -2018, -2800, -11253, -7221, -7299, -2961, -2481, -11771, -6067, -8673, -4298, -1633, -8038, -7159, -8733, -5798, -1147, -5952, -6394, -8592, -4579, -1465, -5627, -4546, -7981, -3215, -2877, -6026, -3884, -7634, -3317, -6058, -4868, -4166, -8562, -4982, -14775, -3836, -5090, -10727, -6290, -6773, -4127, -5961, -10665, -4646, -4232, -6169, -5847, -7353, -4010, -3031, -13470, -5311, -4702, -4576, -2828, -9168, -5029, -3332, -5408, -3340, -7328, -5208, -3058, -5153, -4181, -7644, -6256, -3696, -5304, -5532, -8713, -9250, -4765, -7600, -6878, -7966, -7504, -4952, -13402, -4994, -6511, -4579, -4783, -7267, -3893, -6276, -3691, -5962, -6824, -4245, -7964, -4287, -11713, -9145, -5564, -10924, -6544, -7722, -13292, -6756, -7277, -10999, -4536, -12303, -6903, -6011, -8762, -3384, -8783, -7266, -5094, -1758, 539, -1365, -4791, -4721, -2575, 280, -2241, -2165, -6321, -5738, -745, -3091, -1159, -8461, -5071, -2328, -3748, -1559, -5463, -2303, -4316, -4237, -2643, -4484, -1084, -7260, -4257, -2386, -5808, -502, -9351, -3275, -2278, -5282, -685, -5953, -2327, -4449, -2162, -2211, -4664, -2235, -11079, -874, -6058, -3890, -3257, -3600, -1054, -5523, -3336, -5205, -2252, -3012, -4600, -3611, -4839, -2429, -12304, -6370, -4213, -3251, -3541, -3974, -8535, -3213, -2980, -5442, -2141, -8424, -1759, -4405, -5868, -2593, -9943, -955, -5322, -4002, -5310, -10303, -894, -3296, -3313, -9276, -8628, -1514, -3113, -4392, -6355, -6785, -2784, -5316, -8109, -6109, -6047, -4949, -6070, -7465, -6936, -5086, -6889, -2832, -7369, -6030, -3774, -4208, -1253, -8404, -3820, -3682, -2389, -679, -3868, -2504, -5052, -2034, -1099, -1895, -2037, -4638, -3185, -3038, -868, -2173, -2866, -6430, -9804, -424, -2733, -2356, -7989, -5663, -811, -3507, -2854, -5952, -4975, -1880, -4178, -3808, -6414, -5351, -2707, -4521, -4528, -8718, -2235, -4135, -4597, -4677, -8254, -804, -6268, -4446, -3836, -9373, -640, -2699, -4008, -2669, -9369, -1061, -1315, -3832, -2167, -3958, -1699, -1593, -4476, -2625, -2028, -2486, -3115, -4525, -4117, -1429, -3197, -5245, -3167, -6147, -1533, -3729, -5266, -2557, -5763, -2090, -4646, -4320, -2833, -3939, -3538, -6731, -4405, -3527, -2938, -8177, -7466, -5799, -4107, -3175, -6661, -4212, -7763, -3838, -5107, -3701, -2595, -6778, -3437, -9132, -3471, -2411, -6444, -3854, -5967, -4620, -3650, -7721, -4753, -4224, -4841, -6932, -4576, -5572, -3361, -3391, -7439, -2177, -7651, -2442, -2727, -4821, -1431, -15264, -1812, -3167, -3935, -2009, -9428, -2125, -4544, -3858, -4016, -8822, -3363, -6455, -4417, -8595, -10716, -3291, -9719, -6556, -7831, -9129, -2689, -14961, -11897, -5334, -6140, -4082, -10302, -5638, -4772, -4843, -9858, -6458, -4837, -4478, -4410, -4187, -4183, -5874, -3020, -4188, -2493, -3906, -4757, -1700, -4013, -2692, -5375, -4042, -1573, -4192, -4489, -7997, -4416, -3228, -4402, -8039, -8710, -3564, -6046, -3384, -5108, -7259, -3197, -3036, -2377, -2994, -7188, -4405, -1827, -2444, -2195, -9858, -5077, -1842, -3757, -2257, -9107, -4206, -2181, -6015, -3182, -8494, -4305, -2950, -6589, -4508, -13431, -5429, -4654, -6104, -3609, -6191, -7352, -4738, -6426, -2113, -4235, -6788, -3346, -7461, -1490, -4282, -4553, -3139, -9259, -1646, -5598, -2930, -3924, -11458, -2406, -7733, -2064, -5018, -10187, -3546, -10919, -2177, -5494, -8587, -4725, -11695, -3399, -5475, -7729, -5695, -6528, -5951, -5992, -7138, -6525, -4372, -11951, -6613, -5776, -6964, -4011, -9602, -4965, -4208, -6534, -5737, -7235, -3685, -3411, -5973, -14497, -7473, -3750, -3294, -5934, -5699, -9083, -5165, -3318, -6469, -4112, -8797, -8091, -3206, -7289, -4758, -7385, -13164, -983, -2618, -1430, -6237, -6901, -2444, -3226, -1698, -4829, -7651, -3930, -3933, -2127, -4045, -9454, -3907, -4364, -3061, -5928, -9154, -4016, -4725, -3306, -10267, -6507, -4147, -6880, -2790, -3706, -5966, -4041, -8154, -2811, -1877, -6466, -3886, -4459, -2223, -1488, -7046, -3697, -2987, -1109, -2058, -7563, -3708, -2432, -971, -3695, -8193, -2804, -2787, -2060, -8280, -9323, -1595, -4177, -3683, -6437, -12501, -1280, -6059, -3919, -2800, -11453, -1949, -6527, -3085, -1425, -9891, -3501, -3659, -2804, -1343, -11028, -5985, -1959, -4378, -2792, -6076, -9615, -1845, -9014, -5251, -3560, -11352, -3228, -4238, -3017, -2309, -8728, -5041, -3193, -1803, -1228, -6368, -2893, -4937, -2003, -375, -5447, -749, -9557, -3031, -201, -5586, 505, -3438, -4368, -737, -5887, 1022, -1503, -5542, -1723, -6895, 933, -961, -7023, -2900, -11516, 625, -1297, -12475, -4248, -9750, 605, -2522, -7218, -5872, -6866, 534, -4454, -4463, -8378, -6013, -297, -4135, -4382, -14230, -4859, -2286, -2914, -7407, -9845, -3623, -4097, -2763, -5304, -9005, -3696, -2495, -3462, -2115, -8544, -5963, -1348, -3882, -987, -4457, -7470, -1439, -3310, -899, -2184, -5336, -2739, -3180, -1397, -1390, -5633, -3845, -4027, -2116, -1766, -6484, -3335, -5731, -2782, -2970, -5438, -3612, -7501, -3358, -3969, -4071, -5267, -6485, -3966, -4561, -2938, -8219, -4049, -4750, -6253, -2217, -9780, -2429, -5805, -7919, -1982, -7617, -1792, -7054, -5938, -2146, -6167, -1846, -8343, -5433, -2438, -5843, -1846, -9650, -6905, -2410, -7158, -1193, -9534, -10417, -2000, -12900, -399, -6743, -7047, -1744, -7605, -143, -4190, -4915, -2287, -4745, -836, -2500, -4223, -4594, -3315, -2877, -1744, -4608, -11793, -2157, -6722, -1960, -6021, -5013, -913, -6898, -3122, -7735, -3919, -49, -4869, -4548, -7977, -4797, 55, -4032, -4615, -6303, -6967, -623, -4596, -4538, -4574, -7977, -1834, -6415, -4690, -4360, -7051, -2900, -7709, -3442, -6105, -5977, -3239, -7452, -2039, -4954, -4467, -3367, -4470, -1369, -2568, -3856, -3578, -2824, -1408, -2082, -5095, -3258, -2876, -2106, -3241, -9538, -3047, -4457, -3370, -6342, -6241, -4427, -7243, -4289, -10023, -5125, -7772, -8947, -3484, -8418, -7120, -5262, -7066, -2664, -8736, -10187, -4987, -4961, -2399, -13039, -5705, -7055, -3659, -2047, -8617, -4646, -5492, -3211, -1724, -6067, -4670, -3438, -3741, -2229, -5475, -3997, -2771, -5357, -4129, -5380, -3021, -3085, -7386, -7047, -5142, -2896, -3938, -7699, -6699, -4483, -3973, -5248, -8577, -6873, -3673, -6820, -8722, -9155, -7596, -3153, -15415, -11084, -7236, -7217, -2845, -10475, -6924, -7289, -7188, -2861, -10334, -6502, -11166, -7858, -3324, -9201, -5974, -8784, -9039, -3723, -6916, -4568, -5916, -8996, -3705, -6047, -3705, -5480, -8428, -3879, -6029, -3437, -5810, -8973, -4596, -5666, -3464, -5546, -8858, -5801, -5238, 15165, 2220, 10293, 9886, 8359, 14767, 5638, 9599, 9189, 10163, 13535, 6920, 7288, 6853, 10144, 11358, 6285, 2129, 1303, 9299, 8385, 4271, 475, 1013, 8251, 7587, 1764, 688, 1984, 6512, 8553, 128, -249, -611, 3759, 8828, -867, 256, -6937, 5346, 8283, -328, -509, -264, 6056, 6842, 1506, 1386, 1412, 4279, 4689, 3435, 3697, 2469, -3939, 3292, 4896, 4869, 3037, 1643, 3547, 5663, 5200, 3137, 1847, 4912, 5548, 4834, 2720, -1288, 5655, 4299, 3914, 1229, -7067, 4971, 1763, 2803, -2426, -3092, 2336, 631, 1807, -2942, -2819, -836, 1185, 836, -1536, -5055, 1715, 493, 50, -1759, -1808, 2202, -1063, -527, -2432, -664, 1002, -2089, -1745, -6010, -296, -2271, -1179, -4133, -3901, 1201, -5958, -318, -3961, -898, 2363, -3331, -739, -3644, -745, 2815, -2835, -2475, -6246, -1696, 2777, -3418, -2199, -6704, -874, 2129, -6288, -653, -4689, -13, 121, -6716, -278, -5560, -415, -8130, -1474, -1032, -5326, -1839, -1879, 429, -3153, -3739, -3077, -201, 1026, -7811, -3606, -2202, -740, 728, -17050, -3349, -857, -1628, -260, -9764, -3061, -223, -1872, -1284, -5219, -3867, -554, -3348, -1211, -3364, -4911, -2136, -5185, -949, -3196, -6153, -3803, -4069, -1546, -4273, -11220, -2293, -5814, -3211, -5874, -9225, -1543, -7654, -4453, -6492, -8702, -2022, -3445, -3538, -5984, -11835, -3137, -2778, -3033, -5314, -7909, -4071, -3630, -3184, -5341, -5343, -5856, -4960, -3531, -6565, -3590, -10830, -5853, -3938, -7846, -2905, -4797, -4374, -4549, -6669, -3654, -3344, -2147, -5170, -6659, -4874, -3849, -841, -5242, -9633, -3131, -5622, -363, -4773, -11108, -1937, -7477, -427, -4271, -6912, -1979, -7271, -877, -4149, -5375, -2753, -6536, -2024, -4627, -4488, -3442, -6879, -4657, -5827, -4222, -3640, -8266, -9185, -7401, -4772, -4017, -8267, -7768, -7331, -6096, -5318, -6145, -7204, -6757, -7470, -8929, -4211, -6455, -7478, -7380, -8746, -2915, -6007, -11402, -6159, -5388, -2385, -5302, -10046, -4972, -4620, -2669, -4366, -5827, -4223, -5372, -3708, -4377, -4049, -3955, -7320, -5222, -5567, -3183, -4157, -10406, -6307, -7145, -2926, -4542, -15272, -5720, -7004, -3214, -4562, -9529, -5296, -6641, -4069, -4579, -8847, -6434, -8733, -5309, -5471, -11759, -9022, -9436, -6037, -8163, -10258, -7918, -3794, -5935, -12911, -7705, -6644, -1835, -5753, -8442, -7612, -6550, -1397, -5687, -7383, -8925, -7595, -2077, -5466, -7698, -9273, -9340, -3655, -5085, -7302, -8444, -9286, -6043, -5029, -5724, -8654, -9691, -11093, -5857, -4828, -10089, -13643, -10036, -7491, -4924, -11296, -12769, -6573, -5603, -5821, -10109, -9007, -5561, -4060, -7081, -9241, -7857, -5062, -4361, -8146, -8987, -7778, -4128, -6806, -9337, -8181, -8017, -3304, -13477, -9510, -6888, -7578, -3356, -8468, -7269, -6063, -7039, 8741, 3952, 6975, 8689, 7461, 7965, 4037, 6240, 8235, 7088, 5365, 3753, 3586, 6965, 5982, -709, 2291, -8624, 5319, 4748, -4470, -1068, 620, 4040, 4512, -2797, -1090, 558, 3121, 4183, -367, 1438, -3119, 1993, 3133, -592, 3228, -56, 84, 2502, -3397, 4205, 2057, -3665, 3187, -7182, 4323, 3214, -7878, 4075, 583, 4282, 4808, -2543, 4389, 3794, 4987, 6275, 193, 3820, 5394, 5719, 6925, 1546, 2253, 5734, 5810, 6541, 1361, -167, 4882, 5234, 4868, 613, -2154, 2816, 4206, 1450, 2241, -1280, 161, 2891, 1105, 3465, -94, -137, 982, 2355, 3369, -380, 154, -1515, 1786, 2095, -2752, -326, -166, -31, -185, -7063, -1308, 1459, -1995, -2564, -3374, -2490, 1997, -3375, -4284, -2141, -2608, 1926, -5535, -3928, -2394, -1395, 1648, -6430, -2423, -3605, -709, 1407, -5782, -3505, -4673, -1148, 1209, -7441, -5364, -4258, -3250, 862, -14465, -1560, -2896, -10573, 87, -6434, -360, -1859, -5823, -1257, -4715, -237, -1667, -3697, -2150, -4467, -520, -2329, -2695, -1664, -4289, -1902, -3308, -2223, -1493, -3401, -7242, -3745, -2694, -1736, -3402, -4590, -3741, -4302, -1632, -5902, -1390, -3761, -6770, -1434, -5788, -121, -3823, -8089, -1653, -3119, 547, -3750, -5731, -2427, -3391, 832, -4036, -3416, -3804, -6366, 572, -5602, -2191, -5673, -6006, -681, -10616, -1883, -7549, -4492, -4344, -8372, -2417, -7063, -5091, -6680, -6508, -3977, -5308, -5015, -2084, -6696, -7297, -4537, -3235, -970, -5048, -11384, -4676, -2338, -1043, -3625, -6729, -5139, -2746, -1931, -4086, -4856, -6156, -4940, -3320, -7477, -4850, -11532, -9552, -4050, -10210, -7748, -6825, -6017, -2984, -5601, -10312, -3707, -5121, -1871, -4374, -5851, -3115, -5930, -1696, -4228, -5661, -4027, -6161, -2534, -4901, -7737, -4717, -5627, -4341, -5874, -10902, -3761, -6915, -7455, -6447, -7895, -3654, -18720, -13483, -6889, -6565, -5180, -7222, -9348, -7138, -6865, -9112, -5547, -8639, -6701, -8530, -8968, -6065, -11853, -6201, -8321, -7126, -7279, -10446, -6732, -6220, -6626, -6673, -6152, -9638, -4512, -6631, -6094, -4599, -9879, -3458, -7760, -6785, -4192, -6707, -3481, -12012, -8925, -4470, -6211, -4762, -10526, -11451, -5108, -7719, -7049, -7306, -11076, -5739, -13789, -8367, -6461, -9835, -5993, -8478, -7185, -7141, -8315, -5675, -5652, -6084, -9976, -7564, -5021, -4584, -6254, -17176, -7346, -4589, -4718, -7559, -9942, -7128, -4647, -6373, -9423, -8840, -7063, -4976, -12287, -15035, -9816, -7145, -5328, -7967, -9515, -11203, -6917, -5561, -4906, -6676, -8212, -6556, -4962, -3648, -6157, -6806, -6157, -4169, -3571, -6516, -7052, -5704, -4041, -4950, -6261, -8524, -5911, -4554, -8975, -5784, -10226, -7143, -5486, -8860, -5819, -10541, -7835, -6689, -7483, -6120, -10127, -7749, -7490, -9826, -6313, -10173, -9714, -7104, -11192, 4458, 2870, 7118, 7575, -11243, 3348, 1685, 6636, 7254, -4944, -609, -1185, 5416, 6456, -1588, -1007, 1479, 4418, 5674, 1846, -1635, 2980, 4191, 5048, 4140, -5635, 3251, 3899, 4070, 5286, -975, 2726, 3097, 2906, 5483, -3298, 1238, 1617, 2440, 4715, -1532, -1686, -609, 1671, 2256, 3037, -3160, -3006, -1311, -3579, 5003, 1111, -937, -2107, 2997, 5863, 4373, 1221, 1334, 4453, 5773, 5938, 1434, 2093, 3956, 4642, 5925, -301, 2054, 2136, 2482, 4000, 794, 3022, 2635, 1047, -3405, 2476, 3858, 4138, 880, 467, 2019, 3438, 4503, -16, 1300, -669, 1587, 4082, -466, -1437, -4634, -1483, 3305, -533, -8420, -6667, -6500, 2350, -889, -2601, -5765, -5648, 864, -804, -2077, -1985, -2407, -1520, -198, -1745, -1615, -1994, -1470, 346, -1230, -3470, -2001, -12, 236, -1557, -10862, -1871, 353, -839, -2868, -6024, -2304, -86, -3463, -4276, -3767, -3760, -1369, -9859, -4134, -3319, -5611, -3591, -4525, -3073, -3684, -3931, -4325, -3927, -2727, -4850, -3074, -2305, -7892, -3983, -7513, -5005, -645, -4649, -6189, -13061, -6612, -176, -1450, -2832, -12060, -2315, -1227, -694, -1063, -7551, -1224, -4165, -1451, -781, -4934, -1604, -4534, -3464, -1419, -4606, -2728, -3025, -4085, -2318, -5605, -3903, -2358, -3239, -3209, -5515, -5165, -1846, -3741, -4852, -5936, -7169, -2057, -5461, -7091, -9465, -8962, -3333, -6245, -6562, -7129, -9671, -4477, -6273, -6751, -5552, -11221, -3905, -7579, -9701, -7571, -6112, -4143, -9314, -11239, -9671, -3291, -6937, -9167, -8239, -4276, -1935, -9456, -8446, -5746, -2875, -1615, -5504, -7196, -4037, -2975, -2231, -6170, -5945, -3717, -3918, -3490, -11158, -4926, -4759, -4549, -3561, -4858, -4167, -5523, -4314, -2564, -3533, -3755, -4182, -4855, -2477, -4788, -3605, -3583, -8525, -3652, -11478, -3554, -4205, -6096, -5556, -7369, -3680, -5724, -2706, -6369, -5545, -4411, -7552, -1721, -6916, -6312, -6501, -9040, -2130, -7502, -9788, -11790, -7529, -3799, -6730, -11512, -10105, -6241, -7233, -5022, -7393, -9046, -6171, -8237, -3758, -6358, -8040, -7227, -5758, -3342, -6662, -6714, -10113, -5566, -3729, -8050, -6617, -7486, -7133, -4795, -10028, -7793, -5152, -9578, -6239, -9313, -9877, -4713, -9609, -7260, -7252, -11532, -5531, -9312, -8461, -5703, -11067, -7127, -9298, -11221, -5150, -9746, -8573, -9261, -7140, -6157, -8772, -8980, -9628, -4919, -11494, -8258, -8132, -10059, -4307, -7427, -8265, -6819, -8427, -4611, -4321, -8843, -6113, -6823, -4983, -3504, -9175, -6057, -6212, -4853, -3996, -8911, -5606, -6328, -5217, -5402, -9312, -4622, -7036, -6732, -7241, -10592, -4093, -8669, -7196, -8304, -10786, -4047, -11327, -6214, -7631, -8903, -4054, -8959, -6600, -8118, -8014, -3898, -6536, -8753, -12148, -8668, -3674, -5627, -9694, -9457, -10135, -3660, -6112, -7095, -7659, -4829, -7102, -6498, -5768, -7102, -6936, -6734, -7755, -5765, -7561, -4010, -6378, -10869, -5938, -7981, -2349, -6027, -9615, -5920, -8148, -2201, -6023, -9381, -5366, -7391, -3445, -6148, -9821, -4920, -5938, -6092, -5824, -8314, -5159, -5012, -5167, -5281, -8243, -6280, -5023, -3392, -4739, -11745, -8310, -6182, -3030, -4111, -11193, -10530, -9371, -3623, -3622, -7625, -10460, -15111, -4370, -3745, -6713, -8825, -9433, -4118, -4924, -6975, -8062, -9147, -3587, -7154, -9096, -8549, -11286, -3679, -7569, -12180, -8767, -15624, -4455, -6400, -7286, -7822, -10345, -5084, -4614, -4905, -9334, -7582, -4162, -2134, -2845, -6630, -3609, -2167, -17, -740, -1735, -452, -502, 1187, 862, 480, 1284, 214, 1356, 1522, 1168, 1752, -121, 484, 1039, 556, 972, -1504, -1278, -845, -1431, -1274, -3916, -3357, -4865, -5202, -5812, -7535, -5205, -8171, -12697, -8842, -10191, -6426, -6474, -10853, -7187, -8928, -6003, -6521, -7274, -6582, -9937, -5139, -7692, -6007, -6221, -12284, -5021, -11105, -5926, -5930, -9419, -6087, -10641, -6514, -5528, -7850, -8223, -8236, -7463, -5493, -7054, -9559, -7551, -8722, -6216, -6346, -8339, -8193, -10419, -7790, -6011, -6303, -10805, -11837, -9272, -6640, -4770, -9711, -11618, -9646, -9355, -4113, -7521, -11748, -11232, -9333, -4237, -7380, -13581, -16033, -5474, -4666, -8751, -16529, -14081, -4155, -4990, -11089, -10811, -10738, -4401, -5478, -11609, -8690, -8725, -5911, -6111, -9299, -8324, -8702, -6955, -6697, -7727, -9391, -11741, -6187, -8326, -7471, -11304, -13708, -5902, -16418, -8593, -8898, -9336, -6526, -8725, -11389, -6642, -8172, -7757, -6779, -15746, -5817, -7703, -7228, -7294, -15452, -6349, -7830, -5863, -10127, -14359, -8933, -9199, -5960, -13144, -13676, -12484, -12232, -8559, -10365, -13134, -8452, -10297, -12472, -8164, -12280, -8102, -9018, -8343, -7143, -11929, -10335, -9879, -9266, -7373, -13421, -14360, -10807, -12668, -8397, -14255, -10952, -8965, -8240, -9241, -9871, -10460, -7929, -7171, -9145, -8414, -11568, -7746, -7378, -8297, -8713, -11369, -7947, -6951, -7257, -9695, -10045, -8383, -5811, -6687, -9494, -9430, -8879, -4912, -7073, -9061, -8905, -9013, -4489, -8822, -8683, -8541, -8780, -4744, -10384, -8191, -8858, -8695, -6062, -8407, -8082, -9874, -9036, -9017, -7240, -8356, -11460, -9588, -8399, -6772, -8776, -14374, -9760, -6181, -6490, -9244, -12994, -9444, -5628, -6383, -9540, -9428, -9244, -6381, -6598, -9933, -7944, -9549, -8644, -6929, -11073, -8064, -10229, -13556, -7220, -13279, -10255, -10962, -15329, -7872, -12613, -25624, -11789, -13159, -9007, -9435, -12071, -12529, -9989, -9948, -7981, -11921, -12561, -7856, -9965, -8073, -14185, -12093, -6894, -9528, -9832, -11276, -11549, -6884, -9140, -13116, -9690, -11024, -7704, -8890, -12101, -9682, -10647, -8939, -8893, -11875, -10968, -10730, -9519, -9104, -13947, -13496, -11562, -9776, -9449, -13752, -11391, -13395, -6389, -9624, -16465, -6442, -7466, -6840, -8839, -10579, -6320, -6329, -8537, -9431, -11509, -6801, -5775, -12776, -11379, -15505, -7008, -5151, -9260, -9727, -9754, -6292, -4510, -7001, -7445, -9310, -5955, -4042, -6402, -6402, -11807, -6881, -3903, -7043, -6345, -13333, -10060, -4227, -9048, -7133, -11438, -15372, -5080, -11930, -8676, -8836, -9456, -6219, -8870, -8569, -6909, -7821, -6827, -6598, -6804, -6603, -7425, -6689, -6119, -6132, -7994, -8306, -6495, -7395, -6363, -12395, -10567, -6375, -10852, -6267, -12735, -12963, -6237, -13169, -5422, -8806, -12784, -6011, -8836, -5921, -9344, -7571, -5404, -4695, -11035, -7611, -3635, -3964, -1767, -2650, -2313, -810, -1627, -153, 156, 10, 820, 120, 134, 1037, 737, 1271, 736, -1071, 492, 190, 517, 160, -4510, -1503, -1532, -1610, -1669, -11587, -5463, -4267, -5254, -4741, -8280, -15162, -7212, -6867, -7758, -8927, -12272, -8991, -6882, -7694, -6603, -11110, -9255, -7925, -6672, -4942, -10171, -7343, -9089, -6634, -4274, -9386, -6059, -9577, -6845, -4610, -9093, -6397, -9470, -6499, -6164, -9931, -8640, -9571, -6537, -7640, -13149, -9624, -10646, -7687, -7070, -15768, -7213, -14142, -10798, -7979, -13044, -6278, -11236, -14927, -12957, -15540, -6364, -7963, -10746, -7243, -13890, -7234, -6878, -9893, -5107, -9341, -8881, -7192, -11066, -4954, -7535, -11376, -8430, -12321, -6650, -6869, -15032, -9283, -9100, -14197, -6967, -15599, -7797, -8152, -8514, -7974, -11753, -5950, -9176, -6387, -10935, -9870, -5311, -10894, -6324, -16341, -9195, -6390, -11663, -7128, -10019, -9261, -11025, -11791, -7568, -9002, -9379, -8652, -9165, -7394, -9352, -8714, -6234, -8158, -7802, -9070, -7488, -5989, -9042, -9344, -8042, -6586, -6864, -12293, -10880, -7590, -6404, -8422, -10823, -10168, -7802, -6856, -9588, -7647, -9961, -8530, -7155, -9057, -6166, -11078, -9897, -6731, -8667, -5798, -14226, -12170, -6542, -9721, -6427, -16335, -13202, -7267, -13399, -7961, -11308, -11535, -9159, -17204, -9854, -9240, -10689, -11900, -12876, -11019, -8235, -11085, -12564, -9966, -10665, -7782, -13555, -11505, -8935, -8942, -7669, -14441, -11151, -10175, -7768, -7950, -10255, -12934, -12839, -7580, -8995, -8485, -17870, -11892, -7973, -12074, -7532, -11100, -16350, -7935, -14477, -6916, -9097, -11120, -7431, -9535, -6860, -8405, -8211, -7274, -8373, -7644, -8478, -8013, -7825, -8867, -8892, -9286, -9248, -9057, -10672, -9452, -11033, -9892, -10176, -13720, -10212, -14444, -9741, -10905, -15857, -11506, -18255, -10059, -11254, -11994, -10817, -13174, -10355, -11549, -10362, -10549, -10748, -10769, -14835, -10895, -11818, -9494, -11104, -12061, -14763, -13702, -9219, -11137, -9622, -10427, -15396, -9879, -11703, -9868, -7912, -13792, -11483, -13580, -11679, -7388, -10885, -13456, -23639, -12058, -8362, -9625, -13018, -12653, -11652, -11247, -9247, -11012, -10383, -11355, -17928, -9261, -9521, -10202, -11240, -15208, -9977, -9045, -11615, -12414, -10114, -3970, -8334, -5869, -8970, -9229, -4310, -13488, -5688, -9313, -7789, -4518, -13098, -6176, -6320, -6221, -4871, -11503, -6972, -5298, -5173, -5314, -10167, -8163, -5540, -4841, -5239, -10524, -10875, -6467, -5194, -4537, -9662, -12428, -7536, -6002, -3813, -6677, -8850, -8483, -6964, -3407, -5263, -6918, -9347, -8347, -3453, -4954, -5744, -10223, -10946, -4005, -5209, -5377, -11445, -14886, -4655, -5733, -5939, -11334, -14268, -4448, -6726, -7298, -9502, -10389, -4105, -8853, -8121, -8992, -8542, -4941, -11153, -8126, -9763, -8478, -7911, -8585, -8538, -12136, -8421, -9635, -5953, -6932, -11206, -5318, -5835, -3192, -3692, -4885, -2082, -2022, -652, -966, -1735, -91, 56, 997, 624, -174, 646, 569, 1520, 996, 80, 193, -421, 798, 70, -999, -1448, -3357, -1397, -2473, -3820, -4221, -12012, -4667, -7935, -10437, -7136, -8222, -5044, -15169, -7808, -7900, -8154, -6085, -15738, -6267, -7565, -9659, -9547, -10544, -5693, -7656, -8504, -8180, -8827, -5122, -9644, -6047, -7165, -7995, -4756, -13342, -4937, -8674, -7220, -4943, -8547, -5094, -16086, -6744, -5605, -7958, -6338, -8025, -6950, -6103, -10312, -8173, -6047, -7703, -6154, -11872, -9040, -5874, -8139, -6608, -7372, -8626, -6821, -8573, -7953, -5926, -8458, -8241, -10022, -9390, -6105, -9443, -8828, -12613, -9850, -7899, -11362, -8784, -12567, -12242, -10835, -9466, -9091, -9564, -11749, -9632, -7662, -9057, -7084, -8390, -8928, -7209, -7888, -5694, -8031, -9046, -7896, -7005, -5408, -10131, -8701, -9926, -7092, -6175, -15552, -8263, -14198, -8416, -7737, -10128, -7893, -19648, -12171, -8898, -8567, -6952, -12958, -14097, -9430, -8408, -5916, -8995, -10367, -11185, -9023, -5393, -7523, -10380, -13151, -10173, -5283, -8047, -13643, -9635, -11738, -5285, -10362, -15064, -7977, -12013, -5510, -7585, -10676, -7525, -10252, -6394, -5210, -9757, -7497, -9468, -8360, -4284, -10698, -7487, -10423, -11830, -4265, -12672, -7843, -14152, -16256, -4728, -11014, -8814, -10652, -14344, -5211, -9543, -10244, -8002, -10937, -5613, -8743, -13338, -7280, -9437, -6035, -8430, -14408, -8177, -8749, -6535, -8710, -9385, -11559, -7945, -7557, -9657, -7736, -17573, -7224, -8791, -12450, -7361, -12250, -7151, -7702, -15480, -7544, -10976, -7976, -6557, -10490, -7928, -9773, -9783, -6497, -9302, -9016, -9029, -12423, -7322, -9630, -11402, -8466, -14060, -8830, -10799, -12772, -8346, -11323, -11245, -10842, -13624, -9383, -9700, -15633, -10561, -14654, -11197, -9269, -11468, -10332, -10460, -10194, -8898, -9169, -8613, -8676, -9056, -8087, -8695, -7213, -8226, -8841, -7587, -9421, -6443, -8782, -9153, -8005, -10086, -6048, -10301, -9820, -9972, -9947, -6109, -12165, -10936, -15691, -10654, -6898, -12113, -13707, -12451, -12240, -8843, -11489, -16271, -10362, -10891, -13140, -11680, -10329, -9403, -9133, -14873, -12631, -8537, -8669, -8325, -13261, -13581, -8354, -8244, -8241, -15671, -13412, -9423, 8813, 10397, 10659, 8490, 6718, 8016, 9942, 10005, 7905, 6152, 5336, 8532, 7937, 6131, 4406, 2646, 6102, 4708, 3216, 1406, 3898, 3039, 3748, -79, -1617, 3079, 1561, 2902, -2100, -2952, 1341, 2545, 195, -3053, -11033, 2008, 3509, -1404, -1508, 91, 3027, 3571, -1222, 373, 2781, 2993, 2556, -2068, 1033, 3773, 1180, -249, -3393, 1549, 3892, -1764, -2551, -5508, 3372, 3544, -603, 2574, -5315, 4896, 2781, -1798, 4386, -3700, 5320, 1226, -148, 4572, -3826, 4542, -1227, 1932, 3323, -4813, 2329, 722, 1888, 248, -3533, -2016, 2718, -179, -2923, -978, -4124, 3098, -7186, -240, 829, -3245, 2120, -3145, 966, 1626, -3372, 108, -941, 1235, 1246, -2906, -3208, -446, 1013, -730, -2199, -3670, -1099, 775, -5065, -1910, 888, -3410, 562, -3306, -711, 1797, -3112, -131, -1919, 646, 210, -1290, -1860, -506, 648, -8568, -1965, -5820, 1012, -1470, -2090, -1702, -7525, 1603, -13126, -1030, -82, -2749, 1247, -2015, -1730, -1340, -1634, 414, -49, -693, -8504, -2743, -122, 377, 1062, -158, -7438, -409, -30, 1753, 991, -4883, -600, -115, 826, 387, -4172, -381, 605, -3979, -874, -6606, -627, 1205, -1725, -2647, -4240, -2689, 1415, 1168, -7682, -3140, -14648, 1137, 1515, -4479, -2758, -2630, 193, 427, -1744, -839, -862, -819, -2238, -1687, 103, -714, -218, -9737, -3465, -557, -1492, 439, -5712, -4673, -1832, -2782, 106, -4317, -3455, -177, -3986, -1112, -3988, -2608, 1099, -5197, -2516, -2516, -2493, 964, -5540, -3544, -1251, -3593, -604, -3070, -5482, -744, -7616, -3978, -1337, -12462, -1125, -7786, -8380, -742, -8535, -2774, -4063, -11811, -1018, -7103, -5773, -3582, -5192, -1771, -6211, -6737, -4687, -2416, -2447, -3962, -9365, -5494, -1557, -2921, -2362, -8857, -3950, -1830, -3256, -1536, -4470, -3112, -2783, -2844, -1492, -2905, -3625, -3987, -1998, -2360, -2419, -5022, -5214, -1659, -4169, -2912, -6536, -5247, -2094, -6068, -4404, -12883, -4173, -3040, -5744, -6282, -6009, -3920, -3782, -4821, -8265, -3423, -4906, -4196, -4536, -11284, -3433, -6995, -4462, -4385, -7178, -6038, -8637, -4578, -3974, -5469, -12730, -7578, -4933, -3589, -5236, -6031, -5920, -5391, -3457, -5734, -5707, -5407, -5162, -3782, -6514, -8844, -6256, -4151, -4442, -7372, -9864, -8398, -3579, -5075, -8072, -5520, -11035, -4064, -5974, -7418, -4383, -9173, -5413, -7400, -6295, -4422, -7142, -6321, -8876, -5980, -5285, -6607, -6100, -9986, -6726, -6866, -7026, -5898, -9719, -9170, -9123, -7579, -6793, -8407, -14646, -18011, -8116, -10370, -8259, -10472, -8183, -8928, -11228, -11437, -10430, -5390, -8883, -8491, -7834, -9696, -4587, -7441, -8322, -4980, -7794, -5017, -6123, -8598, -4332, -6821, -6314, -5720, -8598, -4967, -5271, -8158, -6420, -8336, -6520, -3875, -5633, 5939, 7498, 3816, -4110, -683, 4949, 6931, 3325, -2868, 505, 1173, 5324, 1999, -103, -833, 276, 3248, -27, 688, -4897, 2082, 1688, -1912, -381, -3131, 840, -120, -967, -2153, -1680, 262, -8665, -1243, -4695, -1078, 2055, 581, -249, -3880, -118, 2793, 3291, 1934, -1310, 732, 2875, 4391, 2177, -864, 1025, 2300, 4922, -22, 1560, 741, 209, 5020, 664, 3346, 174, -5471, 4348, 3231, 3735, -310, 664, 2497, 3428, 3167, -723, 2976, -596, 1225, 2238, -952, 3683, -853, -10966, 1769, -404, 3105, 129, 580, 2038, 690, 982, 575, 1900, 2110, 1487, -2467, 895, 1792, 1323, 1460, -1122, 695, 1478, -612, 98, -272, -430, 1702, -4604, -3266, -769, -1265, 2188, -9726, -3476, -2752, -435, 2395, -4439, -2936, -3515, -479, 2059, -3641, -4340, -1159, -2214, 1049, -3233, -5523, -933, -5408, -557, -1956, -6331, -3005, -3736, -2091, -1428, -5164, -7148, -1484, -2616, -2569, -6325, -3510, -129, -2039, -5926, -8524, -1105, 286, -1427, -4879, -3383, 539, -554, -1496, -3624, -1878, 1532, -3859, -1822, -4389, -1500, 1812, -6993, -1536, -6968, -1613, 1247, -2806, -1111, -12036, -2403, -315, -3363, -1365, -10198, -5101, -3183, -6179, -2557, -4521, -3642, -10706, -2277, -4067, -1316, -846, -6087, -392, -4254, 2, -513, -3761, -8, -2085, -262, -2486, -3954, -700, 279, -1985, -7065, -7600, -2532, 1410, -3414, -3956, -5137, -6374, 1188, -3260, -3883, -1687, -7568, -775, -4153, -3148, -403, -4011, -7901, -6251, -1121, 12, -2929, -3366, -9076, -538, -175, -3405, -1694, -10890, -1364, -1269, -5414, -2133, -11695, -3369, -3862, -4455, -3469, -13321, -5873, -5912, -2569, -4727, -12900, -7660, -4463, -2150, -5530, -10061, -6325, -4875, -2331, -6140, -8754, -5603, -6225, -2366, -6844, -9310, -7169, -6174, -2398, -8265, -8591, -9419, -5748, -2759, -11208, -6633, -8630, -4414, -3587, -6956, -6090, -11112, -3346, -4689, -5276, -6994, -12638, -3257, -5399, -6281, -8506, -7850, -3844, -4581, -12244, -8998, -5467, -4606, -3000, -7437, -11024, -3982, -5235, -2214, -5741, -14559, -3415, -5922, -2329, -5662, -8330, -3771, -7270, -2936, -5776, -6914, -5191, -9555, -3375, -5683, -7191, -8282, -11319, -2918, -5387, -8629, -11193, -14322, -1951, -4908, -10776, -7617, -10083, -1392, -4472, -11289, -6296, -7170, -1536, -4382, -8472, -6262, -6463, -2432, -4708, -6520, -7024, -7264, -4142, -5191, -5795, -7500, -9399, -6018, -5687, -6166, -6950, -11079, -5344, -6695, -7335, -6520, -9568, -4151, -9366, -7915, -6668, -7892, -3664, -11859, -7509, -7343, -6626, -3604, -8203, -7554, -8792, -5775, -3673, -7738, -8497, -8781, -5335, -3895, -10352, -12172, -6126, -5371, -4573, -10832, -11214, -4691, -5896, -6076, -7233, -7274, -4370, -6438, -8981, -6794, -6313, -4781, -6075, -13189, -8392, -6425, -2794, -5014, 2094, 4062, 775, 920, -1146, 2417, 2589, 4936, 3051, 1403, 3034, -10342, 6765, 3262, 2457, 3411, 2193, 6895, 1430, 2447, 3277, 3251, 5772, -1085, 1645, 2595, 1631, 3600, 407, 163, 1554, 580, 1491, 38, -2249, 561, 2839, 709, 1250, -4808, -409, 3087, 963, 3247, -3035, -3537, 1405, 2691, 3955, 288, -2711, 1159, 3357, 3626, 2891, 2046, 2533, 2067, 2343, 4115, 3543, 1477, 434, -88, 3895, 3370, -3691, 2722, -1088, 1912, 1934, 1207, 3667, 520, -1062, 770, 2300, 4338, 568, 928, 733, 877, 5272, -1201, 1467, -155, -3759, 5542, -4377, 614, -2033, -7205, 4832, -1541, -509, -3463, -4153, 3246, 619, -614, -4077, -3923, 1866, 1284, 58, -3159, -5763, 2323, 970, 376, -1191, -9738, 2746, 571, -167, 163, -2991, 2090, 518, -1675, 606, -1285, -9, -5, -3919, -66, -1182, -4671, -1455, -6022, -2343, -1636, -6281, -3871, -8176, -6628, -825, -2241, -6933, -6604, -3550, 737, -1412, -7588, -3941, -1937, 1675, -2996, -5979, -3184, -1677, 1721, -5206, -4511, -3779, -2436, 861, -2233, -3094, -4685, -4646, -1042, -1167, -1844, -4323, -12324, -5943, -1999, -1198, -3691, -5630, -4199, -7219, -1373, -3991, -2125, -623, -4238, -1845, -4512, 48, 499, -2786, -1957, -3037, 1229, 646, -6367, -2558, -2054, 1263, 280, -2470, -2945, -2372, -233, -556, -172, -2081, -3973, -2944, -1700, -275, -2455, -10596, -1288, -1024, -2207, -5302, -4313, -725, 450, -5139, -15950, -1506, -2403, 849, -4575, -11619, -1381, -5521, 241, -3617, -10848, -3952, -4205, -629, -2762, -9008, -10166, -4152, -1251, -2646, -13814, -3670, -7243, -2545, -4078, -6141, -2909, -7624, -5308, -7177, -4140, -3531, -3071, -7346, -6519, -4223, -4333, -1660, -7726, -5860, -5727, -4502, -1749, -7183, -6056, -7503, -4412, -3281, -4656, -5271, -6772, -4827, -7504, -3650, -3645, -5648, -5674, -9299, -3597, -2461, -5263, -5178, -6334, -3368, -2197, -5509, -3935, -7568, -2920, -2855, -6093, -3293, -11061, -3300, -3975, -6699, -3216, -6724, -5529, -4297, -7015, -3670, -5820, -8424, -3813, -6821, -5098, -6949, -4491, -3662, -6529, -8867, -9136, -3331, -4482, -6795, -12447, -9999, -3576, -6464, -8371, -8162, -10053, -4297, -6243, -11225, -7268, -8150, -4944, -5010, -7377, -7233, -6136, -5842, -5271, -5335, -8012, -5435, -6803, -6653, -4850, -9710, -6171, -6797, -8058, -5448, -11619, -7080, -5864, -8252, -6766, -11448, -5552, -5293, -7839, -8005, -9893, -4396, -5711, -7421, -8020, -8635, -4153, -7208, -6681, -7290, -7992, -4352, -8804, -5837, -7035, -7624, -4365, -8369, -5335, -7635, -7078, -3812, -8074, -5399, -9177, -6562, -2998, -8894, -6445, -13334, -6483, -2447, -9350, -9490, -11962, -6895, -2528, -7762, -14601, -8024, -7449, -3536, -6936, -11336, -7346, -8039, -5960, -7576, -12136, -9686, -7937, -8472, -9287, -3496, -7503, -8433, -8897, -10383, -4426, -5678, -6649, -7783, -6855, -7695, -4832, -4747, -6722, -5148, -7399, -4425, -3662, -6695, -4683, -4367, -4128, -3404, -7448, -5218, -3807, -3883, -3796, -8240, -6667, -4906, -3967, -4597, -8482, -9104, -7851, -4858, -5533, -8476, -10049, -10036, -6751, -6587, -8181, -7837, -7628, -6463, -8581, -7612, -7054, -7060, -4725, -11410, -7441, -7732, -8435, -4225, -7490, -8598, -9807, -9328, -5025, -5693, -12061, -14319, -6423, -7758, -5131, -9252, -16790, -5234, -17193, -4865, -7176, -12803, -5477, -7934, -4707, -6494, -11724, -6881, -6387, -5316, -6151, -11360, -9805, -6221, -7437, -5109, -10351, -13271, -7217, -9062, -3882, -9080, -7205, -10676, -7973, -3569, -9486, -5212, -11092, -9780, -4564, -12814, -4973, -8225, -13128, -7084, -12401, -6159, -7772, -7994, -9596, -10001, -8795, -7764, -6861, -9734, -8743, -13018, -8587, -6936, -10458, -7666, -16832, -13248, -7464, -11157, -6865, -13350, -8835, -8364, -12259, -6464, -10412, -6063, -9754, -10762, -6847, -8698, -5100, -11149, -9803, -8488, -7883, -4924, -10474, -11642, -13066, -7668, -5416, -8495, -11305, -13263, -8182, -6834, -8020, -8702, -9646, -9635, -7661, -9712, -8259, -8472, -10820, -6223, -12439, -8311, -7929, -10802, -5712, -8917, -8296, -8237, -10867, -6521, -6645, -9213, -9927, -9922, -7500, -5195, -10675, -10293, -8680, -6508, -4594, -9877, -8656, -7971, -5540, -4911, -7628, -8495, -7962, -5331, -6144, -6128, -9506, -8988, -5546, -8410, -5828, -10408, -12057, -5777, -11265, -6702, -9785, -14430, -5836, -8674, -8660, -8797, -10904, -5568, -6489, -10644, -8964, -10424, -4712, -5601, -9813, -11439, -11621, -3802, -5747, -8579, -11469, -11915, -3544, -6736, -8169, -8615, -9917, -4222, -7571, -8891, -7903, -9164, -5899, -7390, -11613, -8061, -9634, -7748, -7776, -12381, -8261, -10773, -7733, -10101, -9310, -8382, -11118, -7290, -13743, -8720, -8758, -9523, -7255, -9444, -9833, -9839, -8479, -7638, -8215, -11816, -11469, -8316, -8413, -8325, -11585, -11035, -8254, -8751, -9150, -11193, -9967, -8321, -8034, -10605, -11760, -9553, -9412, -7233, -14406, -11946, -9279, -11210, -6727, -12462, -12255, -8889, -10244, -6605, -8051, -15851, -8480, -9993, -7124, -6429, -14108, -8135, -12885, -8908, -6275, -11362, -7831, -14963, -12904, -7163, -12241, -7476, -10451, -9523, -8431, -23659, -7144, -9732, -8050, -9233, -10722, -6999, -10200, -8585, -9996, -8487, -7020, -11260, -9236, -11182, -8138, -7204, -13736, -8276, -10763, -9119, -7783, -18582, -7917, -9568, -11103, -9010, -14757, -8302, -9259, -14129, -10997, -14171, -8989, -9768, -14633, -13936, -12129, -11061, -10782, -10645, -20938, -10071, -19054, -11648, -9323, -16545, -9286, -10579, -11734, -9386, -14180, -9455, -9479, -11729, -10118, -13190, -10268, -10695, -11622, -11141, -12357, -11626, -14135, -9898, -12644, -12714, -13309, -18135, -8553, -14126, -16128, -13935, -11560, -8260, -13613, -15183, -13687, -5460, -5452, -11196, -9790, -6817, -6056, -5513, -9729, -8527, -7462, -6792, -6547, -8323, -8116, -7521, -7897, -8488, -7397, -7994, -6971, -9023, -9701, -7447, -8062, -7417, -9471, -8606, -8319, -8659, -8879, -9053, -7016, -9132, -9522, -9267, -8717, -5973, -9771, -9712, -8848, -8000, -5820, -10974, -9332, -8454, -7183, -6355, -9140, -9043, -8340, -7705, -7043, -6816, -7799, -9236, -11026, -8276, -5938, -6492, -11037, -13919, -12229, -6516, -6059, -12418, -10092, -11244, -9211, -6435, -12527, -10279, -8786, -16235, -7044, -12617, -10954, -8149, -9443, -7371, -12099, -10423, -6895, -7777, -8077, -10603, -10177, -5797, -6952, -9957, -11431, -8600, -5629, -6369, -10092, -13096, -6683, -6349, -5890, -7907, -8525, -5796, -7962, -5661, -7485, -7186, -5890, -10650, -5852, -9032, -7611, -6651, -9081, -6749, -12763, -8409, -7470, -7463, -9612, -12106, -7683, -7599, -8078, -13115, -12183, -6457, -7475, -9603, -7910, -17086, -5794, -8052, -7818, -7213, -14571, -6190, -9540, -7204, -8812, -11549, -7308, -10768, -8684, -14668, -10139, -7048, -10197, -12322, -13194, -9157, -6602, -9200, -12084, -10056, -8285, -7252, -8627, -12810, -7922, -7328, -8022, -8385, -11429, -6773, -6689, -7771, -8045, -8789, -7003, -6466, -7631, -7573, -8432, -8996, -6556, -8270, -7469, -10263, -11910, -7045, -9701, -8035, -15432, -10726, -7968, -9492, -8998, -12569, -11408, -8956, -7808, -9465, -9476, -11573, -9228, -7152, -8629, -7377, -9487, -8537, -7727, -7552, -6347, -7904, -7637, -10031, -7612, -6232, -6806, -7240, -15664, -9616, -6842, -6692, -7670, -9481, -10893, -8064, -7899, -9089, -7650, -7844, -10338, -9958, -11632, -7788, -6743, -15399, -9672, -14526, -9735, -6879, -9602, -9141, -14182, -9734, -7913, -7734, -9744, -13034, -7855, -10075, -7958, -10335, -12388, -7859, -12946, -10337, -9381, -12022, -9788, -8896, -15956, -8627, -11608, -12881, -7129, -11091, -9218, -11313, -10909, -7331, -9856, -12378, -10599, -9289, -8453, -10636, -14063, -9657, -8366, -7316, -14168, -9587, -9603, -7885, -6435, -12406, -8310, -10827, -7918, -6999, -9890, -8193, -13505, -8799, -8627, -9652, -8718, -16357, -10594, -10108, -11474, -9647, -11601, -9607, -9776, -16771, -10976, -8973, -7534, -8982, -12427, -12469, -7884, -6626, -9249, -10560, -12453, -7916, -6818, -11029, -9956, -11459, -8787, -8394, -14866, -10541, -11158, -10044, -12984, -16609, -13795, -11623, -11747, -11577, -15079, -15484, -11876, -18280, -9348, -13700, -10976, -11500, -12031, -9298, -12239, -9985, -10336, -9195, -9849, -11672, -10390, -9080, -8701, -9727, -10923, -11246, -8823, -9799, -8697, -8961, -9886, -9284, -12383, -7919, -7485, -7816, -9307, -15202, -8285, -6939, -6696, -9471, -12960, -10168, -7129, -6570, -10868, -10858, -11686, -7784, -7360, -12979, -9968, -10203, -8744, -8974, -13473, -9813, -9332, -10319, -11144, -14184, -10010, -8908, -14214, -12825, -16374, -10464, -8726, -12654, -12828, -21747, -11321, -8842, -9372, -12247, -13544, -12614, -9218, -9057, -9536, -11694, -10012, -10812, -9707, -14010, -13820, -12716, -10251, -6857, -14040, -13994, -9343, -12918, -5936, -9919, -10056, -7413, -13393, -6025, -8555, -6813, -6237, -9227, -5917, -9202, -5305, -5587, -7527, -5636, -14629, -4851, -5726, -6898, -6312, -9374, -5153, -6618, -7181, -8660, -6488, -5724, -7500, -8430, -12088, -5575, -6115, -7335, -8971, -12970, -5820, -6878, -5845, -7404, -11189, -7265, -9106, -4676, -6434, -8058, -11195, -11526, -4566, -6239, -6886, -12075, -9203, -5535, -6462, -6907, -8017, -8769, -7501, -6576, -7458, -6817, -9307, -10182, -6217, -8087, -7065, -9381, -14000, -5790, -9111, -7695, -9273, -14013, -5530, -9469, -6265, -7964, -8628, -5245, -7611, -5366, -6227, -6624, -4801, -6887, -6173, -5867, -6126, -4380, -8080, -8235, -7523, -6694, -4270, -12832, -8111, -10652, -7851, -4643, -11482, -8314, -8778, -9029, -5509, -8708, -8613, -9667, -9666, -6783, -7574, -6763, -15752, -8621, -8420, -6630, -5875, -10426, -7571, -11014, -5964, -6041, -8652, -7110, -16756, -6136, -6739, -7334, -7024, -8682, -7497, -7024, -6649, -7826, -6229, -9272, -6467, -6947, -10813, -5450, -9178, -6030, -7863, -13031, -5848, -9559, -6195, -8376, -10567, -7039, -11033, -7016, -8152, -13587, -8136, -12396, -8158, -7953, -11075, -9305, -14775, -8235, -8296, -6976, -9759, -12712, -8007, -9244, -5595, -7951, -10772, -9307, -8603, -5583, -7666, -10898, -11411, -6726, -6690, -9241, -12558, -9605, -5889, -8239, -9273, -16695, -9047, -6261, -8320, -8281, -12356, -8355, -7796, -8204, -9367, -9069, -6581, -10290, -9000, -12092, -7293, -5492, -12402, -10646, -11428, -6309, -5349, -13143, -13503, -11224, -5961, -5992, -12181, -11390, -11425, -6118, -6902, -10596, -9237, -9379, -6499, -6978, -10052, -9085, -7620, -6983, -6004, -9964, -10892, -6877, -7917, -4814, -9631, -13976, -6852, -9618, -4085, -10410, -10403, -7118, -11857, -4145, -16169, -9094, -7372, -14266, -5161, -10884, -9700, -7793, -11879, -7035, -8524, -12626, -8692, -9682, -7916, -8797, -15806, -9044, -8925, -7578, -11683, -11961, -8553, -8639, -8371, -13669, -11163, -8835, -8225, -10796, -11336, -10129, -9206, -7826, -11944, -11962, -8899, -9312, -7680, -11506, -13009, -8766, -11443, -7934, -14209, -11887, -9428, -15040, -8677, -16195, -10058, -9453, -9580, -9204, -11942, -8270, -9110, -7994, -8292, -11405, -7274, -9576, -7425, -7484, -11145, -7187, -10667, -7253, -7809, -10004, -7976, -10382, -7373, -9628, -9389, -9718, -9708, -8018, -13756, -9756, -13145, -10434, -10148, -25925, -11243, -16287, -13292, -19021, -16248, -14065, -11228, -23071, -9222, -13028, -12224, -9445, -14471, -7451, -13009, -9687, -8828, -11633, -7669, -19763, -8689, -8807, -10563, -9429, -13228, -8834, -9196, -10590, -11230, -10881, -9994, -9838, -10660, -10238, -10778, -11866, -10049, -10486, -9334, -11957, -12076, -9901, -10670, -9106, -15188, -10807, -10374, -11336, -9513, -16229, -10619, -11442, -12249, -10440, -12259, -12338, -11888, -11873, -11920, -8255, 8218, 8518, 4703, 137, -5140, 7753, 8166, 5106, 540, -3250, 6287, 7108, 5555, 791, -1631, 3470, 5348, 5428, 570, 1156, -2180, 2995, 4792, 899, 3233, -668, 588, 3980, 1142, 3964, 991, -1786, 3029, -304, 3094, 702, -8279, 1340, -3512, -478, -1112, -2044, -2134, 1037, -733, -2611, 604, -2068, 3033, 1683, -1222, 1844, 96, 3771, 1510, 67, 2656, 175, 4017, 111, 1671, 3035, -950, 3948, -1754, 2724, 2612, -511, 3152, -2003, 2721, 832, 1060, 745, -727, 1420, -4550, 1752, -1065, -971, -2190, -886, 1588, 2265, -2517, -4913, 1840, 1015, 3345, -3708, -1224, 2726, 1227, 2817, -8670, -906, 2485, 2340, 982, -2849, -1446, 1054, 3226, 62, 537, -684, -2201, 3490, -115, 1737, -56, -7898, 3096, -4738, 1778, -982, -6826, 2077, -1031, 828, -3160, -10160, 152, 2222, -1483, -1212, -4060, -4423, 3118, -5594, 248, -2787, -2026, 2878, -3903, 324, -3570, 406, 1755, -1324, -124, -2496, 719, -230, -71, 80, -720, 417, -1210, -232, 469, -854, 1272, 220, -1195, 159, -4591, 2291, 1101, -1698, -765, -3671, 2406, 1309, -821, -1862, -197, 1487, 1173, 791, -3180, 112, -262, 591, 1361, -5797, -1610, -1179, -998, 493, -6925, -5420, -742, -4666, -1194, -1936, -3467, -1125, -7554, -890, 178, -2146, -2983, -3930, -629, 876, -2217, -5998, -2068, -2152, 306, -2729, -7022, -1218, -7188, -2206, -3760, -5448, -1174, -7687, -10954, -4143, -3419, -1516, -5093, -3138, -2143, -1985, -2057, -4052, -2775, -1117, -1170, -2641, -2138, -5550, -995, -1224, -2670, -735, -9578, -567, -2007, -2219, -342, -7692, 524, -3086, -1683, -948, -7077, 1296, -5370, -1194, -2221, -3256, 1257, -4950, -1069, -3383, -1472, 233, -1693, -1771, -4892, -1180, -1980, -419, -3866, -6621, -2138, -5474, -156, -6157, -4795, -4213, -5127, -339, -4524, -3590, -6570, -3194, -780, -4325, -3557, -8074, -2608, -1703, -5544, -4800, -8634, -3328, -3206, -6749, -7973, -8729, -5125, -3443, -7786, -7871, -10310, -6026, -2155, -10906, -7845, -13434, -5541, -1414, -10743, -15660, -9978, -4354, -1374, -6485, -6403, -8967, -2751, -1939, -3752, -4951, -9769, -1632, -2963, -1807, -5986, -10566, -1131, -3689, -669, -9595, -13136, -1276, -3427, -415, -12170, -10248, -2242, -3000, -1194, -7320, -5671, -4156, -2917, -3317, -4703, -3638, -4702, -3214, -6274, -3608, -2845, -3237, -3756, -5799, -3894, -3093, -2684, -4211, -6050, -5378, -4583, -3074, -4323, -7715, -6447, -7930, -4186, -4257, -7771, -5940, -12505, -5731, -4563, -6867, -5028, -13601, -5859, -5985, -5732, -4149, -8554, -4586, -10478, -4734, -3890, -6391, -4026, -10602, -4790, -4268, -6069, -4167, -7309, -6658, -5053, -6613, -4131, -6262, -15018, -6338, -8256, -3866, -5088, -7044, -8316, -12071, -4221, -4230, -5000, 5922, 2877, -2652, 7225, -1942, 5515, 2353, 3865, 6686, 1766, 4165, 730, 5510, 4940, 3051, 1358, 904, 5010, 2671, 2092, -5564, 2646, 2289, 3628, -1862, -4151, 2909, 607, 4154, -5251, -1857, 1644, 3858, 3041, -1910, 10, -602, 4972, 1045, -3599, 1195, 605, 4873, 810, -9585, 1429, 2420, 3718, -155, -2336, 1055, 3117, 1407, -5780, -222, 808, 2803, 890, -817, 1013, 1218, 2085, 3289, 1366, 1234, 2027, 2761, 4672, 1799, 198, 3034, 3583, 5051, 1359, -1866, 4040, 3129, 4518, 319, -2769, 4706, 813, 3008, -854, -1545, 4699, -3603, 235, -113, -1184, 3630, -1158, -2969, 2063, -2284, 709, -774, -662, 3467, -4019, -992, -2120, 629, 3772, -6185, 1582, -4819, 128, 3272, -7246, 1865, -11520, -1190, 3004, -2061, 812, -2624, 278, 2945, -906, -60, -184, 1228, 1770, -859, 174, 294, 611, -203, 858, 249, -1086, -1130, 369, 2022, 241, -1940, -1573, 174, 1316, 853, 929, -1203, -2489, -2748, 1830, 2295, -2578, -11287, -3262, 2455, 2604, -3068, -6488, -1289, 2326, 2428, -89, -5309, -4264, 1290, 1918, 846, -5271, -4314, -320, 742, -190, -8586, -2029, -1024, -1542, -4638, -9557, -2594, -476, -4319, -4176, -6330, -1582, 565, -4829, -1713, -7113, 14, 1462, -5858, -2051, -10818, 631, 1639, -10144, -3800, -2388, 300, 683, -5406, -5103, 539, -1099, -2281, -2988, -3971, 1757, -3044, -12130, -3151, -2522, 1792, -3792, -3819, -4758, -1578, 714, -4145, -3659, -3347, -1303, -1851, -4225, -5126, -1984, -1914, -7118, -4073, -6039, -1921, -3745, -4571, -3449, -5360, -3066, -4057, -3408, -2754, -3995, -5962, -2056, -3713, -2999, -3494, -8482, -1508, -4204, -3874, -4233, -7004, -2412, -4300, -3411, -6686, -7724, -5074, -4663, -2566, -11435, -8951, -9769, -6523, -2522, -4694, -8805, -5417, -11164, -3203, -2571, -9365, -3728, -7995, -4366, -2390, -9768, -3197, -6963, -5469, -3829, -5474, -3229, -6954, -5628, -4607, -3508, -4104, -6926, -5201, -3017, -3258, -6781, -6688, -5292, -1676, -4259, -8702, -5994, -6273, -442, -6137, -8217, -5305, -7539, 275, -8081, -8464, -5335, -7354, 147, -8731, -3499, -5803, -6249, -888, -7789, -2032, -5607, -5626, -2776, -5259, -2924, -6184, -5689, -5352, -4394, -5429, -9887, -5982, -8624, -5787, -2827, -11662, -5790, -12709, -12312, -1539, -7007, -5155, -13300, -9568, -1918, -4272, -4926, -10232, -7642, -3585, -2757, -5668, -7063, -6153, -6748, -2676, -6399, -5254, -5138, -17375, -4308, -5488, -4550, -5500, -8419, -9177, -5281, -4523, -7549, -5931, -6620, -6823, -4509, -7848, -5396, -5237, -11409, -4001, -5616, -6506, -6804, -9460, -3360, -5102, -6861, -10260, -7357, -3247, -6051, -4702, -6499, -6841, -4070, -8027, -3936, -5306, -6850, -6079, -8982, -4609, -5490, -7067, -9131, -7701, -6456, -6575, -7263, 7862, 3577, -3578, 6519, 8233, 7387, 3047, -265, 6189, 8002, 5799, 1670, 1362, 5358, 7334, 2052, 840, 1291, 4485, 6244, -1155, 1285, -128, 3838, 4508, 3300, 1833, -1630, 2803, 2706, 4122, 2146, -633, 1071, 4250, 3709, 1664, 733, 1908, 5011, 3086, 48, 1542, 2952, 3427, 2686, -1076, 1275, 2652, -882, 1801, -599, -870, 1956, 3469, -227, -932, -10134, 1353, 4678, -4543, -2031, 84, 400, 4984, -3068, -3364, 2172, 945, 5524, 86, -5368, 2475, 1878, 5646, 1514, -4784, 1380, 1394, 5202, 1857, -1441, -806, -1002, 4984, 1045, 477, -635, -4379, 4954, -1648, 1641, 644, -2797, 4288, -3253, 2644, 972, -1322, 3020, 397, 3596, 687, -101, 2814, 1834, 4182, 349, 33, 3996, 2236, 4101, 852, -964, 4939, 1990, 3145, 1720, -2451, 5058, 1103, 1231, 1760, -3097, 3923, -603, -635, 322, -2722, 262, -3038, -1189, -4472, -2620, -1060, -2899, -2015, -3919, -3436, 2012, -984, -1798, -597, -2320, 1947, 383, -902, 216, 171, 124, 1242, -747, -309, 1428, -2713, 1657, -1183, -2483, 1433, -3601, 1756, -1977, -7766, 72, -2811, 1657, -2306, -10583, -3253, -2841, 1340, -2238, -6886, -4297, -3968, 519, -1825, -2592, -2136, -5200, -1223, -213, -715, -1543, -4770, -2527, 325, 291, -1608, -3019, -1503, -1502, 1062, -2140, -1168, -526, -6645, 1322, -3678, -154, -132, -1217, 627, -7430, -550, -1186, -480, -1285, -4158, -3529, -5876, -1895, -3438, -2063, -7058, -5493, -3733, -3336, -2027, -2192, -3358, -3342, -3693, -3797, -2182, -4358, -3690, -4396, -7597, -4956, -6387, -3553, -4124, -8527, -3015, -6323, -2577, -4534, -6396, -614, -4495, -3322, -6881, -3609, -8, -3697, -7313, -9857, -2506, -696, -4470, -5693, -9221, -3224, -2436, -6633, -4554, -7967, -5896, -3135, -4783, -6263, -6039, -5094, -2310, -2602, -6682, -6548, -3167, -2169, -1943, -6395, -13476, -2639, -2628, -2692, -6610, -7486, -2796, -3263, -5452, -3570, -5008, -3103, -4128, -14413, -2148, -4189, -2920, -5986, -6298, -2296, -3889, -2034, -9934, -5030, -3815, -3879, -1032, -9400, -5194, -6892, -3773, -352, -10041, -6318, -11567, -3246, -68, -11535, -8678, -11611, -2635, -19, -9312, -9926, -10994, -2358, -75, -16555, -8034, -10548, -2571, -458, -5942, -7471, -10320, -3233, -1499, -3288, -7675, -10172, -3883, -3313, -2820, -7216, -10202, -3874, -5729, -3540, -5958, -9375, -3945, -8679, -3976, -4982, -6867, -4869, -14072, -4032, -4766, -5660, -6485, -12797, -5370, -5521, -6325, -7500, -10770, -7950, -7705, -9406, -7495, -9962, -5439, -14339, -7057, -8173, -7902, -3887, -8710, -4512, -9782, -6912, -3828, -6140, -3589, -7110, -7707, -5054, -5275, -3751, -5350, -11512, -8205, -5413, -4861, -5301, -10081, -12683, -6424, -6305, -6681, -6900, -8432, -8580, -7125, -8259, -5725, -8012, -8535, -8108, -5274, -4485, -4669, -8641, -6926, -6248, -6259, -5340, -11387, -7950, -6505, -7441, -6765, -6574, -10861, -6476, -5437, -8423, -4254, -15479, -7169, -4629, -8620, -3606, -12207, -9201, -5047, -7602, -3747, -8709, -11083, -6616, -6982, -3893, -6456, -10302, -9628, -7076, -3962, -5050, -8471, -12842, -7508, -4693, -4689, -7345, -11734, -6814, -6884, -5827, -7439, -11003, -5609, -12702, -10190, -7761, -10101, -5059, -13157, -9423, -6792, -8744, -5142, -9739, -6426, -5961, -7578, -5798, -7210, -5659, -6137, -6867, -7190, -5969, -5808, -7719, -6570, -8674, -6533, -6466, -11384, -6787, -10674, -10207, -6446, -6049, -8001, -9156, -4805, -4379, -2756, -6357, -4016, -2200, -2543, -1038, -3515, -1868, -1601, -1907, -492, -2414, -1319, -2497, -2527, -1066, -2857, -2123, -4310, -4353, -2907, -4978, -4412, -4906, -5775, -6566, -9626, -8518, -5234, -5106, -10306, -12933, -10710, -6888, -5272, -8755, -11421, -11443, -8847, -6832, -9574, -10006, -14369, -8444, -8294, -12115, -10349, -17059, -8218, -6559, -12109, -12793, -14743, -8958, -5232, -10175, -11258, -13735, -8599, -5377, -8724, -9164, -15455, -7532, -7007, -8339, -8083, -13265, -7816, -9196, -8268, -7815, -11564, -9832, -9775, -6952, -7926, -13187, -13063, -10765, -5906, -7782, -15584, -12379, -10490, -6108, -8448, -12091, -9122, -7745, -7751, -11906, -13267, -7103, -6600, -10677, -10751, -17622, -6265, -7042, -12941, -9065, -14011, -6049, -8883, -9876, -10813, -20246, -5982, -9756, -7965, -14369, -10195, -5954, -8426, -8195, -13464, -7762, -6066, -7427, -10571, -16908, -7728, -6619, -6541, -17431, -10379, -10433, -8506, -5986, -12697, -9069, -11079, -12715, -6155, -8603, -9403, -7391, -8120, -7531, -6590, -9741, -6131, -6525, -10710, -5535, -10606, -5838, -6682, -8170, -4985, -13638, -6081, -7904, -6235, -4881, -13114, -6427, -9614, -6178, -5447, -11671, -6425, -10083, -7648, -6948, -11728, -6684, -8257, -10462, -9234, -10779, -8225, -6923, -12661, -10619, -9710, -13744, -6671, -16022, -11446, -9270, -10943, -7321, -12995, -13079, -9065, -8320, -8063, -9957, -11276, -9036, -7934, -8312, -9468, -8819, -9467, -8590, -8967, -10645, -7828, -10501, -9496, -10112, -11590, -8063, -11299, -8770, -10139, -10255, -8887, -10595, -7676, -9236, -9306, -8792, -9146, -7960, -8973, -8622, -8151, -7974, -10602, -10019, -8011, -7899, -7927, -14595, -12994, -7918, -8135, -9534, -10919, -13005, -8829, -9017, -14014, -12278, -11690, -11613, -9955, -15600, -15036, -12645, -19515, -9337, -14409, -10368, -12627, -13603, -8850, -15890, -9811, -10021, -14068, -9407, -16778, -11374, -8387, -13052, -10373, -14304, -14554, -8023, -11012, -10984, -11336, -16887, -9066, -10720, -12363, -9353, -14030, -11340, -11317, -15637, -8510, -12135, -12642, -11503, -16126, -8884, -12226, -13096, -11769, -12705, -10963, -14302, -13279, -13499, -9957, -19172, -16625, -12660, -15562, -8688, -13533, -15111, -11206, -13165, -8805, -11767, -13777, -10342, -11808, -10262, -11397, -12807, -10458, -6477, -8783, -9156, -7244, -9578, -6328, -9733, -13536, -7400, -7805, -7936, -9056, -8489, -8789, -6259, -11497, -8573, -7079, -7972, -5792, -7806, -8781, -7542, -4974, -6663, -6561, -8910, -10156, -3840, -9021, -7269, -8634, -12588, -4296, -11760, -9368, -8887, -8988, -6455, -9678, -11606, -9632, -8275, -8061, -6691, -10323, -9533, -9416, -6173, -4993, -7891, -9118, -12433, -5687, -4293, -6883, -9419, -16123, -6407, -4190, -7167, -9529, -14934, -8109, -4288, -8700, -7897, -9795, -12745, -4326, -12059, -6700, -7222, -10335, -4404, -16733, -6277, -6233, -6387, -5099, -11768, -5417, -6268, -5291, -8062, -6109, -3571, -5826, -6571, -8834, -2852, -1710, -3620, -8090, -3887, -1178, -580, -1986, -3856, -2366, -779, -430, -1643, -2432, -2403, -1609, -1343, -2671, -2818, -3680, -3795, -3377, -4520, -4806, -5870, -7664, -6535, -4420, -8343, -7916, -15536, -10653, -4084, -12695, -9889, -11828, -13098, -5003, -9736, -11340, -8721, -12170, -7176, -7383, -8885, -7056, -10148, -10846, -7232, -7236, -6012, -8370, -17930, -8908, -6677, -6057, -7995, -20861, -13738, -7012, -7767, -9371, -11406, -14260, -7883, -13412, -16421, -7421, -10815, -8644, -11246, -10137, -5665, -9564, -9488, -9443, -7578, -5485, -9463, -9239, -9567, -7295, -6693, -9922, -7080, -9377, -8432, -8617, -7936, -5892, -8845, -9031, -9569, -6097, -6073, -8837, -8300, -9826, -5514, -7909, -9189, -8287, -8081, -5938, -13439, -9856, -8392, -6871, -6969, -11578, -10508, -7797, -7008, -8090, -9814, -9997, -7225, -8278, -9567, -10223, -9397, -7195, -10334, -11868, -10981, -8329, -7907, -12488, -10352, -11151, -6826, -9507, -13503, -9198, -11249, -6094, -11238, -11431, -9771, -11613, -6580, -9476, -9627, -10380, -12747, -9020, -7275, -8856, -10247, -13736, -16003, -6086, -8414, -11570, -11831, -8566, -5962, -8008, -16748, -11574, -7193, -7054, -8048, -14475, -13484, -7650, -9263, -8539, -11817, -12244, -8730, -9245, -8822, -10515, -10283, -8339, -8075, -8612, -9537, -8883, -7938, -7841, -8409, -8677, -7755, -8264, -8050, -8787, -7793, -7192, -8081, -8359, -10367, -7308, -6991, -7332, -8931, -14232, -8007, -6797, -7132, -9800, -13835, -11501, -6596, -7893, -9831, -11601, -12887, -6679, -9853, -9139, -11078, -8894, -7338, -11703, -8684, -11386, -8556, -8925, -10719, -8095, -12223, -9890, -12600, -10678, -7601, -13352, -10997, -14219, -12580, -7914, -14900, -10834, -10587, -17160, -9606, -17509, -11831, -9792, -14535, -14620, -15935, -13545, -10180, -13387, -14109, -12626, -11733, -11259, -12852, -11649, -10359, -9112, -13805, -10874, -12114, -8940, -7478, -11162, -8905, -13014, -8389, -7070, -8300, -7873, -12301, -8759, -7897, -7516, -7945, -11441, -9479, -9758, -8260, -9257, -10055, -8912, -11370, -10436, -12243, -9002, -8078, -11958, -13352, -17471, -8733, -8008, -12959, -11729, -16054, -8775, -8649, -14557, -9828, -16015, -8934, -9793, -14432, -9459, -15591, -9838, -11052, -12957, -10547, -15496, -12015, -11458, -12524, -12694, -8230, -7691, -5468, -9481, -8670, -9001, -7408, -5868, -8990, -6591, -9581, -7771, -6956, -7195, -6580, -10393, -7327, -8931, -6473, -7471, -7970, -5549, -11685, -6128, -7159, -7631, -4150, -11748, -5513, -7929, -9741, -3795, -10485, -4303, -17918, -8069, -4614, -8971, -3127, -7586, -6064, -6814, -7951, -2698, -5489, -5580, -10569, -7771, -3189, -5469, -5785, -11898, -7226, -4466, -6865, -6114, -10132, -6694, -6073, -9733, -6129, -6873, -7455, -7364, -13436, -5859, -5163, -9935, -8014, -13410, -5672, -4931, -11197, -8088, -11952, -5759, -5908, -8516, -8227, -10857, -6700, -7381, -6294, -7948, -7578, -7593, -6226, -4093, -5630, -4017, -4501, -4020, -2154, -3361, -1993, -2598, -2742, -1072, -1949, -1330, -2120, -2586, -1063, -1517, -1931, -2742, -3767, -2267, -2219, -3885, -4222, -6305, -5003, -4359, -7515, -6275, -6329, -9340, -7607, -12642, -7451, -5676, -9219, -6602, -13829, -5922, -6883, -7370, -5890, -10794, -4729, -10218, -5433, -6630, -9067, -4538, -15278, -4265, -8349, -8557, -5277, -15622, -4066, -8880, -8228, -7025, -17999, -4908, -8895, -7876, -9730, -20204, -6995, -10528, -7947, -8986, -15609, -11480, -8558, -8529, -6973, -14060, -13132, -6336, -9480, -6072, -14891, -8563, -5576, -9787, -5940, -12477, -6978, -5672, -9075, -6201, -9322, -6417, -6451, -8859, -6523, -7573, -6467, -7443, -9016, -6973, -6791, -7238, -7352, -8515, -7959, -6689, -8750, -7373, -7939, -9814, -6907, -8398, -8020, -7907, -11790, -7184, -6899, -8017, -8015, -10770, -7572, -6198, -8602, -7580, -9305, -7928, -6155, -12835, -6869, -8482, -8451, -6730, -11413, -6489, -8152, -9575, -7862, -8206, -6709, -8087, -8522, -9050, -7654, -7533, -7890, -6803, -9935, -8072, -8451, -7253, -6535, -11353, -8295, -8740, -6322, -7893, -15348, -7725, -8988, -5476, -11460, -13262, -7221, -9483, -4995, -10780, -10224, -7251, -9437, -5058, -8963, -8837, -7649, -9570, -5841, -9093, -8473, -8169, -11427, -7607, -10154, -9463, -9020, -13397, -10596, -9380, -11766, -10451, -10172, -10965, -8168, -11446, -11564, -8940, -9038, -8329, -11145, -11019, -8637, -7810, -10112, -13124, -9888, -8452, -7159, -12460, -13661, -8969, -8120, -7365, -11740, -11131, -8617, -7994, -9199, -10800, -9901, -8864, -8338, -18405, -9328, -9597, -9573, -8683, -9092, -8348, -10440, -11231, -8532, -7338, -8315, -13288, -13336, -8470, -7996, -8943, -11069, -10472, -9040, -11538, -10138, -8492, -9458, -10575, -12131, -12718, -7794, -10389, -12879, -10330, -17404, -8374, -12979, -12355, -11566, -15374, -10212, -15777, -12279, -12726, -16126, -12892, -15051, -17251, -12160, -15098, -11206, -13405, -13200, -12773, -12624, -9967, -12677, -10384, -12458, -10770, -10191, -12112, -9969, -12304, -9488, -11298, -11629, -10552, -12837, -9005, -12997, -11904, -11543, -11254, -9555, -14936, -12024, -13036, -10176, -11863, -16570, -11122, -14227, -10661, -18824, -15736, -10527, -14187, -13092, -11981, -10996, -10305, -17064, -21464, -10450, -9195, -11056, 4273, -1175, 9553, 9450, 3052, 4463, 3879, 9185, 8848, 3751, 3691, 5671, 8199, 6996, 2976, -6, 5626, 6835, 3747, -666, 792, 4574, 5106, -1149, 3063, 2037, 4190, 3092, -4209, 3800, -358, 4688, 1661, -2811, 2384, 554, 4827, 2424, -2806, 1978, 2707, 4521, 3968, -690, 2707, 2711, 3757, 4130, 2386, 1913, 2064, 2494, 2508, 3667, 712, 2465, 1624, -715, 3416, 4000, 3141, 2531, -43, 2698, 6322, 3113, 4058, 1241, 3628, 7327, 2097, 4876, 2277, 4319, 7299, 1273, 4438, 3268, 3504, 6323, 1854, 3006, 3946, 376, 4314, 1023, 3672, 4062, -5035, 714, -3398, 4912, 3429, -584, -8156, -3245, 4998, 1886, 697, -982, 327, 4263, -1023, 1589, 1056, 3814, 3295, -5086, 2308, 1972, 5817, 2295, -2104, 3082, 2652, 6521, 377, -467, 3600, 3493, 6229, -3459, -114, 3379, 4039, 5186, 1078, -559, 2118, 3913, 3637, 3134, -594, -248, 2957, 1526, 3430, -111, -1222, 986, -1358, 2163, -472, 56, -2241, -835, -1865, -2532, 1237, -4694, -594, -748, -9471, 2363, -695, -6239, 2071, -3963, 3385, 1107, -315, 2712, -1725, 4066, 1139, 2838, 1943, -850, 4185, 385, 3798, -1034, -810, 3729, 409, 3633, -3631, -1834, 2835, 188, 2725, 946, -4437, 1381, -1223, 1115, 1704, -6992, -1534, -2586, -1552, 193, -4345, -4134, -2019, -2514, -5752, -3653, -1077, -1083, -444, -2084, -4006, -412, -207, 462, -456, -2819, -1217, 425, 537, -907, -1298, -3329, 342, 278, -2320, -650, -6489, -974, -53, -2929, -765, -4640, -4479, -814, -2364, -1373, -2710, -9811, -2690, -2639, -2160, -1708, -7460, -5063, -4249, -3165, -1116, -6249, -2842, -5023, -4942, -960, -3882, -1322, -3471, -8502, -1330, -3190, -894, -2532, -9041, -1644, -3392, -1071, -1851, -6633, -1087, -3902, -1602, -1002, -5609, -598, -5119, -2438, -522, -4698, -1066, -6220, -3522, -1088, -4180, -3025, -5845, -4633, -3574, -4309, -9354, -5815, -5317, -8883, -4318, -4059, -5763, -4295, -4753, -3956, -1188, -5059, -3028, -5161, -4196, -282, -4459, -2775, -9570, -4659, -623, -4394, -3602, -6541, -2769, -1731, -5262, -4933, -5054, -1102, -2424, -8236, -4875, -4457, -759, -1695, -5776, -4752, -4278, -1699, -657, -3225, -5190, -6168, -3979, -402, -2833, -3816, -9388, -7674, -1212, -3869, -2747, -4540, -11357, -3107, -5078, -3168, -3531, -8642, -5995, -4722, -5514, -4313, -5362, -8466, -3742, -12373, -6390, -3513, -7445, -3093, -5643, -8647, -2786, -5096, -3357, -3478, -8699, -3144, -3019, -4871, -3100, -8418, -4030, -1802, -7819, -4520, -8160, -3842, -1386, -9033, -9826, -8837, -3438, -1593, -5964, -4630, -9426, -3444, -2068, -3661, -1901, -7578, -3273, -2546, -2794, -963, -6642, -3195, -3431, -3491, -1447, -6127, -3465, -3316, -6683, -3872, -5921, -3687, -2004, -9602, 6954, 9472, -4937, 4408, 9914, 6202, 9072, -277, 4177, 9310, 3917, 7959, 2087, 3212, 7388, 683, 6428, 3014, 2072, 3868, 582, 4826, 3459, 2377, 1248, 2628, 3240, 3879, 2178, 2305, 3044, 2265, 4056, 802, 3017, 977, 2908, 4021, -218, 2782, -1481, 3752, 3866, 9, 1238, 1895, 3814, 3406, -734, -1246, 2452, 2890, 2862, -2419, -2154, 1980, 744, 2974, 458, -160, 2350, -3684, 3764, 1833, 1209, 2987, -188, 4442, 1831, 1820, 3272, 3009, 4590, 1979, 2915, 3663, 4306, 4297, 2743, 3739, 4182, 4135, 3864, 3231, 3347, 4460, 2066, 3431, 3057, 1366, 4330, -4188, 2732, 2029, -2450, 3903, 673, 1244, 597, -4712, 3501, 1868, -1737, 1065, -6321, 3025, 1724, -4798, 2014, -4691, 2115, 726, -4126, 2091, -2153, 873, -214, -4141, 2340, 833, -948, 3005, -788, 3695, 2866, -1217, 4662, 580, 4650, 3917, 1403, 4843, 599, 4670, 4315, 2157, 4046, 1278, 4078, 4281, 968, 2668, 1969, 3638, 3946, -3127, 868, 1315, 3439, 3449, -3484, -1794, -954, 2896, 2900, -913, -7509, -3831, 2195, 2366, -124, -8891, -3278, 2169, 1966, 447, -9929, -2773, 2353, 1726, 974, -7235, -4046, 1859, 1446, 1041, -4166, -4206, 167, 963, 362, -4972, -2035, -4366, 733, -1274, -4793, -1814, -2747, 1230, -3148, -1473, -3520, -65, 1452, -1912, -365, -4497, 161, 630, -1234, -1045, -2661, -1458, -1577, -2481, -4519, -1881, -2648, -5054, -7214, -6705, -1632, -918, -5935, -5615, -2820, -1622, -958, -7067, -2567, -3478, -2015, -3264, -8679, -1535, -8165, -2000, -5201, -6614, -1732, -1751, -1280, -3369, -6594, -3178, 554, -656, -3463, -5552, -6775, 1130, -171, -4938, -3561, -8282, 471, 41, -5423, -2609, -2999, -1300, -94, -3325, -2318, -1368, -3745, -379, -1975, -2221, -1283, -5095, -900, -1983, -2245, -2265, -4743, -2068, -3757, -2644, -3826, -3992, -4546, -8374, -3572, -5080, -4028, -10704, -6822, -3868, -5142, -5987, -4616, -6468, -2488, -4351, -9791, -2110, -7995, -1434, -3764, -4731, -1066, -5576, -1032, -3972, -3632, -1165, -2801, -647, -4636, -4538, -2905, -1633, -126, -4203, -4911, -9326, -1965, -14, -3423, -3255, -5919, -3705, -551, -3487, -2473, -5154, -6023, -1571, -4266, -2469, -9219, -7353, -2958, -4869, -2960, -9120, -8008, -5357, -5053, -3932, -6637, -6305, -7577, -4855, -5276, -6676, -3559, -5508, -3928, -8032, -5416, -1765, -4957, -3400, -7311, -3173, -977, -5631, -3807, -3876, -1883, -1052, -7343, -5107, -2784, -1889, -2034, -7426, -6933, -2888, -2758, -3039, -5105, -7268, -3435, -3180, -1892, -4394, -6583, -3779, -3925, -902, -5305, -7276, -4089, -6806, -1123, -7841, -8526, -5036, -5094, -2829, -12767, -7115, -6830, -3640, -4196, -6814, -6351, -5633, -5165, -2616, -4037, -7365, -3552, -12596, -2570, -3857, 5615, 3635, 5008, 8307, 8560, 5276, 3327, 4031, 7670, 8181, 4450, 2321, 1492, 5751, 7141, 3678, 319, 2251, 3453, 5936, 3177, -3642, 2484, 2769, 5359, 2469, -8211, 83, 1311, 5080, 1111, -4452, -710, -1942, 4119, -1054, -5164, 75, -988, 1760, -2503, -5947, -2624, 1559, 2341, -664, -399, -3492, 2666, 4350, 1598, 1249, -3523, 2324, 4896, 3228, 1656, -2654, -128, 5228, 4019, 2532, 406, -2052, 5724, 3668, 2788, -39, 2565, 5583, 1650, 1405, -870, 3978, 4515, -2496, 933, 2143, 3757, 2798, -1109, 2023, 2958, 2232, 2025, -625, 1457, 2016, 114, 2601, -1397, 894, 15, -1423, 2450, -2000, 2236, -1643, -11317, 1123, -1329, 2933, -2148, -170, -824, 557, 2647, -1452, 2212, -2245, 2466, 1557, -1140, 2175, -1229, 3422, -218, -1811, -164, 581, 3061, -2526, -3445, -5945, 1800, 1065, -5835, -5227, 176, 2800, -702, -8766, -4097, 2096, 3326, 706, -3323, -2528, 2868, 3305, 365, -1412, -980, 3057, 3440, -2261, -908, 566, 2721, 4059, -3183, -1116, 1551, 1749, 4440, -1772, -1045, 1894, 359, 4158, -2445, -643, 1789, -242, 3144, -4745, -967, 1530, -193, 1520, -4033, -2696, 1308, -892, 52, -2012, -5652, 978, -2084, 18, -1076, -4025, 301, -647, -37, -1324, -2462, -748, 993, -756, -4055, -1989, -1544, 1716, -216, -4336, -1713, -798, 1934, 646, -734, -585, 182, 1874, 632, -120, 181, 146, 1506, 245, -1036, -461, -1386, 874, 294, -1857, -2886, -4885, 226, 715, -1534, -4240, -3475, -156, 764, -1498, -4122, -2271, -228, 6, -1893, -7978, -2968, -98, -1350, -2696, -7527, -3951, 161, -2049, -4314, -4112, -2768, 377, -2023, -6945, -2920, -1353, 292, -2319, -8120, -2399, -663, -146, -3012, -6529, -2890, -708, -576, -3730, -5428, -5567, -1452, -537, -4195, -5525, -6484, -3160, -453, -4817, -7842, -2593, -7125, -1080, -5487, -7095, -1935, -11674, -2918, -3832, -3255, -3267, -7803, -5583, -1555, -1853, -3193, -4682, -4558, -248, -2116, -1765, -1967, -3151, 143, -4549, -2223, -635, -3122, -199, -11564, -4887, -375, -5590, -1244, -3692, -4172, -974, -6671, -3216, -1978, -1813, -2305, -2030, -4099, -1808, -942, -4570, -619, -1963, -2460, -1148, -8696, -699, -693, -2703, -2454, -6312, -2090, -404, -2307, -4238, -5549, -5742, -910, -2557, -4134, -8368, -6972, -1986, -3818, -4147, -5337, -2869, -2843, -5667, -5483, -2721, -1442, -2606, -6727, -5661, -2118, -1262, -2025, -6217, -4312, -2781, -2241, -1803, -5391, -4079, -3978, -4918, -2132, -5481, -4602, -4163, -8880, -3134, -7374, -4419, -3967, -5455, -4967, -8361, -3621, -3249, -4093, -6857, -4338, -2503, -1548, -3482, -6420, -2519, -1318, -657, -3514, -4889, -2151, -979, -1116, -5343, -2908, -3067, -2029, -3077, -8158, -1527, -6560, -5790, -3832, -2206, -4127, -3399, -4292, -4940, -4974, -2793, -2362, -2653, -10980, -5415, -3649, -2321, -1871, -4721, -2919, -4537, -2595, -2070, -2139, -2575, -1729, -2704, -3356, -1931, -3305, -753, -2510, -6063, -3729, -5163, -1706, -2349, -9383, -5256, -11377, -5034, -2566, -7340, -2712, -5787, -9046, -3593, -6261, -1699, -3302, -9886, -6186, -6696, -1792, -2738, -7512, -8622, -9946, -2511, -3281, -3572, -4661, -8071, -3873, -4912, -2319, -2313, -4209, -6451, -7637, -2129, -1412, -2828, -5466, -7336, -2281, -2182, -2979, -2911, -6517, -2539, -6309, -4981, -2174, -6412, -2590, -4489, -7737, -3255, -4516, -1907, -1229, -3607, -5026, -1662, -835, -276, -1725, -2208, 222, -152, -496, -1159, -920, 934, -298, -1543, -1731, -1278, 570, -1511, -3107, -3860, -2520, -665, -4148, -5063, -9601, -3563, -2338, -7677, -6647, -9347, -5738, -4128, -5612, -6055, -8722, -11473, -5027, -4799, -5335, -10194, -3950, -3216, -5976, -4666, -6511, -2263, -1858, -11547, -3776, -4016, -2056, -1812, -6608, -3305, -3151, -2510, -3001, -3221, -3992, -3655, -3160, -3823, -2022, -7049, -4559, -3915, -3231, -2280, -10880, -4556, -4119, -3716, -3862, -5402, -5662, -3493, -5324, -6761, -3992, -12154, -3430, -4389, -10854, -3634, -7926, -4819, -3306, -7653, -3998, -6180, -8424, -3646, -7246, -5270, -5766, -6096, -5140, -8179, -8096, -4530, -3860, -7042, -4222, -14070, -3643, -3048, -7790, -2448, -6400, -3436, -2945, -7516, -2289, -3818, -3584, -3237, -8134, -3080, -2611, -3866, -3720, -8361, -3900, -2253, -4413, -4300, -4948, -5062, -2574, -5451, -4891, -3104, -9966, -3473, -6412, -4902, -2675, -7509, -4489, -6146, -4202, -3286, -5122, -4607, -6019, -3941, -4588, -5910, -4538, -6926, -4744, -5937, -9521, -5491, -8071, -6459, -6309, -11466, -8106, -7592, -7168, -5891, -9960, -11277, -5992, -5987, -5797, -9214, -8528, -4722, -4286, -6720, -6405, -6920, -4206, -3205, -6913, -3869, -6418, -4041, -3431, -4272, -2550, -7061, -4052, -5496, -2653, -2424, -7305, -4873, -5290, -2181, -3493, -5061, -7351, -2919, -2649, -5876, -3521, -9266, -2294, -4077, -10095, -2802, -7212, -2773, -5907, -8717, -2538, -7541, -3682, -5534, -5626, -2788, -11674, -4209, -5122, -4904, -3801, -7671, -4054, -5863, -6040, -5899, -5640, -3933, -6746, -7308, -9937, -6103, -4673, -7159, -6200, -11302, -8101, -6783, -8030, -6107, -10018, -8576, -9051, -8822, -7101, -11354, -9780, -10360, -7996, -7714, -12917, -14236, -12235, -6338, -6552, -11621, -9197, -7458, -5166, -4849, -8419, -7984, -6006, -4844, -3899, -6185, -7370, -5861, -5552, -3962, -5079, -6536, -5921, -7571, -5142, -4988, -5869, -5594, -8610, -7533, -6242, -5003, -4945, -7103, -8357, -10606, -4213, -4411, -7081, -6808, -6725, -4030, -4417, -8126, -6290, -3779, -4559, -5224, -8156, -7091, -2724, -5747, -6887, -7593, -10336, -2890, -7675, -7564, -7008, -10528, -9120, -3096, -4727, -4287, -7491, -4825, -4498, -3189, -5400, -5052, -2316, -9808, -3096, -4647, -2070, -1095, -6897, -3549, -5188, -1297, -802, -4170, -4566, -6792, -1008, -1259, -3154, -7079, -7195, -699, -2081, -2734, -15953, -4835, -883, -3234, -2323, -6262, -3110, -1629, -6398, -2055, -4209, -3242, -2189, -8191, -2449, -3915, -5945, -2211, -3292, -3650, -4302, -8079, -2289, -1759, -5461, -3952, -6295, -2647, -1335, -7280, -3541, -8559, -3380, -1636, -6264, -3789, -13940, -5077, -2738, -4418, -4242, -9014, -9489, -4759, -3781, -4495, -5163, -5181, -6342, -4922, -5022, -3683, -2458, -8291, -7631, -6580, -4346, -1075, -8462, -2754, -4878, -3071, -243, -2870, -537, -1919, -316, 204, -1089, 0, -670, 949, 296, -995, -644, -856, 1038, -27, -2143, -1944, -2630, 177, -943, -3767, -2880, -7857, -1420, -2684, -4335, -3313, -6982, -3321, -5534, -4204, -3754, -4830, -5405, -9695, -4094, -4340, -5866, -8479, -13551, -3983, -5277, -8131, -10593, -13952, -3253, -5526, -5080, -10748, -15480, -2255, -3728, -3198, -8577, -12923, -1884, -2381, -2588, -6205, -8805, -2267, -2100, -3295, -5584, -7718, -2484, -2385, -6230, -5795, -5552, -1869, -2196, -8137, -4130, -3618, -1475, -1783, -4668, -2520, -3253, -1644, -2018, -3820, -2332, -4373, -2114, -3077, -3941, -3940, -5092, -2411, -4569, -4179, -8094, -3619, -2672, -4884, -4497, -4430, -2644, -4021, -3878, -5995, -2571, -2405, -8544, -3126, -13961, -2273, -2688, -7916, -2867, -5187, -2779, -3384, -6460, -2694, -2522, -3542, -4525, -8638, -2424, -1563, -4042, -6247, -15573, -2544, -1488, -4321, -7301, -10773, -3226, -1982, -4677, -5448, -7491, -3714, -2968, -4713, -3784, -4511, -3859, -4348, -4788, -3045, -2910, -4707, -5446, -6259, -3197, -2664, -6729, -5219, -8369, -4314, -3598, -10067, -4589, -5702, -6900, -4468, -14336, -4819, -4702, -15129, -3976, -12010, -5059, -4953, -8456, -3869, -11674, -3651, -5724, -6693, -4473, -12949, -2778, -7384, -6712, -4823, -12265, -3244, -8545, -6116, -4636, -12510, -5433, -7265, -4422, -4448, -10423, -12733, -7066, -3619, -3561, -7027, -7660, -6530, -3902, -2370, -5509, -5134, -6155, -4675, -1971, -5581, -4506, -7476, -5309, -2794, -7460, -5683, -10713, -6690, -5356, -12984, -11029, -9099, -8566, -9806, -12260, -7688, -7849, -6230, -7807, -9346, -5945, -8325, -4902, -7786, -6910, -7009, -8612, -5072, -9369, -5536, -10069, -6354, -6591, -10282, -5508, -8597, -4974, -9521, -9013, -7028, -7475, -4960, -12767, -7785, -11313, -6752, -6424, -12740, -7696, -11893, -5091, -9821, -12027, -8870, -7707, -3872, -8602, -12424, -10914, -5108, -3573, -6720, -12253, -11214, -3706, -4009, -6618, -10520, -8551, -3648, -4646, -8112, -8389, -6121, -5259, -4687, -12149, -7513, -4632, -10013, -3921, -11291, -8555, -4036, -8911, -3076, -9212, -12275, -4365, -7671, -2822, -8690, -8791, -5970, -9197, -3530, -8578, -6469, -5236, -4781, -6658, -2943, -1061, -7932, -4475, -8167, -934, -1390, -5860, -2757, -4476, -89, -2212, -2857, -2192, -2450, 167, -3011, -1371, -1832, -1663, -238, -3480, -972, -1294, -1547, -1734, -4059, -1244, -897, -1830, -3042, -5447, -1757, -863, -2291, -1205, -7176, -2443, -1068, -2025, -309, -6780, -3996, -1493, -1345, -773, -7187, -6478, -2689, -1326, -2301, -8534, -3977, -5782, -2000, -3862, -7084, -2219, -12366, -2773, -4157, -5134, -1684, -8569, -3243, -4514, -3676, -1609, -7788, -3766, -5119, -3547, -1606, -7236, -4041, -5522, -4209, -2205, -8857, -3681, -5065, -3096, -4882, -10267, -5416, -4456, -2720, -5063, -4605, -5564, -5785, -5154, -1789, -1874, -728, -5549, -5346, -1221, -874, 786, -2209, -2249, -2372, -1341, 650, -767, -1850, -3870, -3180, -695, -403, -3195, -3004, -5858, -2351, -602, -6531, -2624, -7577, -2869, -893, -7728, -3960, -8577, -3177, -1114, -5156, -6189, -9822, -3652, -1729, -4802, -4580, -9729, -3535, -3155, -6991, -3884, -9499, -3153, -4561, -8089, -3763, -8259, -3177, -3769, -5249, -3167, -6487, -3448, -2869, -6451, -2904, -5645, -3415, -2875, -6168, -3025, -5571, -2856, -3942, -2709, -3116, -6335, -2206, -6728, -1971, -2853, -8948, -2071, -11805, -3066, -1838, -12433, -2644, -6024, -5840, -967, -6445, -3627, -4214, -8153, -878, -4446, -4481, -3426, -6547, -1549, -3317, -5099, -2609, -5216, -2762, -2450, -5268, -1988, -4438, -4504, -1871, -4618, -2094, -3854, -7470, -1826, -3355, -2869, -3289, -17753, -2802, -2154, -3651, -2710, -7254, -5823, -1379, -3810, -2387, -4293, -7421, -1022, -3262, -2595, -2864, -4888, -984, -2695, -3096, -2603, -5210, -1266, -3076, -3220, -3347, -6868, -1982, -5280, -2894, -3896, -7007, -3145, -17998, -2759, -3266, -7738, -4097, -6380, -3554, -3183, -10779, -3979, -4415, -6024, -4240, -12735, -3976, -3511, -9161, -6071, -12265, -5311, -2484, -10379, -6941, -7090, -10284, -1505, -12420, -5684, -4708, -7921, -1099, -7151, -3929, -4140, -4845, -1423, -7725, -2906, -5352, -4079, -2415, -10884, -2767, -9575, -4751, -3868, -4996, -3267, -11989, -7115, -5006, -3391, -3812, -11979, -10810, -5188, -3586, -3784, -8891, -6382, -5441, -5553, -3438, -5727, -3479, -5894, -12436, -3191, -4619, -2024, -5517, -7064, -3122, -4018, -1711, -4483, -4948, -3381, -3236, -2307, -3707, -4471, -4159, -2468, -3365, -3586, -4439, -5249, -1958, -4202, -4446, -4159, -5909, -2016, -4686, -7049, -3815, -5830, -2881, -5316, -8985, -3897, -5727, -4315, -6894, -6111, -4099, -6446, -5802, -10967, -5680, -3778, -8126, -8852, -12693, -6969, -3660, -9269, -11311, -8799, -8984, -4230, -10135, -6885, -6827, -8416, -4706, -12410, -6134, -6142, -7269, -4802, -11045, -6734, -6913, -6875, -5306, -7901, -7838, -8307, -6747, -5268, -6268, -8514, -7424, -6007, -4627, -6013, -7963, -6595, -4887, -4943, -6881, -6893, -6953, -4348, -6424, 8312, 5887, 763, 6240, -363, 8294, 6155, 1032, 5545, -1258, 8007, 5877, 1907, 2928, -1251, 7048, 3746, 3572, -1938, 911, 5242, -371, 4533, 2396, 1978, 3126, 3069, 3923, 2713, 1787, 2172, 4094, 719, 14, 481, 3186, 4027, -121, -4285, 838, 4514, 3804, 2625, 180, 2550, 4919, 3657, 2521, 1067, 3483, 4582, 3362, 258, 2969, 3998, 4482, 2739, -6911, 4973, 4239, 4254, 3194, -2381, 5869, 4139, 2316, 4698, -612, 5539, 3654, -2238, 5395, -864, 3736, 2454, 913, 5114, -2219, 274, -5, 1216, 4154, -2132, 1318, -2522, -67, 2602, -1085, 2215, -2412, 131, -283, -886, 1268, -4026, 1186, -8097, -1710, -1149, -6953, 1561, -4291, -3347, -4797, -2354, 1522, -1303, -3727, -6138, -433, 1412, 133, -2083, -4125, -87, 815, -292, 172, -1455, -1082, -27, -3173, 1392, 845, -3508, 747, -2476, 1285, 1824, -1900, 1521, -1280, 820, 1686, 181, 1523, -4127, 1264, 491, 504, 1582, -1000, 1071, -3544, -907, 1450, 2030, -655, -2890, -3654, 3, 2817, -492, 659, -651, -4158, 2016, 1441, 818, 725, -10322, -840, 1979, -1194, -2, -8915, -5398, 1183, -1790, -2223, -6956, -2149, -1520, -56, -1105, -3460, -2442, -10631, 261, -303, -1559, -3357, -1627, -200, -1439, 167, -1243, -98, -570, -2185, 1208, 270, -178, -341, 51, 1412, 678, -1143, 5, 1425, 1216, -292, -1832, -159, 1825, 1256, -3538, -1494, -1115, 1555, 1587, -1977, -404, -2659, 1059, 1717, 80, 665, -3520, 841, 1159, 162, 792, -3107, 657, -448, -835, -464, -2113, 58, -3922, -1838, -3144, -1636, -806, -10528, -1556, -2638, -2444, -1534, -4173, -477, -1284, -3701, -2217, -3028, 311, -1290, -1968, -2833, -2955, 532, -2286, -406, -2998, -3034, 207, -3360, 179, -3012, -2639, -619, -2785, -62, -3928, -1952, -1977, -1827, -1392, -7686, -1681, -4262, -1592, -5592, -9053, -1987, -8758, -2354, -5422, -6045, -2718, -7035, -4539, -1752, -6965, -3828, -5662, -10232, -853, -7632, -5907, -6125, -6723, -855, -6549, -8259, -5978, -3467, -1133, -6529, -4785, -4562, -2279, -1386, -6847, -3401, -3669, -2823, -1427, -7821, -3833, -3606, -6032, -1374, -8088, -6000, -4148, -7704, -1368, -5769, -7785, -4977, -4936, -1565, -4181, -5556, -6132, -5997, -2140, -3599, -3794, -7335, -13081, -3091, -4133, -2413, -7218, -7692, -4501, -5860, -1528, -6840, -6739, -7249, -6578, -1438, -8422, -8001, -17811, -5284, -2387, -10105, -7352, -7847, -4947, -4342, -5643, -6214, -7228, -6386, -5210, -4781, -7105, -8778, -13916, -4956, -6509, -11004, -8787, -7620, -5986, -13650, -7198, -9389, -6170, -8564, -12574, -5441, -18478, -7578, -14813, -12988, -5656, -9929, -14786, -9762, -8635, -6950, -8535, -8450, -6373, -7771, -7891, -9058, -5077, -5412, -8878, -7258, -9097, -3639, 1446, 4870, 5496, 3432, 778, 2169, 4055, 4926, 2644, 1374, 2487, 1165, 2583, 1077, 1593, 1238, -9366, -4050, 2166, 1722, -1745, -4241, 2422, 3098, 2608, -1709, -11737, 3101, 2365, 2776, -656, -3138, 698, 90, 1600, -336, -1552, 42, 1775, 821, 87, -2168, 3276, 3289, 2542, -194, -1324, 4464, 2620, 4013, -3154, 646, 5129, 658, 5289, -802, 2092, 5542, 3390, 6094, 2705, 3242, 5233, 4793, 6071, 3909, 3952, 3664, 4131, 5190, 3726, 4040, -489, 463, 3738, 2159, 3503, -3730, 867, 2626, -1511, 2218, -177, 3882, 2668, -891, -258, -454, 4726, 2825, 821, -1874, 271, 4810, 2074, 230, -1089, 2122, 4593, -88, -2783, -2625, 2683, 4179, -4117, -7287, -3032, 1897, 3611, -3947, -3767, -1114, 377, 3060, -3057, -3805, -1994, 650, 2579, -4042, -6118, -6273, 1787, 1891, -5161, -6898, -5117, 1980, 863, -4271, -2408, -6868, 696, -89, -3863, -556, -3126, -4108, -359, -1906, 282, -431, -1615, -145, 439, 855, 479, 930, -166, 1445, 1122, 957, 828, -616, 1130, 775, 1433, -1303, -1174, -415, -162, 1415, -1521, -1711, -2517, -798, 37, -129, -1913, -2753, -848, -5232, -1012, -1887, -1764, -1762, -2590, -3901, -2498, -512, -2482, -429, -2118, -3514, 660, -1072, -597, -614, -4241, 1327, -790, -1868, -22, -3086, 1275, -2170, -2804, 433, -738, 732, -5131, -1557, 660, 408, 493, -6968, -83, 401, 317, 544, -3263, 920, -609, -882, 79, -592, 1584, -2882, -2961, -889, 747, 1898, -6333, -3936, -1213, 1066, 1671, -4477, -3040, -1196, 501, 605, -3687, -2741, -2076, -948, -1863, -3725, -3608, -3615, -3514, -8203, -2846, -5675, -4626, -7676, -5780, -2051, -5646, -4864, -7906, -4712, -1879, -4707, -4460, -8375, -6614, -2083, -5367, -4632, -16250, -14775, -2613, -7158, -5467, -7373, -10453, -3500, -9096, -6113, -6672, -12921, -4584, -8025, -7107, -9112, -8602, -5586, -6671, -8545, -6273, -4569, -6001, -6944, -6493, -3572, -3106, -5768, -6814, -5466, -2070, -2986, -5942, -6051, -6991, -1191, -3900, -7742, -5497, -10539, -980, -5624, -12196, -4103, -5565, -1540, -7062, -9523, -2878, -3827, -2988, -7111, -10643, -2372, -3418, -5831, -7249, -6598, -2449, -3770, -9218, -7702, -3064, -2873, -4524, -5252, -7390, -1470, -3361, -5234, -3699, -6322, -1108, -3863, -5805, -3796, -5425, -1798, -4517, -5806, -5718, -5233, -3353, -5104, -5088, -8064, -5966, -4350, -5365, -4661, -4926, -7452, -3960, -5678, -4644, -3868, -8402, -3993, -6276, -4768, -4497, -7430, -4679, -6686, -5100, -6680, -6008, -5367, -6348, -5765, -9584, -5354, -5330, -5759, -6800, -8074, -5635, -5118, -5631, -8313, -6312, -6572, -5525, -6352, -9706, -5356, -8122, -6676, -8115, -9754, -5232, -11807, -8113, -11082, -8604, -5830, -12132, -9036, -11127, -6709, 6577, 2520, 4753, 4151, -6277, 5589, 1368, 4321, 3621, 3271, 1874, 1192, 3362, 3087, 5773, -3867, 3437, 3263, 3753, 6554, 33, 4131, 3884, 3777, 6045, 1716, 3607, 3956, 2241, 4189, 2850, 2007, 3377, 1367, 1161, 1951, -1589, 2473, 3501, -395, 715, -2136, 1248, 4026, 2129, 3597, 349, -3343, 2390, 4017, 5389, -34, 904, 1934, 3345, 6038, 2492, 4607, 4228, -325, 5722, 4891, 5595, 3828, 4094, 4293, 5306, 4624, -1214, 5181, 1633, 3550, 792, 2721, 3531, 821, -5316, 717, 4457, 1230, 1080, 1384, 2685, 3550, 4020, -580, 2553, 2205, 205, 4954, -2816, 1369, 590, -8658, 4742, -1698, -1211, -629, -6616, 3828, -646, -3831, -237, -7037, 2574, -273, -4698, 467, -3754, 2042, -103, -5349, 849, -1731, 1984, 182, -8257, 951, -381, 1267, -129, -15880, 728, 94, 47, -1664, -9613, -14, -844, -405, -4780, -6293, -1484, -3930, -408, -5712, -3936, -4110, -1411, -383, -5165, -3535, -12188, 935, -295, -5321, -4553, -5474, 1539, -921, -1715, -3578, -2731, 969, -1541, 604, -1873, -1981, -490, -371, 1661, -1224, -2605, -2349, 191, 1867, -915, -4072, -4724, -641, 1362, -614, -5444, -7437, -1715, 46, -997, -7221, -4130, -770, -2305, -2440, -4308, -2677, -259, -4370, -3465, -1358, -2415, -715, -2586, -2698, -199, -2647, -834, -516, -1834, -588, -2857, -569, 258, -1793, -2251, -2194, -1192, -898, -1937, -2191, -852, -2583, -7152, 351, -1356, 102, -3698, -2950, 1852, -1932, 359, -6144, -1220, 1854, -2172, 55, -6653, -2009, 546, -1185, -340, -2419, -4113, -1290, -1150, -478, -1239, -6890, -2098, -2300, -959, -1842, -9870, -3081, -3299, -2614, -4334, -6524, -5286, -2315, -6323, -8689, -6324, -7051, -1389, -9340, -7912, -11485, -6039, -1331, -5992, -8125, -7089, -4737, -2125, -3981, -10595, -4020, -4177, -3806, -3357, -10943, -3272, -5259, -6807, -3837, -5883, -3671, -7274, -11253, -4242, -4281, -4544, -3604, -11765, -3483, -4209, -5169, -1853, -10870, -3008, -4896, -5876, -1572, -6055, -3923, -5510, -7833, -2223, -4625, -8226, -5841, -12540, -3583, -5274, -6509, -6567, -8375, -5407, -8003, -3287, -8715, -6207, -7424, -13138, -2446, -9753, -5663, -9630, -15199, -2672, -7218, -6661, -6037, -12704, -3539, -6174, -10491, -3939, -8698, -4719, -5061, -8431, -3339, -7629, -5801, -3775, -6080, -3854, -8518, -6103, -3128, -5811, -5276, -7916, -5332, -3191, -6563, -6015, -7152, -4632, -3752, -7412, -5063, -9671, -4680, -4701, -7650, -4302, -9953, -5723, -6167, -7995, -4104, -6363, -8287, -8535, -10190, -4399, -5858, -9631, -15346, -16341, -5128, -6659, -6771, -9534, -9119, -6612, -7005, -5858, -6761, -7614, -10632, -5834, -6800, -5861, -5931, -9280, -4667, -11591, -5616, -4315, -6135, -4309, -8330, -5613, -3928, -5865, -4985, -5460, -6193, -6200, -8553, -6508, -7937, -3343, -9220, -7479, -7092, -7098, -3815, -7377, -7211, -10560, -7407, -4573, -4819, -7566, -10829, -9354, -4967, -4005, -9157, -7836, -11251, -4939, -4060, -12517, -7841, -9124, -5106, -4032, -9702, -9763, -8266, -5876, -3708, -8169, -12969, -8955, -7321, -4019, -8001, -13153, -12277, -7778, -5533, -8327, -10652, -9170, -6266, -8421, -8485, -7668, -6262, -5238, -12272, -9176, -5981, -5445, -4819, -11447, -10176, -5855, -6189, -5005, -9051, -7100, -7117, -8724, -5961, -11311, -5790, -8166, -15544, -6816, -9360, -5149, -8190, -8935, -5866, -9914, -6606, -9288, -12789, -10198, -444, -785, 22, -512, -111, 3825, 3700, 4011, 3732, 4105, 5934, 5876, 6050, 5867, 6151, 6562, 6530, 6678, 6554, 6749, 5860, 5810, 6005, 5934, 6042, 3714, 3491, 3871, 3867, 3881, -362, -1720, -451, -332, -462, -8244, -5334, -9966, -11060, -13928, -14965, -3825, -7231, -7838, -7538, -14237, -5644, -11454, -9635, -12447, -11333, -7218, -10735, -7740, -14281, -7785, -7484, -7030, -8134, -10768, -7984, -8501, -5343, -10237, -8640, -10149, -11186, -5127, -16213, -8201, -9637, -11594, -6077, -11188, -8957, -7394, -11445, -8346, -8459, -9894, -6577, -12171, -11157, -7507, -9402, -7244, -8254, -10331, -7807, -8790, -9451, -6069, -11115, -9174, -9743, -15000, -5165, -15623, -9049, -13810, -14946, -4951, -14153, -7619, -17394, -12244, -5271, -10076, -7398, -15090, -10956, -6246, -8342, -8767, -16558, -10643, -7892, -8455, -11276, -11013, -12434, -9863, -11098, -10564, -8306, -14245, -11683, -14496, -10210, -7352, -10358, -11766, -9902, -11844, -7797, -8521, -9587, -9240, -12672, -9598, -7539, -8180, -10056, -9348, -11558, -6969, -8082, -10771, -7471, -10510, -7045, -8843, -10586, -6675, -9127, -8457, -8768, -9414, -6932, -8309, -12611, -7940, -7554, -8612, -8127, -10569, -7552, -6501, -11995, -8345, -8661, -7566, -6721, -11127, -8660, -8710, -7776, -8403, -9893, -9024, -10124, -8184, -9859, -9545, -8899, -13021, -8806, -8623, -9544, -8291, -12631, -9539, -8508, -10086, -8184, -10718, -11079, -9891, -10988, -8798, -9846, -15501, -12770, -12005, -9506, -9090, -11859, -16988, -13076, -9577, -8205, -10545, -15281, -12434, -9458, -7601, -10825, -15101, -10698, -9846, -7697, -9290, -15813, -9752, -11370, -8616, -8167, -14591, -9649, -15588, -9597, -8495, -15462, -9906, -14673, -9892, -9926, -20536, -9793, -11426, -11057, -10986, -12734, -9231, -10131, -14054, -10780, -10743, -8703, -9892, -13703, -10864, -10543, -8545, -10911, -13096, -11370, -11418, -9104, -13976, -11827, -11626, -12918, -11025, -13271, -9958, -11491, -14768, -15232, -11312, -9615, -11615, -13200, -12779, -11637, -10649, -12531, -11272, -11775, -13881, -10788, -13604, -10618, -12568, -17230, -9775, -13103, -10832, -13373, -17598, -9893, -12065, -11959, -13262, -15866, -11391, -11454, -14518, -13114, -14350, -13728, -11407, -14804, -13246, -14622, -13285, -11845, -13064, -12030, -18307, -11760, -12159, -12305, -10412, -15123, -6324, -9477, -9400, -7057, -5710, -6352, -8487, -9278, -5078, -6096, -6298, -7707, -8482, -4442, -8448, -5661, -7246, -8358, -4752, -12692, -5302, -6206, -10007, -5788, -7182, -6166, -4983, -13270, -7494, -5273, -8510, -4454, -10594, -9438, -4780, -10193, -4690, -8615, -10919, -5125, -11052, -5489, -7798, -13036, -5854, -12236, -6499, -7745, -7401, -6635, -10632, -7170, -7794, -4840, -7557, -11145, -7431, -7733, -3910, -8096, -11765, -8948, -8494, -4135, -6962, -9891, -12542, -10049, -5225, -5766, -10963, -10163, -8393, -7226, -7008, -9025, -7379, -6072, -8597, -9535, -13454, -7980, -10483, -10619, -10454, -524, -357, -673, -521, -913, 3774, 3850, 3806, 3801, 3726, 5896, 5951, 5941, 5949, 5967, 6539, 6579, 6562, 6618, 6666, 5850, 5857, 5818, 5968, 6006, 3680, 3600, 3535, 3900, 3852, -704, -1039, -1074, -41, -442, -20425, -13137, -8880, -7008, -7180, -7676, -7249, -9812, -10616, -7360, -10279, -5481, -10821, -11285, -6744, -11031, -5069, -9065, -12055, -6518, -9991, -6225, -8756, -16333, -8667, -10592, -8419, -8312, -11250, -10011, -12191, -13430, -7967, -10377, -10608, -12739, -13080, -6812, -11457, -12300, -13509, -10314, -6313, -16158, -13876, -18989, -8759, -6995, -16806, -12813, -11600, -7944, -8763, -18811, -7810, -8523, -8087, -8626, -13671, -5455, -7530, -9310, -6986, -10603, -4667, -7855, -10926, -6627, -10213, -5114, -9406, -10426, -7630, -10276, -6652, -10178, -9082, -9365, -9640, -9105, -8955, -8049, -10069, -9361, -12141, -8768, -8044, -10018, -10155, -15871, -8742, -9890, -9962, -13161, -22128, -8200, -13833, -10789, -16792, -13824, -8273, -10713, -12965, -14624, -10183, -8548, -10172, -10605, -20387, -7962, -7851, -11897, -8350, -13740, -6838, -7172, -13924, -7292, -11677, -6817, -7315, -12211, -6859, -11522, -8153, -8547, -10846, -6858, -11643, -11284, -10893, -10119, -7332, -10993, -11217, -11394, -10115, -8360, -10006, -9632, -11033, -10993, -9848, -9822, -9397, -11758, -12169, -11656, -11314, -9647, -10253, -11377, -15028, -17323, -9926, -8792, -9976, -15320, -14192, -10389, -8646, -9355, -11446, -12505, -11423, -9549, -9778, -10204, -13602, -12870, -11143, -11814, -10021, -18248, -12820, -12849, -14717, -10517, -16157, -11201, -13626, -10610, -12078, -13136, -9927, -13163, -8579, -14304, -11833, -9257, -12540, -7856, -12246, -10955, -9144, -12407, -8209, -10861, -10350, -9797, -13195, -9967, -10891, -10379, -11896, -15556, -14905, -11801, -11591, -19418, -16477, -13344, -11845, -15351, -14372, -14073, -11411, -10850, -18659, -12416, -13199, -12060, -10790, -15823, -12264, -12718, -14280, -12046, -18986, -12902, -11598, -15084, -12664, -17066, -13984, -10396, -15153, -11569, -16303, -14781, -9857, -17401, -11389, -22830, -13452, -10185, -27068, -12151, -13558, -11746, -11330, -16623, -13653, -11224, -11074, -13063, -14198, -16091, -10707, -11621, -15303, -13355, -14189, -11493, -13829, -17195, -14040, -11965, -13852, -18027, -14642, -17286, -11045, -17219, -15206, -12429, -22284, -10583, -15085, -14255, -5111, -8181, -6549, -4897, -8234, -8490, -18312, -7810, -5765, -17195, -9800, -10653, -8301, -7841, -9189, -8646, -14834, -8803, -9710, -7281, -9213, -10024, -8625, -9340, -7338, -8926, -7689, -7824, -9330, -9147, -8812, -8023, -6553, -11359, -13026, -9700, -9056, -5691, -13529, -8406, -8745, -9062, -5610, -9201, -6813, -7212, -9078, -5853, -7526, -6881, -7424, -9496, -6434, -7064, -7710, -9464, -9887, -8019, -8062, -9180, -11192, -8688, -9004, -14243, -11558, -10074, -6315, -7134, -10315, -9984, -10918, -5924, -6393, -10145, -11123, -9806, -6673, -6775, -7294, -7563, -10028, -6767, -6627, -6054, -8211, -673, -269, -153, -410, -462, 3658, 3899, 3790, 3794, 3863, 5808, 6013, 5839, 5920, 5990, 6444, 6660, 6471, 6571, 6643, 5689, 5989, 5790, 5895, 5987, 3325, 3884, 3647, 3761, 3929, -1754, -187, -639, -440, 50, -8211, -8616, -11834, -10163, -5789, -7590, -10466, -8996, -13313, -6715, -11943, -10600, -9727, -8406, -6591, -9097, -9376, -8364, -7190, -6668, -9015, -8462, -8907, -8539, -6303, -8460, -7343, -9806, -10953, -6011, -7663, -6472, -10571, -9496, -6413, -6880, -6655, -11790, -8082, -7031, -6522, -8223, -11268, -8737, -7692, -7118, -10117, -11663, -12041, -8448, -9533, -9593, -15313, -12392, -9478, -18602, -8816, -11429, -8895, -12054, -11179, -8822, -9217, -7784, -14643, -9564, -9603, -8496, -7855, -9020, -8861, -10482, -8191, -8705, -7733, -9082, -10202, -8062, -11167, -8627, -11604, -8907, -8473, -16546, -10658, -11858, -7812, -9627, -9355, -8890, -8190, -7538, -10633, -7706, -7730, -6849, -8080, -9108, -7559, -8057, -6720, -9112, -7655, -8306, -9830, -7647, -9889, -7064, -9763, -12763, -10007, -9471, -7045, -11985, -12538, -15469, -8243, -7479, -13782, -13003, -15736, -7151, -8434, -12474, -20353, -12992, -6507, -9800, -11537, -12301, -10376, -6345, -10815, -11652, -9995, -9366, -6590, -10528, -12500, -9541, -10271, -7098, -9549, -13197, -9750, -10632, -7794, -8985, -12956, -10146, -8248, -8486, -9275, -12169, -11215, -7216, -8669, -10398, -11343, -13727, -7454, -8569, -11756, -11006, -18229, -8521, -8946, -12224, -11114, -19315, -9737, -10248, -12077, -11015, -19702, -10458, -12370, -12977, -10475, -14351, -10803, -11973, -16841, -9938, -11685, -11222, -10314, -13740, -9705, -10829, -11841, -9569, -11818, -10113, -11856, -11386, -9666, -11946, -12096, -16134, -10401, -10214, -12794, -20737, -13145, -10467, -10065, -13294, -10923, -11149, -11854, -9264, -13455, -8919, -11022, -12777, -9041, -13589, -8787, -12370, -11861, -9846, -15421, -10085, -14716, -11869, -11867, -17826, -12719, -11822, -12688, -15281, -12752, -15662, -10433, -12735, -18034, -11246, -19506, -10818, -12305, -15670, -11170, -13583, -11790, -12741, -14857, -11642, -11180, -10749, -14781, -16906, -11816, -10866, -9400, -21844, -15369, -11386, -12020, -8669, -18289, -11859, -10840, -13480, -8294, -17206, -10414, -10607, -13398, -8217, -16096, -10103, -10802, -13232, -8573, -14197, -10582, -11426, -13681, -9469, 13787, 14482, 4978, 9252, 11837, 13142, 13944, 4781, 8623, 11115, 11041, 12305, 4122, 6636, 8769, 6500, 9549, 4653, 3113, 4014, 364, 6117, 5897, 1273, -1449, 4622, 4026, 5912, 1807, -4079, 4377, 4233, 4397, 762, -2972, 2131, 4306, 2088, -94, -1821, 731, 3764, 2965, 2827, 2767, 3262, 3394, 4029, 4634, 4859, 3406, 3613, 4412, 5302, 5672, 1375, 4227, 4558, 5029, 6061, -3400, 4918, 4488, 3616, 6377, -5761, 5197, 3982, 355, 6282, -1053, 4744, 2957, 363, 5315, 1144, 3424, 2115, 2646, 3131, 1395, 1044, 2637, 3056, 656, 956, -3300, 3401, 2110, 1208, 105, -6609, 3508, 681, 1312, -4040, -3827, 2964, 2051, 978, 1360, -3994, 2019, 3680, 1426, 4160, -4790, 653, 4368, 1589, 4987, -2691, -1786, 4311, 977, 4326, -936, -2880, 3675, -26, 1433, -152, -260, 2708, -1196, -3895, -336, 944, 2077, -1140, 1532, -1804, 1016, 2018, -230, 1660, -1298, -2, 1662, -783, -759, 725, -2655, 492, -2131, -5217, 1363, -4750, -1417, 88, -5661, 1034, -2778, -3746, 1317, -4242, 311, -3574, -8503, 817, -373, -340, -2916, -7619, -68, 2394, -443, 58, -4328, 1397, 3818, -149, 1292, -2863, 2312, 3943, -590, 1294, -1452, 1738, 2645, -2903, 176, -1242, -587, -913, -3009, -2557, -3482, -6100, -3543, -97, -9954, -8191, -6916, 150, 820, -8630, -3025, -6507, 1377, 444, -7535, -2068, -5282, 1773, -1119, -5293, -1568, -3256, 1565, -4468, -4636, -860, -2027, 631, -6159, -6005, -239, -1157, -1430, -4037, -5551, 152, -397, -5342, -3689, -2472, 10, 41, -3431, -3131, -596, -819, -40, -1561, -2261, 413, -2281, -549, -1152, -1936, 780, -3916, -1306, -1405, -1886, 549, -3835, -2180, -1917, -1818, -387, -2792, -3422, -2357, -2055, -2215, -2501, -6241, -2373, -2782, -4704, -3033, -8393, -2033, -4217, -6929, -4108, -6246, -1681, -8068, -11620, -5597, -7465, -1732, -6024, -6720, -8259, -13971, -2807, -3209, -4535, -10705, -11232, -6537, -2961, -4340, -6189, -8549, -6525, -4973, -5306, -4475, -6917, -3450, -8409, -6693, -4114, -8079, -3555, -4950, -7082, -4463, -11262, -6691, -4196, -5694, -5222, -4124, -9836, -4855, -3625, -6954, -1699, -5164, -4765, -1928, -14286, -663, -4169, -4080, -956, -6668, -472, -3927, -4223, -808, -4050, -927, -4054, -4659, -1518, -3273, -2043, -4659, -4806, -2857, -3485, -4026, -5012, -5753, -3289, -4506, -7114, -4157, -8458, -2383, -6814, -8776, -3046, -10124, -1919, -9729, -8006, -2438, -8481, -2476, -7223, -8942, -2651, -8119, -4495, -6713, -10699, -3729, -9751, -9391, -8462, -9084, -4869, -12085, -14189, -11420, -7217, -4537, -9290, -6958, -10445, -5602, -3890, -8713, -2884, -7885, -5075, -4081, -6824, -993, -5433, -6297, -5445, -6813, -581, -4298, -11537, -8013, -10279, -1352, -4068, -9035, 8985, 6518, 7563, 8877, 9046, 8234, 6594, 7027, 8347, 8532, 6331, 5677, 5772, 6952, 6924, 5024, 981, 5111, 5260, 4061, 3806, 2037, 5742, 3558, 440, 967, 4386, 6629, 2409, -783, -883, 3656, 7114, 1283, -349, 2952, 2413, 7141, -2137, -67, 5129, 3158, 6509, -1857, 1100, 5734, 3958, 4491, -2596, 2334, 5404, 4255, -814, -4981, 2856, 5080, 4016, 3871, 763, 3031, 5362, 3360, 5969, 2332, 2827, 5563, 3133, 6510, 2666, 2052, 5428, 3497, 6210, 2579, 1018, 5290, 3136, 5414, 2374, 388, 5181, 962, 4383, 1588, 226, 4666, -8481, 3193, -1021, -410, 3159, -2200, 1715, -119, -2705, -842, -2369, 539, 2781, -10846, -1682, -8065, 649, 3237, -2652, 2167, -6821, 272, 1411, -187, 3126, -4139, -1393, -1419, 809, 2593, -188, -2666, 1660, 526, 549, 1751, -2642, 2880, -2175, -3542, 2355, -1774, 3630, -3843, -7162, 2117, -33, 4132, 594, -10058, 1187, 935, 3783, 1152, -5997, -1100, 903, 2279, -742, -2986, -9530, -343, -685, -1943, -1738, -800, -4534, -5764, -203, -1451, 1532, -3386, -6807, -385, -1934, 2482, 154, -5475, -748, -492, 2676, 1176, -4795, -405, 1741, 2257, 901, -4046, -832, 3050, 1426, -528, -2648, -2209, 3695, 768, -3119, -495, -2869, 3888, 478, -7138, 1492, -1466, 3557, -528, -7174, 2892, -1106, 2438, -2650, -3884, 3745, -2364, -20, -2147, -2024, 4007, -3977, -5755, -2340, -122, 3501, -3717, -2271, -6275, 838, 1949, -2174, -28, -2191, 445, -1442, -698, 540, -615, -1399, -6006, -537, -92, -1203, -4365, -1382, -2154, -1656, -2113, -3715, -389, -7872, -2267, -1547, -2291, -928, -3354, -1762, -1495, -2020, -2464, -599, -1845, -2575, -2336, -4021, 372, -2314, -4497, -2622, -4010, 282, -2952, -6128, -2952, -3405, -535, -3805, -5759, -4534, -3411, -1497, -3776, -4343, -9672, -3453, -2263, -3392, -3115, -3355, -2792, -3364, -4273, -2577, -1414, -2260, -5289, -5577, -3117, -1496, -2341, -8298, -4319, -5022, -3242, -2912, -10586, -3495, -6735, -4189, -3526, -8272, -2519, -5886, -3111, -3694, -6397, -1252, -4882, -4093, -3443, -5273, -804, -4317, -8079, -3204, -5308, -1356, -5169, -5436, -3218, -6950, -2610, -7845, -5021, -3555, -7503, -3948, -7689, -5972, -4387, -6617, -5066, -6911, -3284, -5760, -8977, -5918, -6541, -1693, -5689, -10069, -5800, -5469, -1504, -3599, -6215, -5202, -4553, -2416, -2353, -5588, -4994, -3747, -4273, -2588, -5373, -5430, -3370, -6208, -5044, -4717, -6317, -4029, -6065, -5950, -4743, -6737, -6835, -5706, -3061, -5988, -6782, -8754, -7073, -2705, -8530, -6424, -4552, -7345, -4113, -12075, -5777, -3244, -3463, -6001, -15697, -6055, -2947, -1629, -6014, -9874, -7633, -2862, -1191, -6825, -7375, -9082, -2771, -1903, -6828, -6079, -12057, -3123, -3750, -5684, -5858, 7254, 3780, 5352, 8324, 7066, 7171, 3086, 5094, 7895, 6213, 6727, 851, 4354, 6526, 3843, 5390, -2087, 3193, 4117, 3207, 2262, -2314, 1654, 2565, 3126, 2013, 745, -46, 3361, 1325, 4042, 3062, -104, 3836, 2767, 4176, 3288, 1227, 4010, 3783, 3360, 1017, 1727, 3485, 2176, 2138, -2184, 1294, 1347, -6664, 531, 1541, -80, -1763, 1195, -1041, 2582, -3103, -380, 1419, -1732, 2633, 1146, -1351, 1509, -3214, 1956, 3383, 707, 3109, -4593, 393, 3552, 2910, 2673, 1140, -2294, 1842, 3182, 2083, 3269, -1350, -478, 1649, 4232, 3696, 858, 1509, -3165, 5058, 2523, 1699, 2458, -4177, 4411, -2484, 2717, 2408, -2617, 2814, 58, 3860, 2037, -6038, 2143, 3316, 4150, 1901, -3622, 2863, 4118, 3282, 2190, -1326, 3523, 3616, 979, 2192, -1138, 3638, 1956, -3769, 1246, -1925, 2589, -1005, -4772, -664, -3082, 144, -4808, -5487, -1236, -3921, 1631, -3920, -4314, -289, -1963, 3125, -997, -878, 536, 568, 3125, 1100, -87, 1132, 2375, 2481, 2173, -588, 916, 3384, 1815, 2460, -1252, -670, 3538, 1108, 2340, -1871, -4154, 2703, 850, 1950, -2672, -4339, 499, 1269, 1169, -3861, -2132, -4124, 1562, 169, -6132, -261, -2596, 1437, -843, -2396, 722, -781, 871, -1632, -1151, 484, -292, -168, -807, -2771, -188, -270, -1242, 784, -14377, 384, -752, -1214, 1457, -2334, 652, -2146, -1095, 669, -88, -423, -4151, -2159, -1953, 663, -2218, -4541, -2894, -2170, 348, -3093, -5154, -892, -404, -488, -3708, -4906, 109, -283, -802, -2311, -3105, -386, -1719, -713, -1343, -2995, -2943, -6075, -972, -1948, -5119, -4035, -6812, -2209, -3295, -11489, -1136, -4506, -5033, -2868, -7918, -847, -5278, -7842, -2304, -3639, -2461, -4408, -11924, -2104, -1206, -4600, -2108, -7483, -1639, -277, -4610, -1091, -4659, -1884, -464, -3838, -1260, -5409, -3828, -1361, -2961, -2613, -11108, -7331, -2289, -3521, -5412, -5253, -5834, -2362, -7268, -7961, -3699, -5927, -1680, -7667, -6690, -4054, -7101, -1061, -4319, -6204, -4494, -5229, -805, -4567, -6323, -4150, -3547, -893, -8945, -6568, -4867, -2577, -1066, -7158, -7404, -8847, -2021, -890, -4696, -10328, -8292, -2006, -644, -5885, -7639, -5119, -2603, -1086, -10119, -4971, -4890, -3480, -2684, -5412, -4289, -6038, -4012, -5439, -4182, -4826, -6486, -4081, -6591, -4286, -6108, -5920, -4195, -6369, -4245, -8101, -5814, -4660, -6888, -4094, -8298, -5812, -5539, -7734, -4961, -5751, -5919, -6810, -8659, -8082, -4912, -6634, -7885, -10439, -10783, -5265, -8314, -7614, -11534, -7287, -5005, -10458, -6328, -7728, -6504, -3880, -9864, -5156, -6502, -6430, -3550, -9472, -4517, -7652, -6597, -4643, -8696, -4595, -11083, -7127, -7788, -6724, -5271, -8046, -8521, -10178, -5892, -5092, -6057, -10780, -9513, -5852, -2958, -4130, -5138, -9591, -4239, -4771, -4595, -3537, -7593, -4988, -6791, -6457, -3617, -5186, -9184, -8984, -9752, -5332, -3757, -9695, -8023, -9904, -8192, -3567, -7496, -5663, -6636, -10251, -4988, -10139, -4265, -5209, -8259, -7312, -10026, -4064, -4842, -5919, -6798, -9178, -5491, -4279, -5506, -4718, -6877, -7453, -4436, -4938, -5641, -10793, -7051, -8165, -5146, -6237, -5783, -3706, -5657, -6567, -6163, -7552, -5332, -4544, -7934, -4428, -7473, -7132, -2816, -3669, -7263, -5272, -6182, -5161, -8287, 1297, 1380, 382, 427, 1207, -5695, -8279, -4121, -8316, -6680, 8561, 8618, 8700, 8553, 8437, 13004, 13007, 12983, 12916, 12893, 15159, 15134, 15101, 15057, 15049, 15814, 15765, 15745, 15709, 15700, 15123, 15045, 15056, 15018, 15001, 12934, 12800, 12884, 12824, 12786, 8481, 8155, 8507, 8337, 8234, -6212, -3159, -3672, -8783, -6067, 355, 1573, 140, 692, 704, -6870, -5118, -3656, -13381, -7976, -3363, -8489, -2432, -4041, -3085, -13187, -6128, -4945, -14447, -7311, -7663, -3928, -4995, -7782, -6564, -11356, -5002, -6850, -10812, -11615, -6916, -5388, -8674, -8337, -12006, -7994, -4573, -8011, -5441, -11762, -8180, -4139, -6462, -4421, -16667, -10089, -4886, -7481, -4405, -7607, -13750, -5921, -8591, -4365, -5118, -9873, -7548, -9934, -5196, -5328, -8781, -10656, -14920, -6792, -7727, -9037, -11447, -11389, -8594, -14847, -9884, -10947, -8958, -9617, -6934, -9289, -10973, -8780, -9326, -5223, -7221, -8742, -8512, -9119, -5599, -6083, -6824, -7067, -9787, -7035, -6014, -5755, -6035, -12388, -7980, -7264, -5557, -6080, -13525, -8373, -10795, -6081, -7427, -10104, -7020, -11727, -7375, -11093, -7431, -5927, -8775, -8995, -13316, -5955, -5824, -8544, -9358, -9168, -5567, -6647, -11194, -9332, -7582, -5880, -8291, -12999, -10338, -6506, -6668, -9652, -8827, -10795, -6129, -8010, -10285, -7865, -9139, -6920, -9528, -11676, -7471, -8425, -8858, -9571, -11366, -7427, -8712, -10255, -9618, -10512, -8751, -8954, -9471, -11316, -11523, -14983, -9112, -8722, -16038, -13343, -10452, -10208, -9099, -11641, -9484, -7683, -10772, -11344, -9792, -7278, -7034, -11116, -15446, -10288, -6693, -7359, -16187, -12218, -11828, -7788, -7894, -9483, -11724, -10789, -12571, -8252, -6930, -13333, -10655, -11221, -8965, -6238, -12123, -12075, -8249, -10092, -6645, -9684, -12421, -8088, -9963, -7965, -8294, -11999, -9632, -8837, -10239, -7443, -12000, -13315, -8706, -11505, -7439, -12416, -14043, -10646, -10071, -8528, -13571, -10865, -15017, -8877, -10497, -11921, -8804, -11247, -7730, -13069, -10791, -7478, -11828, -6398, -15423, -12001, -7192, -20448, -5201, -16101, -13201, -8376, -13641, -4585, -14289, -9748, -13001, -13041, -4645, -11616, -8328, -11523, -14627, -5170, -11110, -8451, -8356, -13502, -5950, -12049, -9883, -7761, -10373, -7152, -12526, -12659, -8455, -8713, -9156, -11939, -16142, -9589, -8459, -12138, -11687, -14965, -9961, -10498, -4366, -6670, -6268, -6777, -7229, -6131, -9281, -8240, -7699, -8929, -7196, -10164, -9029, -7444, -11207, -7603, -9629, -8669, -5848, -6033, -7414, -11634, -7184, -5213, -4398, -8612, -8062, -6308, -5370, -3304, -13810, -6177, -7408, -4579, -2825, -7811, -5579, -7973, -3825, -3546, -6430, -4992, -8108, -3809, -4781, -4527, -4429, -6506, -4269, -4491, -4848, -3487, -4891, -7768, -3571, -7588, -2584, -3465, -8846, -7026, -5220, -5205, -4060, -11604, -5445, -2622, -4630, -3540, -3661, -13629, -16253, -13092, -4810, -7932, 231, 618, -82, 543, 843, -6248, -7054, -4917, -3788, -8231, 8605, 8622, 8675, 8654, 8498, 12929, 12970, 12956, 12954, 12918, 15061, 15099, 15067, 15070, 15063, 15710, 15741, 15699, 15705, 15706, 15022, 15042, 14988, 14999, 15003, 12839, 12842, 12761, 12787, 12794, 8398, 8357, 8181, 8271, 8320, -6355, -9827, -5114, -8031, -11445, 742, 449, 897, 548, -492, -6196, -9566, -10589, -7494, -5073, -8525, -3144, -3699, -3026, -2223, -5070, -7672, -10938, -5874, -3889, -3862, -8293, -8123, -6864, -3393, -7232, -5562, -14238, -6677, -5029, -8078, -4318, -11472, -7169, -5990, -6359, -5438, -12955, -9248, -7282, -4699, -6061, -8298, -7138, -7975, -4437, -5255, -4977, -7199, -7408, -4404, -5040, -4346, -6498, -8164, -4424, -5932, -5922, -6287, -13094, -5022, -6947, -8673, -7353, -11799, -6385, -7265, -8889, -6892, -9465, -7244, -8190, -8641, -5854, -8326, -7533, -11441, -8925, -6478, -7704, -8121, -12430, -8424, -8580, -8303, -8555, -9459, -7952, -11706, -10874, -8801, -7781, -7932, -11601, -11746, -9392, -6681, -8702, -9492, -10771, -8897, -6269, -11134, -7989, -10751, -7531, -6453, -13250, -7211, -8926, -7404, -7610, -10312, -7486, -7607, -8600, -12793, -8181, -8674, -7479, -10202, -9162, -6921, -8904, -7697, -11286, -6098, -6608, -7722, -7804, -11937, -5398, -6998, -6592, -8510, -11931, -6006, -7656, -5732, -10168, -11643, -7700, -7865, -5153, -9670, -11404, -9945, -7621, -4734, -7718, -11938, -10592, -7930, -4469, -6955, -14370, -10031, -9183, -4556, -7329, -15667, -10284, -10498, -5050, -8892, -12373, -11084, -10118, -5802, -11839, -10744, -9393, -8932, -6557, -10599, -9939, -8174, -8555, -6929, -8379, -9147, -8371, -9724, -6772, -7539, -8646, -9213, -12563, -6454, -7698, -9055, -8331, -11230, -6225, -8717, -10672, -6809, -10830, -6241, -10608, -14785, -6331, -14765, -6812, -12383, -14279, -7241, -12980, -8388, -10530, -11516, -10115, -9969, -11681, -8633, -11517, -17696, -8967, -17098, -7730, -9999, -15671, -8469, -13164, -7734, -8058, -16219, -8806, -10957, -8309, -7622, -12298, -10108, -10766, -8402, -8250, -10221, -11010, -13232, -7994, -8410, -9360, -11065, -14546, -7912, -7768, -9280, -10873, -10923, -7989, -7800, -10287, -9905, -10087, -8439, -9129, -12060, -9325, -10332, -10265, -12743, -9949, -9270, -9962, -11686, -19639, -8180, -9033, -9152, -9150, -14519, -7532, -8746, -9194, -8408, -10822, -6541, -4087, -5366, -7217, -12242, -8318, -3539, -5595, -5565, -10054, -10115, -3416, -6678, -5715, -9487, -10487, -3463, -9138, -5286, -11194, -7805, -3598, -8649, -4087, -14458, -5912, -3513, -5294, -3330, -15491, -5595, -2995, -4509, -2842, -9703, -5078, -2744, -5044, -2878, -6441, -4684, -3510, -5504, -3700, -5324, -5093, -4428, -5770, -3850, -7746, -5534, -4368, -9431, -3672, -6965, -5120, -3532, -8148, -3980, -5835, -12972, -4140, -6914, -7836, -3209, -4326, -4421, -2653, -4978, -4388, -5867, -4333, -6509, -8827, 759, 1307, 1420, -92, 441, -7569, -6729, -8428, -3816, -5727, 8547, 8521, 8509, 8797, 8689, 12911, 12937, 12918, 13017, 12962, 15045, 15072, 15054, 15101, 15063, 15687, 15707, 15695, 15716, 15688, 14985, 14996, 14991, 14996, 14973, 12773, 12778, 12783, 12769, 12751, 8257, 8274, 8289, 8231, 8207, -5729, -13222, -9847, -7725, -6606, 365, -216, 347, 366, 774, -5794, -4154, -13970, -10100, -11214, -3024, -1610, -5056, -3311, -4302, -8556, -5486, -9925, -10494, -10449, -8816, -15377, -7035, -9377, -10897, -9692, -6966, -10351, -7962, -7623, -6415, -5614, -6263, -6224, -6176, -8085, -6004, -8928, -7974, -8482, -8961, -6683, -15713, -8733, -11044, -8909, -9524, -9595, -6530, -10027, -9220, -16761, -7156, -6052, -9278, -8183, -10191, -6519, -8056, -10499, -7503, -8314, -6524, -9726, -8568, -7912, -7454, -6168, -7788, -6564, -8006, -7323, -6360, -6623, -5660, -7513, -8958, -7956, -6270, -5558, -7624, -12761, -8830, -6275, -5664, -9072, -13250, -8080, -6211, -5807, -11441, -10268, -8066, -6481, -6255, -11688, -8512, -8791, -7602, -6731, -9345, -7804, -8950, -9074, -6544, -7603, -7631, -7568, -9252, -6544, -6215, -7159, -6531, -8562, -7341, -5194, -6266, -6163, -8140, -8458, -4865, -5520, -6092, -7987, -7760, -5326, -5329, -6243, -7926, -6852, -6405, -5870, -6721, -8345, -7595, -7663, -7234, -7119, -10125, -10775, -8350, -8534, -7286, -16410, -8787, -7965, -7840, -7968, -12117, -7281, -7110, -7247, -9360, -9899, -8670, -6584, -7114, -10510, -9248, -13548, -6732, -6288, -10753, -9136, -8383, -7539, -5229, -10635, -9847, -7519, -8798, -4756, -9004, -10133, -9215, -10716, -5047, -7250, -7926, -15045, -11737, -6079, -6478, -6366, -13869, -9279, -7261, -6801, -6041, -12884, -8079, -7599, -8272, -7054, -12862, -8067, -7855, -10268, -10148, -11724, -8568, -8570, -10879, -14031, -10273, -8699, -9357, -11814, -9495, -8848, -8366, -10098, -12661, -8400, -7876, -8351, -10997, -11791, -8652, -7701, -8922, -10359, -10201, -9356, -8575, -9593, -9505, -8288, -9822, -11194, -10080, -11126, -7323, -10529, -21742, -10828, -10949, -7205, -11905, -11172, -12073, -7210, -7450, -13675, -9491, -14562, -6110, -8045, -13884, -9622, -13397, -6723, -9438, -11220, -11368, -11545, -9052, -12156, -10030, -16389, -12288, -12561, -18890, -10493, -15268, -16791, -11629, -15410, -12913, -14502, -14921, -11217, -12042, -19888, -28647, 13098, 8550, 12481, 11510, 6595, 12477, 8828, 11738, 10975, 6030, 10405, 8846, 9290, 9300, 4418, 5407, 8596, 4699, 6340, 3498, 4144, 8868, 3899, 2446, 4495, 6787, 8970, 2932, 1036, 4904, 6608, 8465, 1355, 3923, 4740, 4907, 7665, 1149, 4657, 4591, 551, 6910, 744, 2513, 4346, 634, 6196, 1842, -279, 3940, 3736, 5306, 2460, 4698, 3741, 4214, 4093, 2261, 6028, 3943, 2999, 3252, 2051, 5861, 4558, -1126, 3221, 2513, 4490, 5250, -2272, 2371, 2501, 2731, 5767, 1238, 375, 1447, 3380, 5850, 1900, 2377, 1045, 3946, 5011, 2334, 3950, 2051, 3233, 2580, 3282, 3982, 2613, 1159, 159, 3710, 2869, 2481, 487, 1210, 3661, 1243, 1716, 2588, -657, 4677, 1926, -421, 3542, -546, 5690, 3141, -7300, 3727, 2018, 5486, 2751, 1503, 3443, 2021, 4042, 1177, 3537, 2839, 305, 2858, 2208, 3935, 2313, -2395, 2622, 2907, 3506, 1766, -2201, 820, 1286, 2877, 816, -25, -2138, -2230, 2460, -253, 1158, -185, 2089, 2181, -948, 1834, -429, 3619, 1837, -1815, 2181, -2963, 3555, 1253, -3382, 1436, -7497, 2318, -221, -1989, -2519, -3937, 466, -5658, -553, -383, 130, 109, -2147, -554, 2605, 1478, 993, 944, -327, 2950, 1038, 1962, 1665, 621, 1470, -1293, 2675, 1147, 637, -1902, -6527, 2557, -113, -766, -2756, -2414, 1072, -1280, -3066, -1732, 176, -407, -1687, -1358, -1275, 1793, 1532, -1903, 714, -738, 2727, 2283, -2128, 1424, -1013, 2830, 1480, -1826, 1085, -2187, 1872, -748, -1223, 504, -1724, -540, -3577, -1331, 302, -372, -3290, -3077, -2456, -212, 453, -1665, -2179, -2590, -1244, 769, -958, -2758, -1194, -2220, 646, -1298, -5466, -206, -3085, 298, -2484, -13396, 244, -3976, -448, -5072, -6577, 67, -3844, -1491, -15234, -3075, -866, -2785, -1116, -7562, -1541, -2665, -2528, -294, -7910, -1687, -5553, -3298, -160, -10161, -3578, -10016, -3192, -472, -3439, -5625, -9486, -2319, -951, -1201, -4550, -9342, -2459, -1431, -458, -4420, -6978, -3757, -1541, -854, -3911, -4840, -6298, -1450, -2480, -2853, -3829, -7433, -2031, -5517, -2518, -2354, -5552, -3672, -8558, -2856, -980, -3831, -4039, -6818, -3270, -177, -2357, -3496, -4436, -2980, 111, -1947, -5155, -3473, -2306, -187, -2633, -5752, -3380, -2078, -1182, -3664, -3089, -3429, -2692, -2826, -3918, -2817, -3812, -4573, -4250, -3465, -4590, -5220, -9117, -4231, -3124, -8516, -7993, -11830, -4338, -3576, -11939, -7717, -7077, -4823, -4840, -12315, -4104, -4608, -4103, -4752, -7408, -1875, -3730, -3127, -3489, -5600, -790, -4849, -3237, -3361, -3940, -662, -9472, -4932, -4740, -2668, -1493, -4366, -5298, -7908, -2498, -3603, -2126, -3150, -9119, -3642, -8609, -1767, -2772, -5899, -6106, -6767, -2754, -4208, -3280, -5059, 6690, -8153, 10131, 7048, -919, 6500, -1237, 9535, 7554, 1466, 5763, 2689, 7584, 8134, 2435, 4781, 4620, 3350, 8012, 1830, 5661, 5048, 658, 7105, 778, 6783, 4105, 3704, 5783, -74, 6618, 2593, 4285, 5187, 720, 5186, 2589, 3617, 5421, 1199, 4084, 2423, 1579, 5335, -518, 3879, 2804, -894, 4502, 692, 1989, 4329, 1791, 2961, 3354, 1889, 5035, 3692, 1175, 4608, 4214, 4861, 3955, 476, 5123, 4452, 4207, 2604, 1752, 4949, 2423, 3388, 1864, 3468, 3937, -2942, 2577, 4006, 4407, 2053, 2979, 2078, 5120, 4232, -451, 4465, 1539, 5069, 2721, -2834, 4398, -366, 4056, -1059, -4394, 3825, -1555, 2553, -3650, -4648, 3783, 984, 1518, 220, -2108, 4223, 1564, 1432, 1126, -416, 4287, 927, 1765, 985, -266, 3353, 180, 1171, 1319, -1422, 700, 323, -1087, 2497, -1730, -3577, 986, -4078, 3156, -379, -145, 804, -5633, 3189, 347, 692, -838, -2836, 3184, 591, 372, -3742, -1062, 3175, 815, 775, -4880, -1859, 2491, 1139, 1429, -2167, -6691, 487, 1412, 1693, -494, -3217, -4289, 1377, 2490, -297, -193, -6386, 972, 3451, -977, 1287, -4593, 571, 3687, -1970, 2053, -4635, 521, 3061, -3478, 2249, -3130, 572, 2009, -2216, 1942, -2060, 642, 1428, 431, 1191, -2079, 677, 1189, 1781, 15, -3089, 122, 430, 2063, -996, -816, -1523, -2164, 1360, -575, 1708, -3664, -6231, -374, 368, 2832, -4666, -355, -2308, 889, 2960, -3159, 1093, -1614, 588, 2495, -820, 1216, -287, -1047, 1888, -233, 463, 180, -5792, 1396, -1210, -1699, -456, -5831, 827, -1932, -4360, -1542, -3116, -181, -1081, -1611, -1293, -2754, -1835, -1012, -752, -892, -3009, -3416, -1665, -1331, -1022, -3744, -2976, -2081, -3307, -1008, -5304, -1919, -2296, -6978, -599, -9515, -1543, -2617, -2689, -324, -5503, -2134, -2837, -849, -552, -2105, -4034, -2991, -641, -1427, -987, -9344, -3313, -1334, -3026, -1507, -5572, -3958, -2143, -3900, -4232, -2728, -4591, -2131, -2097, -11497, -1606, -4683, -1188, -635, -4314, -772, -4588, -392, -95, -3143, 504, -5553, -420, -401, -3153, 1642, -12972, -1425, -1560, -3376, 2085, -5530, -3346, -3278, -3476, 1682, -3339, -6006, -4696, -2954, 318, -3931, -8714, -4326, -1709, -2490, -3776, -10887, -1777, -777, -10400, -1479, -12866, -745, -686, -5189, -826, -8513, -1537, -1478, -4025, -1742, -7835, -3353, -2888, -5665, -3837, -6347, -2788, -3952, -17953, -6267, -4056, -2692, -4012, -4997, -8544, -3186, -4337, -4604, -2943, -5270, -3660, -6473, -9815, -2948, -2994, -3978, -7759, -4141, -4830, -1837, -2409, -9588, -365, -8098, -1245, -1044, -7724, 1152, -7450, -1150, -518, -3907, 1373, -5088, -1650, -941, -1635, 501, -2392, -2714, -2385, -835, -1466, -920, -3973, 8763, 8553, -1506, 9043, 5045, 8329, 7818, 4856, 8679, 5189, 7124, 5235, 6475, 7547, 4899, 5539, -2724, 5978, 5518, 3051, 4243, 1960, 3948, 2257, -764, 3257, 2827, 3653, -4867, 3192, 1750, 1546, 4642, -1789, 4821, -503, -1688, 4092, 759, 4430, -877, -10154, 1867, 814, 540, 675, -6481, 292, -964, 1989, 2501, -5274, 1801, -2428, 5702, 3249, 984, 1939, -1699, 6847, 2841, 3143, 325, -4114, 7089, 2120, 3203, -449, -1716, 7005, 1932, 879, 1514, 1679, 6616, 1470, -1494, 1524, 2209, 5686, 383, 1209, -1306, 129, 4051, -917, 274, -2145, -4903, 1958, -3227, -10316, 421, -2018, 2525, -6570, 1371, 165, -7468, 4230, -1425, 3275, -1489, 652, 4741, 506, 3377, -3377, 3027, 3845, 1603, 2098, -3518, 3347, 845, 2379, -1130, -505, 2476, -1302, 2437, -2395, 1055, 832, 1731, 1313, -13, 1424, -1240, 1930, -1705, 66, 1181, -2536, -493, -10492, -1451, 1033, -3839, -1341, -10204, -4003, 1254, -2854, 2599, -4882, -4488, 1321, 1188, 3988, -429, -2851, 976, 3064, 4135, 1534, -2062, 521, 3641, 3510, 2383, -2765, 362, 3398, 2477, 2512, -4557, 551, 2803, 1501, 1934, -2537, 731, 2299, 1677, 334, -1009, 638, 1833, 3102, -2805, -1109, 447, 969, 4139, -2513, -2382, 332, 160, 4254, -556, -4855, 342, 1225, 3384, 230, -9011, 901, 2469, 1469, 344, -1342, 1682, 2800, -1616, -299, 1071, 1871, 2211, -4908, -1796, 1832, 1146, 841, -4058, -3723, 1510, -467, -884, -1918, -4119, 501, -1711, -2314, -531, -2890, -225, -1369, -3129, -539, -2156, -60, -1479, -3522, -2704, -2097, -308, -2167, -4943, -4489, -2310, -2024, -1823, -6980, -1326, -2668, -4405, -951, -3549, -759, -3620, -2580, -708, -1778, -1286, -4578, -2603, -1275, -1417, -1385, -4056, -6586, -2563, -2143, -1543, -3927, -5338, -3925, -3430, -2858, -3746, -2880, -4848, -3057, -6455, -3291, -3926, -5108, -1669, -7064, -3807, -11714, -3433, -786, -2551, -3780, -5750, -2579, -553, -530, -2358, -3964, -3609, -1075, 313, -1908, -4017, -7855, -2455, 274, -2862, -4266, -6328, -4246, -274, -4876, -3763, -3283, -5502, -747, -4153, -2845, -1491, -8382, -1394, -2877, -2209, -403, -9169, -2948, -2452, -2235, -95, -4587, -3623, -1834, -3028, -594, -2742, -2108, -1247, -4172, -2123, -1891, -1002, -1352, -4534, -5646, -1920, -289, -2096, -4388, -7798, -3139, -214, -3092, -5273, -5865, -6345, -1249, -3905, -8090, -9013, -7257, -4051, -3610, -4638, -7809, -5399, -7985, -2443, -2722, -4250, -5762, -4407, -1562, -2710, -3316, -6933, -2448, -1343, -3403, -2966, -9019, -1554, -1776, -3475, -3180, -8528, -1840, -2636, -4344, -4117, -2747, -3535, -3723, -9379, -4126, -312, -3640, -5202, -6598, -3572, 711, -1680, -6312, -3807, -3978, 831, -1188, -4245, -4310, -7584, -1936, -2416, -3598, -3759, -6397, -1902, -1112, -4363, -2385, -4368, -2542, -971, -7739, -1412, -4526, -2295, -1956, -5969, -909, -9751, -1952, -3951, -3203, -1013, -5079, -2482, -5007, -2823, -1841, -2115, -3485, -3893, -4508, -3042, -1813, -3944, -2476, -8390, -3065, -3524, -3411, -1102, -5568, -2684, -5474, -2825, -289, -5226, -3652, -2696, -2998, -310, -5345, -8172, -1250, -4284, -1246, -3334, -6708, -857, -7354, -2712, -2274, -3151, -1019, -9777, -2957, -2140, -2087, -1432, -5676, -2471, -2637, -2178, -2087, -3877, -2453, -4159, -3341, -3348, -3197, -2388, -7626, -5980, -5700, -3484, -2026, -4123, -5319, -5244, -4475, -1800, -1513, -2944, -2875, -4371, -1973, -696, -2443, -2122, -3853, -2977, -1062, -3546, -2808, -4503, -5683, -1769, -6391, -4870, -4615, -6658, -1760, -9873, -6902, -2950, -4382, -1757, -8724, -7033, -1944, -4151, -2451, -6731, -8317, -1880, -5179, -3833, -5847, -8860, -2768, -5707, -5330, -5913, -6610, -4725, -4401, -5875, -6154, -6022, -5516, -3292, -6049, -6410, -6349, -4202, -2875, -6326, -6422, -5028, -3904, -2945, -6690, -5428, -4164, -4081, -3296, -7285, -3982, -5411, -4086, -4066, -7589, -3160, -9155, -4876, -6195, -8635, -3481, -6154, -7075, -13717, -17795, -5003, -5407, -6101, -4434, -6576, -5973, -6237, -4436, -2085, -3952, -5654, -5689, -4266, -1523, -3278, -7182, -4895, -5054, -2485, -4046, -8509, -5342, -6065, -5898, -5987, -3994, -6742, -6265, -7377, -5848, -2032, -6876, -4901, -3902, -4456, -1474, -5497, -3380, -3330, -4201, -2127, -4147, -2510, -4583, -4967, -4416, -3244, -1952, -8653, -6811, -11506, -3228, -1339, -6706, -10673, -7462, -4530, -996, -4300, -9813, -5660, -7329, -1301, -3779, -7764, -4954, -5833, -2200, -4394, -8093, -4546, -4186, -3206, -5595, -9355, -4807, -4028, -4239, -6176, -8076, -5462, -4511, -6117, -5945, -6543, -5732, -4528, -9712, -5220, -5844, -5094, -4086, -9797, -4710, -5940, -3813, -4005, -6182, -4521, -7039, -3016, -4075, -4228, -3924, -8014, -2996, -3576, -3577, -3383, -6866, -3434, -3182, -3886, -3540, -6838, -3964, -3752, -4418, -4241, -8312, -4467, -5897, -4328, -4970, -7845, -4810, -10414, -4067, -5665, -7341, -5217, -8887, -4270, -6873, -8852, -6348, -9758, -5437, -10058, -9898, -8191, -11707, -8987, -10901, -9673, -6973, -7642, -9459, -6637, -15261, -6045, -7429, -5868, -5225, -6272, -7219, -10226, -4687, -5036, -3421, -10001, -13849, -4330, -5559, -2544, -8478, -12205, -4389, -6394, -3113, -7046, -11090, -4939, -7445, -5228, -6198, -9975, -6280, -9031, -9711, -5579, -11368, -6788, -10330, -11091, -5669, -10241, -4890, -8679, -8822, -6936, -7734, -3785, -6695, -7786, -7611, -6787, -3772, -5455, -7664, -6296, -6440, -4766, -5136, -8690, -6163, -5953, -6939, -6212, -9519, -7597, -5168, -8792, -10846, -8362, -11220, -4762, -7115, -7982, -8059, -14884, -5349, -6460, -5340, -4174, -1237, -4037, -530, -4954, -4174, -2522, -3614, -994, -6100, -2920, -3954, -2632, -2247, -9287, -1616, -4426, -2914, -4583, -5939, -845, -4044, -3528, -6908, -2561, -797, -4028, -2921, -4638, -1136, -1577, -4795, -2614, -3579, -1038, -3496, -5431, -3322, -3708, -2270, -7766, -4628, -3843, -4251, -5138, -7506, -3381, -3110, -4437, -7679, -4581, -2569, -2639, -4356, -7414, -3575, -2247, -2931, -4870, -6583, -3313, -2108, -3925, -6622, -4064, -3390, -1943, -5490, -7479, -2462, -3729, -1799, -7472, -5139, -1960, -4159, -1785, -11648, -3484, -2290, -4479, -1986, -10230, -2910, -2944, -5338, -2099, -6642, -4165, -4211, -8715, -1448, -5782, -8041, -8232, -8483, -722, -5205, -3221, -5106, -4944, -913, -4297, -1544, -3085, -3364, -2204, -3838, -1820, -3118, -1824, -2690, -3507, -4098, -3537, -968, -1757, -2774, -21301, -3335, -1385, -1588, -1829, -4718, -2810, -3704, -1814, -1186, -3376, -2211, -21827, -1887, -1290, -4445, -2342, -4557, -2236, -2360, -8339, -3652, -3064, -2763, -3372, -6379, -6009, -3624, -2998, -2490, -4106, -8994, -6324, -3087, -2093, -4128, -13751, -9152, -2466, -3083, -7281, -11801, -4567, -1805, -4833, -8001, -10322, -3041, -2281, -3630, -4067, -9236, -3017, -4560, -1911, -3684, -8263, -4517, -10479, -1119, -5675, -6364, -10327, -20358, -1023, -10732, -4767, -6247, -8368, -1528, -4746, -4216, -2983, -4246, -2913, -2574, -4841, -1884, -2734, -6145, -1727, -7198, -2100, -2697, -11135, -1772, -7530, -3580, -3827, -7508, -2708, -4040, -6147, -6024, -7296, -4290, -2445, -7961, -8740, -5872, -4995, -2092, -7900, -10261, -4057, -5117, -2828, -5617, -9008, -3259, -6224, -4583, -4048, -7363, -3309, -7746, -6672, -3700, -7212, -4105, -7622, -9777, -3554, -8676, -6131, -6578, -5873, -2582, -10892, -12501, -5608, -2886, -1768, -7949, -6930, -5185, -2165, -1734, -4853, -4810, -5409, -3225, -2563, -3271, -4393, -6393, -6190, -4328, -2921, -4492, -5464, -6662, -6721, -3605, -4504, -2806, -5473, -7027, -5113, -4566, -1484, -5975, -6032, -6411, -5262, -1418, -7516, -5429, -5497, -7180, -2201, -8448, -5025, -4215, -8562, -2727, -7362, -4902, -3800, -7443, -2685, -6053, -5415, -4525, -7229, -3456, -5082, -6395, -6904, -6703, -5888, -4365, -6522, -9974, -5301, -7193, -3975, -5716, -6555, -4081, -6234, -4262, -4815, -4722, -3544, -8030, -5932, -4538, -3835, -4174, -10042, -12196, -5802, -3681, -7210, -5852, -8365, -11229, -4208, -10922, -4575, -6589, -6415, -5101, -5875, -4948, -7750, -4057, -6052, -5357, -6997, -11230, -3570, -7159, -6148, -12133, -7698, -3994, -8878, -6703, -11760, -4551, -4813, -13831, -7419, -7405, -2793, -5913, -12081, -9096, -5796, -2280, -7953, -9445, -8924, -5801, -2982, -14337, -9974, -7061, -6966, -4944, -8875, -10837, -5828, -7896, -8018, -6489, -8304, -5412, -7048, -8014, -6504, -6799, -5686, -6278, -6303, -8279, -6485, -6170, -6540, -5936, -5547, -3390, -4884, 313, -2275, -5205, -3825, -4419, -712, -6002, -6433, -4252, -3189, -2211, -7314, -9619, -4710, -2507, -3601, -3322, -6767, -6094, -2362, -3490, -2405, -4586, -10020, -2379, -3266, -2906, -3675, -10631, -2392, -4206, -4625, -3173, -8286, -2611, -5431, -5448, -2849, -8566, -3250, -4016, -2558, -2961, -7528, -4419, -2752, -883, -4098, -5385, -6192, -2356, -731, -8262, -3910, -8129, -2542, -2219, -5083, -2952, -5691, -3190, -5673, -1978, -2423, -2901, -4317, -4986, -924, -2528, -1423, -5413, -3747, -850, -3729, -1128, -4775, -3680, -1003, -7519, -2264, -3471, -3324, -746, -8795, -6607, -2657, -2284, -461, -4480, -6069, -2310, -1272, -796, -3395, -3008, -2363, -836, -1808, -3736, -3082, -2986, -1026, -2795, -5576, -5211, -4724, -1269, -3337, -11530, -5590, -9675, -898, -3985, -7161, -3814, -7127, -399, -4453, -4459, -3717, -4424, -272, -4145, -3612, -4997, -3564, -698, -3620, -3438, -7013, -3593, -2199, -3800, -3317, -8395, -4469, -7607, -5528, -3399, -7366, -5659, -4618, -14263, -3532, -5910, -5974, -1672, -5954, -2692, -4889, -4994, -1074, -3646, -1954, -3507, -3351, -1526, -3297, -2598, -2770, -2700, -2589, -3889, -6451, -3521, -3070, -4159, -4155, -5944, -6990, -3590, -6149, -3818, -2166, -9168, -4215, -7917, -3963, -1372, -4878, -6426, -7147, -4834, -2278, -3570, -10798, -4734, -5753, -5726, -2839, -6221, -3579, -5617, -9161, -2446, -4039, -3903, -4882, -4570, -2575, -2848, -5119, -4334, -4000, -2973, -2471, -5503, -4278, -4478, -2937, -2861, -6736, -4598, -5032, -2978, -4320, -9367, -4628, -6017, -4192, -10281, -4014, -4672, -8068, -5377, -5145, -1725, -5761, -10937, -3245, -2092, -688, -4328, -10058, -1908, -1239, -363, -1743, -6145, -1607, -1582, -580, -715, -4074, -2175, -2512, -1221, -956, -3665, -3863, -3144, -2089, -1971, -5056, -4436, -3419, -2881, -2545, -9684, -2025, -3608, -3396, -2396, -12097, -994, -3362, -3588, -2442, -10976, -1438, -2872, -3295, -3008, -11353, -3386, -2753, -2876, -4564, -8431, -7063, -3675, -2700, -9427, -7128, -8582, -6544, -2614, -7480, -6192, -8026, -6297, -2497, -4253, -4874, -8420, -3969, -2731, -3707, -3623, -8860, -3467, -4105, -4764, -2854, -8585, -3975, -7415, -5983, -2595, -7169, -4972, -5572, -5020, -2861, -5735, -6013, -3911, -4773, -3655, -5287, -7482, -3890, -5173, -4776, -6153, -10354, -4815, -4027, -5856, -7702, -8618, -6613, -2938, -6685, -6564, -6505, -8551, -3061, -7454, -5335, -5890, -6235, -4488, -8389, -5273, -6417, -4250, -6685, -7292, -6254, -8490, -3528, -7534, -5091, -8071, -16270, -3670, -8866, -3933, -8751, -10555, -4230, -13174, -3898, -7635, -7917, -5234, -11510, -4896, -6785, -6733, -6968, -9992, -6789, -6312, -6186, -6140, -10876, -9400, -6279, -6354, -4174, -14447, -13489, -6691, -7307, -3387, -9865, -9254, -7337, -6874, -3650, -8955, -6250, -8217, -5054, -4855, 6703, 3204, 1586, 6835, -3668, 6345, 2720, 1801, 6394, -1134, 5365, 1177, 1741, 5107, 1061, 4119, -2197, 898, 3222, 2289, 3167, -8615, 284, 1169, 2993, 2409, -2027, 1073, -2036, 3106, 1086, -1293, 1938, -5374, 2331, 547, -1753, 2523, 5, 797, 1067, -24, 2946, 1931, 656, -1071, 1855, 2833, 2952, 2201, 1457, 3108, 1416, 3439, 3749, 4705, 4256, -32, 3213, 5112, 5749, 5414, 2752, 1872, 5989, 5477, 6280, 3819, -160, 6105, 4546, 6504, 2810, 1047, 5312, 3980, 5820, -433, 1945, 3821, 3567, 3844, 2125, 1419, 2976, 2419, -320, 3857, 176, 2403, 1613, 164, 3877, -1456, -24, 2528, 1172, 2732, -3532, -1812, 2889, -517, 1047, -144, -435, 2003, -408, 292, 1904, -883, -362, 1147, -1093, 2728, 1437, -5296, -94, -8915, 2993, 2659, -7021, -10282, 1091, 2931, 1639, -4613, 811, 3232, 2468, -3024, -2828, 2863, 3548, 1460, 1274, 126, 3568, 2711, -394, 3262, 1813, 3683, 1363, -4406, 3223, 2242, 3312, 403, -1225, 1673, 1474, 2497, 23, 1854, -1056, -1611, 1466, 825, 3183, -2861, -3901, 473, 1839, 3504, -5223, 1113, -398, 1868, 3128, -6163, 2229, -1538, 795, 2285, -3406, 1855, -2338, -252, 1237, -3807, 544, -276, -252, 395, -4846, -970, 948, -1082, -25, -2043, -860, 533, -2352, -229, 9, 484, -1634, -993, -505, 1165, 1547, -3511, -590, -974, 1707, 2050, -2970, -2518, -1589, 1697, 2108, -5249, -2631, -2542, 1152, 1867, -7052, -177, -3760, 137, 1291, -3246, -75, -3836, -1175, 229, -3124, -2183, -2316, -2709, -1316, -3948, -6511, -993, -4539, -3187, -2271, -6249, -588, -4778, -5457, -695, -10341, -1169, -3864, -4383, 156, -7273, -2097, -4081, -2309, 567, -4283, -1895, -5611, -1484, 490, -3179, -1638, -6577, -1538, -352, -2336, -2480, -5376, -2014, -2253, -1795, -4154, -4983, -2025, -3769, -2038, -3711, -5141, -1714, -2523, -3799, -2234, -4715, -2128, -1522, -9073, -1593, -3986, -4264, -1285, -7244, -1632, -3726, -5375, -2149, -8677, -1852, -4676, -1688, -4917, -7194, -1826, -8096, -492, -12282, -2964, -1637, -7885, -1091, -6994, -2175, -1556, -5414, -3828, -5926, -3777, -1687, -4540, -20328, -5444, -8621, -1951, -4144, -6359, -4912, -3849, -2310, -4653, -5526, -4968, -2186, -2929, -6903, -5798, -5746, -2091, -4192, -8093, -5356, -6310, -2948, -6581, -5592, -4002, -6308, -4391, -7763, -5412, -2773, -7445, -5002, -6596, -8029, -2051, -14411, -4477, -7266, -10649, -1923, -8147, -4639, -10554, -7352, -2289, -6031, -5873, -13132, -8828, -3032, -6298, -7359, -9153, -7857, -4502, -7934, -7195, -6047, -4379, -7915, -9677, -5741, -4285, -3318, -9178, -9480, -4826, -3693, -3636, -5388, -7589, -5189, -4258, -4850, -4741, -5690, -7230, -6325, -6145, -6763, -4460, -9858, -11254, -6214, 1293, 6143, 1369, 3002, -6919, 2589, 5625, 2395, 2359, 1396, 3514, 3919, 3497, -60, 4035, 2884, 548, 3781, -7328, 5095, 458, -776, 3353, -198, 5134, 590, 749, 2328, 1795, 4407, 3217, 1141, 412, 2568, 3058, 4693, 983, -4580, 2762, 858, 5438, 119, -3118, 2391, -2306, 5534, 1281, -1659, 1589, -3437, 5182, 4135, -72, 1068, -106, 5599, 5719, 3958, 1330, 2715, 6580, 6093, 5937, 1590, 3934, 6784, 5487, 6334, 1391, 3827, 6024, 4268, 5213, 2532, 2476, 4725, 2996, 1936, 4331, -143, 3626, 1903, -1202, 5311, -3511, 2869, 75, 1116, 5583, -4604, 1661, -5912, 358, 5407, -3736, -1659, -312, -3236, 4889, -4575, -6926, 993, -10314, 4077, -4774, -2910, -919, -8073, 3183, -3574, -2594, -1749, -4815, 2386, -4578, -223, 2025, -402, 1379, -3131, 1151, 3552, 1653, -307, -1652, 1588, 4067, 2550, -1863, -2704, 1634, 3913, 2716, 128, -4038, 1601, 3233, 2298, 1743, -976, 1691, 2509, 1212, 2014, 106, 1861, 2459, -545, 910, -530, 1893, 2695, -1881, -2392, -3240, 1653, 2586, -1497, -7493, -4522, 1314, 1810, -577, -1369, -554, 1343, -279, -149, -17, 1383, 1717, -1704, -736, -337, 2342, 1784, 1357, -2468, -1523, 2672, 1083, 2579, -4590, 301, 2526, -625, 2299, -4465, 2389, 1926, -3639, 566, -2154, 3378, 857, -5484, -3344, -534, 3636, -375, -2516, -12965, 58, 3478, -860, -379, -4807, -35, 3069, -38, 1062, -567, -587, 2468, 1059, 1903, 1600, -1397, 1548, 1590, 2101, 2320, -1832, -55, 1443, 1640, 1993, -2134, -1309, 726, 561, 1127, -3168, -521, -312, -1202, 354, -4864, -373, -945, -4005, -663, -6055, -1355, -869, -4117, -2990, -5865, -3041, -902, -2457, -8170, -5027, -4746, -1442, -2935, -10249, -4432, -5016, -2340, -7190, -6067, -4864, -4258, -3037, -6829, -2751, -6363, -3300, -3169, -4239, -1698, -5350, -2072, -3388, -5548, -2701, -3534, -1137, -4792, -7117, -7722, -2995, -814, -8137, -3626, -6399, -3808, -1096, -7043, -2003, -4058, -6258, -1518, -6399, -1569, -4900, -9322, -1486, -6839, -2077, -8802, -7117, -1405, -5116, -3519, -8928, -5047, -1596, -3431, -5787, -5447, -4194, -1928, -2840, -6319, -3920, -4545, -2079, -3631, -4603, -3377, -5533, -1722, -6507, -3148, -3755, -5508, -1590, -10105, -2108, -5016, -5074, -2436, -9812, -1715, -6540, -5372, -4575, -11719, -2270, -6622, -6098, -6740, -5126, -4204, -5991, -7256, -5343, -3221, -8612, -5590, -9812, -4101, -3040, -8594, -5369, -9472, -3783, -4275, -6415, -5323, -8459, -4783, -6485, -5315, -5352, -9788, -9495, -5953, -4822, -5571, -10721, -6150, -5775, -5135, -6381, -10666, -3189, -8294, -6049, -7777, -12603, -2586, -7554, -6878, -8223, -10970, -3410, -5760, -6977, -5866, -9642, -5563, -6499, -6528, -4094, -9282, -9337, -8436, -6019, 6460, 8585, 6506, -1671, 2320, 6263, 7904, 6607, 4638, 4738, 5687, 6070, 6838, 6771, 5155, 4927, 4654, 6804, 7110, 3835, 3991, 3955, 5957, 5941, 436, 2319, 1879, 3752, 2813, -1564, 1025, -2462, 1189, 481, -1290, 1768, -6966, 2144, 1278, -4873, 1698, -2827, 2060, 2646, -3446, 695, -839, 2309, 5169, 1280, 485, -121, 3583, 6523, 3448, 1856, 216, 3940, 6911, 4334, 2638, 242, 2952, 6260, 4036, 2291, -887, -240, 3493, 2322, 858, -4898, -6552, 1023, -1619, -2154, -1399, -694, 5282, -1276, -6278, 670, -750, 6114, 394, -1566, 783, -2170, 5681, -62, -1027, -185, -2775, 5170, -2306, -3586, -1760, -3144, 4729, -7322, -3833, -3287, -1245, 3711, -19766, -589, -3358, -222, 2242, -8093, 27, -3191, -970, 1022, -4243, -1122, -3548, -3359, 209, -3298, -4685, -2986, -5363, -298, -4225, -7646, -1347, -5386, -964, -8173, -6611, -132, -5248, -1823, -6344, -5415, 315, -4457, -999, -2598, -2179, 144, -3868, 105, -1560, -1501, -509, -3549, 279, -2197, -2952, -1794, -3053, -246, -3620, -5376, -3607, -2577, -1222, -2705, -4183, -4144, -3278, -3791, -1762, -2836, -2395, -6206, -5145, -1087, -2115, -305, -1526, -1274, 104, -2627, 818, 929, -498, 781, -4614, 704, 1460, -1142, 253, -4524, -603, 434, -2681, -2192, -2584, -777, -2499, -5398, -5049, -1574, 712, -11590, -2509, -2376, -1586, 1435, -3710, -250, -3423, -1846, 1829, -1418, 701, -2715, -487, 2131, -1248, 1073, 867, 716, 1818, -3331, 1106, 2047, 902, 523, -12523, 682, 1608, 253, -1466, -6181, -499, -528, -912, -1687, -5199, -2605, -6409, -2194, -639, -4671, -4952, -5239, -3145, -138, -4332, -7433, -3721, -3566, -337, -4663, -12593, -5254, -3552, -1391, -4762, -7195, -8644, -3370, -3758, -4647, -6089, -5053, -3458, -6957, -4791, -6491, -3648, -4299, -5356, -4950, -5986, -4012, -6366, -4894, -5337, -4762, -5765, -9859, -5770, -6680, -4250, -7849, -8077, -6539, -8993, -4049, -7880, -5595, -7021, -7878, -3440, -7817, -4289, -9246, -6359, -2550, -7828, -3690, -14931, -5444, -2002, -6701, -3536, -8096, -4238, -2251, -5883, -3852, -7104, -3132, -3703, -6021, -5128, -8187, -2707, -7868, -6281, -9567, -9829, -3158, -8433, -6121, -7803, -9826, -4530, -4120, -6513, -4211, -8745, -6605, -2590, -7734, -3280, -8554, -8064, -2129, -8656, -3965, -8337, -8232, -2411, -7856, -6265, -5359, -8473, -3191, -6319, -7133, -3973, -8603, -3961, -5119, -5602, -4297, -8081, -4038, -4657, -4597, -5804, -7912, -3391, -5386, -4008, -6926, -8704, -2602, -7435, -4229, -8161, -11275, -2156, -7266, -5466, -9710, -14398, -2307, -7574, -7933, -7565, -8732, -3190, -11110, -10776, -7046, -7437, -4874, -5258, -8394, -8759, -8230, -6787, -3350, -6713, -15560, -10338, -6749, -3291, -6291, -10373, -10250, -6686, -8081, -3861, -7544, -12242, -5296, -4990, -3638, -6283, -9534, -4842, -4384, -3611, -6077, -7659, -5782, -4796, -3644, -6173, -6376, -8535, -5620, -3851, -5851, -6373, -7229, -7298, -4720, -5509, -7419, -6000, -7694, -6763, -5797, -6459, -6692, -5630, -10988, -6929, -4902, -7763, -4236, -14770, -8883, -4496, -7651, -3452, -10059, -11134, -5015, -7245, -3129, -8703, -10550, -5908, -5993, -3172, -8592, -8335, -6287, -4910, -3536, -8320, -7303, -6516, -4655, -4341, -7341, -6919, -7810, -5046, -6037, -7272, -6556, -9608, -5551, -10399, -8040, -6681, -8608, -5595, -11077, -7942, -7533, -8245, -5352, -7727, -7381, -8621, -9242, -5506, -7582, -6260, -8946, -12264, -6541, -9181, -4954, -6697, -9602, -8278, -11606, -4501, -5073, -6425, -8221, -10750, -5169, -4816, -5116, -7345, -8677, -7055, -5554, -4801, -7546, -6583, -8102, -6044, -5165, -9019, -5398, -6459, -5659, -6100, -11315, -5408, -5590, -5940, -7048, -10794, -6623, -5433, -7994, -6872, -9456, -8768, -5395, -11278, -6691, -8343, -10468, -5121, -8059, -7592, -7063, -9210, -4766, -7158, -9540, -5863, -7060, -4729, -7870, -9096, -5170, -6140, -5375, -10321, -6839, -5354, -6402, -6812, -17832, -5637, -6724, -7307, -7519, -9106, -5496, -8705, -7919, -6604, -7291, -6224, -7896, -8120, -6267, -7301, -7367, -7235, -7994, -6827, -8576, -7996, -7929, -7577, -8062, -10179, -7451, -9083, -7175, -9730, -10866, -6625, -8186, -7108, -10845, -10002, -6490, -6085, -7891, -10350, -8082, -6925, -4784, -9322, -9988, -7385, -7246, -4706, -9306, -9214, -8374, -7127, -6081, -8930, -7544, -11900, -6299, -9353, -8191, -6706, -12636, -5464, -8912, -7071, -7185, -9948, -5367, -7078, -7114, -8801, -8905, -6146, -6768, -9244, -9259, -7689, -7835, -6756, -14682, -8430, -6448, -10286, -6334, -9283, -8936, -5805, -10398, -6232, -8215, -11595, -5907, -8780, -6925, -9266, -12734, -6654, -8245, -8377, -13011, -10854, -7601, -9180, -10070, -16819, -9726, -8044, -13164, -10194, -12386, -8277, -8308, -11393, -8966, -11102, -7739, -9389, -8107, -7966, -9149, -8758, -12630, -7110, -7712, -7642, -12974, -16843, -7381, -8716, -7506, -12816, -12094, -8807, -12294, -9444, -9445, -12427, -11430, -13088, -13175, -9000, -11861, -13592, -11056, -8018, -9609, -8138, -13507, -13650, -6437, -9416, -6223, -13215, -10254, -6645, -8461, -5572, -11994, -7187, -8797, -8068, -5900, -11103, -6167, -12028, -8353, -7192, -10938, -6353, -8272, -9002, -9690, -9898, -7507, -7329, -9624, -12416, -8870, -9500, -8506, -10184, -12048, -9132, -11676, -11289, -10610, -13399, -10614, -12017, -9963, -10329, -17632, -12277, -10225, -9342, -10059, -11794, -12810, -8551, -11024, -11152, -9739, -10594, -7666, -13738, -16279, -9015, -8973, -7541, -10362, -14029, -8803, -8840, -8188, -8717, -11141, -8518, -10270, -9868, -8657, -10411, -8097, -13847, -13647, -9581, -10752, -7837, -17834, -19148, -9836, -12529, -7931, -20091, -13792, -9977, -11735, -8497, -13887, -12597, -5991, -3744, -8902, -11410, -8909, -5391, -4875, -9033, -8824, -11574, -4686, -7483, -10082, -6786, -9772, -4221, -8386, -11713, -5534, -7215, -4427, -7160, -11370, -5162, -6295, -5663, -6160, -9608, -5567, -4910, -8094, -5465, -8462, -6479, -3906, -10248, -5571, -7955, -7540, -4028, -12081, -6664, -7881, -8728, -5443, -11211, -8168, -8236, -8905, -8792, -8369, -8285, -8463, -7148, -12392, -7433, -7569, -6835, -6183, -8421, -7292, -7064, -5297, -6863, -7661, -6998, -7198, -5058, -10533, -8750, -6326, -8437, -5922, -10417, -12173, -5678, -11215, -5797, -7091, -13441, -5301, -12537, -4946, -6199, -9546, -5184, -10470, -5456, -6234, -8400, -5204, -9073, -7572, -6855, -8838, -5254, -8304, -8123, -8270, -9406, -5340, -6641, -7515, -10446, -8337, -5466, -4801, -9911, -9273, -7318, -5471, -4036, -10924, -7826, -6955, -5336, -4542, -5788, -7617, -7424, -5559, -6493, -4346, -7735, -8804, -6796, -10525, -4645, -7064, -9692, -8022, -24960, -6532, -6083, -8804, -5864, -12193, -8419, -5556, -7612, -4576, -9891, -7835, -5563, -6365, -4740, -9331, -8463, -5905, -5533, -6383, -9772, -10027, -6335, -5503, -10656, -11335, -8994, -6706, -6632, -12304, -14695, -8003, -7338, -10125, -8839, -10698, -8142, -9166, -11785, -8201, -8931, -8256, -12605, -7731, -8399, -9187, -7673, -13029, -6747, -8740, -10575, -6812, -18001, -7123, -9667, -10123, -6003, -8773, -8340, -10541, -9335, -6346, -6194, -9319, -7978, -8672, -9434, -5109, -9667, -6188, -7126, -11739, -4909, -10658, -5687, -6117, -7850, -5786, -12360, -6263, -6042, -7688, -7843, -10842, -7874, -6553, -7756, -7997, -9353, -10055, -7000, -6986, -6754, -9075, -10057, -6836, -6558, -6460, -9185, -8933, -6373, -6269, -6889, -9051, -8414, -6409, -6204, -7961, -9056, -8596, -7465, -7027, -9355, -10020, -9444, -9167, -9397, -10302, -13686, -10432, -8710, -12956, -12171, -13586, -10825, -7945, -10608, -20602, -9473, -11381, -8347, -9115, -11084, -8096, -11883, -9886, -8625, -9771, -8113, -11845, -12840, -9157, -11089, -9648, -13506, -17357, -11322, -15611, -10725, -12426, -12935, -11703, -15018, -8182, -9198, -11329, -8610, -14320, -6861, -8047, -12005, -7322, -9497, -6595, -8139, -16254, -7258, -7208, -7013, -8970, -11442, -7916, -6760, -8093, -10028, -9065, -8420, -7990, -10361, -10859, -9035, -7877, -11779, -17250, -11230, -11400, -7004, -17858, -11925, -11498, -11424, -6944, -12917, -9719, -12969, -8998, -8374, -11280, -9195, -13799, -8777, -12118, -10145, -9121, -10062, -10183, -12353, -10403, -9174, -8311, -11381, -11711, -11370, -9726, -7643, -9668, -11575, -10860, -10616, -7382, -8398, -9651, -10141, -9582, -7492, -7666, -8988, -10232, -7922, -8451, -7308, -10074, -11430, -7321, -10715, -7654, -12915, -12854, -7852, -10677, -9120, -11435, -11781, -9380, -8932, -12507, -9987, -11731, -11085, -9085, -16788, -10218, -12420, -11560, -12065, -13337, -11069, -11049, -11568, -15013, -12380, -10784, -10065, -11213, -10293, -11080, -10060, -10459, -10470, -4645, -7279, -8322, -10262, -8200, -7235, -10412, -8067, -11503, -7272, -7172, -11788, -8851, -12891, -5541, -5762, -10109, -10237, -24390, -5888, -5896, -11184, -11610, -11714, -8864, -8080, -13501, -12644, -10258, -8987, -10534, -9757, -11648, -13154, -6682, -6602, -7124, -11465, -13310, -6786, -5208, -5621, -14978, -9388, -9169, -5411, -4955, -14351, -8002, -12895, -7435, -4944, -10748, -6909, -8310, -12699, -5243, -9682, -6661, -7229, -8543, -5389, -9297, -7954, -7459, -6961, -5349, -9556, -11466, -8024, -6584, -5736, -11375, -10080, -9118, -6553, -7427, -10460, -7665, -10338, -6999, -11786, -7307, -6465, -8590, -8550, -13963, -5895, -6046, -7109, -10132, -14164, -4839, -6536, -6678, -7674, -8115, -3733, -8272, -7110, -6862, -6329, -3312, -11836, -8294, -7997, -6689, -3960, -10943, -9089, -9066, -8144, -5551, -8517, -7720, -8118, -8383, -6593, -7131, -6316, -8435, -8351, -6436, -6196, -5747, -9933, -9374, -7091, -5701, -5978, -9258, -11383, -10144, -5677, -6655, -7256, -11110, -12618, -5888, -6986, -5780, -10439, -7687, -5980, -6480, -4776, -8935, -6403, -6059, -5546, -4204, -6751, -6283, -6454, -4842, -4038, -5731, -6589, -7155, -4825, -4279, -5682, -6878, -7933, -5746, -5162, -6189, -7117, -9120, -7767, -7193, -6874, -7464, -11775, -10395, -9418, -7089, -8237, -10760, -10105, -8380, -6914, -10549, -8362, -8312, -8602, -7812, -14282, -7759, -7345, -11042, -11655, -9857, -8144, -7312, -13243, -12635, -9634, -8513, -7797, -12732, -10126, -12235, -8198, -8174, -13280, -8696, -11478, -8139, -8563, -13062, -7110, -10727, -9314, -9222, -17312, -6665, -13161, -12697, -10077, -11454, -7278, -14893, -13504, -12326, -7911, -8250, -8763, -11000, -13215, -6521, -8694, -6221, -10134, -9276, -6203, -8828, -5189, -10501, -7422, -6533, -9168, -5264, -13122, -6549, -7343, -9686, -6382, -14479, -6508, -8844, -10154, -9085, -10108, -7377, -10863, -10607, -17692, -8197, -9145, -10507, -11689, -9599, -7331, -11922, -10398, -11527, -8239, -7226, -16751, -13203, -9232, -9399, -7455, -11164, -13717, -8828, -13202, -7527, -8539, -11117, -11690, -10044, -7620, -6948, -11590, -12705, -8974, -7925, -6103, -12496, -8686, -10038, -8381, -6360, -10878, -8348, -12467, -8828, -8132, -9960, -9718, -13730, -8801, -11835, -9764, -10661, -11965, -8838, -14391, -9139, -10330, -10710, -9810, -12038, -7957, -10940, -10779, -11834, -8383, -7025, -12421, -11755, -13472, -6596, -6669, -12898, -13153, -14344, -6041, -6955, -12086, -15793, -14101, -6451, -7941, -11562, -21332, -10627, -8039, -9853, -12192, -22607, -8947, -11731, -13727, -15488, -17383, -8963, -12440, -17614, -16423, -13197, -10609, -11382, -13433, -12505, -11141, -13491, -14398, -12776, -11681, -10186, -13165, -16676, -12033, -11957, -10227, -11562, -13239, -11000, -11789, -11349, -10535, -13464, -10916, -10743, -12834, -10362, -12974, -11947, -10160, -12579, -11610, -13058, -12664, -10771, -12170, -16505, -12734, -11097, -13525, -11957, -12217, -10174, -9629, -13331, -11881, -9968, -8909, }; +//int32_t position_embedding[1936] ={196, -7348, -7382, 1712, -10706, 1192, -2694, 1918, -6099, -3297, 121, -2851, -5180, -4712, -1750, 13596, 9600, 3479, -260, -4836, 1525, 4241, -2302, 4529, -900, 3399, -6545, -1652, 3663, -9180, 4876, 3043, -2909, -1064, 4044, 3782, 9062, 1131, -11358, 1565, -1527, -360, -8696, -9012, 1582, 12600, -3776, -1521, 5412, 2481, 1324, -4161, 13922, 5353, -4342, -1956, -1648, 2128, -11661, -6865, 6676, 3476, 3854, 8205, -6787, 6070, -2006, 2531, -13202, -4385, 2898, 2619, 7081, 7595, -1546, -9370, -2303, 2956, 6760, 5943, 4413, 4207, -3058, -4963, 6809, 5599, 3394, 460, 6411, -4390, -2761, -3172, 9835, -7277, -1952, 1675, -7690, 3179, -9750, -7583, 5347, 10512, -1649, 1281, 11435, -5484, 9637, 3355, 1422, 1506, 4282, -3563, 1374, 3387, 1124, -8658, -2358, -4699, -4142, 490, -3377, -2415, -7181, -1534, -597, 12306, 5111, 16385, -4726, -7888, 2951, 81, -2326, 7865, -5223, -6500, -3798, 4601, -3666, -618, -11033, 12947, -534, 10781, -9595, 6606, -209, 130, 1359, 3264, -4327, 2847, -302, -4247, -8282, 402, 7925, -2107, -2138, 8384, 2522, 6636, -777, 96, 3798, 8934, -10498, 2998, -1701, 4036, 4295, -6322, -4076, -118, -4425, 7939, -127, 2611, -3533, -13055, 776, -1126, -7048, -2041, -1031, -2451, -1461, -15072, 1542, 185, 22, -8805, -4022, 348, -5263, -5852, -8468, 6756, -3619, -4270, 2868, -5721, -4657, -3375, -2366, 7595, -591, 2305, 1837, 4089, 7194, 1445, 9971, -5729, -11176, -188, -6837, -3708, -7535, 8617, 3044, 10526, -2912, 2707, -5639, -671, 7353, 2677, 6239, 9202, -9854, -3893, 834, 2775, -7384, -2147, -2039, 9885, 1003, 3164, -7241, 6396, -3139, -10976, 8473, 1252, -10979, -1952, -134, 1954, -4129, -6521, -129, 1874, -234, -675, 1052, 14765, 896, 2509, 1602, -1855, -13043, -10309, -2265, 2743, -4266, -2706, 836, 2445, 512, 18564, 2667, 7664, -10884, -4509, -1825, 5502, -2222, 8628, -1803, -15446, 5921, -1472, 11098, 4316, 5132, -7807, -2586, 5918, -2599, -2611, 3376, 2489, -1817, 4732, 3388, -1536, -1365, -10085, 8422, -2155, 6762, -2014, -8955, 4150, 439, 4460, -1990, -2740, -1333, 349, -8757, -2081, -7922, -4516, -3423, 3926, -4, 1547, 979, 9047, -6177, 568, 1446, 6488, -6201, -2358, -7308, -391, -349, -4329, 2976, 8472, 5717, 2301, 5198, 1549, -3488, -6818, 896, 5382, -12555, -320, -1272, -1351, -11423, -5350, 114, 5480, -1229, 109, 2501, -11900, -944, 5306, 3113, -6048, -3661, -5327, 1334, 10289, -9589, -2279, -1588, -3509, -6272, 10002, 5967, 5551, -6935, -4327, 2791, 9216, -9959, 4473, 1978, -15959, 2149, -7863, 307, -4521, 9051, 6015, -897, 5300, -6371, -260, -800, 2709, -5341, -110, 9833, -7331, -49, -4877, 6976, -4835, 9914, -3133, -4385, 4190, -5738, -465, 2371, 9339, -7956, 6917, 550, -4353, -6041, -4530, 1078, -264, 7846, 3506, -3651, -6858, -126, 1678, 7383, 6218, -2889, 299, 2333, 651, 7628, -751, 2680, -1033, -2285, 7088, 1915, 3198, -17, -11549, 8693, 814, -2438, -2575, 134, 5825, -10139, -1796, 5422, -328, 3026, 7844, 7875, 151, 5205, 6808, 2670, 7859, -12952, 786, 3422, 7597, -6877, -8084, -5465, 532, -10992, 14251, 8151, -2947, 9253, -2637, 10375, 6905, -6967, 6725, -1279, 6702, -3149, 2110, -6067, -4028, -3569, 3633, 1111, -4331, -1496, 5413, 7091, 1720, -8921, -978, -1209, 829, 255, 1729, 1379, 307, -3612, 6083, 5152, 10108, -1758, -12600, 7086, 10504, -9339, 8476, 213, -3269, -8160, -720, 8930, 7891, 205, -2909, -1424, 2115, 8759, -2722, 4276, 10615, -4849, 1589, -6607, -6358, -16955, -355, 2535, 10376, 4434, 4805, 5135, 1439, -3213, -5002, 5087, 687, 1086, -4681, -2821, -14266, -11179, -2582, 7730, 104, 8271, 6464, 4981, 3696, -5874, -5849, 1397, 1046, -12206, -1665, 2201, -439, -2283, 2989, 6710, 167, 3424, 226, 5465, 1487, -3130, -5497, -2878, 3131, -4859, 1596, 4630, -7875, -3226, -7328, 5413, -1135, 3646, -3147, -4163, 1187, 6921, -4376, -394, 2658, -2362, -2453, -2948, -5, 2681, -9107, -1191, -11249, -9502, 2395, -4479, 5486, -9094, 4493, 2749, 9093, -13265, 1179, -2309, -4304, -943, 763, 7495, 1353, 6170, 5194, -2838, 5307, -6865, -789, 3717, 2676, -3582, 5513, 2849, -6748, -929, -452, -74, 10928, 4100, -2011, -4080, 7555, -5922, -4585, 2941, 5010, -9571, 3639, -7514, -8163, -9381, 6471, 6542, 10530, 1936, 12466, -8631, 2326, -2711, -5686, -3652, 9719, -5176, 4973, 3079, -2078, -3088, -1273, 4810, 7839, 4100, 2226, -10032, -1859, 3094, -588, 3594, -4821, -12113, 4966, -199, 8597, -5230, -9595, -2768, 1170, -7238, 6502, 3566, 1014, -859, -2509, 8922, 5700, 3053, -5515, 2418, -9141, -11804, -6197, -485, 3796, -3860, -249, -3930, 6901, -6496, -10185, 3596, 2732, -1355, 983, -527, -6415, -11871, 5991, 1217, 3176, 1131, 3719, 1786, -4878, 2575, 301, 1830, -1133, 1374, -3349, 164, 3352, -1368, -7919, -7348, 5071, -949, 9665, -510, 1889, -5429, -11519, -367, -329, -4465, 3694, -4588, 2112, 638, -7040, 3411, 6658, -1359, 6764, 1210, -5077, -1410, 11878, -1644, 7113, -1193, 424, -3177, 1180, -1788, -194, 2381, 7231, 583, 12532, -2873, 10938, 499, -1249, 5818, 4605, -4712, 4018, 8740, -4365, -45, -5998, 7774, -12177, -2624, 2729, 3998, -108, -8892, -3748, 5248, -2207, -5953, -1195, -2204, -11208, -7020, -3089, 591, 2701, 3647, 4811, 5174, -793, 1089, -4844, 3268, 42, -8431, -6365, -473, -6021, -7345, 4530, 1754, 9097, 1264, 3335, -4713, 5214, 8575, -4620, 4652, 4686, -5145, 4579, -5352, -7520, -5546, 5278, -1174, 3277, 5639, 6893, -6939, 889, -2533, 4578, -2099, -2107, -1194, 7229, 3163, -12403, -15160, 9385, -1258, 4658, 7070, 6925, 2730, 9222, -5450, -7277, 4427, 10517, 5277, 5046, 3242, -4736, -6004, -4718, 2550, -2531, -1704, -4376, -1463, -4121, -2849, 3464, 2406, 8299, -1272, -5814, 5850, -5042, -7367, -7965, 718, 6263, -2666, 4066, -1047, 10409, 4553, -2990, 13574, -1465, -9180, 5031, -2361, 828, -3184, -9065, -927, 9733, -2748, 1466, 4699, 5731, 6123, -6454, 195, 5271, -14124, -2202, -1832, 2, -12207, -3771, 420, -6557, -1144, 9838, -2994, 821, 5869, 4339, 2391, 11899, -8278, -4483, -2896, -1849, -8299, 5111, 260, 10086, 3929, 5539, -6377, 13205, -3131, -1461, 1465, -207, -6114, 1402, 5214, -7641, -973, -1233, -4298, 9744, 2985, 14273, 143, -2463, -1160, -7427, 6119, 7836, -4500, 921, 2153, -287, -5492, -7355, 322, 8465, -1047, 2054, 497, 10097, 7018, -4490, 2046, 6496, 1872, 3413, -9124, -779, 6169, -6458, 1514, -3490, -10698, 3100, -1862, 2875, 6368, 1318, 658, 1050, 219, 3709, -10295, -2636, -4041, 5012, -61, 4480, -3406, -2850, 302, -7649, 5732, 7661, 7424, 5693, -2459, -7557, -6075, -1802, -11208, 3080, -7096, 6845, 1575, 5391, -2403, -2489, -1433, 2278, 7747, 4970, -13012, -5878, 6852, -9159, -4405, -374, 4644, 948, 8329, 4469, 2672, -812, -5394, -11335, 5476, -1149, 831, 1394, -4572, -5319, -8258, 3435, 1955, -972, -4931, 4098, -362, 10748, -4493, -7594, 7251, 7377, -5753, 5011, 5545, 812, -9204, -5784, 3585, -2369, -2755, 6910, 3144, 9649, 1338, -4350, 8637, 10729, 4980, -2094, 2339, -9914, 4376, 1377, -3161, -9768, 10043, 2351, -5890, 3685, -5198, -198, 9585, -2097, 251, -271, -6207, 2402, -7706, 2448, -2452, 4762, -2401, 8514, -3997, -3465, -1079, -1985, 1855, 12959, -3239, 3580, -7527, -141, -10696, 1692, -1395, -4360, 3321, 8854, -1479, -556, 2118, -6509, 1766, 3286, 6377, 587, 2108, -3565, -4028, -1202, 6234, 10107, 4402, -3022, 1785, 11342, -2046, -8556, 10844, 9710, -6141, -2186, 7498, -6214, -10161, -706, 10836, -3416, 1141, 7550, 10477, -2297, -2264, 2035, 4234, 3055, -8828, 677, 4606, 5708, -8930, -12070, -3840, -1422, 7871, 3303, -1806, 3930, -8954, -14512, -6258, 3705, 2788, 7841, -5298, -2605, 9229, -6623, 6570, -1780, 8058, 2401, 82, 3209, -2819, 5653, 4950, 11482, -815, 2924, 13697, 538, -2681, -6465, 6221, -14698, 4160, -1397, -1421, 3050, -2808, -4229, 8893, 8020, -16289, 2108, 42, 1162, -7427, -6701, 7883, 8297, 1597, 5038, -2443, 931, -4441, -6867, 6905, 3184, -18314, 3272, 3904, -4514, -2738, -3360, 8473, 11965, -1353, 12774, 643, 3839, 3358, 2682, 8232, 6960, -4297, -836, -6527, -1543, -6549, -2445, 586, 11268, 246, 18235, 13, 1016, -1328, -669, -3472, 7036, -1343, -2877, 1927, 4696, -8023, -4754, 8818, 3667, 6334, 7176, 3254, 5146, 5763, -887, 1357, 5270, -12799, 5511, 7894, 830, -3383, -12477, -5669, 1653, -2524, 2412, -7996, -6546, -4264, -8583, 6337, -2213, -802, -2847, 2, -3954, -8564, 604, -1101, -887, 1889, 5294, 2636, 8182, -2383, -2636, -3763, 9006, -3445, -4557, -453, 6281, -10285, 493, 461, -237, 7249, 4140, 2612, 9505, -1959, -3777, 791, -1044, -5313, -5067, -1969, -4218, -5337, -761, 1536, 10589, 4648, 16378, -2512, 1416, -5251, -7837, 5860, -4262, -4829, -9612, -1219, -4834, -8699, 1980, -3450, 6160, -3204, 6195, 3463, 9506, -5485, -8112, -4138, -724, 1512, 918, 1741, -10433, -14466, -6574, 12705, 2220, 11707, -4228, 346, 10643, -2137, -4149, -1762, 5518, 7242, 5374, 1826, -2245, -30, 586, 4427, -10485, -212, -4218, 3951, 8882, 932, 1660, 1355, 2252, 250, -7325, 1686, 2198, -6366, -7720, 853, -3684, 972, 3909, 2243, 7001, -484, -1258, 3933, -1780, 1998, -2576, 3712, -10146, -1859, 694, 4870, 10322, 6968, 2166, -3058, 4834, -3061, -582, -2964, 8615, -4992, 11852, 1768, -9018, 221, -5394, 3845, 5675, -3122, -3868, -1592, -879, -7691, -2872, -424, 2273, -4646, 923, 3113, -4257, -10901, 3142, 4453, 943, -2176, -1475, 1806, 5221, -5723, -12716, 1026, 5810, -7981, 898, -4108, -3235, -9229, -3181, 5933, -3481, 1041, 8501, -8344, 7251, -346, -8282, -3530, 4398, -6469, 331, -1543, -7201, 5033, -3596, 2641, -2910, 5563, 3475, 3365, 8598, 3284, -9382, -1039, 8790, -3126, 4164, 9639, -8403, 4317, -9679, 12168, 1929, 4278, 13619, 2864, 3590, 532, -5407, -4325, -1887, -3285, -443, -2136, 4922, -13579, -1682, 3007, 1898, -5139, 12461, -1291, 3241, 2362, -4873, 4000, -1434, -4710, -4441, -1077, -9310, -3098, -2394, 8959, 2132, 3326, 10103, 7219, 7674, -3532, -3918, 2722, 4192, -7496, 3443, -2661, -5911, -13391, -6098, -6935, 3533, -4270, 9580, -2819, 10422, -1715, -6566, 1072, 7238, -7981, 5947, 6971, -2932, -8276, -6662, -2739, 1783, 7551, -822, 714, 6140, -2272, 1579, -1586, 2848, -4921, -5685, 2468, -4065, 8038, -1181, 3849, -7741, 8319, -4081, 540, -331, 2632, -8020, 3331, 2738, -10207, 10376, 1578, -6226, -7393, 1824, -3637, -2150, 4912, 3303, 97, 7901, -3422, -11877, 11709, 7670, 1157, -1433, 14410, -4035, -5654, -2636, 1646, -3398, 4553, 3448, 1590, 6668, 1229, -631, -639, 7354, -5577, -1004, -4027, -4623, 1226, -6965, 6190, 5682, 6399, -2992, -5282, 4553, -301, -5865, -1087, 5129, 372, -397, 7112, -11645, -7985, -3391, 886, -665, 1259, 3809, -7332, 3309, -5446, -1452, -3214, 7524, -7810, -4991, 6479, -5773, -2147, 504, 8548, -414, -1342, 4170, -2569, -570, 4688, 6138, 2469, 7672, -1794, -4615, 2466, -2698, -1092, -8501, 2056, -9155, -3875, 4456, -5823, 6540, 1286, -5507, 604, 3683, -5865, 1624, 10940, 397, -7894, -3904, 7932, -3332, -1916, -453, 4174, 9373, -8885, -11755, 2603, 1730, -4719, 2118, -3560, 2020, -5513, -828, 4869, 6686, 1224, 2484, -1048, 1258, -6406, -9003, -1844, 7966, -5982, 2834, 257, -12060, -2571, -399, 7284, 2855, 2137, 7453, -228, 8378, -5410, -7611, 2233, 10363, 959, 204, 6403, -2208, -9057, -1205, 10133, 6597, -3193, 1573, -9256, 1178, -1660, 423, 3115, 8276, -10066, -9202, 1808, -1862, -6246, -8949, -9359, 3781, 7604, 6050, 328, -2843, 1670, 5750, -1362, 490, -1824, -1695, -6753, 7309, -2915, -3351, -835, 4938, 1274, 839, 6488, -2967, -6740, -2742, 9887, 9589, -4916, 569, -583, -1105, 1792, -554, -677, -5544, -1202, 9332, 7015, 4194, 847, -5562, 6385, 7952, -13964, 3095, -2044, -4642, -12211, -11113, 803, 6275, 3938, 11288, -3246, 7863, 5390, 1234, -2093, 10643, -7571, 9591, -1187, -6426, -10116, -2729, -1892, 11679, 2705, 383, 5100, 290, -1186, -5636, 3468, 8022, -4437, -7619, 1079, -6484, -5701, -6167, 5154, 2463, -4677, -678, 1465, 2782, -1074, -3588, -1667, 8992, -10088, 5435, -2560, 3760, -13964, 941, -3134, 7520, -5560, 4607, -6430, 7678, -7308, -4429, 6823, -24, -6644, 9550, 8560, -8120, -6287, -1422, 5070, -3360, 10365, -1586, 2224, 2928, -6037, -9535, -4078, 7441, -2257, -2203, 3939, -2139, -854, -1630, 1062, 1906, 910, 510, -6428, 6919, -2506, -12797, -3276, 822, 1002, -2871, 8174, -8013, 47, -2337, 6914, -1141, 1825, -5894, 2829, 9621, -1258, -1760, -7474, 4528, -4157, 4937, 3116, -6704, -6168, 357, 11296, -721, -2325, 4340, 6459, 4289, -4798, -3662, 2985, 6979, -5045, 1388, 7683, -1556, -1681, -8961, 12688, -6371, -5467, 1561, 11487, 169, 5750, -6795, 3916, -2576, -10949, 6332, -7643, -3722, -8052, -6156, -2037, -713, -4781, 15583, 1208, 2386, 460, -923, -1273, 2499, -2653, 2952, -3185, -6835, -5247, -3670, 4576, 2211, 5279, -313, 806, 3856, -12356, -4425, 2318, 4636, -281, 4072, 11650, -4005, 3906, -4887, 10698, -2211, -1905, 191, }; +//int32_t encoder_out[1936] ={-3006, -13563, -12330, 18429, -5740, 7757, -11785, 19611, 5385, -14561, -4444, -13231, -273, -10749, 1769, 14144, 6853, -7264, -3989, 9728, 6174, 14216, -13342, 20866, 8739, -9327, -15258, -12849, 11503, -16206, 6678, 4712, -3368, -10248, -323, 17739, 14650, 9631, -22149, 18791, 8398, -12585, -14408, -19795, 9133, 7335, -2016, 218, 3745, -8689, -3055, 8517, 19150, 15896, -17422, 15479, 8259, -11139, -19673, -16118, 13716, -2489, 4658, 10756, -8425, -1803, -6892, 18482, -7281, 2743, -5683, 20533, 17587, -5318, -5861, -19906, 5187, -1484, 11114, 7230, 228, -6363, -6655, 9139, 10365, 14506, -7711, 16482, 16422, -16187, -11228, -14695, 18943, -13552, 882, 2345, -11537, -6686, -11743, 7935, 7791, 17995, -10134, 17477, 20963, -15352, 3390, -7308, 7919, -5904, 5447, -2132, -1507, -5768, -3574, 4260, 2652, 4375, -17098, 18282, 7600, -16904, -13845, -10678, 3984, 7624, 6440, 18787, -4814, -13887, -3132, 16328, 2480, 14219, -15608, 12369, 9305, -6755, -9780, -9805, -5951, 7635, -752, 10670, -12533, -1822, -5518, 14468, 5185, 10349, -16181, 20586, 11674, -16543, -15452, -10119, 14549, -6957, -6, 9185, -723, -2247, -6201, 13563, 6180, 16249, -20590, 20376, 10058, -7715, -3023, -17945, 3895, -5125, -2581, 8922, -2947, -8726, -6576, 454, 5031, 8435, -17115, 13176, 8105, -15541, -9771, -26546, 11608, -5647, 2820, -7509, -6901, -8206, -9755, 8543, -4364, 13458, -13971, 14118, 14418, -17485, -10573, -13533, 3500, 3417, 1789, 2659, -978, -5582, 1754, 15694, 16021, 4131, -25353, 19627, 4040, -17391, -14517, -908, 8276, 5537, -632, 4351, -5816, -9106, 1921, 17213, 11727, 17095, -21631, 14579, 12311, -9099, -14541, -11745, 4595, 4505, 1362, 3649, -8561, -4528, -7242, 1546, 12875, 10656, -23093, 14368, 9969, -10482, -12326, -17341, 8191, -4029, 394, 1754, -4055, 5990, -5765, 14625, 4312, 6787, -27034, 9123, 10688, -12565, -11754, -11023, 5809, -1559, 1929, 21333, -4137, -3938, -12844, 10591, -577, 14611, -11639, 24979, 7176, -26631, -1815, -11506, 18175, -2329, 7633, -5593, -5884, -4737, -5611, 11342, 7139, 11005, -11085, 19903, 12770, -13858, -8696, -21227, 17759, -8275, 9465, -767, -10777, -3937, -4997, 19747, 3537, 5078, -11440, 19340, 2302, -15039, -12820, -14607, 2856, -841, 3066, 3019, -3662, -1769, -10455, 13468, 4293, 16466, -18227, 16129, 3082, -13989, -7767, -13065, 8357, 2831, 6949, 5188, 3071, -9636, -7742, 5922, 5691, 15255, -25481, 17238, 8637, -13963, -19659, -15803, 6774, 81, -32, 1563, 2272, -18979, -5995, 21439, 8942, 882, -13145, 12693, 12852, -1774, -13667, -12866, 4715, -8892, -4644, 11093, -422, -5046, -10092, 9053, 4390, 18136, -20282, 20232, 11824, -28001, -6060, -18339, 7227, -10905, 11389, 7704, -5617, -4712, -9613, 13707, 2698, 10574, -14994, 15975, 19634, -19674, -6834, -15951, 15005, -10525, 13284, -2557, -7022, -5978, -9209, 13370, 5896, 17525, -17853, 23255, 10249, -15506, -12905, -14879, 7564, -6889, 9077, 4961, -5693, -13709, -3604, 18055, 9899, 13762, -11124, 16051, 12696, -9712, 1954, -12613, 9317, -8709, -1939, 8967, 1074, -7952, -4365, 1336, 14539, 11503, -16097, 14413, 10291, -7622, -18878, -11665, 12678, -6553, 3328, 10297, 6128, -7062, -776, 21889, 6628, 14075, -23131, 19239, 16078, -4247, -13226, -18217, 1223, -3829, -9830, 14185, 7628, -11920, 4644, 13153, 16201, 15229, -17074, 24769, 9515, -4742, -10565, -9459, 1060, -10122, -2606, 3948, -1114, -12072, -5986, 20459, 11262, 9498, -19128, 16965, 9743, -10716, -4806, -8878, 6640, -6002, -2477, 7561, 1982, -2676, -5055, 535, 11206, 21236, -22742, 25469, 9341, -15296, -17869, -11445, 16623, 1860, 1645, -1316, -3186, -7917, 3771, 11779, 10191, 20504, -18291, 20597, 3803, -19284, -25289, -9539, 8301, 5012, 5881, 5836, 423, -9288, -6980, 9044, 9488, 11661, -12011, 13275, 6737, -27917, -19263, -11345, 12851, -6200, 10087, 8955, 805, -7845, -9519, 6972, 5407, 11348, -25740, 15166, 12016, -13473, -11119, -7590, 13181, -6210, 4865, 1932, 1081, -9226, -6301, 8222, 638, 11695, -14984, 17147, 14184, -20129, -11090, -19273, 14319, -6545, 7140, -2883, -7634, -6844, 1066, 10066, 2738, 9623, -11962, 14367, 9260, -13035, -5203, -21472, 9516, -15976, -5773, 1460, -9266, -4569, -13189, 17706, 5167, 17608, -25065, 18705, 8341, -16412, -8140, -8555, 12759, -4921, 7306, 7143, -5731, -4578, -9634, 13517, 8002, 10713, -12955, 22717, 12124, -18190, -5714, -10473, 5509, 5176, 6163, -359, -8158, -2435, -10629, 8846, 6458, 14548, -23898, 22129, 3490, -21086, -17176, -1972, 10069, 4788, 2566, 15234, -10502, -7098, -6553, 8756, 422, 16611, -15354, 21749, 13913, -13106, -9909, -11836, 11777, 2514, 5699, 2834, -9025, -9450, -2209, 14080, 8578, 1880, -21538, 21410, 11247, -3034, -10588, -21030, 5698, -3899, -6210, 8263, 1423, -8707, -5358, 11613, 14847, 15042, -9044, 13159, 12370, -21378, -18525, -16342, 6187, -1641, -1324, 601, -6478, -3701, -10467, 3996, 8764, 12689, -15030, 19272, 9605, -18728, -19845, -3559, 5652, -3275, 1863, 5597, 953, -12340, -1849, 15916, 6577, 6932, -6837, 14165, 10642, -8840, -5685, -19038, -506, -466, 640, 11242, -2583, -8288, -9136, 1140, 3106, 8936, -15763, 19152, 5437, -10478, -6910, -17981, 11343, 596, -535, 9676, -956, -11538, -6862, 27331, 3241, 13859, -10920, 19079, 8564, -10570, -5761, -9812, 7378, 2110, 3067, 13426, -7632, 1378, -4034, 12624, 8594, 11389, -14816, 19965, 20021, -16429, -7859, -18291, 17532, -17084, 1335, 2532, -230, -10488, -12058, 9814, 9352, 7707, -17859, 16019, 7254, -23813, -13478, -12000, 4898, -3686, 4841, 7461, 2075, -11495, -3560, 8605, 9092, 10922, -23374, 13014, 9729, -19426, -15298, -4780, 6518, 3642, 2751, 5038, -7917, -4041, 3806, 10222, 9947, 13664, -18028, 22791, 5628, -20491, -13863, -4558, 4180, -2485, 7495, 8047, -8674, -6502, -7094, 20470, 4307, 5030, -11802, 25527, 13764, -24719, -19127, -150, 2611, -1029, 10121, 7295, -564, -2071, -8611, 7205, 7906, 19158, -4511, 22058, 12822, -15749, -13811, -15922, 10977, -8554, 572, -3316, -3058, -12151, -7466, 17638, 7109, 15570, -11320, 12053, 16600, -16480, -12338, -18142, 7339, 1133, -639, 4681, -2768, 563, 140, 10280, 18510, 7490, -20426, 21980, 7790, -12230, -10133, -20188, 7033, 4754, -724, 3781, 1123, -4142, 542, 6839, 4322, 13990, -27587, 16011, 10164, -13827, -21794, -13802, 6966, -11049, 212, 10254, -5240, -7852, 48, 18922, 7869, 20456, -21871, 15636, 8900, -14475, -15940, -3293, 4716, 4900, 4879, 5831, -10344, 5091, -8364, 12194, 5127, 6790, -17157, 19659, 17195, -20674, -6316, -10681, 818, 5437, 5760, 15987, 26, -12619, -5085, 5931, 11086, 16895, -15453, 17332, 11797, -11451, -12670, -18508, 8468, 2444, -226, 3621, -4802, 518, 1732, 9351, 3782, 13992, -8001, 21509, 2538, -13698, -2189, -17680, 11326, -8055, -7364, 2616, -4362, -5926, 1259, 17264, 6588, 10125, -11527, 23188, 336, -15507, -11028, -5887, 6504, -827, -376, -1999, -1245, -15610, 133, 23226, 13612, 13851, -13972, 12359, 5370, -14127, -16831, -6162, -1943, 1322, 3421, 5663, -5809, -11947, -5660, 15584, 12366, 13584, -25102, 11684, 17176, -21626, -11137, -10079, 10452, -5009, 10119, 5420, -65, -11647, -8754, 3245, 10677, 9533, -12684, 18626, 4942, -17226, -16617, -6602, 7393, -8438, -4143, 6338, -2537, 284, -9020, 5285, 10882, 15554, -17336, 21522, 16400, -11034, -17315, -17011, 11620, -7641, -1386, 8084, -2420, 69, -2624, 10573, 11725, 19946, -5672, 15176, 12457, -22436, -3894, -8411, 4078, -16955, 12734, 4176, -6871, -5084, -10675, 13733, 14814, 6282, -11763, 18189, 5281, -9665, -13267, -7431, 3116, -1217, -1328, 10698, -4987, -11999, -6191, 13751, 6734, 21035, -14470, 21428, 3669, -10964, -18630, -7913, 3893, -11562, 3538, 9623, -2585, -10690, -1158, 8651, 8416, 13162, -4612, 17794, 11025, -16093, -10889, -11824, 14167, 4031, 7210, -1987, -2342, 118, -6577, 4108, 14469, 19290, -20145, 15233, 18126, -18927, -19462, -10776, 17850, -8965, 2825, 8776, 9353, -12187, -6053, 16045, 10053, 11844, -18217, 17431, 14030, -6834, -14632, -22585, 3625, -7252, 9905, 4965, -6913, -6715, -10856, 1146, -4132, 13295, -5848, 22031, 3541, -14635, 853, -16929, 14867, -10080, 10242, 5538, -2911, -5900, -6975, 20120, 9190, 18659, -9922, 19385, 24080, -11026, -9187, -18048, 15138, -20644, 7384, -1591, -3322, -7729, -7178, 7882, 12850, 17169, -29152, 18653, 10324, -11162, -15366, -16757, 15256, 2707, 2295, 7212, -5099, -8408, -8961, 5473, 10208, 11194, -31132, 19405, 14988, -16836, -9705, -13365, 15011, 6886, -322, 15129, -2238, -4700, -2510, 15719, 12068, 15263, -17201, 18006, 5600, -14695, -13099, -10819, 5409, 6557, 1060, 20661, -1231, -8256, -6287, 13102, 1531, 15969, -12840, 14428, 12701, -8763, -15013, -14635, 16024, -1976, 8039, 8323, 1163, -4029, 1295, 13050, 5608, 12345, -22125, 21563, 18581, -11256, -10267, -24770, 3444, -2881, 479, 2431, -8476, -15408, -8011, 6272, 12904, 6282, -12405, 13611, 10172, -15424, -14768, -9625, 4751, -8107, 2882, 6915, 558, -1968, -7735, 11214, 1121, 18832, -16162, 14475, 10584, -7412, -18754, -9101, 6134, -5932, 8014, 5473, -2118, -128, -7230, 8462, 4284, 8683, -19400, 13767, 9541, -19055, -12613, -9168, 5520, 6085, 5818, 19566, -4967, -8263, -10320, 5186, 11308, 5608, -19345, 9650, 10010, -18178, -15500, -7019, 875, 728, -2431, 8600, -489, -1635, -8656, 6244, 627, 9692, -10156, 17995, 10687, -24421, -22420, -16582, 19462, -3430, 14473, -2169, -4748, 299, -5356, 11832, 777, 13351, -1567, 22147, 12026, -13901, -7808, -10741, 13146, -16640, 3079, -3068, 751, -285, -4640, 15415, 6281, 11059, -11255, 11059, 12984, -12162, -13589, -17987, 8424, -8545, 4051, 4753, -1922, -2756, -4453, 12951, 8903, 7796, -10048, 15724, 13579, -23594, -8454, -9019, 10395, 5265, 9772, 3949, -7364, -5175, -6215, 14174, -650, 14808, -12845, 28486, 12197, -19556, -5598, -16908, 11933, 1177, 331, -3723, -3169, -10619, -11448, 11612, 5069, 10765, -16340, 18499, 12963, -15722, -17082, -7403, 10093, -5279, -483, -1019, -2179, -6192, -9761, 138, 4022, 16176, -21635, 17535, 6239, -16161, -19177, -13231, 12251, -9925, 1566, 10893, -14047, -2666, -4217, 5942, -1564, 12132, -16661, 16392, 9506, -19765, -3372, -14345, 10870, -8606, 8542, 4691, -1876, -1064, -1200, 3602, 1012, 16364, -13975, 19559, 20924, -21303, -4196, -21408, 21603, -2487, 7945, 14237, 1470, -5301, -5154, 7858, 792, 6535, -16442, 18356, 9757, -8942, -21051, -11587, 8733, -2330, -4570, 13093, -5873, -6572, -2524, 8223, 7618, 8123, -18128, 12879, 9984, -23137, -11363, -12249, 15711, -3050, 5569, 12160, 4083, -2078, -8447, 9337, 6811, 12941, -19345, 21916, 8262, -18851, -20268, -15872, -1733, -1214, -2670, 11017, -4959, -157, -5468, 6929, 5662, 15289, -18151, 22569, 16912, -15083, -15593, -17894, 5010, -3382, 9746, -40, -5306, -3361, -6415, 16370, 952, 11072, -14498, 11353, 12985, -17035, 618, -11686, 12166, -13891, 12010, -3450, -1176, -9985, -753, 6891, 9043, 11060, -20824, 26305, 11316, -17920, -14594, -9230, 2777, -8907, 6890, 3935, -2320, -2538, -7024, 1691, 16832, 16628, -10460, 15082, 24286, -16158, -13634, -13556, 9365, -9506, 6446, 4493, -3193, -4061, -2893, 13112, 2437, 16475, -16245, 16377, 6162, -18041, -6740, -17056, 14220, 288, 9610, -2208, -8660, -4425, -4622, 8500, 3326, 12309, -10290, 16961, 18099, -23750, -14866, -14424, 8017, -5322, 4468, 3755, -11645, -5534, -10514, 12200, -474, 13851, -19413, 12801, 18684, -17540, -9202, -9935, 15524, -4871, 1224, 3998, -5864, -7892, -1162, 20918, 6517, 14193, -11343, 12942, 14462, -15089, -7462, -19859, 10933, -14142, 98, 3743, -7844, -3084, -3274, 8235, 5354, 10502, -16842, 17912, 22126, -11752, -15506, -15935, 17307, -7699, 1119, -935, 961, -2984, -12227, 813, 6519, 13134, -18401, 19312, 5803, -11180, -14533, -10765, 10838, 366, 1436, 5799, -6026, -9234, -9767, 4700, 524, 16873, -18033, 19048, 10559, -23621, -11091, -10671, 13415, -3442, 3701, 9035, -2814, -2557, -9638, 5850, 6306, 18884, -11488, 18210, 17064, -13909, -16839, -11630, 17459, 1751, -1371, 2436, -11033, -7206, -6848, 14214, 7744, 16099, -20816, 8966, 13109, -14437, -12666, -18172, -3320, -1772, 8626, 7304, 10, -11047, -3896, 21065, 4666, 9300, -11349, 16631, 3824, -5909, -7915, -14171, 7029, -667, 3960, 1565, 2782, -12537, -10300, 11758, 12762, 18572, -15625, 17045, 9661, -11897, -5784, -10756, 5216, -13503, -805, 11559, 3901, -6574, -3466, 6907, 10363, 17436, -26414, 20128, 8295, -17817, -20323, -20804, 7154, 1155, 5136, 13470, -5469, -1455, 807, 15944, 2686, 18128, -17961, 27966, 9550, -18449, -16653, -13179, 4493, 7287, 5197, 760, 1500, -10621, -5921, 7359, 7581, 17717, -17649, 10306, 11416, -18892, -14387, -16829, 13281, -2882, -1957, -351, 1159, -6311, -6635, 10989, 3535, 16933, -22238, 24300, 9058, -7718, -21583, -9173, 2480, 2573, -5305, 4740, -9380, -2832, -9839, 9766, 11385, 8620, -16707, 25052, 17508, -20031, -13020, -12162, 12100, -10151, 12370, -79, -1518, -7732, -9555, 4088, -686, 15800, -13213, 14653, 14378, -13888, -8837, -12851, 8542, -3624, 3106, 1206, -10739, -3570, -5822, 1881, 634, 8596, -9144, 13755, 18369, -20422, -7515, -13588, 15796, -6124, 5742, -5391, -2255, -170, -5938, 12486, -4898, 12070, -15414, 22543, 14595, -19373, -14154, -11389, 18806, -4725, 1237, 4293, 2099, -6089, -9000, 9513, 5640, 14807, -15826, 16983, 18406, -13532, -9893, -21230, 22742, -11495, -2039, 1731, 7707, -9512, 957, 6361, 8277, 5846, -22667, 24396, 3553, -17504, -15340, -16114, 3937, -5080, -2916, 16451, -2466, -7719, -3050, 13639, 2875, 11755, -13224, 19848, 6314, -19502, -12653, -14361, 11483, -3612, 7826, 924, -3683, -6214, -15062, 9777, 4574, 11937, -9206, 19258, 21549, -14860, -2556, -16578, 19355, -8190, 907, 1251, }; +int32_t prototypes[32] ={-1394, -5770, -6778, 762, 4001, -653, -5906, -20, 1220, 3795, -73, -3028, 635, -448, 7677, -6204, 5745, 3112, 1206, -1120, -3618, 1076, -649, 943, -3896, 2462, 4658, 2494, 3996, 1220, -1144, -1013, }; diff --git a/sw/applications/transformer/dense_layerC.c b/sw/applications/transformer/dense_layerC.c new file mode 100644 index 00000000..08d6c6b3 --- /dev/null +++ b/sw/applications/transformer/dense_layerC.c @@ -0,0 +1,69 @@ +// +// Created by alireza on 10/6/23. +// + +#include "dense_layerC.h" +#include + +void createDense(Dense* dense, size_t input_dim, size_t output_dim, quant_bit_width *weight, quant_bit_width* bias) { + dense->input_size_ = input_dim; + dense->output_size_ = output_dim; + dense->weight = weight; + dense->bias = bias; +} + +void destroyDense(Dense* dense) { + // Free the memory allocated for the Dense struct + free(dense); +} + +void multiplyweight(Dense* dense, size_t seq_len, int32_t* input, int32_t* output) { + for (int length = 0; length < seq_len; length++) { + for (int out_idx = 0; out_idx < dense->output_size_; out_idx++) { + int32_t* weight_ptr = dense->weight + out_idx; + int32_t* output_ptr = output + (length * dense->output_size_) + out_idx; + int32_t* input_ptr = input + (length * dense->input_size_); + int32_t sum = 0; + for (int i = 0; i < dense->input_size_; i++) { + sum += MUL_HQ(*weight_ptr, *input_ptr); // MUL_HQ macro + input_ptr++; + weight_ptr += dense->output_size_; + } + *(output_ptr) = (int32_t) (sum >> NUM_FRACTION_BITS); // NUM_FRACTION_BITS macro + } + } +} + +void addbias(Dense* dense, size_t seq_len, int32_t* output) { + for (size_t idx = 0; idx < seq_len; idx++) { + for (size_t feature_idx = 0; feature_idx < dense->output_size_; feature_idx++) { + output[idx * dense->output_size_ + feature_idx] += dense->bias[feature_idx]; + } + } +} + +void computeDense(Dense* dense, size_t seq_len, int32_t* input, int32_t* output) { + //multiplyweight(dense, seq_len, input, output); + printf("\rMul %dx%dx%d\n", seq_len, dense->input_size_, dense->output_size_); + multiply_cgra(input, seq_len, dense->input_size_, dense->weight, dense->output_size_, output); + if (dense->bias != NULL) { + addbias(dense, seq_len, output); + } +} + +void activation(Dense* dense, size_t length, int32_t* input, int32_t* output) { + float in_float, in_tanh; + int32_t x3, in_tanh_fxp; + for (int i = 0; i < length; i++) { + x3 = MUL(MUL(input[i], input[i]), input[i]); + x3 = MUL(x3, 183); // 183 = 0.044715 in fixed-point 12 bit + x3 += input[i]; + x3 = MUL(x3, 3268); // 3268 = sqrt(2/PI) in fixed-point 12 bit + in_float = (float) x3 / (float) (1 << NUM_FRACTION_BITS); + in_tanh = tanhf(in_float); + in_tanh_fxp = (int32_t) (in_tanh * (1 << NUM_FRACTION_BITS)); + in_tanh_fxp += (1 << NUM_FRACTION_BITS); + output[i] = MUL(in_tanh_fxp, input[i] >> 1); + } +} + diff --git a/sw/applications/transformer/dense_layerC.h b/sw/applications/transformer/dense_layerC.h new file mode 100644 index 00000000..c67d4571 --- /dev/null +++ b/sw/applications/transformer/dense_layerC.h @@ -0,0 +1,30 @@ +// +// Created by alireza on 10/5/23. +// + +#ifndef FVLLMONTITRANSFORMER_DENSE_LAYERC_H +#define FVLLMONTITRANSFORMER_DENSE_LAYERC_H + + +#include +#include +#include +#include "param.h" +#include "cgra.h" + +// Define the struct +typedef struct { + size_t input_size_; + size_t output_size_; + int32_t* weight; // quant_bit_width is a typedef for int32_t + int32_t* bias; // quant_bit_width is a typedef for int32_t +} Dense; + +void createDense(Dense* dense, size_t input_dim, size_t output_dim, quant_bit_width *weight, quant_bit_width* bias); +void destroyDense(Dense* dense); +void multiplyweight(Dense* dense, size_t seq_len, int32_t* input, int32_t* output); +void addbias(Dense* dense, size_t seq_len, int32_t* output); +void computeDense(Dense* dense, size_t seq_len, int32_t* input, int32_t* output); +void activation(Dense* dense, size_t length, int32_t* input, int32_t* output); + +#endif //FVLLMONTITRANSFORMER_DENSE_LAYERC_H diff --git a/sw/applications/transformer/main.c b/sw/applications/transformer/main.c new file mode 100644 index 00000000..a4c81ea4 --- /dev/null +++ b/sw/applications/transformer/main.c @@ -0,0 +1,156 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include +#include "main.h" +#include "data_cpp/signal.cpp" +//#include "data_cpp/signal_fft.cpp" +#include "SYLT-FFT/fft.h" +#include "weightsAndBiasesC.h" +#include "transformerBlockC.h" + +// For the cgra +#include "multiply_cgra.h" + + +// FFT +#include "stftVec.h" + + + +float error_check(const quant_bit_width* groundTruth, const quant_bit_width* output, size_t length){ + long error = 0; + for (int i=0; i> NUM_FRACTION_BITS); + return (float) error/ (float) length; +} + +void prototype_distances(quant_bit_width* prototypeVec, const quant_bit_width* modelOutput, int32_t* distVec, size_t prototypeLength, int prototypeNums){ + for (int p=0; p< prototypeNums; p++){ + long dist = 0; + quant_bit_width * prototypePtr = prototypeVec + (p * prototypeLength); + for (int i=0; i> NUM_FRACTION_BITS); + distVec[p] = (int32_t) dist; + } +} + +void transformerInference(quant_bit_width * transformerInput, quant_bit_width * transformerOutput, quant_bit_width* input_normalized, quant_bit_width* qkv, quant_bit_width* intermediate, void * kperf){ + quant_bit_width * weightVec[NUM_LAYERS*(3*NUM_HEAD+5)+5]; + quant_bit_width * biasVec[NUM_LAYERS*(3*NUM_HEAD+5)+5]; + //getWeights(weightVec); + //getBiases(biasVec); + quant_bit_width * clsTokenVector = getClassToken(); + quant_bit_width * posMatrix = getPosEmbedding(); + TransformerBlock* selfatten = createTransformerBlock(D_SEQ, D_MODEL, D_Q, NUM_HEAD, D_FF, weightVec, biasVec, clsTokenVector, posMatrix); + computeFixedPoint(selfatten, D_SEQ, transformerInput, input_normalized, transformerOutput, intermediate, qkv, kperf); +} + +quant_bit_width compute_log_amp(int32_t real, int32_t imag){ + real = MUL_HQ(real, 25) >> (NUM_FRACTION_BITS - 9); + imag = MUL_HQ(imag, 25) >> (NUM_FRACTION_BITS - 9); + int32_t real2 = MUL_LONG(real, real) >> NUM_FRACTION_BITS; + int32_t imag2 = MUL_LONG(imag, imag) >> NUM_FRACTION_BITS; + float pow2 = (float)(real2 + imag2) / (float) (1<< NUM_FRACTION_BITS); + float amp = sqrtf(pow2); + float stft = logf(amp+ 1e-10f); + quant_bit_width stft_int = (quant_bit_width) (stft * (1< +#include +#include "param.h" + +float error_check(const quant_bit_width* groundTruth, const quant_bit_width* output, size_t length); +void prototype_distances(quant_bit_width* prototypeVec, const quant_bit_width* modelOutput, int32_t* distVec, size_t prototypeLength, int prototypeNums); +void transformerInference(quant_bit_width * transformerInput, quant_bit_width * transformerOutput, quant_bit_width* input_normalized, quant_bit_width* qkv, quant_bit_width* intermediate, void * kperf); +quant_bit_width compute_log_amp(int32_t real, int32_t imag); + +#endif //FVLLMONTITRANSFORMER_TRANSFORMER_H diff --git a/sw/applications/transformer/matMulC.c b/sw/applications/transformer/matMulC.c new file mode 100644 index 00000000..eb60c96c --- /dev/null +++ b/sw/applications/transformer/matMulC.c @@ -0,0 +1,22 @@ +// +// Created by alireza on 10/6/23. +// + +#include "matMulC.h" +#include + + +void MatMul_multiply(size_t seq_len, quant_bit_width* input, quant_bit_width* weight, + quant_bit_width* output, size_t input_size, size_t output_size) { + printf("\rMul %dx%dx%d\n", seq_len, input_size, output_size); + multiply_cgra(input, seq_len, input_size, weight, output_size, output); +} + +void MatMul_scale(quant_bit_width* input, int shift_scale, size_t mat_size) { + + for (size_t i = 0; i < mat_size; i++) { + *input = (*input) >> shift_scale; + input++; + } +} + diff --git a/sw/applications/transformer/matMulC.h b/sw/applications/transformer/matMulC.h new file mode 100644 index 00000000..9844b787 --- /dev/null +++ b/sw/applications/transformer/matMulC.h @@ -0,0 +1,21 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_MATMULC_H +#define FVLLMONTITRANSFORMER_MATMULC_H + + +#include +#include "param.h" +#include "cgra.h" + +#define BLOCK_SIZE 4 + +typedef struct { +} MatMul; + +void MatMul_multiply(size_t seq_len, quant_bit_width* input, quant_bit_width* weight, quant_bit_width* output, size_t input_size, size_t output_size); +void MatMul_scale(quant_bit_width* input, int shift_scale, size_t mat_size); + +#endif //FVLLMONTITRANSFORMER_MATMULC_H diff --git a/sw/applications/transformer/multiply_cgra.c b/sw/applications/transformer/multiply_cgra.c new file mode 100644 index 00000000..69eef852 --- /dev/null +++ b/sw/applications/transformer/multiply_cgra.c @@ -0,0 +1,177 @@ +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : HEEPsilon ** +** filename : main.c ** +** version : 1 ** +** date : 01/10/23 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL ** +** All rights reserved. ** +** ** +***************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file main.c +* @date 01/10/23 +* @brief An application to run a matrix multiplication. +* +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "cgra_x_heep.h" +#include "cgra_bitstream.h" +#include "multiply_cgra.h" + +// For interrupt handling +#include "csr.h" +#include "handler.h" +#include "rv_plic.h" +#include "rv_plic_regs.h" +#include "hart.h" +#include "cgra.h" + + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +// Size of the input buffer for the CGRA +#define CGRA_COL_INPUT_SIZE 4 + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + + +// Handler for the CGRA interruption +void handler_irq_cgra(uint32_t id); + + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +// Plic controller variables +volatile bool cgra_intr_flag; + +// CGRA variables +static cgra_t cgra; +static uint8_t cgra_slot; + +// CGRA input and output buffers +static int32_t cgra_input[CGRA_N_COLS][CGRA_COL_INPUT_SIZE] __attribute__ ((aligned (4))); + + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +void multiply_cgra(int * matrixA, int ROWS_A, int COLS_A, int * matrixB, int COLS_B, int * matrixC) +{ + int ROWS_B = COLS_A; + int ROWS_C = ROWS_A; + int COLS_C = COLS_B; + // Prepare the input vector for the CGRA + // Col 0: &B[0][0], nItLoopColsC, &A[0][0], &C[0][3] + cgra_input[0][0] = &matrixB[0]; + cgra_input[0][1] = COLS_C/CGRA_N_ROWS; + cgra_input[0][2] = &matrixA[0]; + cgra_input[0][3] = &matrixC[3]; + // Col 1: &C[1][0], &B[0][1], nItLoopsColsA, &A[1][0] + cgra_input[1][0] = &matrixC[COLS_C]; + cgra_input[1][1] = &matrixB[1]; + cgra_input[1][2] = COLS_A; + cgra_input[1][3] = &matrixA[COLS_A]; + // Col 2: &A[2][0], &C[2][1], &B[0][2], nItLoopColsC + cgra_input[2][0] = &matrixA[2*COLS_A]; + cgra_input[2][1] = &matrixC[2*COLS_C+1]; + cgra_input[2][2] = &matrixB[2]; + cgra_input[2][3] = COLS_C/CGRA_N_ROWS; + // Col 3: nItLoopRowsC, &A[3][0], &C[3][2], &B[0][3], + cgra_input[3][0] = ROWS_C/CGRA_N_COLS; + cgra_input[3][1] = &matrixA[3*COLS_A]; + cgra_input[3][2] = &matrixC[3*COLS_C+2]; + cgra_input[3][3] = &matrixB[3]; + + // Set CGRA kernel L/S pointers + for(int col_idx = 0 ; col_idx < CGRA_N_COLS ; col_idx++){ + cgra_set_read_ptr ( &cgra, cgra_slot, (uint32_t) cgra_input[col_idx], col_idx ); + } + + // CGRA Execution + cgra_intr_flag = 0; + cgra_set_kernel( &cgra, cgra_slot, 1 ); + // Wait until CGRA is done + while(cgra_intr_flag==0) { + wait_for_interrupt(); + } +} + +// Initialize the CGRA +void initCGRA(){ + // Init the PLIC + plic_Init(); + plic_irq_set_priority(CGRA_INTR, 1); + plic_irq_set_enabled(CGRA_INTR, kPlicToggleEnabled); + plic_assign_external_irq_handler( CGRA_INTR, (void *) &handler_irq_cgra); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; + CSR_SET_BITS(CSR_REG_MIE, mask); + cgra_intr_flag = 0; + + // Load kernel + cgra_cmem_init(cgra_imem_bitstream, cgra_kmem_bitstream); + + cgra.base_addr = mmio_region_from_addr((uintptr_t)CGRA_PERIPH_START_ADDRESS); + // Select request slot of CGRA + cgra_slot = cgra_get_slot(&cgra); +} + +// Interrupt controller variables +void handler_irq_cgra(uint32_t id) { + cgra_intr_flag = 1; +} + +void countersInit(){ + // Enable and reset the CGRA performance counters + cgra_perf_cnt_enable(&cgra, 1); + cgra_perf_cnt_reset( &cgra ); +} + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/applications/transformer/multiply_cgra.h b/sw/applications/transformer/multiply_cgra.h new file mode 100644 index 00000000..d43ba4fd --- /dev/null +++ b/sw/applications/transformer/multiply_cgra.h @@ -0,0 +1,6 @@ +#include "performance.h" + +// Multiply the matrix in the cgra +void multiply_cgra(int * matrixA, int rowsA, int colsA, int * matrixB, int colsB, int * matrixC); +void countersInit(); +void initCGRA(); \ No newline at end of file diff --git a/sw/applications/transformer/param.h b/sw/applications/transformer/param.h new file mode 100644 index 00000000..6e4163a4 --- /dev/null +++ b/sw/applications/transformer/param.h @@ -0,0 +1,26 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_PARAM_H +#define FVLLMONTITRANSFORMER_PARAM_H +#include "stdint.h" + +#define D_Q 4 +#define D_SEQ 120 +#define D_MODEL 16 +#define NUM_HEAD 4 +#define NUM_LAYERS 4 +#define D_FF 4 +#define D_EMBEDDING 400 + + +#define NUM_FRACTION_BITS 12 +#define MUL(x, y) (int32_t) (((int32_t)(x) * (int32_t)(y)) >> NUM_FRACTION_BITS) +#define MUL_LONG(x, y) (int64_t) (((int64_t)(x) * (int64_t)(y))) +#define MUL_HQ(x, y) (int32_t) (((int32_t)(x) * (int32_t)(y))) +#define SHIFT(x) ((x) >> NUM_FRACTION_BITS) + + +typedef int32_t quant_bit_width; +#endif //FVLLMONTITRANSFORMER_PARAM_H diff --git a/sw/applications/transformer/performance.c b/sw/applications/transformer/performance.c new file mode 100644 index 00000000..421d39be --- /dev/null +++ b/sw/applications/transformer/performance.c @@ -0,0 +1,62 @@ +#include "performance.h" + +// For the timer +#include "rv_timer.h" +#include "soc_ctrl.h" +#include "core_v_mini_mcu.h" + +// Timer +static rv_timer_t timer; + +void kcom_perfRecordStart( kcom_time_diff_t *perf ) +{ + timeStart( perf ); +} + +void kcom_perfRecordStop( kcom_time_diff_t *perf ) +{ + timeStop( perf ); +} + +void timeStart( kcom_time_diff_t *perf ) +{ + perf->start_cy = getTime_cy(); +} + +void timeStop( kcom_time_diff_t *perf ) +{ + perf->end_cy = getTime_cy(); + perf->spent_cy += perf->end_cy - perf->start_cy; +} + +uint64_t getTime_cy( ) +{ + static uint64_t out; + rv_timer_counter_read( &timer, HART_ID, &out ); + return out; +} + +//Initialize the timer +void timerInit() +{ + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + mmio_region_t timer_0_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); + + rv_timer_init( timer_0_reg, (rv_timer_config_t) { .hart_count = 2, .comparator_count = 1 }, &timer ); + + rv_timer_tick_params_t tick_params; + + // The same frequency is provaided to get one tick per cycle. + rv_timer_approximate_tick_params( freq_hz, freq_hz, &tick_params ); + rv_timer_set_tick_params(&timer, HART_ID, tick_params); + + // Juan: see if i cannot remove this! + rv_timer_irq_enable(&timer, HART_ID, 0, kRvTimerEnabled); + rv_timer_arm(&timer, HART_ID, 0, 1); + + rv_timer_counter_set_enabled(&timer, HART_ID, kRvTimerEnabled); + +} \ No newline at end of file diff --git a/sw/applications/transformer/performance.h b/sw/applications/transformer/performance.h new file mode 100644 index 00000000..301f4874 --- /dev/null +++ b/sw/applications/transformer/performance.h @@ -0,0 +1,63 @@ +#include +#include "cgra.h" + +typedef long int kcom_time_t; +typedef kcom_time_t kcom_param_t; + +typedef struct kcom_col_perf +{ + uint32_t cyc_act; + uint32_t cyc_stl; +} kcom_col_perf_t; + +typedef struct kcom_time_diff +{ + kcom_time_t start_cy; + kcom_time_t end_cy; + kcom_time_t spent_cy; +} kcom_time_diff_t; + +typedef struct kcom_timing +{ + kcom_time_diff_t sw; + kcom_time_diff_t cgra; + kcom_time_diff_t load; + kcom_time_diff_t input; + kcom_time_diff_t output; + kcom_time_diff_t reprogramCols; + kcom_time_diff_t bitstream; + kcom_time_diff_t proto; +} kcom_timing_t; + +typedef struct kcom_perf +{ + kcom_col_perf_t cols[CGRA_N_COLS]; + kcom_col_perf_t cols_max; + uint32_t cyc_ratio; // Stored *CGRA_STAT_PERCENT_MULTIPLIER + kcom_timing_t time; +} kcom_perf_t; + +typedef struct kcom_run +{ + kcom_param_t sw; + kcom_param_t conf; + kcom_param_t cgra; + kcom_param_t repo; +} kcom_run_t; + +typedef struct kcom_stats +{ + kcom_run_t avg; + uint32_t n; + uint32_t errors; + uint8_t *name; +} kcom_stats_t; + +#define HART_ID 0 + +void timerInit(); +uint64_t getTime_cy( ); +void timeStop( kcom_time_diff_t *perf ); +void timeStart( kcom_time_diff_t *perf ); +void kcom_perfRecordStop( kcom_time_diff_t *perf ); +void kcom_perfRecordStart( kcom_time_diff_t *perf ); \ No newline at end of file diff --git a/sw/applications/transformer/selfattentionC.c b/sw/applications/transformer/selfattentionC.c new file mode 100644 index 00000000..7b0c175a --- /dev/null +++ b/sw/applications/transformer/selfattentionC.c @@ -0,0 +1,68 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include "selfattentionC.h" + + +void create_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, int32_t** weightVector) { + self_attn->pre_seq_len = pre_seq_len; + self_attn->head_hidden_size = head_hidden_size; + createDense(self_attn->query_layer, input_dim, head_hidden_size, weightVector[0], NULL); + createDense(self_attn->key_layer, input_dim, head_hidden_size, weightVector[1], NULL); + createDense(self_attn->value_layer, input_dim, head_hidden_size, weightVector[2], NULL); +} + +void destroy_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn) { + free(self_attn->query_layer_out); + free(self_attn->key_layer_out); + free(self_attn->key_transposed_layer_out); + free(self_attn->value_layer_out); + free(self_attn->attention_scores); + + destroyDense(self_attn->query_layer); + destroyDense(self_attn->key_layer); + destroyDense(self_attn->value_layer); + + free(self_attn); +} + +void removeExtraCols(int32_t* input, size_t rows, int cols) { + int nElems = 3; + for(int r = 1; r < rows; r++, nElems+=3){ + for(int c = 0; c < cols -3; c++){ + input[r*cols+c -nElems] = input[r*cols+c]; + } + } +} + +void compute_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, int32_t* input, int32_t* output, int32_t* qkv, int32_t* intermediate) { + self_attn->query_layer_out = qkv; + self_attn->key_layer_out = qkv + self_attn->pre_seq_len * self_attn->head_hidden_size; + self_attn->value_layer_out = qkv + 2 * self_attn->pre_seq_len * self_attn->head_hidden_size; + self_attn->key_transposed_layer_out = qkv + 3 * self_attn->pre_seq_len * self_attn->head_hidden_size; + + // This 3 mmul need to think they have 124 rows instead of 121 + // TODO: Check that the outputs have enough space for the extra 3 rows + computeDense(self_attn->query_layer, self_attn->pre_seq_len +3, input, self_attn->query_layer_out); // 121x16x4 + computeDense(self_attn->key_layer, self_attn->pre_seq_len +3, input, self_attn->key_layer_out); // 121x16x4 + computeDense(self_attn->value_layer, self_attn->pre_seq_len +3, input, self_attn->value_layer_out); // 121x16x4 + + transpose_quant(self_attn->key_layer_out, self_attn->key_transposed_layer_out, self_attn->pre_seq_len +3, self_attn->head_hidden_size); + MatMul_scale(self_attn->key_transposed_layer_out, 1, (self_attn->pre_seq_len +3) * self_attn->head_hidden_size); + + // 121x4x121 + MatMul_multiply(self_attn->pre_seq_len +3, self_attn->query_layer_out, self_attn->key_transposed_layer_out, intermediate, self_attn->head_hidden_size, self_attn->pre_seq_len +3); + + printf("\rRemove cols\n"); + // 121x124 -> 121x121 Remove extra cols + removeExtraCols(intermediate, self_attn->pre_seq_len, 124); + + printf("\rSoftmax\n"); + // Now intermediate is 121x121 + computeSoftmax(intermediate, self_attn->pre_seq_len); + + // 121x121x4 + MatMul_multiply(self_attn->pre_seq_len +3, intermediate, self_attn->value_layer_out, output, self_attn->pre_seq_len, self_attn->head_hidden_size); +} diff --git a/sw/applications/transformer/selfattentionC.h b/sw/applications/transformer/selfattentionC.h new file mode 100644 index 00000000..b2e3ab2c --- /dev/null +++ b/sw/applications/transformer/selfattentionC.h @@ -0,0 +1,35 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_SELFATTENTIONC_H +#define FVLLMONTITRANSFORMER_SELFATTENTIONC_H + +#include +#include +#include +#include "dense_layerC.h" +#include "softmaxC.h" +#include "transposeC.h" +#include "matMulC.h" +#include "param.h" +#include "cgra.h" + +typedef struct { + Dense* query_layer; + Dense* key_layer; + Dense* value_layer; + int32_t* query_layer_out; + int32_t* key_layer_out; + int32_t* key_transposed_layer_out; + int32_t* value_layer_out; + int32_t* attention_scores; + size_t pre_seq_len; + size_t head_hidden_size; +} SingleHeadSelfAttn; + +void create_SingleHeadSelfAttn(SingleHeadSelfAttn*, size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, int32_t** weightVector); +void destroy_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn); +void compute_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, int32_t* input, int32_t* output, int32_t* qkv, int32_t* intermediate); + +#endif //FVLLMONTITRANSFORMER_SELFATTENTIONC_H diff --git a/sw/applications/transformer/softmaxC.c b/sw/applications/transformer/softmaxC.c new file mode 100644 index 00000000..f9f8bd2b --- /dev/null +++ b/sw/applications/transformer/softmaxC.c @@ -0,0 +1,38 @@ +// +// Created by alireza on 10/6/23. +// + +#include "softmaxC.h" + + +void computeSoftmax(int32_t* input, size_t seq_len) { + size_t width = seq_len; + float input_float = 0.0f; + for (int i = 0; i < seq_len; i++) { + // Look for the biggest value of the row + int32_t max_val = input[i * seq_len]; + for (int j = 1; j < width; j++) { // Assuming its squared (width = seq_len) + if (input[i * seq_len + j] > max_val) { + max_val = input[i * seq_len + j]; + } + } + for (int j = 0; j < width; j++) { + input[i * seq_len + j] = (int32_t) fmax(input[i * seq_len + j] - max_val, -32767); + } + // Sum all values on the row + int32_t sum = 0; + for (int j = 0; j < width; j++) { + input_float = (float) input[i * seq_len + j] / (float) (1 << NUM_FRACTION_BITS); + input_float = expf(input_float); + input[i * seq_len + j] = (int32_t) (input_float * (1 << NUM_FRACTION_BITS)); + sum += input[i * seq_len + j]; + } + float sum_float = (float) sum / (float) (1 << NUM_FRACTION_BITS); + float sum_inv = (float) (1 / (sum_float + 0.00001)); // prevent zero divide! + int32_t sum_inv_int = (int32_t) (sum_inv * (1 << NUM_FRACTION_BITS)); + for (int j = 0; j < width; j++) { + input[i * seq_len + j] = (int32_t) MUL(input[i * seq_len + j], sum_inv_int); + } + } +} + diff --git a/sw/applications/transformer/softmaxC.h b/sw/applications/transformer/softmaxC.h new file mode 100644 index 00000000..fa47176f --- /dev/null +++ b/sw/applications/transformer/softmaxC.h @@ -0,0 +1,17 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_SOFTMAXC_H +#define FVLLMONTITRANSFORMER_SOFTMAXC_H + +#include +#include +#include +#include +#include "param.h" + +void computeSoftmax(int32_t* input, size_t seq_len); + + +#endif //FVLLMONTITRANSFORMER_SOFTMAXC_H diff --git a/sw/applications/transformer/stftVec.h b/sw/applications/transformer/stftVec.h new file mode 100644 index 00000000..62243064 --- /dev/null +++ b/sw/applications/transformer/stftVec.h @@ -0,0 +1,3 @@ +#include + +int32_t stftVec[49920] = {14912, 16305, 15424, 7300, 9641, 14329, 15823, 14833, 8710, 8912, 12488, 14281, 12956, 9398, 6336, 9702, 11379, 9458, 8448, -1345, 9383, 7575, 5905, 6193, 3111, 9534, 6388, 5963, 4307, 3857, 8353, 3661, 5646, 4840, 2974, 7109, 3348, 5522, 5048, 3034, 7513, 5345, 5058, 3058, 4169, 7233, 5680, 3618, -1939, 4739, 5392, 5531, 33, 3007, 4967, 5296, 5527, 2470, 3793, 5821, 6674, 5596, 4762, 3355, 6805, 6530, 6062, 5061, 3296, 7232, 4892, 6914, 3984, 3459, 7001, 1128, 7354, 1476, 3216, 6049, -4246, 7120, -809, 2509, 4113, 1815, 6269, 1109, 1261, 649, 3559, 4808, 1742, -1118, -2260, 4541, 2638, 1333, -3683, -2573, 5324, 1096, -41, -624, -6914, 5797, 1474, -749, 1036, -1670, 5676, 1178, 1827, 1675, -136, 4838, -524, 2920, 1334, -531, 3606, -5997, 2613, -295, 48, 2645, -2879, 1699, -2664, 1454, 969, -350, 1126, -2504, 1496, -4513, 428, 343, -2119, -288, -2229, 1388, -1021, -1983, -3119, -993, 1492, -842, -2102, -953, -1, -371, 77, -3653, -82, 1169, -1377, 613, -13738, -824, 674, 323, 1161, -3526, -3042, -2042, -359, 1511, -495, -3982, -2008, -5367, 1620, 1015, -2366, 202, -646, 1594, 1724, -2351, 739, 1997, 1015, 1845, -2589, 177, 2716, -743, 1526, -470, -1415, 2187, -4764, 870, 808, -3751, 227, -6828, -105, 405, -2589, -2027, -4123, -1632, -2546, -762, -542, -3523, -4738, -7353, -263, -416, -3632, -11115, -1954, -1127, -2297, -2954, -4223, -1644, -3840, -5020, -878, -3430, -2904, -10526, -3978, 912, -4403, -3360, -6759, -4464, 1940, -4478, -2115, -5273, -6310, 2291, -4053, -1078, -4874, -7426, 2178, -5158, -729, -4946, -5026, 1817, -7019, -795, -4583, -3242, 1282, -4693, -973, -3386, -2762, 493, -3012, -1475, -2270, -2920, -526, -3119, -2724, -2058, -3040, -1411, -4985, -5214, -3154, -2122, -1653, -5183, -11004, -4021, -1058, -1492, -3140, -6113, -1651, -856, -1647, -2264, -3441, -398, -1874, -2567, -2166, -2328, -798, -4980, -4395, -2596, -2396, -3644, -6692, -6640, -3482, -3798, -7317, -2442, -9695, -4718, -7081, -2114, -1099, -12776, -6194, -10210, -933, -1213, -7281, -6705, -7503, -1230, -2569, -5561, -6399, -4361, -2941, -5049, -4606, -5694, -2735, -8393, -7371, -3951, -4559, -2440, -6246, -6732, -3286, -3792, -3112, -4097, -4957, -3010, -3817, -4315, -5844, -3629, -3569, -5020, -5387, -6388, -2664, -5189, -8333, -6113, -2933, -3172, -7335, -9106, -7623, -2443, -5793, -6899, -6885, -8790, -3850, -8549, -6246, -6705, -6422, -6173, -5584, -6214, -8112, -5561, -6842, -3056, -5853, -11115, -5960, -6204, -2619, -5710, -8982, -6899, -5422, -3612, -6354, -6516, -7562, -5662, -4805, -6666, -5380, -5988, -8942, -4464, -5836, -6103, -4564, -7665, -3820, -5569, -8363, -3404, 10828, 5093, 9764, -637, -1552, 10180, 2996, 9296, 6157, -1414, 7937, 1593, 7768, 8228, -1236, 3042, 5579, 4561, 8634, -1291, 5745, 5866, -6705, 8019, 155, 7198, 3995, 2562, 6854, 2672, 6888, 2944, 4211, 6122, 4286, 5550, 4832, 4819, 6019, 4892, 5059, 5588, 5210, 5793, 4758, 5333, 5427, 5537, 5286, 4384, 4038, 4426, 5806, 4500, 4318, 2973, 2464, 5976, 4362, 4433, 5399, 2003, 5762, 5286, 4124, 6167, 3180, 4809, 5521, 2925, 5501, 3242, 2970, 4332, 1057, 4220, 2436, 677, 1175, 673, 3549, 1524, -996, -167, 1419, 3283, 855, -620, 1349, 1891, 3126, 21, 330, 1025, 1342, 3396, -364, 327, -259, -1672, 3904, 71, -113, -1710, -6133, 4303, -450, 51, -3479, -1414, 4283, -3264, 810, -3551, -2265, 3610, -6553, 1101, -15, -3014, 2068, -975, 654, 2445, -489, -830, 960, -122, 3656, 93, -5306, 1371, -1404, 3822, -1012, -2156, 480, -2754, 3166, -4172, -672, -1771, -874, 2085, -8220, -826, -4369, 125, 855, -4587, -2741, -5810, -768, -817, -3047, -6434, -8304, -5387, -1710, -1638, -3329, -2813, -2703, -143, -570, -1822, -1158, 622, 1100, -62, -1450, -1265, 1921, 1670, -287, -1317, -885, 2352, 1712, -1175, -749, 658, 2223, 1136, -476, 383, 1404, 1729, -347, 1100, 1501, 1061, 1107, -1263, 1494, 2095, -436, 523, 769, 671, 1946, -3210, -247, 1958, -288, 949, -4718, -1497, 1982, 172, -953, -3906, -2817, 1200, 314, -3714, -2514, -3680, 118, -902, -5827, -757, -4795, -515, -4974, -5055, -82, -5592, -101, -5554, -3961, -884, -5933, 355, -1759, -3638, -3811, -7708, -148, -1153, -4611, -11004, -9064, -1975, -2050, -6628, -7066, -5638, -3629, -3916, -6914, -10138, -3680, -2139, -5897, -8982, -6516, -2553, -1392, -8304, -9106, -3362, -1838, -1752, -14784, -4184, -2143, -1250, -3007, -9936, -2855, -1925, -717, -3695, -7644, -3151, -2452, -369, -2181, -5988, -4708, -3049, -406, -1225, -4564, -6602, -2813, -792, -1364, -3741, -5897, -2208, -1155, -2590, -3824, -4028, -1736, -1501, -5768, -5031, -2655, -1393, -2299, -7426, -5979, -2328, -1391, -3447, -2811, -5085, -3314, -2265, -3927, -1129, -4344, -5091, -4821, -3474, -589, -3947, -4532, -5623, -2869, -734, -4086, -4238, -3644, -2960, -1232, -4991, -6388, -3824, -4195, -1711, -5189, -11115, -5121, -4853, -2061, -3415, -5208, -4620, -2935, -2325, -1779, -3653, -3518, -1713, -2205, -884, -3294, -2666, -1488, -1954, -786, -3284, -1922, -2323, -2517, -1617, -3324, -1739, -4929, -5037, -4168, -3501, -2587, -9479, -5646, -10613, -4234, -5299, -4821, -2382, -2999, -6504, -7066, -3704, -1370, -1359, -28777, -4180, -3334, -1195, -1571, -6457, -2863, -2720, -882, -3203, -4974, -1921, -2339, -720, -4649, -4918, -1642, -2490, -1214, -4693, 8017, 5947, 8461, -2751, 9815, 7223, 6127, 8022, 2956, 9154, 4829, 5941, 7036, 5360, 7050, 4691, 5145, 5777, 5602, 3055, 6247, 4556, 3163, 3280, 1784, 6437, 3659, 2851, -3773, 4380, 5688, 1593, 5111, 3385, 4920, 4215, -50, 5408, 4045, 2722, 2053, -1742, 5027, 3237, 1031, 686, -10526, 5369, 2846, 5125, 2484, -1146, 6142, 3540, 5804, 4808, 926, 6608, 4504, 5018, 5994, 2364, 6477, 4881, 5104, 5893, 3248, 5468, 4141, 5982, 4460, 3000, 3115, 1903, 6320, 1467, 1021, -374, -2309, 6455, -3121, -5933, 1092, -3853, 6291, -4226, -2543, 1916, -3034, 5247, -2984, -312, 1637, -1636, 2669, -1564, 1060, 993, 444, -5085, -348, 2313, 309, 2137, -1156, 752, 2779, -235, 3077, 440, 1579, 2012, 269, 3224, 1158, 1843, -941, 1646, 2635, 2681, 1328, -8165, 2411, 1417, 3713, -223, -1668, 2049, 42, 3602, -2294, -1941, 537, -310, 2031, -1652, -2813, -577, 669, 624, -1099, -1117, 2, 1906, 2465, -1414, -852, -10, 2704, 3213, -1290, -2107, -628, 2970, 2815, -1178, -3975, -987, 2822, 2019, -1959, -4119, -1014, 2387, 1699, -3856, -2022, -896, 1673, 1995, -4500, -99, -984, 548, 2192, -1913, 1011, -757, -1355, 1698, -643, 1138, 883, -4408, 100, -1165, 162, 2147, -2661, -3259, -1635, -1216, 2327, -155, -10284, 1244, -206, 1579, 1159, -5793, 2667, 1028, 571, 1620, -2739, 2356, 869, 144, 1279, -1083, 29, -1014, -14, 96, -609, -8754, -1797, -161, -2169, -1144, -3281, -350, -385, -5554, -1973, -2571, -1009, -768, -4274, -1250, -3947, -4929, -1129, -3638, -687, -5509, -7464, -1615, -4331, -1858, -6204, -5584, -2211, -2430, -3557, -5531, -10001, -2042, -703, -856, -3471, -4115, -1611, -507, 467, -2635, -2046, -1894, -2326, 329, -3692, -1847, -2990, -6007, -1055, -9479, -2388, -5020, -991, -3992, -4559, -2541, -9936, 756, -8718, -2172, -2325, -5115, 971, -5266, -1954, -2102, -2722, 152, -3879, -3031, -2394, -2316, -1551, -4837, -4810, -3609, -3436, -3927, -12123, -5960, -3615, -4980, -4319, -4003, -5380, -2853, -3299, -3027, -1630, -4795, -4064, -1941, -2835, -1077, -4963, -9238, -1576, -4226, -1491, -5836, -5735, -1713, -9873, -2353, -7484, -4478, -1912, -6666, -3025, -11629, -5509, -2004, -3923, -3124, -14195, -7503, -2003, -3735, -2847, -9238, -6928, -2170, -4550, -2569, -5020, -4597, -2973, -3876, -2259, -2514, -3147, -5360, -2971, -1992, -1383, -2703, -12319, -3367, -2531, -1215, -2447, -5524, -4674, -5043, -1759, -1943, -4270, -3930, -6719, -2637, -1755, -4555, -2320, -4064, -2416, -1813, -4743, -1622, -4659, -1259, -1760, -5422, -1971, -7774, -641, -2088, -9479, -3574, -5638, -733, -3194, -6943, -7034, -5465, -1246, -4307, -4230, -12319, -8942, -1642, -3947, -3735, -8220, -7464, -4545, -4420, -4100, -4527, -2182, -4157, -5654, -1990, -2831, -1894, -4089, -5888, -1433, -2648, -3083, -3365, -4659, -2673, -3172, -6225, -3215, -3261, -5988, -3647, -8333, -3191, -2580, -17034, -2939, -6928, -2590, -2912, -6553, -2438, -6759, -2232, -4230, -3594, -3465, -5718, -2718, -5988, -3135, -5599, -4219, -4365, -10069, -4274, -3331, -3748, -9022, -6842, -6225, -1217, -4238, -7408, -4980, -8304, -146, -4067, -4145, -5906, -8683, 89, -3286, -3362, -5638, -5031, -634, -3577, -3580, -4491, -3430, -2642, -5726, -3621, -6173, -3378, -6246, -11356, -3455, -7445, -4523, -5793, -7644, -3968, -5710, -6640, -4858, -7066, -4805, -5429, -7004, -5906, -10899, -4968, -3444, -4923, -7752, -8165, -5576, -3114, -3680, -4319, -4242, -7464, -4991, -2851, -2485, -2437, -6615, -8165, -1779, -2273, -1313, -5662, -7523, -1053, -3326, -705, -6870, -4858, -1173, -4831, -749, -9064, -3311, -2031, -5415, -1427, -10069, -2891, -3342, -4951, -2348, -6103, -2977, -4957, -4532, -2809, -3076, -2952, -5444, -4826, -2731, -1731, -2861, -4093, -5810, -2825, -1404, -2952, -3801, -6492, -3680, -1752, -3650, -5759, -6553, -5444, -2937, -5726, -8942, -6958, -7623, -5638, -10526, -5906, -7865, -9429, -6828, -12534, -6434, -8903, -8086, -4597, -10442, -11004, -8363, -4935, -4299, -7687, -5554, -6516, -3232, -5743, -5374, -3609, -4754, -3067, -8276, -4270, -3554, -3560, -4713, -6045, -4278, -4847, -3149, -8942, -4550, -4946, -6354, -3537, -14784, -4759, -5970, -5202, -4319, -8549, -6759, -7050, -4035, -4390, -3710, -6885, -6540, -3653, -3415, -1844, -3763, -5531, -3883, -2969, -1482, -2312, -4912, -4184, -4003, -2247, -2188, -4399, -3309, -7752, -3923, -3301, -3820, -2055, -7503, -5615, -5227, -3609, -1579, -5279, -5694, -5879, -4555, -2116, -5607, -4698, -5145, -7842, -3476, -7960, -3543, -4082, -8138, -4592, -15615, -2543, -3187, -5260, -5227, -10442, -1836, -3163, -4455, -6007, -9585, -1480, -4130, -3920, -5997, -12319, -1490, -4219, -2982, -4688, -13365, -1631, -2859, -2295, -3259, -9238, -1475, -2268, -2720, -2843, -7019, -1047, -2589, -5592, -3754, -5670, -787, -3692, -9238, -6321, -4211, -1091, -5776, -4779, -13738, -2752, -2452, -8247, -4616, -9936, -2111, -6016, -6856, -5170, -7644, -2749, -13365, -5951, -5170, -7623, -5115, -7936, -5646, -5458, -9238, -8393, -8192, -5480, -6153, -9193, -6214, -6143, -6354, -7464, -7912, -5862, -4718, -9380, -9238, -8517, -8304, -4523, -8165, -6800, -8304, -10799, -5183, -6504, -5380, -5437, -5630, -6133, -7796, -5026, -3741, -4028, -6153, -28777, -4455, -3261, -3717, -5844, -8582, -4258, -3707, -4254, -5836, -7113, -5020, -4464, -5554, -6163, -7179, -6679, -4842, -7130, -8009, -7353, -8718, -5266, -7960, -13049, -7503, -9585, -6214, -8034, -11945, -6973, -9106, -8192, -9284, -10284, -6267, -6899, -13738, -10613, -5487, -6246, -5408, -12776, -6007, -3717, -4555, -2540, -3259, -2526, -6814, -5214, -5014, -4513, -4361, -7665, -12123, -6914, -5266, -3850, -3689, -4858, -4176, -5827, -2472, -2419, -2973, -2615, -6773, -2116, -2401, -3982, -2319, -5759, -2344, -3165, -6540, -3404, -4683, -2664, -4759, -4100, -6299, -4611, -2778, -8683, -3279, -6528, -4625, -2470, -7623, -4097, -4718, -4555, -2247, -3804, -5801, -3741, -6143, -2831, -2311, -7623, -2743, -13365, -4674, -2091, -9429, -1872, -4946, -8165, -3203, -7603, -1785, -3001, -10284, -6516, -5208, -2929, -2557, -8942, -6288, -4315, -5924, -2735, -6528, -3817, -4093, -12534, -3441, -5592, -3449, -3399, -5333, -5897, -7523, -4003, -2567, -3135, -9639, -9753, -4518, -2483, -2655, -3329, -5121, -4509, -3479, -3701, -1581, -4810, -4541, -5599, -6173, -1304, -5743, -5768, -5480, -5319, -1830, -3889, -8333, -3281, -4104, -2596, -2847, -4564, -2084, -3893, -3220, -2945, -1420, -1892, -3641, -4003, -3096, 102, -2587, -3659, -5487, -3447, 272, -3763, -4395, -8086, -4784, -888, -4620, -4880, -10526, -5234, -3698, -5374, -4365, -7730, -3863, -8192, -6516, -4149, -5091, -3463, -3504, -8192, -3656, -3490, -4416, -1397, -10138, -2937, -2999, -7213, -731, -8982, -3296, -3635, -5221, -890, -6376, -5694, -4923, -2714, -1481, -3723, -12319, -4874, -2390, -2344, -1961, -5702, -3717, -4592, -3653, -1198, -4086, -2877, -9022, -6204, -1377, -3788, -2650, -2819, -13738, -2488, -4149, -3184, -1308, -7464, -4654, -5221, -4282, -1307, -6016, -8009, -8549, -5480, -2356, -6692, -11781, -8485, -7019, -4486, -7644, -6732, -3779, -8393, -8304, -5960, -3269, -1903, -5654, -17034, -4644, -1553, -1214, -3482, -13738, -4352, -1036, -1380, -2472, -8009, -4743, -1560, -2359, -2308, -6288, -5133, -3135, -4307, -2809, -7213, -4743, -5494, -7503, -3603, -5784, -4509, -5615, -10001, -4127, -2594, -5333, -4513, -9022, -4149, -1202, -7162, -4199, -7984, -3883, -1068, -8009, -4373, -6640, -3795, -2002, -6332, -4573, -5694, -4336, -4024, -4759, -4518, -5718, -5997, -7644, -4369, -4274, -7644, -9022, -9064, -5429, -4344, -10526, -7019, -6422, -8192, -4800, -5061, -4578, -6173, -9873, -4578, -3417, -3196, -8165, -8276, -3589, -3656, -2383, -12319, -6516, -3309, -5260, -2084, -11356, -4469, -4274, -6083, -2228, -10799, -3010, -7623, -6123, -2733, -12319, -2455, -10526, -7281, -3827, -28777, -2960, -5480, -5670, -5524, -10799, -4743, -4635, -3903, -6388, -6928, -4698, -5702, -3324, -6007, -4810, -2557, -7264, -3592, -5465, -3603, -1878, -6480, -4486, -5183, -3126, -2516, -6267, -5569, -5008, -3509, -3985, -7389, -5960, -4644, -5319, -5394, -8683, -5387, -4469, -9936, -6310, -8138, -4874, -4874, -8683, -5638, -6943, -5247, -5694, -7603, -4800, -5862, -6577, -6842, -8982, -5339, -4858, -7687, -8060, -12534, -7408, -4583, -7066, -8615, -17034, -6434, -5924, -6173, -8276, -8827, -5253, -12319, -6007, -7687, -5646, -6553, -1616, -3168, -4523, -6016, -3795, -1521, -2644, -7130, -5091, -1944, -1469, -2478, -11115, -4863, -1434, -1404, -2879, -4795, -4006, -2223, -1601, -3860, -2770, -1831, -3982, -2524, -5458, -2497, -198, -5026, -4698, -9064, -3600, 328, -4013, -9380, -8754, -4429, -321, -2904, -11004, -5844, -3707, -2216, -2825, -12123, -5630, -3964, -5827, -3476, -12319, -6773, -4853, -12776, -3989, -7445, -7752, -4569, -4837, -4644, -6093, -7066, -4597, -2904, -5524, -5654, -6054, -5170, -2916, -5401, -5569, -4455, -3735, -4420, -4344, -5451, -2621, -1704, -5630, -3493, -4674, -1621, -745, -5472, -2865, -2960, -1343, -1158, -7353, -1661, -1247, -1313, -3352, -12319, -744, -222, -1299, -7247, -7936, -858, 81, -1263, -4896, -10613, -2191, -231, -1343, -3261, -7644, -4482, -1159, -1726, -2947, -4679, -3474, -2504, -2605, -4142, -4053, -1219, -3286, -3913, -6183, -4010, 40, -3726, -3574, -4795, -3732, 355, -4880, -1321, -3883, -3208, -275, -7299, 124, -4630, -3463, -1966, -13049, 606, -6988, -6007, -3563, -5906, 326, -8942, -8865, -2741, -4278, -326, -8247, -5465, -2248, -4491, -836, -5292, -4601, -1898, -4635, -1391, -3729, -3827, -1090, -3551, -2791, -3971, -3175, -619, -2560, -5133, -6016, -2642, -662, -2094, -5008, -10704, -2646, -816, -2348, -4266, -11115, -3352, -1060, -3471, -4688, -6246, -2737, -1822, -5451, -4912, -4203, -1507, -3085, -6899, -3671, -3304, -1426, -4262, -5319, -2751, -2895, -2861, -5360, -4203, -2811, -2619, -6928, -7196, -3982, -3580, -2599, -10138, -9812, -4523, -3944, -3227, -6376, -6528, -5686, -3430, -4991, -4299, -4149, -5333, -3161, -7984, -2364, -3189, -3923, -3476, -6958, -1409, -3163, -3412, -3999, -5109, -1477, -3961, -3606, -3957, -4601, -2559, -6299, -4348, -3653, -5751, -4130, -11356, -5670, -4086, -10704, -4504, -7050, -5915, -5897, -10526, -4601, -8009, -4254, -7196, -8827, -4211, -6870, -2685, -5662, -8582, -2813, -2803, -1836, -5906, -5516, -2305, -1349, -1816, -9380, -4447, -3247, -1220, -2386, -10799, -5240, -6422, -1849, -3294, -5735, -8363, -8582, -2821, -4644, -3833, -17034, -5546, -3795, -4703, -3045, -15615, -5067, -4250, -3535, -2887, -8582, -5718, -4331, -3644, -2931, -4929, -7130, -5014, -5531, -3147, -3476, -7503, -6343, -7066, -3482, -3554, -4805, -6354, -5394, -3889, -5607, -2731, -5531, -5686, -4550, -28777, -1501, -6133, -9429, -5592, -6719, -926, -12534, -9331, -7130, -5988, -990, -6214, -6640, -9238, -9331, -1743, -3326, -7353, -11945, -8220, -3261, -2889, -9106, -17034, -5776, -4991, -4226, -8086, -13738, -5253, -5195, -8165, -7960, -11488, -3695, -4559, -9284, -6856, -10799, -2517, -4336, -6928, -4640, -11629, -2720, -4923, -6615, -3447, -13365, -4513, -6640, -6786, -3314, -13049, -8333, -9064, -6692, -3916, -28777, -9022, -8333, -6133, -4500, -9429, -7213, -7034, -6064, -4258, -7264, -6434, -6705, -6666, 932, 7831, 7734, 5628, 2792, 5612, 7584, 7412, 5643, 3008, 7135, 6918, 6604, 5495, 2765, 6849, 6058, 5777, 4981, 1614, 6250, 5237, 5093, 4168, 1506, 6575, 4429, 4081, 3167, 2167, 6332, 3603, 2703, 2383, 1879, 4534, 3082, 2056, 3001, 993, 3610, 3376, 2564, 4093, 389, 5459, 4085, 3280, 4615, 372, 6118, 4222, 3667, 4530, 2164, 5969, 3504, 3511, 3670, 4618, 5289, 2286, 2860, 1070, 6124, 3514, 1379, 2043, -2992, 6525, -1364, 1278, 1404, 1455, 5802, -978, 1386, 1268, 2186, 3730, 1196, 584, 1598, 1340, -866, 922, -1921, 1457, 769, -4713, -145, -4564, 368, 1357, -1004, -636, -1618, -1302, 1839, -702, -80, -725, -2412, 2166, -1106, 443, -2079, -3261, 2277, -1727, 577, -3618, -6365, 1796, -2718, 249, -744, -6045, 720, -4863, -707, 556, -2038, -108, -10799, -2226, 1149, -860, -359, -9193, -3430, 1821, -474, -807, -6528, -4184, 2401, -299, -1386, -4168, -5853, 2410, -639, -2007, -2487, -6786, 1465, -1693, -3311, -1512, -4365, -930, -3110, -6628, -773, -3529, -2578, -3985, -10526, -262, -4290, -251, -4918, -5121, -291, -6492, 561, -6153, -3378, -1169, -9064, -98, -4918, -1758, -3326, -5516, -2714, -3444, -714, -7796, -3103, -3788, -2713, -804, -6988, -1880, -81, -2328, -1839, -3184, -1669, 1150, -2536, -2733, -1206, -2677, 582, -4258, -2391, -935, -5333, -2257, -9753, -1548, -2621, -5702, -2871, -9936, -1141, -1943, -4082, -887, -5353, -1427, 350, -3735, -1374, -2737, -1841, 835, -3507, -2276, -2207, -1448, 107, -2900, -716, -4191, -453, -520, -2289, 295, -6045, 217, -106, -1898, 182, -2333, 101, 222, -2008, -1052, -1240, -1064, -119, -2873, -3853, -1394, -4017, -1567, -4482, -8865, -2108, -7842, -3399, -5710, -7984, -2900, -2879, -1551, -4290, -5960, -4082, -1188, -263, -2294, -2567, -4242, -932, -254, -1130, -479, -2597, -2079, -1087, -1029, 454, -2294, -5339, -1921, -1894, 557, -4003, -4779, -2204, -1987, 202, -8827, -2457, -2797, -806, -339, -6376, -2121, -4527, -431, -1240, -4416, -3027, -7464, -1214, -2699, -2728, -3126, -5879, -3220, -4743, -864, -1900, -3940, -7842, -7665, 373, -2057, -3213, -8247, -6016, 477, -5055, -3386, -4923, -2300, -848, -6354, -3683, -4738, -13, -3650, -2904, -2813, -5002, 1256, -4523, -3051, -1623, -5227, 1543, -4611, -6093, -971, -6958, 712, -6256, -9812, -884, -4713, -1903, -7066, -6288, -1225, -2655, -15615, -5686, -6225, -1772, -1821, -3577, -5422, -7317, -2079, -1233, -2217, -7247, -7445, -1820, -1109, -2010, -4940, -5494, -1430, -2050, -2150, -2705, -3873, -1524, -4513, -3163, -2322, -3577, -2619, -7019, -5031, -3140, -5279, -5718, -5026, -4885, -4991, -7842, -12534, -4254, -3726, -10362, -4728, -6204, -4262, -2906, -6565, -3512, -5678, 4316, 6840, 4580, 3259, 2961, 3196, 6302, 4364, 4515, 4850, -2189, 4595, 3767, 5579, 6678, -8, 1191, 3113, 5479, 7398, 1764, -3457, 3130, 4156, 7223, -72, 553, 3813, 980, 6468, -7371, 2078, 4266, -23, 5328, -2265, 2586, 4023, 2669, 3707, -2463, 2829, 3190, 2994, 2463, -102, 3540, 2562, 2035, 2297, 2715, 4283, 2588, 2467, 1653, 4380, 4206, 2668, 3759, 2099, 4951, 3010, 2580, 4152, 3622, 4324, 1384, 2176, 3648, 4382, 2404, 1373, 1205, 2377, 4348, 941, 1380, -7, 487, 3747, 2119, 362, -75, -1494, 2973, 2771, -1351, 64, -2320, 2439, 2497, -1677, -1025, -2226, 1842, 1102, 224, -3422, -1604, 663, -1923, 1872, -5061, -679, -443, -1422, 2804, -5139, -1046, 330, -8, 3132, -1012, -4578, 1123, -743, 3080, 1385, -1940, 966, -3101, 2873, 2456, 533, 283, -2601, 2558, 2671, 941, -133, -1694, 1944, 2146, 846, -549, -2331, 805, 739, 952, -1741, -3735, -908, -1928, 513, -3463, -3203, -3018, -6256, -680, -3647, -1755, -5115, -8034, -1650, -4564, -1343, -5266, -6856, -1319, -2139, -1374, -4611, -3732, -501, 441, -37, -5494, -1592, -474, 1434, 1374, -7162, -797, -1931, 1590, 1724, -5924, -1475, -7162, 1209, 792, -6732, -3999, -4774, 4, -1714, -3957, -7019, -1597, -2432, -4399, -515, -7004, -533, -4433, -3830, 886, -7213, -678, -3360, -2885, 914, -6469, -2046, -2772, -823, -221, -12123, -2254, -3201, 351, -2128, -5020, -269, -5043, 406, -3049, -2102, 720, -8247, -453, -2027, -1515, 723, -9429, -1477, -926, -1857, -35, -6288, -644, -118, -1424, -1418, -5121, 610, 332, -336, -3010, -7130, 1036, 334, 407, -3726, -5509, 532, -84, 788, -3266, -3337, -942, -752, 896, -2929, -4046, -3027, -1414, 705, -3738, -4258, -3944, -2129, 86, -6064, -2058, -3638, -3543, -1160, -5387, -1560, -3501, -6914, -3441, -3671, -2279, -3978, -5561, -7146, -2516, -2531, -5202, -2555, -7213, -1473, -1336, -7179, -1366, -5509, -786, -174, -6958, -1460, -4743, -383, 263, -4089, -2606, -4890, -250, -23, -2473, -3457, -5818, -641, -581, -2185, -2791, -4957, -1481, -1194, -3626, -2176, -3158, -1772, -2403, -12776, -1952, -2175, -1504, -4482, -3018, -2062, -1852, -1760, -9331, -537, -2648, -1958, -2752, -4946, 15, -3985, -1967, -4592, -1143, -841, -6267, -1828, -9429, 148, -3334, -8485, -2964, -6856, -115, -8827, -7796, -11004, -4234, -1987, -10069, -6469, -3603, -3989, -4429, -28777, -4774, -1689, -2833, -1841, -7196, -3425, -2690, -1066, -410, -4980, -3259, -7162, -712, -360, -4816, -4733, -3135, -2079, -1277, -5546, -5415, -506, -4842, -1949, -6411, -3717, 630, -3686, -1086, -6679, -3085, 724, -2351, -227, -5539, -1996, -194, -1837, -24, -4536, -775, -2095, -1846, -600, 4204, 4660, 8026, 4595, 10348, 5216, 6364, 7879, 6734, 10114, 6388, 7902, 7603, 8184, 9483, 6672, 8301, 7352, 8347, 8510, 6065, 7650, 6789, 7585, 6985, 4981, 5876, 5470, 5887, 4510, 4088, 2554, 3362, 2625, 913, 3100, -926, 1407, -2228, -1682, 1032, 1499, 500, 1081, -984, -5374, 2541, -499, 1444, 74, -63, 2881, -21, -1083, 380, 2868, 3249, 2361, -2468, 2511, 3658, 3656, 3250, 2448, 4665, 2668, 3597, 2784, 4143, 5772, -546, 3238, 2202, 4779, 6199, 1526, 3364, 2774, 4899, 6270, 3139, 3512, 3183, 4641, 5958, 2564, 2909, 2858, 4004, 5026, -600, 1562, 1949, 2914, 3245, -4270, 109, 896, 1058, 679, 400, -274, 447, -2273, 42, 1204, 271, 808, -1407, 771, 785, 102, 1315, 1105, 385, 659, -2121, 1218, 2230, -1169, 1082, -6705, -6, 2556, -2267, 537, -1325, -2918, 2243, -1235, -1197, -490, -2675, 1355, -1544, -853, -1973, -450, 731, -2145, -220, -5415, 436, 1433, 489, -1404, -5630, 824, 2053, 1834, -3647, -3933, 1111, 1895, 1760, -3840, -1071, 1164, 1358, 889, -5561, 379, 857, 1312, 299, -6332, 591, 524, 1344, 648, -3080, 239, 679, 365, 1063, -1778, 463, 1396, -2128, 683, -575, 1417, 2220, -1558, -613, -261, 1921, 2688, -201, -1114, -2478, 1256, 2491, -850, -483, -5234, -1437, 1384, -2399, -648, -747, -3603, -914, -1382, -941, -779, -244, -2722, -688, 270, -3504, 390, -1014, -1146, 1486, -1465, -367, 121, -2292, 1870, -288, -1530, 429, -3773, 1307, -1486, -2531, 51, -4728, -401, -5480, -4028, -988, -4352, -3476, -12123, -5531, -2524, -3031, -7912, -7213, -5569, -4536, -1974, -28777, -4620, -5085, -4674, -2094, -10210, -3367, -5170, -1721, -3471, -8304, -3213, -5561, -277, -4826, -6256, -3444, -4784, -27, -4951, -4164, -4286, -4907, -532, -2670, -2130, -7796, -8192, -1419, -372, -1249, -6640, -4365, -2580, 615, -1821, -2967, -1713, -4282, 474, -3883, -1777, -1338, -6705, -574, -6958, -1553, -2962, -7050, -1909, -6083, -1713, -7644, -5979, -2574, -4601, -2608, -5319, -6133, -3795, -5234, -6194, -2805, -7299, -9064, -9238, -6692, -1369, -7281, -3161, -8517, -3201, -1020, -3444, -403, -6773, -2432, -1950, -828, 488, -7819, -1538, -3638, 235, 262, -4816, -647, -3883, -250, -765, -1513, -668, -3428, -2956, -2107, 221, -1687, -3294, -5240, -2637, 845, -3227, -3321, -2197, -2455, 567, -4211, -2766, -1743, -3438, -578, -4429, -1332, -2407, -10362, -2926, -4923, -359, -3801, -3609, -7842, -7603, -317, -4810, -877, -4469, -6143, -1126, -2950, -247, -2541, -1842, -2576, -1837, -697, -2922, -164, -5480, -1197, -1926, -7004, 63, -9531, -408, -5319, -5942, -1040, -2975, -67, -5183, -2497, -3692, -1281, -558, -960, -1859, -3840, -2176, -4053, -3080, -4795, -4290, -1389, -3754, -2438, -2566, -7335, -483, -3187, -1656, -1071, -4769, 227, -2231, -1377, -274, -2779, 499, -2701, -1962, 11, -2603, 361, -5465, -3194, -105, -2339, 37, -4569, -3883, -603, -1494, -218, -2971, -3071, -1480, -1470, -339, -4112, -1980, -2726, -2605, -705, -6814, -1701, -3227, -2447, -1825, -4382, -2442, -1534, -464, -3982, -3964, -3574, 24, 504, -4017, -4219, -3662, 867, 149, -2107, -2889, -2908, 1201, -1943, -1336, -2090, -2165, 1240, -6093, -1559, -2105, -2086, 1110, -4968, -2231, -1734, -3692, 520, -5049, -2076, 39, -10526, -1695, -603, -447, 2042, -1748, -2943, 1814, 1402, 3282, 518, 1279, 2560, 2470, 3513, 1056, 2696, 2051, 2503, 2648, 589, 2458, 359, 1399, 535, -181, 801, -2617, -1019, -3023, -357, -1397, -6343, -3801, -5654, -84, -1883, -7562, -2964, -5743, -332, -2805, -5584, -1599, -7687, -1928, -4464, -3846, -705, -12776, -6123, -4013, -3334, -459, -6045, -5784, -3062, -3769, -902, -3975, -4278, -2322, -4764, -2051, -3680, -4644, -1726, -5906, -3795, -5726, -5646, -1544, -6577, -5299, -7408, -5576, -2053, -6399, -4968, -2601, -4390, -4042, -6553, -3650, -1226, -4191, -14195, -7445, -2893, -1850, -4968, -2821, -6528, -3083, -5319, -3546, -393, -4718, -3373, -5951, -1532, 218, -3704, -2361, -3401, -735, -517, -3306, -1231, -4067, -1150, -2356, -2257, -607, -7445, -2686, -3257, -765, -349, -8485, -5127, -3430, -172, -510, -5599, -7523, -5472, -1054, -1458, -3213, -7389, -6422, -3496, -3814, -2080, -5951, -4587, -2158, -7503, -2356, -4315, -4504, -671, -4880, -4168, -3005, -3814, -1130, -3843, -9585, -2867, -2065, -4028, -3833, -8165, -4142, -1002, -9106, -3319, -5554, -6732, -713, -3850, -2398, -5853, -11945, -1125, -2774, -1831, -7842, -8034, -2292, -2248, -1784, -6958, -4191, -4311, -2020, -2216, -5079, -2853, -7371, -2562, -3237, -4242, -2608, -6842, -3612, -5227, -3618, -2962, -4606, -4223, -7050, -2762, -4053, -3415, -4708, -5524, -2214, -6133, -2776, -5026, -5415, -2317, -5836, -2592, -5374, -7752, -3060, -4172, -3025, -8112, -10138, -4500, -4013, -4046, -6565, -6988, -4885, -5592, -4901, -3311, -4654, -2900, -10799, -5152, -2507, -3420, -1932, -8718, -6214, -3187, -3580, -2276, -6745, -7408, -4918, -4968, -3626, -7730, -5055, -5997, -5743, -5152, -14784, -3206, -5827, -4282, -5924, -8034, -2182, -6422, -2920, -6528, -5387, -1613, -7936, -2179, -7408, -4386, -1411, -8718, -2104, -9238, -4138, -1513, -9639, -2728, -8942, -4842, -1716, -8683, -4226, -7842, -7335, -1868, -6288, -6288, -10526, -12123, -2152, -5888, -5933, -9753, -9380, -2941, -7708, -5067, -5458, -10799, -4442, -10284, -5195, -4587, -10001, -6035, -8649, -5494, -5888, -7774, -7081, -10799, -5306, -10442, -8009, -8304, -11356, -5055, -5988, -9812, -8615, -3900, -553, -5221, -2473, -2213, -3140, -1576, -5247, -3701, -4282, -2123, -3837, -3425, -6026, -2889, -1109, -3563, -4412, -11629, -1478, -291, -1218, -8333, -4157, -894, 217, 97, -3012, -1869, -830, 310, 567, -1073, -1373, -1528, -156, 288, -260, -2328, -3626, -1521, -787, 241, -4698, -8165, -5253, -2875, 333, -5026, -8060, -6054, -6565, -417, -3383, -6214, -2006, -7213, -2264, -3049, -3509, -1206, -3723, -3184, -3906, -1796, -2219, -2139, -2108, -3659, -1083, -5662, -1870, -1939, -1976, -998, -10001, -2316, -2718, -1005, -1446, -3650, -2795, -3978, -562, -2661, -972, -2877, -3735, -168, -4985, 1098, -740, -1271, 673, -3735, 2599, 1206, 435, 1678, -1448, 3280, 1886, 935, 1957, -1076, 2983, 1328, 255, 1045, -2863, 1566, -630, -1661, -1194, -6422, -1276, -4564, -4630, -2668, -2473, -5988, -3824, -4078, -2334, -1148, -6469, -1571, -2292, -2235, -1289, -5561, -511, -1786, -1513, -1826, -5710, -14, -3038, -1143, -1943, -6828, 6, -9380, -1432, -2883, -7408, -558, -2845, -1815, -8192, -5871, -1991, -925, -2204, -3817, -4482, -4858, -1420, -2675, -1124, -4006, -7389, -4784, -2574, -812, -3650, -5472, -7912, -2470, -1980, -1889, -5067, -3479, -3441, -3903, -280, -5509, -2686, -5576, -4723, 199, -4550, -2943, -4654, -4348, -712, -2378, -3554, -2825, -3597, -3244, -867, -4142, -2356, -3092, -2935, -259, -4315, -3455, -3172, -1121, -393, -3763, -7445, -4038, -624, -1052, -2999, -8649, -5312, -716, -2066, -2893, -6163, -3686, -813, -3447, -3247, -5970, -2030, -804, -3866, -3203, -5465, -1772, -1001, -3182, -2877, -4578, -2606, -1740, -3638, -2863, -3094, -3701, -3378, -4195, -3417, -1825, -3735, -6310, -2845, -5531, -1286, -2517, -4606, -2580, -6492, -1435, -1390, -2545, -4089, -3215, -2314, -1072, -2380, -5394, -2340, -4071, -1687, -3900, -3863, -3151, -5988, -3208, -5360, -3098, -5630, -4597, -4795, -3817, -2967, -12319, -2807, -5638, -3137, -3140, -9585, -1914, -7371, -3344, -3683, -5879, -2235, -6225, -4242, -4901, -2847, -4478, -5299, -6814, -7426, -826, -6310, -7445, -7603, -8220, 71, -3704, -4896, -4254, -5942, 63, -3269, -2205, -3373, -5319, -536, -3954, -1660, -3665, -5002, -1393, -4800, -2724, -3232, -3665, -2205, -5970, -5176, -2031, -2599, -2107, -8393, -5444, -1426, -2375, -1440, -8086, -4149, -1504, -2529, -1431, -5768, -3788, -2152, -2610, -2323, -5091, -4327, -3485, -2952, -3671, -5871, -5127, -5906, -3843, -4340, -8615, -4207, -8363, -5214, -3827, -28777, -3175, -6928, -6745, -3289, -10442, -3254, -6480, -6719, -3471, -8827, -4442, -6204, -6800, -3954, -7523, -6173, -4784, -9284, -3893, -6590, -6870, -4226, -10138, -3785, -6376, -6773, -5158, -8220, -4134, -6640, -6732, -7819, -9149, -4733, -6653, -6899, -10069, -12319, -5139, -5942, -7484, -7865, -13738, -5273, -5353, -8247, -4115, -1217, -1712, 369, -2442, -2083, -1941, -2851, 474, -4053, -1533, -2184, -3225, -137, -6163, -1936, -2447, -3096, -1098, -4438, -2583, -5008, -3352, -1674, -2681, -2956, -7371, -4386, -1320, -1531, -3135, -2855, -5979, -676, -577, -3817, -2679, -7196, -238, -143, -6026, -5561, -7644, -40, -688, -6565, -4266, -6988, -80, -2787, -6399, -1821, -5592, -539, -5312, -15615, -1349, -5415, -1734, -2429, -5494, -2051, -8304, -4578, -805, -3615, -3213, -3609, -10704, -387, -2097, -2969, -955, -3321, -1073, -650, -1614, -438, -1816, -2465, -1057, -992, -1442, -1947, -2954, -9022, -2679, -3498, -1970, -2764, -199, -5924, -2047, -73, -560, 2556, 351, 586, 1562, 1676, 2931, 1882, 1790, 2018, 2694, 1170, 1523, 1804, 1111, 2643, -8086, -394, 860, -1328, 1838, -705, -2546, -795, -2574, 862, 729, -1582, -2835, -1761, -163, 56, -617, -4748, -2222, -2720, -1583, -416, -6045, -2931, -5569, -3592, -790, -6045, -2737, -1166, -6958, -1225, -5319, -2470, -295, -8865, -1251, -3964, -2666, -1258, -7912, -1126, -2514, -3563, -3571, -4532, -1563, -1660, -5202, -4847, -1441, -2992, -1781, -4774, -4611, -322, -4997, -3198, -2952, -5942, -603, -5394, -6214, -2440, -6411, -1917, -4901, -5584, -3543, -5793, -3729, -4390, -3415, -7264, -8582, -5234, -5014, -2235, -8942, -4395, -6310, -8549, -1569, -6054, -2170, -7603, -5002, -1463, -5195, -2267, -9149, -2964, -1978, -3792, -4644, -9022, -3714, -2735, -2034, -13365, -7146, -6480, -2779, -635, -5444, -6256, -2807, -2774, 63, -3879, -7247, -1273, -4226, -70, -3677, -11781, -1544, -8138, -1093, -4003, -6590, -2997, -3151, -3254, -4810, -3279, -4555, -983, -7247, -5014, -1831, -5227, -463, -7984, -4195, -1944, -6565, -1102, -6828, -4395, -3334, -12319, -2986, -7146, -5784, -3218, -7936, -6246, -4250, -7371, -2606, -6074, -4935, -1803, -10526, -3769, -6045, -3198, -607, -6256, -6565, -4455, -3161, -278, -4082, -6692, -3105, -4649, -535, -4199, -6045, -3027, -7842, -1292, -5279, -7264, -3944, -13049, -2367, -5202, -6457, -5299, -13738, -2007, -6445, -3586, -6828, -13365, -764, -10704, -2758, -8549, -6988, -510, -3187, -3717, -10704, -3529, -1626, -918, -6365, -9695, -1779, -4504, -310, -7819, -7050, -1367, -7264, -937, -7179, -7583, -2398, -5516, -2448, -7050, -12776, -5827, -4523, -3203, -6565, -5415, -8517, -4331, -3549, -6376, -3776, -5097, -5888, -4764, -6615, -4748, -4816, -28777, -2793, -6988, -10362, -5862, -6469, -875, -7796, -4006, -6035, -4331, -367, -10001, -1756, -4693, -3635, -1064, -8903, -1414, -3436, -3360, -3012, -6422, -2417, -2677, -3375, -6973, -6225, -4344, -2743, -3863, -14195, -7484, -5836, -3795, -4578, -7213, -5546, -6016, -5374, -4935, -4896, -3975, -5380, -5759, -4842, -3415, -4010, -5374, -5437, -4980, -2817, -5221, -6928, -5844, -5037, -3156, 12134, 7964, 12326, 10783, 8293, 11562, 8697, 11639, 10187, 7721, 9797, 9075, 9413, 8177, 5757, 6745, 8684, 5434, 3553, 1036, 2902, 8678, 4881, 1333, -516, 1823, 8693, 5646, 2537, 403, 3576, 7805, 5197, 2556, -1100, 5226, 5757, 2662, 4307, 2672, 6239, 1909, -1969, 4505, 4656, 6247, -1849, 2392, 2524, 5823, 5138, 2186, 1376, -1860, 6818, 4252, 3845, 103, 2758, 7621, 4605, 5084, 4192, 4503, 8004, 3809, 5968, 5470, 4831, 7712, 622, 6074, 5073, 4209, 6425, -6679, 4972, 2877, 2824, 3429, -5164, 2167, -4142, 1406, -8549, -254, 641, -189, 942, 154, 1927, 1996, 1319, 726, 1413, 2212, 1668, 1070, 265, 2423, 1716, 12, 453, -417, 3108, 2143, -2306, -3, -1206, 2777, 3224, -3244, -712, -1927, 1433, 3625, -1742, -2493, -1672, -996, 2959, 346, -6504, -480, -8304, 997, 1689, -1503, -141, -2200, -1954, 1909, 1933, -1517, 408, -2375, 799, 3496, -6666, 976, -2447, -1733, 3721, -3311, 504, -1611, -2677, 2714, -318, -471, 66, -2573, 362, 1279, -1383, 1364, -3261, -2514, 2050, -1263, 2640, -1199, -1031, 1912, -97, 3743, 202, 656, 674, 932, 4287, 22, 1240, -1732, 1284, 4099, -1622, 768, -1030, 436, 3021, -3128, -625, 1057, -2791, 1251, -2083, -3056, 2130, -644, 832, -490, -7230, 2697, 1892, 1129, 612, -2488, 2826, 2021, 417, 637, -804, 2143, -284, -901, -111, -1250, 718, -1130, -1436, -548, -2861, 1279, 1877, -849, -1431, -3532, 2499, 2692, -522, -2977, -6074, 2475, 2350, -1123, -951, -3923, 1304, 1465, -2312, -112, -1156, -249, 583, -3003, -787, -954, -804, 120, -3309, -1418, -2543, -593, 238, -3344, -2008, -5960, 15, 460, -2340, -5049, -6759, 779, 33, -949, -6469, -4242, 1171, -1478, -87, -2747, -2863, 889, -3827, -225, -1086, -2411, 233, -4278, -1848, 671, -3433, -26, -2569, -4119, 1954, -8549, -109, -1791, -2231, 2352, -4382, -702, -3220, -2050, 1745, -2109, -1562, -7050, -6343, -110, -2562, -2239, -2225, -3133, -2871, -2801, -4003, -1242, 602, -1289, 430, -6064, -2657, 1996, -53, 2403, -2204, -5879, 2294, -654, 3164, -1335, -5465, 1706, -2933, 2983, -3291, -4184, 44, -1375, 2118, -8138, -1631, -2612, 607, 1069, -3158, 0, -1480, 1163, 425, -3184, 521, 27, 762, 102, -6705, 352, 610, -302, -556, -12534, -36, 795, -1710, -2253, -10899, -454, 87, -2580, -6133, -5702, -1070, -2807, -3187, -15615, -3076, -1921, -5208, -5487, -11004, -2322, -2148, -2003, -4743, -9812, -2473, -1118, -1889, -4003, -4620, -1991, 36, -3135, -4230, -2651, -848, 485, -2877, -1197, -2191, -399, -140, -1445, 146, -2805, -40, -2277, -1081, 335, -3644, 906, -6885, -1855, 568, -3094, 1723, -2910, -586, -256, 7955, 9431, 7065, 269, 75, 7232, 8576, 6787, 1631, -256, 4806, 5686, 5683, 2868, -1796, 3336, 5812, 3812, 3894, -1495, 5162, 7834, 4017, 4552, 1094, 4830, 7956, 4750, 4861, 3850, 1106, 6837, 4338, 4962, 5514, 800, 5479, 3551, 4794, 5981, 3929, 4838, 3787, 3849, 5465, 3666, 3666, 4655, 627, 4800, 720, 1166, 5579, -280, 4901, 572, 944, 6224, 4326, 4821, 3216, 2376, 6230, 5673, 3729, 3832, 2642, 5575, 5501, 1086, 3499, 1583, 4508, 4214, -2672, 2922, -1994, 3126, 3119, 8, 2423, -5915, 1204, 3471, 1033, 1761, -1943, -24, 3162, 631, 1150, -714, 851, 1134, -949, 1902, 1243, 1468, 1570, -4369, 3274, 1994, 1620, 3885, -9479, 3924, 1147, 1842, 4298, -4270, 3576, 129, 2110, 3005, -2621, 2410, 1788, 2122, 1103, -1865, 1274, 2796, 2517, 2250, -1522, 116, 2496, 3813, 2815, -591, -3668, 1378, 4765, 2004, 1073, -4718, 1297, 4694, 198, 2431, -1400, 2068, 3266, -1733, 3082, -1815, 2156, -550, -1699, 2937, -4331, 1401, -6093, -469, 2000, -4669, -324, -1580, 643, 947, -1557, -3957, -2226, 1428, 1061, 608, -3518, -5509, 1763, 1542, 2110, -519, -4974, 1758, 1922, 3083, 211, -1113, 1653, 1831, 3528, -551, 1174, 1511, -43, 3505, -2153, 2361, 1082, -3671, 3210, -2075, 2579, 86, 1497, 2916, 341, 2010, 1027, 2721, 2776, 2116, 1060, 3151, 1887, 2684, 2497, 299, 3847, -784, 2382, 1115, -347, 2894, -1433, 1655, -4779, -1533, 159, -313, 523, -1456, -2114, 157, -871, -383, 966, -1124, 1575, -2049, -438, 1143, -1455, 1545, -898, -255, 324, -5465, 849, 421, -349, -858, -3003, 1005, 757, -693, -2019, 380, 1884, 276, -930, -2885, 1472, 2254, -768, -871, -3412, 1381, 2043, -2011, -793, -4635, 364, 1345, -2132, -786, -7752, -1583, -157, -411, -743, -5607, -5208, -3289, 990, -759, -3560, -8790, -5827, 1501, -1095, -2847, -4348, -2801, 1092, -2051, -2086, -4412, -1752, -335, -3856, -1374, -6577, -2093, -3007, -5654, -554, -1904, -3978, -5960, -4611, 637, 121, -8942, -5569, -3087, 1370, 16, -7542, -4541, -1814, 1094, -2973, -3982, -3354, -391, -429, -6016, -2182, -2138, 1014, -2211, -1538, -1358, -1084, 2016, -374, -1303, -1492, -436, 2426, 943, -672, -2139, -757, 2059, 875, 559, -1998, -2170, 494, -265, 449, -1837, -1204, -2453, -1385, -1280, -2470, 446, -954, -3457, -2635, -3062, 911, 1, -3814, -233, -2333, 724, -1087, 166, 1384, -1346, -17, -3606, 818, 2076, -1003, -1745, -3692, -859, 2164, -1148, -4644, 820, -1743, 1766, -1029, -9639, 3229, 533, 1085, -708, -874, 4011, 1923, 925, -1191, 2077, 3458, 2779, 1197, -3196, 3238, 1601, 2975, 871, 8368, 8649, 11217, 9089, 2759, 7908, 8822, 10713, 8645, 4004, 6361, 8682, 9264, 7484, 3829, 3050, 7720, 7245, 6263, 2746, 4369, 6465, 6179, 5962, 5013, 7078, 5942, 6877, 6620, 5809, 7743, 5666, 7310, 7571, 4972, 6510, 4500, 6983, 8385, 3025, 2319, 222, 6253, 8565, 1389, 4631, 1123, 5188, 7790, 1940, 6545, 3968, 3206, 6076, 1376, 6721, 4951, 2413, 3870, -2165, 6022, 5664, 4337, -24, 72, 4580, 5524, 4530, -49, 1007, 2039, 4130, 2161, 3787, 149, -2783, 2257, -2276, 4606, 1418, -10284, 1590, 2613, 4302, 3173, -8363, 838, 3291, 3659, 4100, -7708, -81, 2399, 2572, 4251, -4191, -1082, 909, -69, 4001, -3121, -2404, 161, -2764, 3990, -2610, -1734, 696, 1203, 4170, -2382, -1397, 1343, 2686, 4120, -2219, -3580, 1245, 2895, 3752, -1654, -9479, -172, 2030, 3066, -842, -2916, -4509, -654, 1982, -244, -1865, -5253, -6800, 166, -472, -228, -2414, 789, -2945, -2887, 1391, -1107, 2896, -760, -4669, 1701, 112, 3687, 2489, 765, 1401, 839, 3641, 4129, 2694, 2037, 1305, 2869, 4570, 3362, 2311, 1486, 1344, 3977, 3261, 1359, 1306, -1243, 2830, 2727, 1584, 920, -8220, 2106, 2319, 2777, -212, -2982, 993, 2216, 2533, -28, 17, -3172, 1340, 677, 3016, 933, -1860, -2178, -2514, 4559, 302, 906, -1548, -3811, 4762, -2580, 1320, 453, -1516, 3905, -2883, 544, -1645, -2470, 2311, 152, -1839, -1755, -2768, 859, 1208, -2805, 1956, 2011, 659, 1685, 626, 2727, 3104, 1089, 2186, 1663, 1896, 1687, 889, 2434, 1138, -647, -5097, -473, 2128, -377, -8192, 684, -2125, 1721, -1707, -3170, 1992, -1529, 2441, -2756, -1328, 978, -908, 3470, -2191, -883, -1999, -1055, 3681, -430, -1117, -3741, -1670, 2816, -52, -2023, -705, -2356, 1098, -1448, -3433, 1467, -2311, 187, -4980, -5067, 2617, -1736, -55, -3577, -6469, 2823, -1540, -1337, -2260, -5810, 2055, -1671, -2555, -1247, -3549, -59, -1492, -1813, 482, -2118, -5422, -679, -877, 1674, -2066, -6928, 259, -607, 2092, -3903, -6590, 744, -2232, 1816, -8615, -3498, 622, -5260, 741, -5951, -43, 421, 526, -1446, -8517, 1176, 1159, 2573, -5702, -4821, 908, 2032, 3070, -8903, -768, -686, 2148, 2411, -3515, 585, -3067, 1365, 545, -609, 695, -5202, 537, -3163, 1236, 374, -7113, 1267, -11115, 2140, 292, -1455, 1836, -3683, 2020, 391, 1074, 1342, -1850, 595, 377, 2525, 211, -986, -2414, 302, 3370, -620, -451, -1466, 393, 3637, -941, -732, -7, 729, 3411, -223, -2720, -287, 1064, 2898, 603, -6732, -1899, 1126, 2168, 1134, -4234, -3701, 909, 1051, 1792, -4837, -2735, 567, -326, 2142, -5208, -1141, -38, -755, 1773, -1419, -35, -2401, 1021, -1310, 2214, -734, -1046, 1163, 74, 2339, -108, 464, 995, 557, 1910, 256, 1384, 727, 460, 861, 786, 1638, 420, -148, -433, 848, 1214, -147, -2297, -672, 503, 272, -1359, -3692, -1173, 571, -866, -2984, -1435, -2510, 1166, -2139, -1773, -2351, 640, 1466, -3843, -179, -2956, 2624, 940, -2248, 163, 338, 3240, 331, 359, -603, 1445, 3055, 1130, 1453, -1188, 1111, 2416, 1872, 1213, -124, -178, 1485, 1970, -125, 468, -1385, 265, 1849, -1076, -142, -824, -1423, 1800, -827, -1193, 336, -4258, 1409, -1427, -650, 1351, -2988, -710, -1215, 416, 2394, 176, -5670, 1344, 1570, 3240, 1391, 1708, 2979, 2617, 3518, 1122, 3488, 3494, 2930, 3063, -448, 3412, 3022, 2164, 1990, -2592, 1725, 1634, 104, 907, -2585, -1732, -379, -2039, 152, -460, -2986, -2271, -920, -1273, 602, -3189, -2933, 222, -4464, 280, -6745, -1325, 733, -7603, -761, -6204, -55, 617, -7819, -1402, -2612, 224, -39, -6026, -2046, -805, -556, -965, -3798, -2642, 364, -2829, -2007, -3232, -2904, 971, -3247, -2889, -3337, -2813, 791, -1196, -3291, -3029, -1963, -700, -923, -3744, -2615, -2053, -4455, -1889, -2841, -3417, -4923, -636, -3083, -1414, -6153, -3876, 1858, -3523, -1351, -3177, -231, 2562, -3971, -2929, -1513, 890, 1812, -4997, -1550, -2245, 528, -386, -6225, 776, -7623, -1071, -1521, -7819, 1657, -4082, -3128, -616, -8903, 1601, -1009, -3269, -108, -4153, 939, 41, -1668, 287, -778, -379, 368, -191, 91, 964, -2500, 350, 587, -994, 1328, -3215, 340, 657, -3062, 306, -1489, 529, 10, -6299, -2411, -92, 619, -1182, -6928, -7371, 616, 356, -2316, -6565, -15615, 762, -194, -4331, -8220, -5043, 724, -1022, -9753, -3471, -1832, 663, -2186, -2314, -533, -711, 320, -2711, -301, 909, -782, -392, -2819, 108, 1408, -1240, -881, -3863, -496, 1299, -1441, -1028, -5145, -1819, 965, -2118, -1966, -4464, -4215, 864, -4266, -5139, -3843, -10799, 1222, -9812, -11945, -4180, -2918, 1641, -5979, -6365, -5615, -599, 1531, -3311, -7984, -5793, -119, 402, -2430, -8276, -3853, -1016, -2244, -2673, -5127, -2871, -2861, -5380, -2668, -4573, -3003, -3344, -4805, -1763, -6204, -3795, -2265, -4985, -1516, -9812, -4348, -1511, -4723, -2566, -3632, -5026, -1407, -3471, -5662, -1293, -6504, -2102, -2140, -6842, -448, -4774, -3944, -1350, -3906, -475, -2825, -7819, -1278, -2950, -890, -2205, -6093, -1735, -2419, -1524, -2390, -3866, -2319, -2043, -2599, -2626, -3546, -2411, -2305, -4172, -2416, -4688, -1973, -3526, -4826, -2057, -7542, -1689, -5002, -4274, -2111, -10210, -2322, -4486, -4311, -3189, -7752, -4748, -4097, -5531, -6504, -5670, -6143, -4929, -8485, -11356, -3801, -3299, -9238, 3235, -1902, 2421, -281, -4365, 2278, -5073, 1347, -2247, 385, 134, -2239, 163, -5871, 2801, -5576, -2430, -974, -1976, 3776, -934, -9812, -1749, 750, 3595, 1489, -2077, -1443, 1740, 2481, 1780, 87, -1497, 1524, 992, 272, 130, -2540, 224, -483, -4923, -157, -2887, -2162, -2630, -4108, 423, -2018, -5569, -3779, -1699, 562, -1319, -7113, -2305, -1973, -482, -1226, -4340, -2170, -1603, -2545, -2254, -1782, -4486, -334, -3671, -4089, 69, -8138, -297, -3876, -3735, 1142, -3133, -1600, -4378, -2064, 1357, -1610, -2348, -5103, -598, 705, -423, -2036, -6064, 479, -488, 1160, -3695, -2672, 1635, -1005, 2546, -3362, -512, 2897, -660, 3138, 23, -3, 3646, -692, 2680, 1304, -940, 3516, -2080, 1062, 1287, -2497, 2303, -9284, -1376, 345, -1213, -399, -787, -3074, -334, 340, -6235, 2101, -4532, 731, 1017, -3665, 3170, -6054, 1665, 884, -1263, 3003, -5670, 1733, -465, -434, 1425, -3479, 1125, -5853, 66, -3594, -2391, 197, -2545, 872, -2211, -2926, -792, 240, 1239, 624, -5195, -1469, 345, 758, 845, -4564, -1862, -1661, -366, -134, -1559, -2641, -6256, -1721, -965, 75, -2863, -1780, -2279, -163, 570, -2445, 247, -1578, 870, -191, -1463, 1078, -1081, 1164, -1765, 586, 1244, -565, 472, -182, 2058, 841, 456, -1163, 1455, 2495, 43, 1297, -2098, 1862, 1844, -686, 1570, -1537, 1555, -361, -1224, 1274, -1375, 1274, -10362, -1018, 535, -955, 1616, -1261, 475, -446, -188, 2302, 1276, 1669, -1429, -372, 2583, 2101, 2073, -2245, -2432, 2063, 1842, 1812, -2569, -9531, 558, 522, 1053, -1720, -9149, -2040, -2024, -170, -332, -6828, -3370, -3900, -1635, 590, -1777, -2311, -1914, -1857, 782, -68, -2460, -760, -1298, 254, -149, -4569, -642, -1302, -681, -1680, -8454, -1348, -2018, -824, -4723, -3782, -2827, -3261, 206, -10613, -2435, -5002, -3378, 828, -8086, -2610, -4968, -2524, 239, -4172, -2967, -2427, -2184, -1878, -3108, -2229, -861, -1519, -2374, -3521, -867, -620, -313, -913, -2350, 98, -2163, 597, -901, -191, 355, -5836, 905, -1969, 892, -116, -2500, 510, -3485, 959, -1134, -1562, -630, -4587, 113, -1826, -3038, -1367, -4199, -1613, -1599, -1941, -333, -3213, -4323, -1772, 531, 251, -2314, -9238, -3264, 1372, -247, -1668, -9238, -5678, 1039, -1707, -1516, -6640, -4219, -130, -4071, -1967, -6814, -2912, -1719, -8247, -3304, -7281, -2829, -3089, -8060, -5202, -5915, -3779, -3615, -6173, -4067, -3944, -4968, -3665, -5897, -2977, -2437, -3391, -4093, -5133, -2817, -1864, -1847, -4907, -3723, -2681, -2473, -1310, -5836, -2555, -2420, -4541, -1505, -6759, -2175, -2599, -5888, -2142, -7299, -2673, -2969, -4382, -2797, -6528, -3883, -2191, -4573, -1230, -335, 645, 429, 357, -3038, -152, -1412, 1329, -229, -4348, -47, -6083, 1594, -1982, -3309, 23, -4635, 1187, -3170, -1646, -1013, -1054, 323, -2394, -1340, -5879, 314, -334, -1773, -3301, -3720, 584, -752, -361, -3698, -1733, 174, -1032, 678, -538, -2670, -549, -864, 491, 78, -2460, -1508, -953, -411, -1808, -976, -2973, -2054, -21, -5844, -672, -4075, -4093, 532, -251, -1414, -1376, -2827, 120, 1505, -3189, 1322, -685, -1286, 2352, -4664, 2820, 588, -7162, 2829, -2247, 3202, 1410, -1640, 2225, -732, 2496, 1687, 1589, -426, -1668, 523, 713, 2413, 912, -3003, -1305, -3247, 1645, 2977, 1544, 1310, -897, -313, 2760, 3205, 2988, 1433, 430, 603, 3140, 3446, 1385, 2077, 454, 1813, 2967, -406, 2819, 1991, 766, 1707, -4138, 3058, 1834, 1570, -371, -9149, 2707, 181, 2282, -3537, -4693, 1413, -2916, 2590, -5810, -1620, -276, -6732, 2826, -6988, -743, -284, -6786, 2924, -9193, -1535, -798, -4013, 2843, -7865, -2470, -2460, -1686, 3096, -2430, -1810, -1476, 143, 3503, 435, -1444, -855, 1322, 3261, 1347, -1227, -1814, 1695, 1779, 552, -487, -3208, 1165, -2364, -2550, 436, -2545, -395, -3334, -6528, 641, -1313, -2999, -573, -3005, -353, -1292, -3947, -842, -2326, -2500, -3001, -2988, -2835, -2207, -2135, -5127, -2670, -4433, -2040, -279, -4683, -2328, -3615, -1618, 769, -6732, -1543, -3242, -848, 1473, -5429, -742, -2061, -292, 1818, -2673, -499, -46, -804, 1349, -1369, -1100, 1304, -3738, -24, -104, -2344, 1780, -2843, -290, 1044, -4759, 1564, 381, 749, 1582, -6256, 1045, 1368, 939, 1323, -1788, 626, 1164, 359, 375, -843, 32, 220, -337, -773, -1428, -1186, -939, -1168, -2023, -988, -1232, -1241, -2205, -3378, 86, -133, -473, -340, -2383, 686, -380, 89, 1460, -1666, 1007, -2470, -263, 1945, -2977, 793, -6093, -1781, 1250, -6973, -227, -5599, -4211, -789, -2994, -2270, -3792, -6528, -5031, -938, -6376, -3144, -7371, -3498, -517, -12534, -4211, -7034, -1516, -1733, -7445, -4654, -13365, -1254, -8112, -6469, -3769, -3266, -1563, -3103, -5879, -4369, -751, -1213, -395, -6183, -5718, -361, -640, 288, -7371, -6332, -1802, -691, 277, -10704, -5260, -7523, -1131, -162, -10362, -3227, -4997, -1278, -1484, -5662, -2720, -2657, -1381, -2382, -4164, -4688, -2956, -2107, -587, -4153, -9238, -4738, -4078, 349, -5139, -2992, -6310, -8247, -127, -6504, -1722, -7213, -5103, -2330, -6565, -2236, -12534, -3509, -4890, -5164, -3886, -7081, -3656, -2385, -4123, -6492, -4258, -4416, -1680, -4295, -13365, -3482, -4455, -2478, -5599, -7562, -3662, -3656, -4215, -3866, -6153, -4078, -2550, -6504, -1831, -7113, -4361, -1401, -10526, -1369, -9064, -4327, -696, -12776, 10974, 5133, 12179, 10614, -15615, 10339, 6509, 11570, 10083, -5710, 8267, 7039, 9596, 8403, -3137, 3870, 5751, 5533, 5286, -2242, 966, 3967, -1683, 389, -1745, 3039, 4025, 615, -2125, -725, 3074, 3004, -787, 404, -66, 2859, 647, -159, 1152, 251, 3039, 1753, -97, -867, 1275, 3871, 2657, 291, -122, 2316, 4697, 2636, 1038, 3007, 2920, 4654, 3017, 300, 4325, 3402, 3192, 3945, -3589, 4568, 3727, -441, 4302, -1647, 3895, 3687, 164, 3558, -93, 2359, 3268, 1703, 1790, -2194, 715, 2426, 1429, 682, -1157, 245, 689, 605, 508, 1833, 125, -4669, 152, -366, 2668, 92, -1704, -620, -1566, 2372, 146, 1236, -1799, -3266, 1346, 211, 1634, -1900, -5942, -366, 469, 661, -1627, -4021, -2935, 903, -746, -1696, -2648, -3751, 1215, -1950, -1262, -2507, -3151, 1423, -4901, -391, -1911, -4644, 1646, -2849, -174, -1012, -8423, 1633, -298, -1270, -1283, -7389, 1189, 127, -3923, -3889, -4728, 492, -991, -6256, -5726, -2366, 48, -3744, -9585, -2028, -1419, 43, -9064, -8485, -1286, -1956, 16, -12534, -5214, -2153, -4774, -291, -6800, -5599, -4464, -7984, -796, -3540, -8165, -7752, -2726, -1325, -1898, -5380, -5988, -1576, -1583, -1682, -2815, -3597, -2080, -1550, -3076, -1475, -1975, -3441, -1987, -4743, -1014, -1593, -4500, -3850, -2366, -1427, -3124, -5561, -9585, -850, -2361, -12123, -8165, -5554, -393, -2359, -3707, -28777, -3741, -652, -1657, -2057, -10284, -4142, -1452, -1378, -3018, -11629, -6800, -2621, -1553, -6354, -12123, -7562, -3580, -2061, -3975, -8138, -4816, -3641, -2711, -2571, -7264, -4378, -3311, -3114, -3018, -6445, -5374, -3189, -3012, -4601, -4550, -7960, -3349, -2900, -6590, -2473, -17034, -3729, -3422, -8086, -1169, -5862, -4258, -4679, -8304, -848, -2760, -5067, -5422, -7066, -1276, -1302, -5997, -5444, -5465, -2008, -968, -6173, -6376, -4134, -2722, -1477, -5576, -7774, -3142, -3490, -2425, -4611, -6354, -2621, -4759, -3401, -3695, -4748, -2914, -7081, -4038, -3577, -4331, -4486, -7097, -3618, -4769, -5176, -7335, -5768, -2735, -6759, -5607, -7542, -5906, -2531, -5176, -4395, -6365, -6842, -3375, -3425, -4168, -5176, -7603, -4985, -2557, -5353, -4447, -7912, -5702, -2040, -6007, -4191, -6469, -6870, -1432, -4842, -2811, -4688, -10799, -782, -3656, -1336, -4203, -7389, -400, -2703, -899, -5312, -6692, -471, -2238, -1490, -5638, -8220, -1081, -2448, -2841, -3632, -9064, -1976, -3158, -4847, -3301, -7050, -2688, -3677, -8903, -5401, -4311, -3615, -3452, -6246, -6692, -2340, -4504, -3056, -3455, -3665, -1210, -3301, -3276, -2726, -3362, -831, -2499, -4957, -3393, -5339, -1122, -3126, -10613, -5103, -6590, -1967, -5487, -9380, -6666, -4278, -3686, -9753, -8220, -7034, -3373, -8138, -10704, -11004, -6235, -2895, -8034, -5374, 1449, 3197, 8375, 3840, -7960, 766, 2347, 7777, 4367, -4940, -1927, -133, 5842, 4880, -1305, -1580, 693, 2403, 4831, 1131, 2049, 2339, 1975, 4742, 2473, 3660, 2578, 2608, 5005, 2976, 4273, 2325, 1635, 5258, 2788, 4387, 1910, 339, 5076, 1996, 4280, 63, 1772, 4314, 901, 3961, -3168, 3391, 3087, -510, 3944, 1918, 4603, 1415, -3362, 4884, 3749, 5577, -1033, 0, 5577, 4087, 5888, -1456, 2902, 5178, 3504, 5074, -1015, 4127, 3391, 2664, 2516, -2295, 4236, 613, 2383, 76, -3089, 3453, 332, 2188, 2452, -3065, 1995, 160, 1504, 2824, -3989, 165, -862, 661, 1778, -4319, -1510, -815, 798, 159, -3383, -2204, 245, 1772, -533, -3182, -1799, 1191, 2324, -12, -5408, -1462, 1702, 2092, 276, -9812, -1961, 1717, 1328, -549, -6321, -2754, 1152, 741, -1920, -2046, -3163, 25, 663, -727, 677, -3247, -632, 751, 513, 1750, -1624, 202, 608, 711, 1575, -453, 946, -73, 120, 269, -470, 832, -861, -948, -2514, -1427, -582, -556, -1909, -5183, -3452, -5221, -79, -2022, -2472, -8718, -3471, -247, -1626, -1334, -4918, -1045, -310, -1642, -1216, -1966, -1503, 105, -2305, -1482, -828, -4853, -154, -3242, -1581, -565, -7113, -1817, -3720, -1001, -713, -5020, -4810, -3606, -92, -903, -4223, -4625, -3444, 437, -1189, -2597, -3393, -3474, 438, -1976, -1954, -2776, -3592, 166, -3103, -2003, -3360, -3532, -40, -1821, -2192, -6445, -3184, -114, -146, -2861, -4361, -3352, -154, 150, -4352, -1705, -4874, 68, -1157, -5183, -974, -8827, 680, -5139, -4847, -1104, -7484, 1084, -6745, -5735, -1184, -4311, 786, -4790, -7542, -1326, -2522, -276, -7097, -5702, -2488, -1661, -1495, -6194, -4985, -4523, -1326, -2377, -3401, -6492, -3203, -922, -4282, -3286, -8333, -2480, -599, -5037, -4869, -5121, -4142, -968, -2825, -3961, -3695, -6719, -2038, -2608, -2208, -3889, -3701, -2312, -4112, -1963, -5333, -3388, -1825, -5960, -2990, -4464, -4348, -2090, -6640, -5067, -2737, -3632, -3326, -5164, -7130, -2590, -3025, -4869, -3225, -5897, -4238, -3603, -6299, -3054, -4336, -7687, -4748, -10442, -4425, -3624, -4885, -4769, -7752, -4769, -3391, -3457, -3632, -5509, -4513, -3853, -3773, -3074, -6083, -6163, -6225, -5599, -3151, -8165, -5260, -8942, -7644, -2745, -5380, -3471, -4013, -5480, -2030, -2992, -2743, -2835, -3820, -1931, -1673, -1823, -3580, -3549, -2599, -1216, -1275, -6973, -4733, -3964, -1741, -1987, -6528, -7281, -5422, -3054, -4659, -3083, -5853, -4138, -3222, -4649, -1944, -3999, -2292, -2743, -2148, -1918, -3523, -1709, -3362, -1462, -2440, -3837, -2587, -4790, -2038, -3140, -4348, -5569, -6194, -3999, -3274, -4800, -8865, -9936, -6354, -2197, -5008, -5183, -8903, -3866, -1736, -4885, -3671, -5183, -2751, -2791, 3552, 2546, 6803, 2428, -607, 2619, 2288, 6397, 3673, 1962, 1236, 1293, 5440, 4737, 2974, 2997, -807, 4409, 4499, 1728, 3993, -904, 2855, 2610, -2696, 3693, 1618, 148, -2758, -1072, 2198, 2870, -14, -1298, 672, -1000, 2921, 490, -235, 318, -5979, 1866, 38, -1825, -2166, -2345, -23, 446, -2661, -3222, -109, -1863, 1191, -1836, 1712, 1648, -2407, 1575, -1586, 3739, 2695, -1357, 1647, -262, 4435, 2996, -539, 1369, 1681, 4231, 2582, 322, 530, 2755, 3487, 1325, 1291, -1313, 2575, 2805, -1219, 1520, -3701, 933, 2599, -6679, 799, -839, -231, 2571, -11781, -520, 673, 1176, 2401, -6399, -1760, 423, 1187, 1965, -3137, -2926, -1317, -990, 1329, -3036, -4361, -3415, -15615, 606, -4282, -2655, -4123, -2158, 219, -583, -251, -4382, -323, 477, 922, 934, -3846, 267, 371, 410, 1118, -3665, 532, -796, -2006, 247, -3266, 866, -2875, -3342, -2342, -1843, 1332, -3798, -2236, -7865, -941, 1451, -1651, -2768, -3757, -1011, 825, 1, -4250, -2979, -1875, -568, 486, -4278, -3927, -2897, -2071, 45, -3409, -5836, -3360, -2050, -1226, -3067, -7819, -3554, -848, -4138, -2843, -7230, -4180, -67, -7264, -2155, -5592, -4885, -265, -2637, -1579, -5103, -3501, -1388, -1746, -2314, -5480, -1786, -1016, -3496, -6026, -5853, -1022, 890, -7687, -3031, -4523, -960, 1892, -1701, -917, -2473, -996, 1951, 293, -1295, -1526, -839, 1363, 995, -3788, -1756, -767, 320, 890, -4698, -3094, -832, -1592, -26, -3615, -5292, -838, -4963, -1790, -4130, -3957, -792, -3010, -3010, -4550, -1954, -1098, -1471, -2610, -4082, -1511, -2256, -771, -2268, -3947, -2411, -5109, 87, -1683, -4270, -3957, -8393, 608, -1141, -4890, -4049, -2707, 521, -784, -5710, -3754, -679, -22, -643, -7179, -4112, -211, -1247, -1275, -10613, -4207, -1117, -4455, -3201, -7464, -2971, -3900, -6045, -3479, -3840, -1497, -6163, -2075, -1089, -2219, -770, -3083, -1019, 77, -2185, -1022, -1958, -1396, 53, -4093, -2083, -1809, -2891, -1158, -8423, -3108, -2282, -4509, -3430, -4433, -3665, -3463, -4142, -3695, -3512, -4303, -6093, -3259, -2548, -5208, -4378, -9812, -2316, -2468, -14195, -4003, -5818, -1296, -3237, -4021, -4180, -5279, -531, -4097, -1752, -4901, -8333, -295, -3866, -1062, -5970, -9695, -686, -3284, -1441, -7542, -5776, -1918, -3031, -2626, -10442, -5031, -4874, -3140, -3804, -7708, -4017, -5561, -3961, -4774, -4779, -3117, -2331, -5853, -7603, -3964, -3577, -1508, -8393, -11945, -5170, -6565, -2225, -9380, -6343, -6602, -7066, -4161, -7819, -4447, -4266, -4303, -6773, -7247, -3220, -3618, -4831, -12123, -6480, -2613, -3441, -5784, -7623, -4723, -2512, -2097, -3242, -3937, -4482, -2564, -1195, -2500, -3137, -5374, -2617, -1416, -3597, -4442, -4203, -10362, -6153, -2210, -5827, -2538, -8304, -8549, -1947, -7034, -1447, -7389, -10704, -2833, -9812, -1377, -6310, -6225, -5702, -8086, -1451, -5247, -4853, -11629, -4754, -1137, -4654, -4559, -9064, -2745, -972, -4644, -5008, -5592, -2411, -985, -5387, -6759, -2653, -4199, -622, -7484, -12534, -1134, -28777, -234, -10210, -8192, -774, -5031, -609, -7146, -6958, -1491, -3698, -2265, -5516, -9106, -3367, -4723, -6653, -4046, -12776, -6480, -8454, -5694, -3119, -7960, -10284, -6958, -2222, -3635, -7019, -11488, -4006, -849, -5067, -8165, -10210, -2893, -477, -4698, -10704, -9479, -3051, -798, -5451, -28777, -9936, -4980, -1666, -17034, -6759, -10284, -11629, -3163, -5067, -3126, -4918, -5615, -4991, -2438, -2012, -2438, -4303, -4211, -1262, -2540, -1617, -5273, -2624, -861, -4532, -1962, -7317, -2075, -1135, -7687, -3441, -7484, -2468, -1991, -7097, -7644, -5662, -3618, -3324, -6064, -7583, -3220, -5145, -4858, -5451, -3795, -1769, -6745, -5810, -3701, -2984, -1371, -10362, -6602, -2211, -3644, -1822, -7353, -8333, -1469, -5509, -3040, -4523, -7583, -1289, -7708, -4985, -3804, -5735, -1540, -9936, -7562, -4064, -5195, -2403, -8192, -10362, -4042, -5933, -4550, -4592, -10899, -3367, -8393, -9193, -3259, -8165, -3020, -8790, -5502, -3438, -5502, -3766, -5960, -3674, -4795, -3496, -6786, -5183, -3007, -6540, -2176, -10613, -6422, -2895, -7426, -1522, -5279, -6988, -3689, -7389, -1313, -4348, -3391, -6074, -7774, -1412, -4442, -1439, -7034, -9429, -1988, -3968, -693, -4880, -9064, -3375, -3668, -825, -4093, -8942, -5599, -4733, -1587, -4323, -11356, -7281, -5694, -2637, -5592, -5145, -7774, -3218, -3923, -7687, -2138, -9284, -1734, -6445, -8683, -714, -15615, -1277, -10362, -8060, -463, -10210, -1379, -7130, -7213, -1375, -7687, -1668, -7888, -8304, -3415, -6640, -1912, -12534, -11356, -6016, -4997, -2139, -6800, -7113, -6928, -3096, -2752, -5234, -5401, -4555, -2047, -3903, -4504, -4616, -3409, -2040, -4541, -4168, -4191, -3543, -2809, -4270, -5569, -4460, -3306, -3992, -4211, -9284, -6163, -2253, -4826, -5394, -4640, -13049, -1625, -3801, -8086, -2997, -8942, -1742, -2637, -4067, -2887, -7081, -2728, -2027, -2256, -3463, -6705, -4929, -1902, -2330, -4238, -7004, -9873, -2606, -3978, -4951, -10138, -9064, -4606, -7912, -5055, -11945, -5979, -8192, -12776, -4606, -7774, -5026, -14784, -9022, -4583, -7335, -4853, -10799, -10138, -5576, -7842, -4754, -9331, -9873, -6653, -7842, -4703, -17034, -7179, -5862, -6399, -4929, -8138, -5988, -5422, -5306, -5170, -5472, -6026, -6214, -4997, -5360, -5422, -8615, -8615, -4583, -5726, -7687, -8009, -12534, -3744, -5933, -11115, -4157, -9331, -3092, -5546, -9380, -2975, -7912, -2829, -4974, -10284, -3168, -8192, -2883, -5097, -7752, -4357, -8485, -3020, -6745, -6035, -6445, -6958, -3182, -7687, -6163, -8982, -6103, -3644, -5531, -7464, -9331, -5678, -2807, -4495, -3326, -5183, -10362, -2509, -5554, -5646, -3329, -4527, -2958, -7888, -10069, -1869, -1568, -4486, -9873, -10799, -2146, -470, -8615, -11781, -8754, -3540, -470, -6054, -10138, -5569, -3001, -1149, -2688, -6422, -3101, -2306, -2075, -1407, -3671, -1899, -3344, -3337, -1431, -2316, -2138, -4473, -6133, -2612, -2375, -4035, -3259, -6376, -4486, -3996, -6267, -3085, -3264, -5115, -8138, -5189, -4545, -2274, -5049, -13365, -4262, -8276, -2774, -6434, -8276, -3449, -7034, -4569, -5776, -6288, -2651, -4315, -4630, -3281, -4134, -2014, -3490, -2548, -2696, -2383, -1828, -3452, -1414, -3920, -1431, -2363, -2319, -1207, -7066, -1259, -3863, -895, -1834, -8683, -1945, -6267, -589, -3151, -7687, -3889, -5524, -1604, -4980, -7644, -7299, -3401, -2783, -7583, -8112, -5494, -2427, -1750, -14784, -6602, -3896, -2526, -1144, -9531, -4795, -3417, -3707, -1616, -5888, -4495, -3798, -5546, -2303, -4149, -5718, -5784, -5615, -2473, -3662, -7562, -8865, -4805, -3242, -4408, -6256, -5353, -4532, -5810, -6469, -5189, -4060, -4433, -13738, -10899, -5286, -3893, -4180, -15615, -9812, -6035, -3609, -4024, -8549, -5292, -6173, -2653, -4541, -4644, -3644, -5073, -1612, -5801, -3404, -3471, -3978, -1255, -6123, -3798, -4149, -3833, -2344, -4100, -5339, -4980, -5121, -7445, -2521, -6376, -5531, -7264, -4723, -2119, -5539, -6183, -6376, -2442, -2383, -4145, -7408, -5085, -3147, -1805, -2809, -5073, -3957, -7445, -888, -1777, -2801, -3827, -7464, -804, -1374, -1879, -5933, -4738, -1888, -1745, -1844, -9380, -4774, -4853, -2701, -2369, -5103, -5678, -11004, -3465, -3476, -4234, -6640, -4946, -3512, -5862, -4620, -10362, -3062, -3476, -9284, -4997, -8615, -2197, -3540, -4416, -4573, -4963, -2325, -3686, -1999, -3474, -4518, -3896, -4149, -665, -2825, -6343, -6732, -5266, -92, -3147, -14195, -4831, -7774, -307, -4532, -8942, -3543, -11781, -1481, -6528, -6064, -3741, -8304, -4311, -8086, -4295, -5026, -4968, -8363, -10442, -3383, -6988, -3089, -4153, -10899, -3507, -9531, -2644, -2912, -8942, -5020, -9149, -3689, -2510, -9331, -9193, -5735, -6528, -1839, -10526, -6332, -4918, -6958, -1345, -7004, -4282, -6083, -5097, -1682, -4918, -4425, -8582, -4408, -3094, -4010, -6800, -7912, -3433, -5915, -3615, -28777, -8247, -2378, -10526, -3163, -6988, -13738, -2036, -7912, -2605, -5458, -5776, -2507, -5227, -2369, -5374, -3249, -3433, -3388, -2819, -6267, -2448, -4067, -2142, -4127, -8754, -2724, -4180, -1590, -5266, -13049, -3937, -4017, -1875, -5339, -6928, -6516, -3723, -3239, -6745, -4874, -13049, -3487, -6553, -13738, -4149, -10613, -3824, -12534, -7066, -4180, -8790, -5408, -5718, -5853, -4532, -8165, -9873, -3612, -7819, -4940, -8086, -9753, -2531, -14195, -5353, -9479, -8827, -2228, -6288, -5915, -13738, -13738, -2887, -4669, -6856, -11629, -9193, -4659, -4569, -8683, -9812, -7445, -2651, -2851, -5401, -4168, -3496, -2574, -6246, -5429, -1510, -4963, -2764, -11781, -5710, -402, -8165, -3218, -5827, -5292, -525, -4708, -2366, -3776, -3498, -1852, -3714, -1358, -2694, -2216, -4578, -5067, -1531, -2730, -1665, -4728, -12123, -3014, -4082, -1831, -3025, -6310, -5827, -5494, -2228, -2522, -4555, -9193, -4997, -1787, -2619, -5422, -7644, -5333, -1144, -2908, -7730, -5662, -6565, -1139, -3618, -6026, -3940, -6365, -1816, -6480, -4532, -2347, -5768, -3299, -7299, -3493, -1326, -5480, -5951, -2170, -2601, -1012, -5208, -5924, -677, -2071, -1429, -5726, -4545, -934, -1721, -2573, -9022, -4669, -3047, -1401, -4395, -10284, -4331, -9284, -1276, -5818, -6321, -3365, -5170, -1650, -5208, -6842, -3549, -3194, -2776, -4352, -14784, -4078, -2419, -3840, -4527, -7708, -2091, -1914, -2960, -6870, -6800, -401, -1620, -1995, -11781, -9639, 142, -1557, -1474, -4527, -5827, -284, -1511, -1121, -2282, -3726, -1313, -1456, -1343, -1242, -3735, -1643, -1672, -2497, -1083, -5031, -950, -2163, -2130, -2026, -4703, -581, -2521, -537, -4713, -3244, -871, -2573, -167, -8683, -2751, -2004, -2424, -558, -6016, -3027, -4654, -2225, -245, -6256, -3261, -7665, -2297, 176, -9284, -3184, -4161, -2778, -287, -5437, -3723, -2962, -3656, -1282, -2713, -6123, -3054, -5312, -1651, -1511, -8304, -4172, -8165, -1834, -1285, -3677, -7752, -8827, -2931, -1833, -1797, -8423, -7484, -4748, -3051, -1197, -3785, -6759, -3360, -4408, -1485, -2270, -6422, -1912, -4509, -1774, -1575, -6173, -2083, -4344, -549, -1022, -4180, -3971, -5091, 589, -576, -2121, -7408, -6074, 661, -530, -1054, -7562, -5576, -424, -1143, -1001, -9479, -5584, -2398, -2606, -1882, -11488, -8086, -3455, -4951, -3135, -6666, -12776, -2883, -6133, -3863, -5638, -8304, -1753, -4455, -4518, -5091, -11004, -903, -3900, -4219, -4625, -10069, -860, -5494, -2472, -4669, -7562, -1756, -12534, -1041, -4145, -11945, -3763, -4541, -302, -3560, -6692, -6773, -2211, -329, -4583, -3577, -8517, -1398, -1249, -8549, -2731, -10362, -1701, -3254, -4674, -2941, -9753, -3074, -5494, -2747, -3436, -8138, -4679, -4365, -2937, -3526, -7281, -5862, -3992, -5247, -3201, -3893, -6653, -6183, -8517, -2817, -2072, -4215, -11781, -4683, -2528, -1878, -2902, -4311, -3447, -2253, -2690, -2971, -2300, -3665, -2051, -2855, -4021, -1583, -5026, -2118, -2545, -5576, -1572, -7371, -2589, -2406, -6278, -1963, -8363, -3465, -2069, -6246, -2642, -5374, -4226, -2273, -7542, -3876, -2853, -4842, -3306, -13365, -6153, -1499, -6973, -3985, -7523, -10613, -1173, -14195, -4698, -5879, -9531, -1611, -6103, -8485, -6577, -6113, -2189, -4611, -7097, -9193, -4601, -2317, -4821, -3999, -8034, -4429, -2361, -6256, -3476, -5970, -5387, -2823, -9585, -4460, -5793, -7196, -4157, -10362, -6800, -7353, -8615, -7687, -5592, -8683, -11629, -7865, -7665, 11108, 15036, 9902, 5969, 8435, 10914, 14606, 9535, 5610, 7636, 10259, 13280, 8492, 4280, 4800, 9422, 10943, 6856, 1240, -2483, 9204, 7308, 4388, -3235, 1828, 8919, 3366, 1632, -1922, 1982, 7442, 5799, 2713, -651, 980, 5082, 7154, 2829, 935, 942, 6232, 7188, 1098, 1365, 1948, 7247, 6255, 1483, 1173, 2999, 6938, 5352, 3522, 1440, 3995, 5610, 5482, 4188, 2033, 4887, 3614, 5927, 3668, 2194, 5521, 584, 6675, 1852, 1440, 5831, -8423, 7046, -2606, -424, 5716, -1380, 6420, -4464, -2599, 5131, -1733, 4583, -901, -2407, 4112, -1003, 1460, -264, -729, 2474, 691, 817, -635, -73, -609, 1211, 2572, -1883, -1241, -9936, 1423, 3290, -1665, -5759, -5026, 1054, 3031, 860, -7389, -6113, -782, 1510, 2398, -6299, -6828, -5353, -1940, 2896, -10442, -4161, -1883, 801, 2600, -5380, -4071, -463, 3135, 1766, -4195, -6516, -1500, 3716, 680, -4149, -13365, -3989, 2859, -453, -3299, -7819, -3741, 332, -1673, -2477, -8034, -13365, -2952, -3846, -2815, -5897, -589, -1263, -8138, -5776, -3362, 2448, 594, -3504, -7146, -2363, 3450, 1412, -1259, -2282, -1884, 3247, 756, -2, -934, -848, 2118, -2114, 877, -981, -23, 214, -5988, 1408, -1870, -234, -2158, -1113, 1581, -3126, -1725, -4013, 441, 1466, -3629, -3014, -5208, 718, 1164, -2359, -1782, -7081, 44, 663, -1002, -1315, -7912, -1241, -240, -489, -2153, -4885, -2417, -1843, -955, -4250, -2749, -3383, -4390, -2438, -6653, -1816, -4049, -7523, -4831, -5678, -2068, -3551, -7162, -7335, -4180, -3393, -3331, -4664, -7842, -3417, -5472, -4042, -3049, -4907, -3252, -6143, -4980, -2152, -3254, -3449, -4104, -6354, -1642, -2969, -3523, -2670, -11115, -1391, -3680, -3133, -2073, -7888, -1386, -4935, -2653, -2008, -4331, -1605, -6411, -2569, -2317, -3225, -1934, -7371, -3098, -3040, -3999, -2350, -6194, -4112, -4215, -7708, -2956, -5176, -5279, -6310, -8754, -4093, -5253, -6928, -11629, -5646, -6246, -6388, -10284, -6321, -4890, -10526, -7464, -12776, -4703, -4616, -8942, -6973, -13365, -4784, -4601, -6123, -6666, -10799, -3365, -4901, -4890, -7066, -6842, -1870, -5615, -4578, -8304, -5694, -1904, -6399, -5227, -11356, -6035, -3769, -5997, -7281, -9936, -5654, -9639, -5299, -8942, -7281, -4278, -8454, -6133, -8165, -7371, -4130, -7665, -7912, -9479, -10069, -5844, -10210, -6399, -9479, -8790, -12123, -4429, -6204, -7445, -6732, -9639, -1990, -7603, -7146, -6469, -8517, -1330, -7665, -7936, -6719, -9936, -2139, -5367, -8903, -6615, -9479, -4683, -4164, -9753, -6602, -7888, -9284, -4195, -11781, -7542, -6365, -5915, -4532, -17034, -8517, -5170, -3999, -4331, -8517, -6434, -5091, -4108, -4184, -6299, -4573, -6422, -5623, -5260, -5662, -3557, -9284, -6278, -9873, -6064, -3254, -11945, -5979, -8982, -7146, -3795, -11356, 7346, 1030, 4464, -12776, 6407, 6665, -1088, 3741, 2106, 6164, 4364, 1993, 1345, 3857, 5496, 1284, 4528, -2681, 3721, 4783, 3733, 4839, -1622, 2856, 4553, 5041, 3469, -864, 2763, 4348, 5302, 546, -810, 3205, 3649, 5070, 1732, -354, 3293, 2757, 4538, 4194, 1158, 3094, 2563, 3228, 5489, 3174, 2986, 3516, 2562, 5913, 4779, 3166, 5004, 5725, 5512, 5750, 3532, 6105, 7544, 4199, 6060, 3726, 6505, 7944, 1810, 5627, 3153, 6212, 7105, -1287, 4297, 784, 5368, 4947, -2125, 1953, -4997, 4230, 1269, -2118, -881, 1771, 3053, -1202, -3259, -2867, 3564, 1792, -908, -2815, -4997, 3953, -231, -569, -514, -6973, 3645, -4728, 873, 382, -5429, 3074, -1582, 1973, 239, -1874, 2533, 100, 2028, 55, 79, 1891, -702, 1148, 898, 817, 513, -4230, -68, 2067, 650, -1868, -3409, -704, 2675, -138, -1249, -2279, -801, 2473, -1144, 212, -4278, -1384, 1477, -1967, 688, -8865, -3850, 209, -2587, 414, -5319, -3801, 34, -3170, -1018, -6814, -1080, 633, -3594, -5240, -5630, -1246, 1007, -3227, -2851, -2353, -5906, 1011, -1982, -62, -1427, -2010, 733, -754, 838, -1663, 798, 344, -266, 609, -2386, 1455, -24, -885, -784, -3168, 1090, -282, -3023, -3883, -3051, 228, -322, -7603, -4810, -2347, -897, -449, -15615, -2098, -2375, -2336, -1301, -8517, -621, -3301, -3659, -3203, -4997, 351, -3430, -3551, -4853, -3920, 980, -2036, -2698, -3232, -3870, 1142, -1050, -2136, -1216, -3168, 779, -988, -1918, -419, -2175, -38, -1907, -1711, -1141, -1970, -1097, -3574, -1369, -3999, -2659, -2160, -4311, -1197, -6958, -3920, -3331, -3744, -1381, -4703, -5145, -4968, -3717, -2034, -5662, -6299, -6054, -4774, -3597, -7281, -8192, -4500, -7066, -7445, -4901, -10526, -3324, -8683, -8009, -4601, -8165, -3189, -8086, -5319, -6035, -6899, -3515, -7665, -4816, -4587, -7730, -3314, -7708, -5299, -2776, -13738, -2440, -9284, -6653, -2396, -8363, -1484, -15615, -5862, -2859, -6214, -724, -6842, -3989, -3378, -6565, -286, -4912, -3808, -3923, -8942, -328, -5818, -6173, -5346, -9106, -998, -8865, -10001, -8304, -7665, -2295, -3635, -4659, -7687, -8138, -3501, -1721, -3485, -5367, -9149, -3900, -1484, -3373, -4790, -8582, -4625, -2366, -3062, -6235, -8485, -6800, -3748, -2465, -12776, -8247, -11232, -4545, -2345, -6225, -6332, -8718, -4713, -3249, -4412, -4555, -6679, -4495, -5776, -4616, -3683, -5319, -4307, -10704, -5979, -3554, -4184, -5031, -8393, -6103, -3951, -3490, -7865, -6786, -5408, -4625, -3551, -13738, -6083, -6354, -5266, -4486, -6958, -6267, -8582, -5988, -5531, -5387, -6973, -6016, -7523, -4616, -4713, -7066, -4940, -10069, -3532, -4578, -7097, -5784, -9380, -3301, -5662, -8138, -8363, -9479, -3933, -10704, -8754, -8790, -10526, -5279, -7960, 1875, 1724, 3700, 3654, 5666, -1330, 1474, 4377, 5065, 5505, 1877, 1044, 5653, 6627, 5593, 4579, 1016, 6246, 7116, 5737, 4478, 542, 5706, 6436, 4948, 2431, -1265, 3984, 4567, 2879, 1205, -512, 1353, 1792, 371, 2124, 888, -1480, -779, 830, 1858, 794, -2540, -2176, 3201, 2063, 23, 1239, -2311, 4719, 3801, -450, 3452, 1213, 5149, 5054, 1528, 4350, 3267, 5136, 5319, 3439, 3872, 3312, 5286, 4516, 3922, 1105, 1387, 5024, 2733, 2864, -738, -414, 3647, 1405, -5, 2700, 306, 816, 1501, -937, 3033, -975, -1782, 1262, 335, 1386, -4223, -699, 548, 18, -3023, -9284, -965, -222, -907, -6814, -1691, -4412, -163, -1271, -2443, 1211, -400, 546, -1384, -898, 2188, 1882, 979, -1953, 214, 2303, 2226, 905, -2548, 940, 2185, 1392, 268, -2336, 1093, 1793, 107, -954, -2075, 442, 810, -690, -2947, -2019, -1257, -802, -1338, -6016, -2049, -2764, -2194, -1307, -5654, -2447, -1529, -1536, -550, -3827, -3535, -967, -178, -353, -2626, -5133, -1504, 415, -710, -1543, -8333, -2259, 45, -1111, -1052, -5879, -1926, -1219, -310, -1749, -1318, -795, -3119, 721, -4184, 411, -32, -2720, 632, -3054, 525, -70, -1071, -512, -956, -748, -454, -1151, -1681, -1015, -3396, 0, -3930, -3299, -3788, -9284, 946, -4469, -9479, -4907, -6045, 1387, -1624, -5164, -1598, -2766, 1209, -843, -3723, -1680, -2244, 870, -495, -4282, -5103, -2902, 655, -458, -6103, -5346, -2322, 90, -1083, -12319, -2809, -1287, -1212, -1908, -7484, -3692, -1202, -2933, -2319, -4723, -9193, -2071, -3811, -3428, -4060, -7196, -3748, -3509, -7299, -5451, -4912, -5970, -3119, -7247, -9873, -5299, -7623, -3393, -4425, -5702, -7774, -7371, -4748, -4674, -4365, -17034, -6343, -7708, -7130, -4853, -11356, -6457, -9479, -7730, -4616, -10613, -8615, -6411, -4104, -3067, -9380, -7752, -4373, -1994, -2516, -9193, -4946, -2906, -1286, -3194, -12319, -4086, -2028, -1984, -4821, -12534, -4703, -2011, -4119, -6943, -9695, -6800, -3098, -5286, -8649, -9479, -8276, -4946, -4230, -7353, -13365, -5286, -5139, -3944, -6732, -9106, -2881, -4842, -4187, -7888, -4532, -1735, -4957, -4842, -7542, -2574, -1898, -4659, -5988, -6225, -1827, -3471, -4764, -6928, -7281, -1880, -5942, -5524, -6565, -28777, -2460, -6163, -5924, -5879, -6133, -3537, -5942, -5103, -5509, -4097, -5531, -6411, -4536, -5097, -4119, -9531, -7113, -5286, -4810, -5686, -7603, -7984, -8220, -5170, -8615, -5607, -9812, -9812, -6411, -10001, -5487, -12776, -8615, -7936, -9064, -6653, -11781, -10799, -8060, -10704, -7623, -11356, -9238, -6814, -15615, -6035, -8615, -6411, -5694, -10001, -4935, -6528, -5516, -4946, -9022, -5103, -5735, -6045, -4242, -8393, -6504, -5546, -9106, -3569, -8247, -9064, -5164, -10899, -3299, -9936, -5979, -5292, -8582, -5480, -9429, -7230, -3843, -10442, -8454, -8247, -9429, -3194, -15615, -9193, -8060, -5979, -3540, -13049, -9022, -8192, -4357, -5139, -9064, -8009, -7665, -4669, -5793, -8165, -6332, -6732, -7523, -4940, -8165, -6016, -6278, -12319, -4038, -7179, -6943, -7281, -8333, -3130, -6899, -8393, -10442, -7984, -2920, -9064, -10138, -7299, -9106, -3218, -9149, -15615, -5247, -8827, -3846, -5702, -13049, -4901, -5670, -4659, -4578, -11488, -5227, -4344, -5152, -4774, -12319, -5145, -4340, -5260, -5630, -8192, -4630, -4649, -5871, -5451, -6035, -4764, -4587, -6842, -4853, -5429, -6914, -5079, -5702, -5152, -6026, -11781, -6299, -3438, -5247, -7484, -4616, -6679, -1875, -4369, -8112, -2758, -5273, -1447, -3689, -6914, -2505, -3916, -1950, -3512, -5979, -3441, -3319, -2772, -3989, -6163, -5554, -3444, -3130, -5380, -7353, -8363, -4060, -3020, -6577, -7389, -7842, -4826, -2945, -5951, -6246, -7034, -6332, -3023, -6422, -5871, -6870, -9479, -3271, -10362, -6553, -6492, -7774, -3717, -7066, -8517, -5933, -6143, -4112, -4654, -11781, -5662, -5924, -4469, -4541, -9936, -5710, -6705, -5451, -6113, -7603, -5915, -8220, -7774, -9873, -5951, -5827, -7819, -11232, -28777, -4606, -5576, -6204, -13365, -13738, -3760, -5401, -5465, -9380, -12534, -3512, -5333, -6007, -7408, -13365, -3900, -5516, -8034, -7264, -28777, -4863, -6123, -8165, -7503, -28777, -6434, -6759, -5924, -7247, -11945, -8549, -6666, -4985, -7247, -8582, -10526, -6007, -5103, -7623, -6640, -10899, -5240, -5960, -7936, -5662, -11004, -4447, -7464, -7583, -5367, -13049, -3903, -10526, -6928, -5623, -13049, -3923, -11232, -6565, -6480, -7865, -4592, -6267, -6914, -8138, -5710, -5615, -4295, -7865, -11356, -5085, -6540, -3732, -8754, -17034, -5844, -7623, -4207, -10442, -9479, -8517, -8982, -5546, -28777, -6988, -13365, -9064, -7687, -8790, -6163, -9064, -7464, -10442, -6786, -6602, -8165, -6083, -13738, -7230, -8304, -9331, -5670, -28777, -10362, -10210, -13738, -6214, -14784, -15615, -9064, -12534, -7213, -10069, -28777, -8754, -8276, -7888, -7247, -14195, -10362, -6590, -8718, -5836, -13738, -11004, -5960, -10442, -5444, -12319, -9331, -5759, -13738, -5710, -8086, -8363, -5380, -15615, -6278, -6653, -7644, -5020, -10442, -6870, -6321, -7247, -5176, -9064, -7050, -6800, -7623, -5979, -9585, -6973, -8112, -8790, -7426, -12776, -6759, -9695, -8903, -9429, -14195, -6732, -10613, -7542, -10799, -9193, -7426, -10899, -7335, -10069, -7299, -9936, -11115, -9064, -9812, -6399, -28777, -12776, -13365, -10799, -6365, -11945, -28777, -11232, -12776, -6988, -14784, -11232, -13049, -9753, -7644, -11781, -9873, -11115, -7523, -7562, -8865, -12319, -8615, -6590, -7004, -9193, -15615, -9936, -6615, -6814, -10362, -10362, -10210, -7665, -7562, -8718, -8903, -6516, -10001, -8865, -7752, -7865, -5387, -13365, -8454, -8393, -6653, -5599, -11629, -7842, -10526, -5970, -6666, -8827, -8138, -7317, -7179, -9936, -6870, -4800, -6388, -6828, -8982, -7708, -4207, -6153, -7912, -6988, -7644, -5176, -5810, -8683, -5718, -7842, -7623, -5208, -6083, -5793, -9429, -7819, -4896, -4550, -7603, -14784, -7019, -5008, -4361, -10001, -14195, -8454, -5451, -5158, -7623, -11004, -7281, -5979, -5458, -6899, -7196, -4935, -6365, -4592, -7730, -4784, -4532, -6973, -4319, -8423, -3801, -6007, -8423, -4951, -7888, -3886, -9639, -9064, -6299, -8304, -4896, -8485, -7960, -8192, -10704, -6719, -8086, -8754, -11115, -10069, -8582, -11629, -8790, -28777, -7819, -9064, -7097, -5759, -10362, -7644, -7936, -4112, -4442, -6445, -7389, -5576, -2668, -4266, -4100, -4495, -4042, -1848, -4698, -2920, -2499, -3773, -1382, -5415, -2851, -1803, -4907, -1347, -6388, -4035, -2419, -8220, -2045, -7912, -6310, -4555, -12776, -4142, -9639, -5906, -6399, -8718, -10704, -7984, -4654, -4606, -8192, -7179, -5933, -4500, -3978, -8754, -5279, -4980, -4748, -4365, -9479, -5554, -5115, -4386, -5145, -10442, -6759, -6504, -3920, -5546, -13365, -8363, -9429, -4438, -5247, -12319, -11004, -13738, -6870, -4733, -7687, -10899, -14784, -12123, -4569, -5844, -7542, -11004, -5638, -5055, -5472, -6814, -7464, -3583, -6045, -6376, -8649, -5531, -2871, -6745, -8754, -28777, -4790, -3025, -6376, -14195, -7774, -5189, -3840, -5494, -28777, -5726, -6565, -5152, -5139, -28777, -5286, -8454, -7034, -5743, -14195, -6123, -10001, -7603, -6988, -11781, -9106, -9695, -6016, -6492, -17034, -10362, -8615, -5367, -5319, -9380, -5942, -8276, -5924, -5247, -6045, -4097, -8615, -7665, -6299, -5240, -3417, -9479, -10799, -7842, -6299, -3493, -11781, -13738, -8423, -9753, -4028, -28777, -11488, -8903, -13738, -4912, -13365, -10704, -9812, -8942, -5988, -10069, -11629, -10284, -7623, -6288, -8112, -15615, -9380, -7730, -6256, -7281, -10704, -8112, -8485, -7389, -7523, -9429, -7912, -7464, -8982, -8683, -11115, -8754, -5768, -8138, -8982, -28777, -10069, -4951, -7445, -8549, -13049, -12319, -5494, -7335, -9331, -9429, -13049, -8333, -6628, -12319, -7299, -8138, -14784, -5862, -17034, -6365, -5862, -8982, -5561, -9639, -7097, -5085, -9936, -5360, -7984, -11004, -5319, -9284, -5286, -8220, -10001, -6113, -7050, -5784, -10284, -6885, -7687, -7335, -6692, -15615, -6943, -13049, -8304, -7113, -12319, -10138, -7752, -7162, -6973, -11629, -13738, -5539, -7484, -6885, -12534, -9106, -5374, -10899, -6602, -10799, -8582, -6399, -9479, -5743, -10442, -9639, -8276, -7247, -5247, -11115, -14784, -9238, -7389, -5759, -10210, -11781, -7842, -9106, -7665, -9429, -9936, -6842, -10526, -10799, -9639, -11115, -6773, -10069, -9812, -9812, -9585, -7317, -10613, -8827, -9064, -8393, -7774, -13738, -9193, -7842, -9812, -7335, -28777, -10210, -7113, -17034, -6759, -12776, -10799, -7503, -11232, -6540, -9873, -10284, -9149, -9149, -6800, -8454, -9585, -13365, -8827, -7542, -8192, -9585, -28777, -9585, -8982, -9238, -10442, -10799, -4473, -6516, -3817, -7464, -9936, -4089, -5979, -5458, -4907, -9429, -4357, -7484, -8034, -4344, -10138, -5299, -8942, -7665, -5615, -13049, -6457, -8517, -7842, -10362, -12123, -7146, -10362, -11356, -10362, -10526, -8060, -13738, -7888, -7130, -9479, -10001, -9238, -5061, -6469, -7034, -11629, -7708, -3873, -6007, -6026, -10799, -7196, -3656, -5422, -7213, -10001, -7130, -4369, -5360, -9429, -8754, -7888, -5260, -5997, -6235, -7317, -10704, -4896, -7113, -5133, -6225, -11629, -4219, -8363, -5871, -5401, -9753, -3230, -9284, -7162, -4733, -6256, -2040, -8517, -6457, -4640, -4082, -1359, -6376, -5247, -5776, -3707, -1356, -4592, -3710, -6332, -4532, -1954, -3589, -2300, -4215, -5002, -3110, -2768, -1620, -3354, -4545, -4805, -1815, -1807, -3992, -4447, -6434, -1261, -2851, -6163, -4683, -5871, -1434, -4688, -9106, -4659, -4980, -2270, -6943, -8754, -4172, -4918, -3600, -8582, -8304, -3560, -5465, -4826, -8423, -7819, -3108, -6988, -5139, -8086, -6553, -3085, -11356, -6074, -9193, -5266, -3808, -6093, -7644, -11781, -4597, -5487, -3798, -5924, -9479, -4918, -6943, -3306, -5202, -8649, -6045, -6411, -3751, -6516, -8790, -6354, -6492, -4161, -8034, -8683, -5951, -7389, -4215, -5465, -8333, -6343, -7708, -4968, -3900, -6480, -6705, -7146, -8247, -3393, -4532, -6411, -6343, -10704, -3444, -3507, -6666, -5253, -6083, -3624, -3407, -7562, -4112, -5170, -3801, -4299, -8138, -3415, -5401, -4250, -6332, -8942, -3370, -6256, -5214, -8942, -11488, -3876, -7960, -6943, -9149, -9639, -4713, -10613, -11004, -9479, -7503, -5924, -13365, -11781, -11115, -7464, -7796, -10704, -7960, -11629, -9753, -10210, -7644, -7960, -10899, -13365, -17034, -6457, -11488, -10284, -9238, -10362, -7644, -12534, -8982, -7687, -6565, -8903, -11781, -8034, -7623, -5422, -5014, -15615, -7912, -8517, -5879, -3535, -7936, -8333, -9331, -7774, -3357, -6434, -9022, -10069, -9639, -3594, -6828, -9812, -10799, -10442, -3910, -8485, -11115, -10001, -10899, -4708, -8304, -13738, -8549, -8454, -5751, -6457, -12123, -6565, -7503, -5202, -5942, -8754, -5097, -8549, -4583, -6163, -7066, -4564, -9022, -5214, -6163, -6074, -4912, -7213, -6480, -6943, -5584, -5862, -7317, -6388, -9639, -5630, -6153, -10069, -6445, -7484, -6246, -5472, -17034, -7097, -5319, -6773, -5049, -11488, -6469, -4826, -6602, -5253, -12123, -5871, -5569, -6615, -6183, -13365, -6422, -7842, -6653, -7865, -13049, -8304, -9695, -6074, -9022, -12776, -13049, -6705, -5970, -8220, -10069, -13365, -5049, -7146, -8034, -8454, -10138, -4303, -9695, -9585, -7484, -9812, -4399, -10799, -13738, -6026, -13738, -5759, -9639, -10001, -4640, -9812, -10138, -8034, -8582, -4149, -5646, -7752, -7034, -9284, -4559, -4112, -4837, -7264, -10899, -5718, -3856, -3817, -8423, -9531, -7426, -4569, -3720, -9639, -7004, -9753, -6045, -4238, -9380, -5531, -13365, -7984, -5189, -8423, -4826, -17034, -8827, -6204, 10085, 11221, 8963, 11018, 8334, 9316, 10859, 8285, 10493, 7927, 7109, 9776, 6180, 8944, 6627, 6461, 8059, 4071, 6596, 4456, 7327, 6182, 4924, 4416, 3687, 6875, 5014, 5059, 3515, 4214, 4988, 4298, 3876, 2967, 3293, 2754, 3230, 899, 2199, 122, 5608, 1801, -3779, 2184, -2036, 6931, 770, 1667, 1695, 1483, 6717, 487, 2971, -1433, 3730, 6108, 9, 2941, -490, 5580, 5814, 1001, 3414, 3220, 6865, 4438, 3648, 4125, 4494, 7290, -670, 4812, 3796, 4447, 6636, 531, 4412, 2070, 3617, 4561, 2454, 2450, -1029, 2858, -167, 1760, -304, -2020, 2464, -1854, 314, -278, -1401, 1950, -249, 50, -185, -1652, 1419, -1168, 992, -816, -1865, 1288, -1944, 1695, -1462, -1035, 1282, -1156, 1557, -1074, -138, 745, -301, 145, 338, -193, -773, -409, -1961, 1326, -1428, -4545, -1606, 840, 1391, -2253, -3656, -2188, 2628, 590, -206, 146, -1766, 3111, -645, 1245, 1269, -2146, 2745, -1472, 1586, 646, -1205, 1636, -1472, 912, -2046, 621, 718, -1254, -677, -3996, 1552, 1851, -1340, -2597, -2210, 1793, 2748, -1003, -2853, -3837, 1757, 2764, -220, -1321, -6528, 1499, 2660, -245, 117, -692, 697, 2803, -2121, 1046, 881, -893, 2547, -5599, 1485, 710, -3420, 1743, -892, 1465, -765, -9695, 847, 294, 1035, -1621, -3744, 60, -765, 367, -1573, -816, -704, -3252, -262, -4336, 410, -996, -1746, -635, -2386, 1060, -803, -526, -674, 787, 1419, -916, -433, -969, 1473, 1277, -2055, -1387, -2391, 458, 445, -5031, -3714, -5827, -2699, -1258, -8454, -4991, -10704, -5516, -4816, -5630, -3177, -5002, -2000, -8192, -5487, -1236, -1732, -415, -3034, -7583, -54, -280, 585, -1935, -10442, -31, -159, 1112, -2766, -5970, -1386, -1286, 969, -5561, -3653, -5061, -4115, 9, -4890, -2635, -8060, -6540, -2042, -2758, -2328, -5176, -4573, -6194, -1894, -2409, -4779, -4754, -6365, -1980, -2873, -3457, -6321, -3600, -3294, -4258, -2686, -6870, -2791, -7708, -6653, -3498, -5292, -2637, -7213, -2648, -4774, -2666, -2345, -4728, -148, -3404, -991, -1798, -5942, 881, -2534, -497, -1494, -7984, 964, -3080, -1008, -1873, -5480, 294, -4723, -1962, -3080, -6035, -1210, -4311, -2273, -3951, -7644, -4149, -3563, -1740, -3286, -4184, -6870, -4278, -1111, -2703, -2793, -3827, -6267, -1123, -2571, -2918, -2766, -9149, -1928, -2541, -4127, -2485, -8034, -2679, -2534, -5784, -2323, -6399, -2679, -3054, -6553, -2873, -7162, -2289, -4451, -6899, -3729, -13365, -1483, -5951, -7665, -1936, -8304, -1236, -5451, -6163, -606, -8138, -2143, -4649, -3626, -686, -8718, -4191, -4890, -2596, -2069, -3843, -4946, -6577, -3386, -4408, -2314, -3720, -8333, -7353, -5554, -2406, -2975, -6214, -9585, -4800, -3147, -2778, -3468, -7464, 5303, 7699, 9187, 7182, 4567, 4998, 6945, 8808, 6800, 6044, 4016, 4641, 7734, 5870, 7372, 2124, 2279, 6223, 5179, 7694, -1627, 1455, 4947, 4994, 7330, -6590, -3557, 4399, 4182, 6588, -993, -433, 3796, 1087, 5559, 501, 2203, 3461, -3198, 4384, 1062, 2649, 4003, 1569, 4012, 14, 2320, 3825, 506, 4519, -168, 2061, 2599, 225, 5207, 4308, 2727, 2718, 4269, 5699, 6329, 3881, 3698, 5604, 5512, 6863, 4638, 3582, 5193, 4359, 6259, 4768, 2425, 2746, 2310, 4553, 4327, 1066, -8363, 817, 1687, 3442, 421, 985, 1515, 656, 2389, -848, 2451, 2318, 1567, 1285, -1548, 2667, 2153, 802, -781, 1189, 2677, 623, -3449, -1863, 2437, 2450, -3399, -2374, 653, 2143, 1299, -4115, 1206, 1239, 557, -672, -877, 2275, 137, -340, 442, -147, 2466, -2253, 976, 1057, -322, 2106, -3583, 1713, -346, -583, 853, -3846, 1280, -1516, -992, -2467, -5002, -1289, -382, -1966, -6786, -5561, -2173, -867, -2024, -953, -3735, 1651, -3235, -468, 821, -1702, 2434, -3665, -100, 1454, -754, 1052, -2165, -2054, 1425, -1578, -2705, -1941, -10442, 1399, -6332, -615, -2427, -1236, 1845, -3179, 545, -2807, 660, 2260, -1174, 79, -3618, 1333, 2397, -1057, -1225, -4486, 1769, 2385, -526, -2787, -3879, 2168, 2090, 369, -2082, -2198, 2192, 1022, 839, -326, 302, 1657, -1595, 736, 328, 1621, 759, -3808, -205, -284, 1520, -113, -2126, -1482, -2129, 10, -749, -3329, -886, -5020, -2924, -1653, -9936, -6, -9695, -5793, -4149, -4564, 217, -10210, -6113, -14195, -3114, 243, -5539, -5020, -4754, -1482, 361, -3546, -3906, -3354, -311, 278, -2435, -2505, -3291, -413, -266, -1920, -1134, -3698, -1820, -953, -1626, -478, -4573, -4831, -901, -1300, -715, -5726, -14195, -316, -1038, -1913, -6457, -7523, 226, -1105, -4336, -7888, -4733, 698, -1600, -5654, -28777, -3191, 860, -2720, -3798, -7730, -2130, 313, -5408, -3354, -5306, -1169, -1352, -7665, -4157, -4842, -298, -4491, -4093, -4869, -5202, 100, -4500, -3846, -4270, -5339, -226, -2999, -6299, -3101, -4847, -1356, -2743, -8333, -2342, -4601, -3360, -3094, -10613, -2462, -6026, -6163, -3680, -5906, -3580, -10001, -7503, -4270, -1680, -6143, -6310, -5615, -3910, -100, -7371, -4303, -4086, -2900, 241, -4226, -2191, -3665, -2779, -208, -2799, -864, -4564, -3529, -1405, -2465, -897, -6828, -3137, -3961, -3156, -2231, -8865, -2653, -28777, -5221, -3689, -6885, -3580, -5014, -4885, -3007, -4433, -5638, -3444, -3326, -2057, -3362, -6235, -4703, -3735, -1624, -3071, -4195, -9812, -6679, -1640, -2300, -3220, -2326, -17034, -1880, -1144, -4837, -67, -7146, -2072, -453, -7299, 484, -3294, -2210, -548, -1998, -191, -911, -2596, -1527, -374, -1921, 206, -2990, 9559, 7043, -6183, 6970, 8473, 9287, 7540, 4242, 7206, 8535, 8438, 8037, 6533, 7465, 8612, 6931, 7830, 7230, 7288, 8385, 5091, 6974, 6978, 6565, 7458, 4710, 5715, 6004, 5247, 5457, 4882, 4077, 4551, 3744, 2095, 3670, 937, 3061, 3880, -710, -698, -4254, 1885, 4317, 484, 1705, 1691, -752, 3453, 1833, 4786, 2420, -2163, 2260, 608, 6022, 3268, 3204, 3217, -7179, 6134, 4795, 4331, 3255, 1001, 4940, 4841, 2835, 2286, 1770, 1232, 2483, -8247, 3633, 3913, -1412, -585, 2881, 4654, 6081, 1930, 2905, 4320, 4163, 6732, 1310, 3242, 3768, 2312, 6124, -2728, 1981, 2061, -740, 4500, -4089, 265, 512, -6411, 2225, -305, -331, 978, -3114, 1372, 487, 6, 2036, 32, 2416, -278, -552, 2470, 1348, 3030, -3526, -3490, 2160, 1784, 3221, -5638, -5702, 1329, 1637, 3304, -1798, -2912, 588, 965, 3035, -994, -4031, 389, -566, 1631, -1134, -8683, 247, -2347, -3194, -1934, -4176, -10, 254, -1407, -3054, -3482, 306, 2206, 1354, -2420, -2764, 1077, 2902, 1785, -1372, -919, 1499, 2692, 1317, -777, -231, 1376, 1797, 150, -448, -109, 870, 348, -3137, -437, 418, 109, -1810, -1811, -833, 539, -1189, -5662, 1290, -1392, -226, -2524, -10001, 1924, -1753, -1592, -15, -4869, 653, -828, -5380, 1940, -3172, -3674, 944, -4226, 2535, -2639, -3151, 1641, -765, 2104, -3507, -800, 766, -1104, 1027, -5654, -257, -2217, -4654, -283, -2302, -188, -4858, -967, -2071, -43, -587, -3860, 476, -4021, 818, -1277, -5592, -405, -3913, 852, -1505, -9695, -3526, -4207, 227, -1956, -12319, -7353, -6143, -1072, -3947, -7004, -9238, -9936, -2320, -10526, -4800, -4311, -10001, -1716, -6870, -4021, -2198, -8060, -1390, -4373, -3600, -2490, -7484, -2427, -2781, -3124, -5367, -7523, -4119, -1721, -3012, -6103, -8582, -4968, -1534, -3698, -3365, -13049, -6885, -2672, -5768, -2490, -8615, -7960, -7247, -11629, -2020, -6590, -5380, -5326, -5768, -1643, -8454, -3360, -1516, -3089, -1556, -9149, -1952, -158, -2075, -1707, -3692, -1761, 150, -2348, -1825, -1774, -3549, -32, -4053, -1852, -1175, -7113, -372, -7623, -2175, -1237, -2192, -1107, -13365, -3586, -1344, -520, -2596, -10799, -7542, -1507, -454, -3444, -6705, -4583, -2282, -1439, -2034, -5164, -2522, -3876, -3124, -815, -4303, -2545, -5319, -5718, -198, -3944, -3846, -5401, -6288, -160, -4307, -4230, -6183, -3179, -900, -4764, -2032, -9695, -2094, -2779, -4223, -257, -8454, -2651, -5561, -3108, 589, -5960, -5312, -5091, -2297, 614, -4266, -10210, -2999, -1944, 83, -2891, -4963, -1704, -1814, -748, -2793, -4361, -1597, -1838, -1921, -3738, -5487, -2557, -2182, -3551, -2916, -2722, -3717, -2988, -4344, -1685, -503, -3521, -4299, -3785, -1759, 237, -2698, -4161, -2540, -3201, -1264, -6492, -4254, -1427, -4442, -132, -3196, -3729, -1206, -5437, 23, -1994, -1991, -2014, -4348, -570, -2107, -1103, -3635, -4323, -1759, -2247, -1505, -5408, -6773, -3220, -1610, -2956, -6434, -6163, -3933, -984, -3367, -4425, -4307, -3515, -668, -2754, -2282, -6457, -2435, -517, -3058, -1276, -5170, -1661, -564, -3474, -1444, -986, -1564, -981, -2311, -2924, 375, -1932, -1674, -1232, -4369, 301, -2655, -1935, -1002, -2731, -760, -3930, -1590, -1680, -1602, -2168, -6256, -1473, -3795, -1616, -2827, -8192, -1865, -8683, -3029, -3194, -5776, -2040, -3016, -8138, -4764, -4541, -1183, -594, -4853, -2869, -4620, -291, 217, -2458, -436, -4997, -117, -229, -2540, 269, -4748, -985, -1822, -4420, -393, -5073, -3347, -2914, -7888, -2388, -5299, -7774, -2262, -8304, -5031, -3732, -6225, -2130, -5584, -5387, -2650, -5037, -2815, -4478, -6103, -2445, -4451, -4550, -5079, -8304, -2979, -3726, -8220, -5394, -7774, -4550, -2956, -6540, -3811, -5049, -6759, -2213, -4963, -3198, -3314, -5915, -1666, -5394, -3438, -2984, -4896, -1567, -7819, -3680, -4172, -4108, -2055, -8454, -3589, -6602, -3621, -3225, -6628, -4093, -6054, -4157, -5279, -7034, -6828, -4625, -6745, -8942, -8582, -7665, -4795, -15615, -4611, -8423, -3989, -7335, -6628, -1768, -7464, -3386, -7445, -5516, -681, -6988, -4912, -4382, -6246, -1021, -7819, -6943, -4176, -7842, -3005, -10526, -3833, -6666, -8754, -6422, -11629, -1928, -6628, -7162, -4545, -9873, -1080, -3096, -4880, -3121, -8165, -1126, -1561, -3080, -2785, -7004, -2165, -931, -1746, -3016, -6540, -4290, -949, -991, -3264, -6388, -7960, -1656, -944, -3360, -6516, -9238, -2843, -1525, -3526, -7299, -5607, -3049, -2195, -3978, -7162, -4315, -2562, -2458, -4545, -5678, -4573, -2952, -3154, -4242, -5061, -6183, -4826, -4923, -3569, -5103, -8220, -9106, -5524, -3074, -5079, -7299, -6842, -4340, -2672, -5061, -4442, -4816, -3811, -2339, -5584, -2774, -4064, -3820, -1939, -7623, -2497, -3650, -4219, -1680, -11232, -3415, -3498, -4837, -1778, -6800, -4929, -3801, -5079, -1995, -5623, -5702, -4545, -5214, -2173, -6422, -5266, -5049, -5793, -2785, -9022, -4597, -5286, -7196, -4532, -10138, -4315, -6376, -10442, -9284, -8790, -3748, -7936, -7819, -7865, -10069, -3175, -6653, -4640, -4974, -9193, -3615, -5960, -3126, -4223, -4923, -5879, -7213, -2540, -4399, -3331, -11232, -9149, -2585, -4779, -3438, -6528, -8060, -3121, -4935, -5387, -4708, -8454, -4180, -5260, -11781, -3971, -12319, -5638, -6445, -10001, -3674, -9429, -6113, -8683, -7317, -3704, -7281, -5234, -10001, -5979, -4142, -7196, -4929, -8304, -5638, -5240, -7842, -5599, -6332, -6800, -7247, -7371, -7264, -5014, -10362, -8982, -5942, -10210, -5002, -8865, -9022, -5055, -17034, -7335, -6434, -10442, -5422, -7752, -12123, -6035, -11004, -8060, -5516, -5793, -3130, -236, -4142, 321, -2964, -3846, -1086, -4779, -411, -3373, -2334, -2833, -4307, -1961, -5546, -639, -5569, -4578, -4559, -10704, 158, -5374, -4550, -9331, -3751, -90, -3321, -3213, -8086, -1527, -1549, -2776, -2756, -6732, -836, -4826, -3913, -3837, -7503, -1241, -6054, -8549, -5279, -6332, -2613, -3401, -7213, -4184, -4274, -4885, -2507, -4266, -3695, -3257, -7730, -2594, -3618, -4223, -3331, -10069, -3479, -3476, -5067, -4743, -8333, -4805, -3140, -6153, -8903, -5121, -5139, -2735, -7281, -10284, -2910, -4795, -2502, -7503, -5718, -1936, -4874, -2342, -6705, -3951, -2385, -5415, -1580, -5933, -4093, -4805, -4447, -434, -4369, -9380, -3058, -2414, 136, -2390, -3866, -399, -1215, -426, -1308, -730, 367, -624, -2422, -1214, 94, -143, -300, -3342, -1780, -573, -1341, -574, -2416, -2420, -2895, -2159, -2264, -3468, -2696, -6399, -2192, -7865, -3546, -2739, -5516, -1920, -3992, -1381, -3071, -6828, -1953, -1986, -627, -4438, -14195, -2675, -1817, -783, -6759, -5429, -4545, -2529, -1280, -4578, -3751, -9753, -3906, -1992, -3179, -4357, -7842, -6973, -2774, -3563, -9873, -5531, -9936, -3833, -6235, -5801, -5472, -3763, -6988, -9284, -3349, -5654, -1719, -6267, -4157, -3870, -4885, -1131, -3433, -2553, -7299, -3586, -1625, -3430, -1965, -5726, -2724, -2450, -4885, -1753, -3130, -2713, -1726, -3279, -2045, -2039, -3677, -778, -1615, -2952, -1468, -6133, -805, -1362, -4064, -1174, -7408, -1804, -2257, -4640, -1264, -3776, -3375, -4361, -4108, -1838, -1954, -4295, -8549, -3249, -2900, -1471, -3782, -10001, -2904, -4429, -2339, -2827, -6054, -3056, -6183, -5465, -2378, -4583, -3650, -6516, -13738, -2657, -4286, -4733, -5415, -7730, -3047, -5061, -5997, -4215, -7389, -2510, -6914, -6225, -3785, -3804, -1699, -6679, -6278, -4573, -2396, -1465, -4390, -7389, -6590, -2912, -2189, -3232, -9149, -6943, -5554, -4399, -2912, -7426, -3677, -10001, -6666, -3010, -4985, -1450, -8485, -4119, -3344, -3254, -568, -10284, -3244, -3529, -2336, -888, -17034, -3594, -2933, -2283, -2065, -9149, -4478, -2283, -2912, -2756, -7503, -5247, -2583, -3626, -2553, -6565, -5539, -4464, -3866, -2741, -5346, -5273, -6590, -4067, -3624, -4100, -4664, -4616, -4523, -4968, -3509, -3985, -4597, -5266, -6492, -3944, -3124, -5524, -6225, -7583, -5662, -2516, -3460, -7213, -7019, -7865, -2841, -2186, -7371, -6540, -7503, -4896, -2291, -6143, -6153, -7408, -9873, -3326, -5726, -6113, -8393, -5759, -4869, -7819, -7317, -10362, -4311, -6615, -11488, -8865, -8034, -4395, -8034, -6422, -7299, -4203, -4923, -8485, -5509, -5654, -2205, -4985, -8304, -5646, -4847, -1551, -5103, -9064, -5339, -4800, -2020, -6332, -13049, -4226, -5002, -3574, -8192, -12319, -3304, -4858, -6528, -6628, -9284, -3101, -4683, -9193, -6054, -8649, -3589, -4912, -6705, -7299, -9106, -4344, -5561, -6163, -5654, -3549, -3222, -81, -2244, -5694, -3554, -5638, -1350, -2713, -5339, -3027, -5408, -4119, -4455, -6194, -2274, -3850, -28777, -5121, -9812, -2179, -2739, -5367, -3698, -10613, -3042, -1953, -4399, -3656, -5152, -4536, -1574, -7644, -5623, -2448, -4790, -1786, -6492, -6653, -946, -3504, -2783, -2534, -2347, -607, -2427, -4805, -1712, -595, -1822, -1884, -8790, -2567, -433, -7146, -1591, -12776, -4104, -1813, -3913, -1258, -5810, -3748, -4625, -1117, -894, -2475, -3647, -3804, -437, -716, -436, -3507, -2452, -641, -852, 417, -1026, -2107, -1092, -1494, -59, 838, -1694, -742, -3096, -2222, 1690, -683, 137, -4674, -3689, 1758, 488, 596, -3029, -1825, 1156, 1340, 616, -2158, -1854, -73, 1654, 396, -2458, -4157, -2088, 1349, -157, -3281, -8333, -5662, 427, -1249, -3362, -5234, -17034, -968, -2817, -2841, -4482, -7066, -2256, -3999, -2679, -3804, -5247, -3457, -3509, -2519, -3239, -3860, -7097, -3284, -1890, -3830, -2747, -6553, -4869, -1263, -5646, -2155, -2383, -10799, -657, -7371, -1975, -1187, -5415, 69, -6565, -1622, -1250, -3103, 421, -4373, -1006, -1950, -2528, -141, -3349, -964, -2803, -3560, -2305, -3954, -2142, -3493, -7247, -11629, -6870, -4097, -3428, -5360, -3638, -15615, -3401, -2622, -3266, -1790, -7603, -2939, -2188, -3276, -1917, -6399, -4086, -2624, -4790, -3067, -6083, -5539, -4172, -9106, -3989, -6083, -3444, -5509, -8086, -4536, -6388, -1885, -3647, -4112, -6343, -4816, -1435, -2997, -2596, -10362, -2791, -1630, -4869, -2279, -7562, -2232, -2659, -10138, -2918, -6332, -3230, -6016, -2855, -4790, -6376, -3893, -3465, -755, -14195, -6516, -1941, -690, 113, -3804, -5465, -770, -83, 316, -1040, -3686, -543, -1045, -65, -259, -2401, -954, -3692, -983, -763, -2179, -1711, -8649, -1742, -1899, -3078, -1957, -14784, -1571, -2358, -4134, -1236, -6885, -1391, -2152, -3996, -703, -5333, -1912, -1945, -4191, -1024, -5933, -3208, -2184, -5319, -2294, -4601, -4723, -3624, -6310, -4336, -3391, -4115, -8485, -5871, -6093, -4826, -2345, -7796, -5759, -6214, -7623, -1213, -5061, -5292, -6516, -2841, -1245, -5183, -3723, -9812, -1501, -3203, -5979, -2939, -8112, -1826, -12534, -5710, -3144, -4319, -3117, -3329, -5422, -3677, -3105, -3913, -1615, -6083, -3788, -3393, -4130, -1546, -8718, -3612, -5306, -4901, -2473, -9585, -3274, -8683, -4951, -4365, -5599, -2956, -6399, -4184, -7503, -4478, -3347, -5444, -4365, -5662, -4837, -5279, -6123, -6133, -3142, -5743, -12776, -7196, -9753, -2478, -6183, -7299, -7146, -11356, -3168, -6773, -5260, -6267, -28777, -3349, -8276, -4929, -5339, -8192, -2032, -9936, -5599, -4896, -5546, -1317, -10210, -7281, -5260, -4764, -1018, -9531, -9812, -6183, -5221, -639, -8718, -11232, -6602, -6732, -524, -7213, -10138, -6504, -6719, -1026, -6480, -8517, -6856, -5158, -2107, 6798, 7074, 7441, 9543, 2855, 6478, 6828, 7179, 8840, 2171, 5702, 5860, 6589, 6326, 401, 4828, 4017, 6047, -2122, 1098, 3984, 3277, 5626, 3316, 2604, 3289, 3498, 5202, 3879, 2561, 1875, 2019, 4429, 2168, 451, -1842, -115, 2741, 2939, -1832, 3531, 2571, 365, 4447, 2033, 5403, 3833, -34, 4609, 3804, 5307, 4087, -1236, 3605, 4946, 3812, 4262, -3680, 1407, 5968, 1780, 4856, 708, -262, 6632, 1250, 5453, 2222, 1059, 6630, 1805, 5377, 1890, 1673, 5727, 1285, 4189, -82, 1402, 3735, -469, 1713, -524, 663, 1218, 1025, 533, 1409, -74, -756, 1815, 1403, 2102, -127, -2165, 789, 1467, 1872, 660, 1720, 1703, 1005, 1135, 1470, 3094, 4127, 567, 369, 1856, 2864, 5396, 582, 70, 1788, 1698, 5552, 653, 202, 1342, 115, 4523, 342, 326, 482, -8, 1890, -92, 520, -1235, 1628, -3653, 246, 1153, -4935, 2207, -3187, 1469, 1582, -6332, 1355, -3179, 2284, 1064, -6492, -1092, -2778, 2077, -247, -3641, -6045, -616, 583, -208, -1200, -7752, 1076, -2776, 116, -852, -2553, 2368, -5333, -1078, -1647, 123, 3239, -2182, -1962, -1747, 1543, 3547, -1483, -493, -948, 1965, 3185, -2791, -188, -767, 1346, 2088, -8220, -1372, -1261, -671, 383, -5933, -2661, -1453, -5472, -871, -3399, -1666, -1409, -6143, -949, -3535, -1652, -2146, -3889, -1023, -4890, -3830, -3594, -3247, -1568, -2897, -6225, -4365, -2619, -2571, -1023, -5451, -3766, -2181, -3563, -591, -9695, -3543, -2599, -4046, -1336, -6163, -5079, -4078, -3833, -2941, -3535, -13049, -5793, -3144, -4659, -2505, -5494, -7213, -2893, -4826, -1204, -3671, -9639, -3225, -3923, -315, -3814, -8333, -3468, -3264, -473, -3833, -7162, -2914, -2906, -1773, -2008, -5836, -2130, -2827, -3913, -676, -4223, -1717, -3281, -5387, -372, -3316, -1943, -4486, -6553, -1151, -3105, -3126, -7644, -6214, -3471, -3128, -5960, -9936, -3982, -10069, -2975, -4541, -4340, -3294, -6615, -2720, -1559, -2567, -4258, -5871, -2841, -264, -2189, -5743, -8138, -3833, -190, -2597, -4669, -9585, -6516, -1363, -3203, -4123, -8247, -8333, -4075, -3811, -5152, -7213, -4842, -6528, -4901, -7050, -5960, -3583, -5480, -7162, -5630, -4901, -3808, -5451, -10442, -3692, -3507, -5768, -6434, -7484, -2633, -2631, -10138, -7796, -5465, -2197, -2778, -5988, -7503, -4683, -2079, -4142, -4923, -7687, -4688, -1940, -7752, -6225, -8454, -5380, -1899, -10284, -9429, -6565, -7050, -2239, -5458, -7353, -5487, -9936, -2929, -4491, -6457, -5784, -8393, -3230, -4764, -7583, -7179, -6399, -2646, -5037, -9531, -9193, -5615, -2264, -5079, -10069, -9064, -5546, -2677, -5121, -7583, -7687, -5988, -3529, -5158, -5638, -7162, -6653, -3629, -5465, -5793, -6899, -7050, -3609, -6183, -9429, -6577, -6679, -4469, -6590, -6332, -2286, 7785, 7586, 8379, 8107, -3208, 7386, 7148, 7748, 7426, 846, 5927, 5541, 5936, 5140, 2902, 2135, 2276, 5262, -603, 3380, -1943, 3251, 6434, -509, 3575, 2411, 4432, 6523, 1883, 4396, 2794, 3957, 5366, 1586, 5210, 2766, 3328, 3344, -922, 5465, 2846, 3027, 1746, -3360, 4925, 2466, 976, 66, -3331, 3307, 1795, -4311, -3189, -1952, 2354, 1665, 2686, 980, 243, 4576, 2192, 4186, 2379, -316, 5805, 2692, 3983, 1994, -5592, 5902, 2750, 2765, 734, -3968, 5346, 2049, 1378, -448, -2512, 4722, 95, 611, -1438, -5472, 4100, -4644, -379, -2910, -7484, 2689, -3837, -1771, -695, -2590, -2022, -836, 109, 1915, -835, -314, 152, 1830, 2369, 168, 2944, 271, 2218, 117, 767, 3371, 119, 1649, -2699, 925, 2096, 265, 517, 1989, 268, -653, 674, -1380, 3055, -1068, -2062, 842, -8138, 3049, 722, -1236, 346, -2594, 3098, 2574, 36, -1193, -40, 3165, 2749, 1334, -2954, -41, 2734, 1090, 2301, 283, -2465, 1732, -3276, 2716, 2783, -7484, 565, -4816, 2094, 4090, -3689, -180, -5299, -632, 4546, -6093, -1008, -3526, -4985, 4304, -4500, -2683, -1453, 797, 3432, -379, -3060, -976, 2427, 2034, 624, -874, -1425, 2972, 531, 188, 855, -1370, 2824, -466, -794, 1954, -140, 1800, -1478, -1714, 2464, 280, -494, -4207, -3301, 2270, -372, -5026, -11232, -2791, 1055, -1574, -7503, -6492, -1003, -2345, -2666, -5592, -11356, -742, -5879, -2997, -3638, -2393, -1761, -1065, -2847, -2280, -33, -3264, -443, -3130, -2528, 336, -4491, -1681, -3474, -5037, -690, -4679, -4790, -4963, -8754, -2661, -2170, -9873, -7888, -5367, -3058, -441, -11488, -3018, -5710, -2650, 279, -6828, -1573, -7665, -3430, 375, -4831, -2123, -4258, -4373, 148, -4592, -4469, -2175, -3801, -292, -5014, -6973, -1410, -3373, -1063, -4536, -5942, -1623, -2213, -2129, -3554, -6083, -2990, -933, -2785, -2904, -7004, -6457, -852, -3110, -2779, -6615, -12319, -2250, -4031, -3187, -5158, -8138, -5067, -4145, -3971, -3900, -7984, -6973, -3554, -5037, -3232, -4826, -7464, -4164, -6480, -3165, -2950, -7097, -5524, -6666, -3626, -2472, -5531, -6007, -5043, -4654, -2933, -4429, -6899, -4460, -6856, -3754, -3954, -5312, -5145, -28777, -4215, -4082, -3367, -6469, -6299, -4469, -4779, -3087, -6516, -3883, -5607, -5067, -4134, -5158, -3329, -8615, -4611, -5208, -3937, -3893, -9331, -4718, -5465, -3686, -4997, -8192, -5743, -6870, -4527, -6083, -9753, -7196, -8615, -6640, -7542, -17034, -8393, -6692, -9812, -9585, -12123, -8276, -5401, -13365, -9064, -11629, -5951, -5026, -14195, -7842, -14195, -3837, -5951, -8138, -8034, -13049, -3003, -9753, -5970, -9022, -10526, -3754, -11232, -4831, -10442, -9695, -7389, -8649, -4067, -14784, -9639, -9429, -10704, -3600, -11356, 6658, 8051, 3191, 5852, 6426, 5577, 7421, 2768, 5544, 5464, 1428, 5620, 1553, 4373, 1558, 2037, 4506, 1016, 2219, -204, 4467, 5472, 3102, 2415, 3090, 5690, 5947, 4428, 3626, 3214, 6069, 5574, 4416, 4380, 2260, 4960, 4051, 3397, 5238, 1077, 1852, -454, 2164, 5482, 453, 2458, 649, 988, 4630, 834, 3979, 3454, -1805, 2821, 243, 3994, 4088, -2935, 907, -4373, 3141, 4061, 1336, -2793, -2906, 1326, 3585, 2243, -795, -1146, -2617, 2485, 467, 2605, -6007, -622, 865, -5768, 3440, 133, 1673, -1535, 1741, 2965, 3133, 1685, -3512, 3312, 1936, 4194, -718, -1045, 3316, 1025, 4256, -3311, 146, 2550, -603, 3830, 950, 521, 1779, -3362, 3464, 2255, 508, 1732, -360, 3331, 2248, 3, 2168, 1211, 3124, 1261, -1391, 2269, 1214, 2613, -934, -4644, 1496, 18, 1691, -5509, -8683, -625, -1999, 343, -3817, -4108, -6565, -1026, -1347, -2552, -908, -3659, 1291, -3007, -4100, 854, -258, 2611, -597, -2462, 1039, 870, 3040, 1617, -75, 242, 609, 2647, 2241, 480, 571, -1064, 1349, 1493, -95, 1096, -4991, -310, -230, -1198, 551, -7687, 247, -1626, -2499, -439, -1502, 1179, -3249, -4583, -1799, 1162, 1165, -2823, -4923, -4597, 2471, 329, -63, -3814, -2795, 2747, -1219, 1003, -2331, -2619, 2139, -3496, 996, 671, -10526, 918, -4728, 536, 1922, -1693, 58, -2460, 160, 1144, 243, 81, -548, 326, -2391, -519, -113, 261, 1099, -1476, -3321, -964, -23, 1681, -98, -1402, -1852, -1229, 1539, -1240, -712, -1507, -2756, 604, -4442, -2833, -1025, -4327, -877, -8363, -6653, -1325, -5988, -2664, -5451, -3615, -1683, -4017, -4266, -3482, -3792, -1126, -1661, -4743, -3717, -5531, -734, -39, -4153, -7371, -6214, -1065, 761, -3076, -4698, -5942, -1607, 739, -3020, -1880, -6343, -1837, -11, -3961, -1380, -7445, -2548, -1373, -4262, -2569, -4527, -4764, -3577, -3463, -6173, -2239, -8615, -6914, -2425, -11115, -1532, -8649, -5422, -2115, -7371, -2241, -11781, -3468, -3117, -7146, -4929, -10001, -2541, -5164, -6321, -12534, -6666, -2105, -5569, -5662, -6457, -6133, -1836, -5546, -6235, -5115, -7247, -1349, -6814, -7389, -4935, -10138, -908, -7603, -6504, -5615, -7865, -984, -6123, -5026, -7264, -5584, -1760, -4853, -4536, -6103, -5394, -3247, -4344, -5444, -4203, -6692, -4664, -4946, -8220, -4134, -8615, -4049, -6705, -8903, -6814, -8582, -3007, -8827, -7019, -10001, -6540, -2745, -9873, -6516, -4880, -5002, -3444, -9812, -6759, -4108, -4625, -5346, -7050, -8247, -5031, -5273, -5970, -4433, -13365, -6615, -6786, -3769, -2615, -6399, -7865, -9429, -2733, -1760, -4134, -7162, -11945, -2538, -1992, -3729, -4774, -9064, -2952, -3537, -4674, -3621, -7264, -4412, -6163, -6469, -4053, -6786, -8582, -5408, -6343, -5888, -4968, -5422, -3647, -6705, -5592, -4119, -4038, -3119, -7179, -5686, -4246, -3096, -3951, -5353, -4997, -6540, -2613, -5888, -3843, -4089, -10704, -2698, -6732, -3710, -4003, -5759, -3529, -5979, -4831, -4728, -4282, -4940, -6943, -6786, -5546, -3795, -5480, -11629, -7912, -5353, -3792, -4536, -9812, -7247, -4963, -4500, -3518, -7865, -6705, -5195, -6653, -2859, -7912, -6732, -5494, -14195, -2716, -8086, -6615, -5152, -10284, -3339, -7247, -6267, -4616, -8454, -5164, -5494, -7408, -4527, -6480, -8718, -3748, -13738, -5127, -4089, -6899, -2610, -13738, -7213, -2345, -6434, -2613, -7960, -7317, -853, -7353, -4597, -2216, -1503, 455, -2504, -2910, 184, 805, 1343, -59, 191, 874, 1438, 1525, 822, 1243, 203, 718, 790, 591, 720, -1761, -1390, -1001, -513, -1610, -4592, -4980, -3698, -2163, -8009, -6692, -7819, -5710, -3612, -6565, -8942, -6399, -6246, -3999, -6214, -12534, -4863, -7113, -3618, -6973, -13738, -4195, -8165, -3337, -4957, -11232, -4184, -8363, -3566, -3735, -7888, -4597, -10210, -4509, -3543, -5710, -5487, -10799, -6093, -3947, -5037, -6504, -8718, -6504, -4693, -6064, -7583, -8138, -5960, -5897, -10613, -9331, -6842, -6214, -7113, -8549, -9238, -6469, -6759, -7004, -5942, -9022, -9380, -6343, -7130, -5735, -8865, -9380, -5569, -7730, -7353, -7371, -5415, -5037, -7019, -14195, -7464, -4974, -4901, -6194, -6504, -10362, -6480, -5115, -6310, -3580, -11629, -8942, -5465, -6528, -2353, -7335, -8485, -5810, -5776, -2136, -5776, -5997, -5933, -5103, -2770, -5312, -4035, -5726, -5394, -4361, -5646, -3370, -5654, -6943, -7247, -7542, -4038, -6133, -10069, -13049, -10704, -6388, -7542, -8827, -12123, -6492, -9064, -11356, -7426, -10613, -5253, -6943, -10526, -7774, -10704, -5942, -6653, -7936, -8060, -10001, -8393, -8754, -7708, -6870, -9531, -9753, -28777, -8393, -6565, -10899, -7819, -11232, -8718, -7408, -10704, -6732, -9695, -9639, -8790, -7730, -6183, -9149, -14784, -9284, -6288, -6376, -8485, -10899, -9479, -5561, -7066, -7603, -7984, -10526, -5152, -7408, -6856, -7019, -11945, -5158, -8276, -6540, -6759, -11945, -5853, -11115, -6411, -6705, -10001, -7179, -13738, -6376, -6516, -8982, -6577, -9936, -6376, -6173, -9585, -5339, -7542, -6267, -5836, -9695, -5444, -6800, -6422, -5630, -7542, -7113, -7113, -7752, -5844, -5988, -9064, -6973, -11004, -6434, -5061, -7264, -6745, -10442, -7644, -4896, -6163, -7623, -11356, -9812, -5951, -6123, -9873, -13738, -11629, -9873, -6388, -13049, -8649, -11232, -10069, -6628, -13738, -7464, -13049, -6590, -7464, -10442, -7752, -28777, -6035, -9022, -8276, -9284, -9936, -6786, -9585, -7542, -13365, -7960, -8517, -9936, -8423, -13365, -7730, -11115, -12319, -10362, -9585, -9193, -13365, -17034, -8790, -9331, -13049, -12776, -14784, -7708, -11781, -13049, -10526, -13738, -8086, -13738, -12319, -8582, -11115, -8454, -8903, -13049, -7623, -9479, -6759, -15615, -3457, -6278, -8247, -10069, -10613, -3647, -4331, -6679, -8517, -10442, -4348, -4270, -5408, -5539, -14195, -6194, -6480, -4550, -5871, -11356, -11945, -17034, -3843, -8790, -7146, -7299, -8582, -3242, -8790, -5678, -4336, -9639, -3069, -6504, -5401, -2992, -11356, -3498, -5960, -5726, -2420, -6299, -4295, -6103, -6388, -2374, -4923, -5253, -5531, -7503, -2694, -4733, -5951, -4784, -9064, -3299, -4482, -5784, -5085, -9380, -4134, -3840, -6074, -6615, -7842, -4569, -3507, -7097, -9639, -6278, -4211, -3692, -8423, -9238, -5367, -3763, -4315, -11781, -9022, -4469, -3220, -4654, -5061, -9064, -2776, -2306, -3537, -1168, -2399, -686, -940, -1132, 793, 53, 718, 307, 677, 1358, 724, 1026, 774, 1301, 571, -17, 17, 304, 671, -1900, -2108, -2881, -880, -1281, -7888, -4451, -14784, -2030, -4541, -6928, -4010, -6183, -3018, -5776, -6278, -3170, -5360, -4940, -4123, -8009, -2947, -6299, -8393, -2945, -11945, -3225, -7484, -10526, -2359, -9936, -3551, -5844, -28777, -2485, -5862, -3710, -5043, -8718, -3671, -4238, -4295, -6204, -6679, -6773, -3923, -6540, -8754, -7019, -12123, -4357, -11004, -8060, -7912, -5988, -5067, -6246, -8333, -8276, -4469, -6143, -5055, -8754, -9531, -4688, -7562, -5152, -7097, -11629, -6528, -7912, -5844, -7004, -10210, -7752, -8220, -7247, -8304, -8220, -5576, -8942, -8865, -8865, -7247, -4513, -8754, -6354, -8718, -7281, -4191, -8423, -4295, -8138, -7752, -4258, -9193, -3512, -6007, -7523, -4733, -10899, -3726, -4923, -7389, -5793, -11356, -4831, -5115, -8304, -7936, -10526, -6958, -6093, -9695, -13365, -7888, -10704, -6553, -10284, -13049, -6035, -28777, -6123, -11356, -8942, -5615, -13738, -6035, -10899, -6445, -6628, -14195, -6928, -8034, -4980, -8683, -12534, -7888, -6732, -4592, -7842, -9149, -7247, -6103, -5189, -6885, -7034, -6943, -5686, -6640, -7281, -6163, -7503, -5726, -7796, -8903, -6064, -8112, -6745, -7426, -11629, -6083, -7842, -9238, -7583, -28777, -5942, -7353, -14195, -8582, -13738, -6093, -6540, -9380, -8615, -10362, -6988, -5109, -8138, -8942, -9380, -8485, -4378, -8827, -9936, -9695, -9812, -4985, -9873, -6773, -11115, -8683, -7081, -10899, -4759, -9585, -7317, -10362, -8112, -4270, -7146, -7247, -9022, -5353, -4963, -6113, -7819, -6973, -4578, -6719, -6332, -6388, -6083, -5810, -8220, -7708, -4991, -6288, -10613, -6899, -9873, -4640, -7050, -6958, -5888, -10284, -4974, -6692, -5020, -6007, -9873, -5638, -5694, -5221, -6225, -9639, -6800, -5319, -7281, -5422, -9380, -9479, -5694, -13738, -5115, -8982, -28777, -6759, -10799, -5933, -9873, -13738, -8086, -9753, -7179, -15615, -11945, -8865, -11629, -7247, -11629, -10442, -9639, -14195, -6814, -8393, -9238, -12776, -12534, -6705, -7281, -8060, -13738, -9812, -6928, -7213, -6628, -8220, -8485, -7299, -8220, -5670, -6773, -8865, -7912, -11629, -5387, -7464, -10899, -9193, -6246, -7523, -7113, -6602, -4049, -4616, -8363, -5576, -3701, -3626, -3933, -4703, -3866, -2564, -4127, -4416, -4805, -3449, -2429, -5871, -6299, -7299, -4238, -3412, -8754, -10442, -11629, -5915, -6332, -8827, -12123, -13049, -7583, -8485, -5933, -11781, -10613, -8276, -5008, -3714, -13738, -6666, -9149, -3840, -2499, -14784, -4826, -11945, -3580, -2023, -10210, -4223, -14784, -3549, -2270, -7583, -4837, -12534, -3468, -3227, -6602, -7247, -10138, -3319, -4790, -6943, -10899, -7603, -3321, -6445, -8903, -6914, -6016, -3415, -7066, -13738, -5465, -5451, -3112, -6745, -12534, -7819, -6422, -2366, -6602, -7445, -4985, -6759, -1265, -5844, -2259, -255, -2435, 46, -2403, 132, 1713, -43, 902, -53, 802, 2295, 890, 780, 936, -73, 1840, 631, -684, 803, -2672, 524, -828, -4532, -246, -5306, -1502, -3626, -7213, -1797, -5768, -3714, -7464, -3968, -3457, -8790, -4800, -8423, -3339, -5195, -7264, -5415, -8112, -3701, -6640, -6103, -6590, -8865, -4800, -11004, -7426, -7353, -10069, -6204, -7264, -12123, -8138, -10001, -6299, -3710, -13738, -9936, -9695, -4997, -2754, -10704, -11232, -9380, -4486, -3065, -9585, -7960, -8942, -5646, -3222, -9193, -5208, -9812, -9022, -2548, -9873, -3751, -11232, -8165, -2231, -13738, -3266, -7353, -7665, -2639, -11781, -3621, -5008, -8582, -3726, -7796, -4985, -3586, -6376, -5451, -6615, -8009, -2733, -4946, -7888, -6973, -28777, -2571, -4564, -10613, -9429, -11629, -3257, -4644, -6773, -14784, -10001, -4997, -4907, -5037, -7819, -8517, -7464, -5516, -5299, -6035, -7583, -7774, -7264, -8582, -5710, -7984, -7130, -11232, -10613, -6074, -9331, -7426, -6914, -6045, -6399, -8060, -8865, -5085, -5020, -6007, -6719, -12319, -5183, -5360, -5260, -6885, -8942, -6828, -7523, -4769, -8485, -5997, -7603, -8942, -4842, -9531, -5115, -6732, -4536, -5509, -8363, -5710, -7004, -2764, -6786, -8247, -6103, -6958, -2388, -7623, -7912, -5091, -6035, -2941, -6856, -6267, -4759, -6035, -3773, -6457, -5374, -5346, -6958, -3900, -7426, -5554, -6376, -7842, -3580, -9936, -6528, -7445, -8276, -3603, -9812, -7503, -8582, -8276, -4108, -8485, -7644, -9064, -7162, -4790, -9238, -7130, -8942, -6123, -5988, -12123, -6692, -9149, -5670, -8615, -10899, -6653, -8549, -5827, -8485, -9695, -7389, -7389, -5607, -6628, -11945, -9429, -6914, -4250, -6640, -14784, -12534, -7353, -3112, -8086, -10442, -14784, -8333, -2827, -10362, -9936, -13049, -9639, -3422, -10069, -10526, -12534, -11488, -4728, -8192, -10799, -9380, -14195, -6133, -7445, -11115, -6388, -17034, -7196, -7644, -13365, -5103, -28777, -8485, -8034, -28777, -4918, -14195, -9695, -8982, -12776, -5374, -11488, -8363, -11356, -10362, -6183, -11356, -6899, -12534, -9585, -7299, -13049, -6365, -11356, -9380, -9284, -15615, -6800, -8754, -9380, -10210, -28777, -8827, -6773, -9380, -7408, -13365, -17034, -6553, -9936, -6194, -9331, -8903, -8086, 11376, 9600, 11660, 11728, 10794, 10645, 9661, 10965, 11136, 10261, 8080, 9419, 8674, 9319, 8615, -18, 8340, 3679, 6278, 6050, 4297, 6180, -3083, 2848, 4811, 4815, 2931, -853, 375, 4712, 3398, -367, 841, -643, 3351, 2719, -1859, 1574, 86, -243, 545, -2462, 2805, 696, -6745, -297, -1544, 3809, 558, -6745, 5101, 348, 3513, 1460, 543, 6903, 1140, 3359, 3129, 4304, 7444, 2841, 4499, 4339, 6106, 7259, 5262, 5216, 4899, 6658, 6464, 6493, 5168, 4629, 6041, 4908, 6444, 4650, 3293, 3916, 2536, 5282, 3973, 311, -1635, 1323, 3644, 2994, -3650, -1062, 1611, 2734, 1071, 469, 991, 1308, 2214, -3412, 2037, 1585, 1509, 2032, -5458, 2347, 1907, 2238, 2269, -3266, 2357, 791, 2229, 2248, -5422, 2591, -10210, 1589, 1720, -2922, 2683, 1545, 1385, 414, -449, 2201, 4051, 1681, -218, -28, 1164, 4505, 1891, 1978, -683, 1006, 3441, 1794, 3098, -1833, 1661, 361, 980, 2706, -5326, 1731, -9873, -128, 1255, -3420, 1665, -3563, 609, 528, -83, 1988, -6899, 1023, -182, 822, 2326, -4764, -818, -3080, 789, 2510, -1636, -4416, -1648, 747, 2369, -395, 464, -533, 563, 1582, 348, 1789, -2585, -454, 230, 171, 1626, -6163, -2612, -261, -1567, 690, -712, -5623, -11, -9022, -642, 887, -5670, -553, -2770, -2791, 1072, -3910, -1872, 156, -8683, 157, -3659, -2248, 1306, -5487, -1837, -4831, -1674, 1494, -3961, -4831, -6928, -1717, 914, -6365, -5091, -8138, -1934, 148, -8192, -2128, -6602, -1076, 504, -3913, -887, -4703, -1, 1157, -2837, -1026, -4153, 495, 1065, -2509, -2064, -6278, 377, 131, -2153, -2997, -6469, -308, -1456, -1927, -2485, -1819, -1437, -2975, -2003, -1340, -322, -2673, -3010, -1298, -769, -276, -2409, -2447, -143, -840, -1041, -825, -2165, 321, -1030, -2071, 107, -1844, -8, -941, -3194, 137, -1774, -805, -729, -4536, -425, -2424, -1370, -618, -6943, -654, -3714, -1699, -795, -4262, -197, -4821, -3071, -1489, -1746, 121, -4997, -6628, -2735, -1214, -4, -4654, -5014, -3916, -2289, -681, -4723, -3365, -4743, -5539, -2107, -4408, -3354, -5784, -14784, -4003, -2754, -3876, -4991, -8517, -5339, -1248, -3521, -4800, -10442, -5444, -396, -2247, -6615, -6705, -3049, -21, -1444, -5516, -4654, -1859, 102, -1650, -4262, -5326, -2053, 59, -3062, -4669, -5401, -2490, -141, -6354, -4896, -2895, -2370, -507, -4630, -4361, -2871, -2778, -1177, -1438, -4258, -6565, -3380, -2364, 127, -5569, -2495, -2071, -3347, 786, -10001, -135, -656, -2253, 525, -7960, 125, -63, -1122, -1137, -5487, -1067, -40, -1082, -5531, -3773, -3457, -352, -2497, -4319, -3165, -6399, -1491, -6565, -2819, -4226, -12534, -4438, -8942, -3215, -5509, -4698, -3083, -11945, 1793, 7416, 7860, 8286, 5452, 1371, 6707, 7367, 7598, 4865, 859, 4671, 6004, 5249, 3697, 1201, 3925, 4138, -188, 3502, 1367, 4927, 1968, 1484, 3547, 1083, 4869, -311, 2595, 3202, 1199, 3943, -770, 2255, 2986, 2004, 2805, 798, 1919, 2818, 2829, 2493, 2401, 1837, 2409, 3360, 2435, 3461, 1020, 2198, 4199, 2700, 4312, -1683, 3264, 5536, 4216, 5425, 452, 4817, 6465, 5055, 6365, 2468, 5736, 6588, 4760, 6417, 2299, 5879, 5957, 3956, 5170, 312, 5403, 4907, 3864, 1965, -1370, 4463, 4040, 3762, -8718, -732, 3017, 3628, 2079, -3647, 5, 1101, 3116, -4664, -6943, 1374, -280, 2106, -571, -5195, 2164, -1166, 1542, -359, -3782, 2141, -2699, 1374, -2999, -4017, 1695, -4361, -142, -58, -4564, 1226, -3076, -3683, 394, -7299, 659, 12, -2952, -183, -1849, -163, 1972, -465, 1043, -1064, 175, 3156, 1730, 1835, -4821, 1291, 3878, 2879, 1654, -2385, 1302, 4166, 2946, 817, -301, -126, 3942, 2059, -691, -1304, -1654, 3174, 283, -1281, -3726, -618, 1811, -2470, 796, -3954, 438, -478, -6504, 1793, -3386, 1220, -5333, -6123, 1070, -1175, 1843, -2470, -2900, -2622, -39, 1965, 110, -788, -4195, 73, 922, 774, 211, -345, -154, -3286, 238, -9, -127, -353, -1614, -1113, -1513, -1868, -778, 1504, -2358, -1355, -6278, -1746, 2188, -2576, 517, -7162, -2918, 1649, -1753, 1130, -4164, -3612, 174, -191, 631, -2526, -3149, -2462, 1037, -441, -2036, -2006, -5871, 1282, -1180, -2265, -1462, -1961, 118, -1614, -1123, -1900, 403, -3347, -2291, 688, -3014, 1543, -7484, -1928, 1715, -3124, 1816, -7819, -171, 1837, -2129, 1362, -5569, 1082, 1220, -1526, 336, -955, 1433, 536, -1068, -1154, 340, 843, 424, -287, -3515, -196, -471, 35, 240, -10526, -3040, -931, -1404, -147, -4625, -7912, -232, -3683, -1975, -2468, -2130, -132, -4901, -7097, -2363, -719, -894, -3846, -6278, -2897, -536, -2411, -1727, -3049, -3065, -987, -4880, -815, -1836, -1671, -1654, -8549, -1481, -1872, 526, -1587, -5686, -3680, -3629, 1639, -788, -3650, -3189, -8247, 1469, -235, -3208, -1495, -7230, 58, -191, -4408, -921, -10069, -2302, -912, -6692, -979, -7034, -4266, -3189, -2900, -1201, -3804, -4278, -7960, -1328, -752, -3135, -3850, -3504, -1635, -181, -2008, -4495, -1849, -2219, -498, -514, -3284, -1613, -1161, -2030, 177, -1225, -2644, -818, -4250, 22, -892, -6480, -1725, -3067, -911, -2745, -5487, -2646, -1057, -2191, -2666, -2741, -2821, 89, -2427, 166, -2277, -3714, 265, -2612, 874, -2207, -4278, -848, -4532, -226, -1957, -3027, -4500, -12776, -4495, -1318, -1769, -6035, -4940, -4743, -55, -906, -2462, -2648, -1382, 517, -714, -1779, -2086, -870, -413, 3125, 4077, 7513, 329, 5137, 2368, 4078, 7330, 2346, 5914, 4496, 4120, 7077, 4812, 6870, 6162, 4241, 6907, 5747, 7093, 5901, 4017, 6273, 5135, 6445, 3593, 2714, 4624, 2982, 4950, -3704, -676, 1298, -573, 3187, -516, -3903, -6732, -2302, 2372, -807, -1953, -2929, -599, 1732, -3726, -1857, -1777, 933, 969, 2994, -108, 189, 2259, 1100, 5327, 2648, 1713, 2849, 1221, 5969, 4394, 1652, 2570, 933, 5191, 4743, -337, 2764, 2724, 2707, 3459, 601, 3544, 4731, -2994, -82, 2471, 3461, 5554, -6469, 336, 2253, 2219, 5207, -3247, 1469, -86, 388, 3696, -1460, 270, -7426, -368, 1416, -454, -2015, -4795, -135, 303, 1089, -1209, -3034, 67, -227, 2194, -100, -2114, -395, -81, 2402, 201, -1272, -2277, 886, 1891, -98, -612, -6399, 1092, 871, -943, -174, -2201, 1433, -395, -2229, -45, 100, 2453, -821, -3808, -306, 952, 2811, -228, -3597, -1055, 861, 2073, -232, -1474, -2223, -70, 931, -1636, -308, -2646, -1899, 910, -6045, -82, -1747, -4718, 1230, -6553, -297, -722, -5487, 1521, -2622, -855, 190, -3609, 1725, -1241, -2361, 899, -1630, 1705, -921, -5539, 1178, 565, 2127, -1912, -11232, 733, 2054, 2927, -5970, -6204, -594, 2509, 3207, -3566, -2813, -1411, 1982, 2359, -720, -1594, -82, 1084, -559, -83, -1879, 952, 872, -3218, -927, -3314, 1339, 668, 961, -2615, -4420, 1314, -327, 2380, -1076, -2819, 1241, -2238, 2687, 352, -1664, 1511, -5584, 2189, 137, -2259, 1823, -3951, 807, -1777, -5339, 1587, -1368, -1627, -2950, -3455, 416, -294, -2294, -1077, -1773, -2355, 233, -465, -544, -2626, -9753, 520, 412, -1343, -6856, -2722, 345, 363, -2819, -6332, -479, -383, -635, -2681, -3788, 496, -1391, -3036, -1817, -2631, 649, -2460, -6842, -1766, -1320, -39, -3804, -2833, -2022, -242, -1637, -4669, -749, -1838, 117, -2737, -4172, 351, -1682, -605, -1030, -4399, 968, -2404, -2937, 672, -7179, 867, -4352, -8582, 1503, -12123, -470, -2603, -6914, 1408, -7130, -3367, -386, -6885, 355, -8790, -1598, 179, -9022, -1652, -6143, 178, -691, -4295, -3388, -2548, 541, -3463, -2015, -3023, -894, 301, -6692, -1305, -3618, -388, -122, -2510, -1773, -7503, -1050, -809, -1005, -3210, -5394, -3337, -1807, -894, -4831, -3269, -3603, -2675, -1827, -8138, -2294, -1187, -2514, -3089, -6007, -972, -224, -1807, -3597, -1361, -187, -99, -1843, -4086, 148, -406, -730, -3357, -5743, -237, -1953, -2622, -4420, -11945, -3124, -6553, -6376, -1752, -6365, -8247, -6267, -5487, -1097, -3683, -3441, -3615, -4482, -3124, -2567, -2076, -1518, -3329, -7081, -1771, -180, 215, -1460, -2073, -1183, 856, 567, -1010, -923, -1428, 553, -630, -3040, -942, -3635, -4315, -2251, -1484, -4226, -3468, -4688, -2135, -2475, -1104, -3741, -9639, -4207, -7389, -309, -4086, -6666, -5049, -3957, -702, -3632, -3989, -2831, -1501, -596, -3191, -4115, -2514, -586, 129, -3025, -6705, -2534, -976, 439, -2861, -13365, -1102, -3923, 1053, -3177, -6786, 293, -5853, 1860, -3738, -4779, 885, -1515, 1766, -3830, -4795, 757, -824, 165, -5933, -7603, 154, -2038, -4046, -5702, -5195, -627, -5951, -5784, -1778, -2076, -1206, -6074, -3218, -931, -1020, -1165, -3276, -1953, -2197, -1397, -771, -2762, -1080, -7984, -3566, -936, -3147, -509, -2615, -11945, -1678, -2280, 304, 632, -2681, -179, 325, 1363, 2254, -344, 1602, 2122, 2034, 2937, 100, 2137, 2605, 1773, 2796, -949, 1536, 1657, 104, 1900, -3507, -96, -987, -3583, 480, -6354, -3210, -4017, -2514, -1136, -6299, -9106, -4810, -968, -2801, -7371, -2893, -4527, -937, -3773, -9531, -1233, -2573, -1604, -3662, -2502, -1258, -2289, -2458, -3856, -224, -2875, -3447, -2845, -4640, 336, -8060, -5576, -2699, -5678, -279, -8276, -5759, -3054, -6288, -1724, -7562, -4527, -4513, -5970, -3744, -7230, -4412, -6267, -5227, -6628, -2641, -4386, -4880, -4738, -6411, -968, -3119, -3471, -4991, -4348, -782, -2090, -3659, -6143, -3149, -1591, -1651, -6828, -5133, -2176, -2992, -1445, -7842, -2910, -1830, -4433, -1449, -3817, -1525, -2807, -5836, -1595, -3698, -371, -5718, -7984, -1610, -5561, 637, -3701, -13365, -1774, -4974, 1135, -1673, -10362, -2592, -4319, 973, -1406, -9331, -4319, -7774, 277, -2432, -28777, -6814, -5487, -603, -4723, -5353, -6653, -1424, -1394, -7603, -2031, -4718, 68, -2140, -7130, -436, -3635, 450, -2914, -5836, -59, -3301, 278, -4067, -5451, -911, -3271, 2, -7213, -5195, -3112, -3098, -164, -8982, -3271, -6445, -2731, -503, -4348, -2165, -7130, -1869, -1571, -2731, -2497, -4985, -930, -3509, -1847, -3754, -3757, -513, -3344, -1672, -4738, -2248, -679, -2409, -3130, -5333, -476, -1378, -2596, -8485, -6045, 553, -2087, -3850, -3279, -6045, 736, -1773, -9429, -1341, -4527, 148, -930, -4703, -1067, -3603, -1199, -164, -1736, -1507, -3365, -3463, 149, -1435, -2150, -3521, -6225, -406, -3170, -2720, -4769, -4219, -1961, -6516, -2540, -6577, -2608, -4089, -3927, -1720, -5055, -2448, -6214, -2881, -1466, -4495, -3177, -9429, -3814, -2119, -5759, -3814, -12534, -6528, -3036, -9812, -3689, -10526, -6553, -3042, -9873, -3574, -6565, -4625, -3096, -5718, -4258, -5152, -4134, -4078, -4161, -6035, -6267, -5879, -6163, -3441, -8112, -28777, -12534, -7371, -2939, -7687, -5718, -4184, -5502, -2482, -5279, -4031, -2505, -4365, -2140, -3873, -4469, -2521, -4038, -1940, -4416, -4985, -3707, -3850, -1894, -9380, -4234, -6123, -3344, -2119, -5286, -4365, -10210, -3319, -2939, -2799, -6093, -11629, -1542, -2366, -3201, -1569, -4416, -3449, -4104, -8582, -3261, -4230, -2619, -6745, -6103, -6376, -1076, -517, -6343, -3856, -10069, -669, 406, -4238, -4513, -8393, -1117, 415, -2236, -5097, -6565, -1002, -163, -583, -2331, -4003, -1060, -1210, 310, 52, -2735, -2211, -3543, 244, 1264, -3518, -2847, -11945, -851, 1255, -6457, -2040, -2617, -3012, -118, -4021, -2223, -628, -6800, -3540, -2887, -3954, -380, -7708, -12319, -3621, -9695, -1351, -3704, -5306, -4644, -6194, -2843, -1240, -3476, -2776, -2768, -2480, 116, -1819, -907, -1489, -1339, 132, -782, -722, -650, -1144, -1346, -1181, -3271, 1068, -1040, -735, -3378, -1696, 2818, 351, 1279, -1225, 1663, 3821, 1190, 1568, 958, 2741, 4022, 696, -42, 1361, 2391, 3459, -1100, -4774, 352, 804, 2211, -3515, -5247, -1807, -1492, 565, -4606, -4195, -2516, -2778, -787, -3425, -4097, -1961, -2841, -1460, -1834, -3482, -2845, -1598, -2148, -859, -4438, -4997, -460, -4071, -542, -8276, -4112, -56, -11629, -1088, -7730, -2701, -218, -4555, -3319, -5942, -1887, -793, -2879, -7708, -6814, -1078, -1925, -3027, -1839, -8718, -303, -4254, -3383, 105, -4390, 327, -6540, -3496, 557, -1976, 392, -3906, -4262, 150, -1095, -813, -2468, -5879, -665, -1458, -5085, -1777, -7426, -1503, -2954, -4123, -1046, -5429, -2472, -4946, -1647, 120, -3034, -3779, -5367, -1913, 1154, -1711, -2893, -4365, -4352, 1504, -1025, -1050, -4495, -7299, 960, -618, -275, -8582, -4254, -661, -454, -437, -6354, -3367, -3540, -830, -1450, -3110, -4003, -4769, -2076, -3886, -2587, -6194, -4278, -3597, -9064, -3352, -13049, -3964, -2543, -2785, -4863, -9238, -2435, -1218, -270, -6214, -6540, -1810, -726, 1002, -4559, -4795, -2999, -891, 1576, -3117, -3968, -5367, -1825, 1555, -3168, -5031, -3071, -3964, 897, -4464, -6288, -2057, -7819, -626, -4929, -3067, -2863, -9022, -3982, -4134, -1598, -5273, -4703, -6732, -4361, -1378, -7426, -1883, -2803, -5979, -1983, -8615, -586, -1935, -7752, -3830, -6565, -557, -1762, -6814, -10069, -3896, -1704, -771, -6480, -4311, -3276, -2956, 83, -6914, -2112, -4416, -2372, -117, -6388, -2111, -8423, -2065, -1687, -5299, -4238, -8982, -2241, -5319, -4611, -17034, -6321, -1842, -8790, -4021, -4659, -8393, -1534, -7644, -3198, -2781, -8333, -1922, -9193, -2581, -2244, -3954, -2531, -4442, -2851, -2197, -2745, -2833, -1551, -4513, -2659, -2926, -3076, -324, -5906, -4176, -4153, -3098, -378, -4810, -7819, -6565, -2507, -1616, -6422, -6074, -8982, -1713, -4097, -9936, -3455, -8276, -1388, -8827, -3870, -2514, -6914, -2191, -7603, -2986, -2519, -5576, -5326, -3042, -4907, -3140, -5043, -9695, -1066, -11232, -4064, -5502, -5554, -455, -3913, -4738, -6732, -6504, -1077, -2425, -5067, -8060, -8982, -3133, -2677, -5726, -8683, -6278, -3161, -1181, -2789, -5743, -1790, -5607, -4918, -2787, -532, -5055, -4863, -5437, -3438, 1153, -4923, -3968, -2285, -7936, 1457, -939, -1872, -441, -3521, 789, 191, -697, 563, -1176, -606, -186, -867, 711, -702, -1288, -2086, -1765, -68, -1274, -346, -5115, -2460, -1966, -1774, 337, -4664, -3515, -5546, -960, 213, -5793, -6354, -11629, -85, -884, -9873, -9479, -6204, 186, -3551, -5115, -3321, -3644, -237, -8276, -3537, -497, -2560, -1990, -2730, -2142, 1089, -2578, -7752, -346, -1516, 1883, -3474, -1892, 753, -1222, 1911, -5319, -316, 1015, -157, 984, -8865, -1908, 604, -58, -97, -1940, -2442, 101, -2462, 1006, 1032, 1535, 786, -2319, 1736, 2215, 2780, 1759, 652, 996, 2082, 2543, 2055, 1236, -1352, 728, 1643, 1718, 336, -4723, -1878, 1452, 877, -1159, -3218, -5735, 1720, -448, -791, -1093, -4703, 1435, -1644, -20, -108, -2698, 551, -1859, -581, 153, -2569, -187, -2229, -2216, -45, -4238, -26, -2438, -266, -1116, -5888, 353, -1402, 1424, -3571, -3638, 339, -416, 1442, -3114, -2412, -388, 29, 143, -1792, -2065, -2305, 182, -778, -2512, -2000, -5615, 77, -606, -5145, -1980, -4433, -566, -1487, -2422, -2414, -3142, -2107, -2069, -94, -3811, -2821, -5214, -569, 790, -4311, -3101, -15615, 275, 718, -2225, -4644, -5170, 80, -188, -922, -10284, -2774, -1011, -1732, -682, -4545, -1800, -1369, -2178, -1427, -1727, -1899, -487, -1194, -1952, -300, -2926, -540, -804, -103, 464, -2677, -2123, -1423, 1369, 671, -915, -5862, -3334, 1645, 235, -12, -10613, -5853, 708, -1123, -92, -6516, -4258, -1471, -4172, -824, -3896, -3543, -3843, -11115, -1507, -2291, -4420, -4703, -6173, -1923, -1647, -6577, -4532, -5970, -2681, -1674, -8582, -2305, -8333, -3047, -2119, -5615, -1080, -12123, -1630, -2419, -4262, -1087, -5546, -86, -1908, -5408, -1884, -2348, 810, -1678, -9531, -2799, -546, 935, -2883, -3975, -3798, 191, 250, -4024, -1848, -5638, -80, -929, -1782, -1066, -7752, -1378, -1106, -938, -870, -7264, -3433, -510, -1741, -928, -3592, -6540, -792, -4331, -1053, -951, -6928, -2651, -6914, -1189, 250, -3067, -6528, -4254, -1197, 169, -1952, -3933, -3020, -957, -1095, -2309, -1879, -2895, -608, -2228, -3401, -973, -3729, -478, -1579, -4469, -606, -5195, -864, -886, -5247, -554, -5008, -1788, -425, -5584, -799, -2973, -2552, -508, -7146, -1484, -1085, -2841, -1664, -14784, -2701, -54, -4049, -4028, -5970, -4031, -53, -8517, -6194, -4569, -4262, -1013, -6640, -6026, -5109, -3707, -1882, -4089, -3779, -5960, -3417, -1490, -3808, -2288, -5429, -3549, -1206, -4858, -2153, -4810, -3944, -1691, -7113, -3438, -5208, -4191, -3161, -13738, -6411, -7196, -3923, -6828, -7113, -6256, -11781, -3471, -6183, 4555, 15411, 7007, 10967, 10737, 8875, 14992, 7271, 10267, 10109, 10369, 13697, 7163, 7923, 8085, 9998, 11391, 5948, 2320, 4153, 8634, 7948, 3896, -513, 552, 7384, 6331, 2489, 442, 440, 6092, 7580, 1513, 355, -2028, 5616, 7957, -317, 1608, -1364, 6813, 7370, -3060, 1339, 780, 6555, 5815, -2195, 251, 2419, 3138, 3196, 430, 757, 3938, 2245, 1437, 3113, 2371, 5047, 5984, 4148, 4832, 3588, 5594, 6338, 6446, 5374, 4266, 5513, 5190, 7346, 4652, 4298, 4535, 3562, 6799, 2430, 3586, 1997, 2533, 4485, 765, 2135, -1617, 1314, -1242, 1843, 164, 184, -1490, -1172, 1405, -1369, -411, -3232, -1131, -1009, -1508, -4093, -927, -3632, -6332, -879, -4119, -297, -1135, -3237, -139, -2075, -671, 60, -1756, 223, -1356, -2143, -962, -2730, 109, -877, -4718, -7097, -2726, -515, -497, -4759, -2241, 518, -1817, -808, -4890, 893, 1886, -3748, -2483, -9695, 2311, 1818, -3444, -7247, -2799, 3001, 615, -1488, -5037, -1157, 3018, -1370, -308, -2401, -1672, 2199, -2904, -13, -1314, -3766, 387, -2545, -743, -705, -6504, -2024, -1526, -2924, -419, -2208, -3449, -1261, -6943, -254, 319, -6026, -1999, -7865, -143, 1382, -8718, -3133, -8393, -323, 1337, -4769, -3677, -8112, -806, 21, -4592, -3751, -9238, -1176, -3632, -5133, -2502, -7665, -1149, -5827, -5026, -1637, -4664, -1204, -2470, -5615, -2340, -4378, -1817, -2118, -8220, -5686, -7264, -3172, -3140, -8827, -8582, -8718, -4708, -4743, -5710, -4858, -4460, -4912, -4573, -4708, -4764, -3769, -4754, -3563, -5133, -6365, -4748, -5607, -3496, -6469, -7484, -6278, -7819, -3827, -6602, -5623, -5319, -8276, -3227, -5539, -3820, -3603, -6732, -2855, -5306, -2772, -2517, -6411, -3729, -6602, -2637, -1956, -6885, -6973, -8582, -3266, -1771, -7408, -11356, -8827, -3827, -1948, -7583, -5915, -6480, -3744, -2819, -7562, -5247, -4518, -3889, -5292, -7408, -5646, -3441, -4940, -17034, -6434, -5607, -2545, -7687, -5422, -5202, -5189, -2416, -7644, -4067, -4555, -5026, -3543, -5158, -4635, -4703, -4683, -5599, -5026, -6577, -5502, -4583, -6973, -6773, -9873, -6246, -5924, -7730, -6153, -17034, -5960, -8060, -9936, -4800, -7960, -4880, -6628, -14784, -5221, -4759, -4127, -7464, -8138, -7774, -3222, -3846, -6074, -6602, -12776, -2809, -3603, -3208, -6288, -7281, -3203, -3375, -2325, -6615, -5472, -3985, -3417, -2935, -7708, -4880, -4635, -3843, -5189, -9585, -5306, -4821, -5279, -8304, -11356, -6516, -4573, -10704, -5103, -13738, -6016, -3951, -7960, -4046, -14784, -5240, -3594, -5020, -4929, -9429, -5306, -3824, -4250, -7730, -7019, -5879, -4601, -4344, -9479, -5401, -7247, -5853, -5189, -8112, -5312, -9429, -7984, -7050, -6732, -7230, -11629, -15615, -9639, -6267, -6267, -12776, -9106, -8582, -6943, -4573, -8138, -5951, -7264, 8226, 411, 6776, 10899, 8024, 7438, 1696, 6047, 10370, 7498, 4785, 3410, 3550, 8707, 5851, -1383, 4361, 1496, 5573, 3279, -6615, 4550, 3681, 387, 2930, -1050, 4148, 3959, 966, 3766, 2183, 3331, 2484, 2219, 3780, 3329, 2233, -378, 2612, 3424, 3556, 789, -265, 2591, 3346, 2596, 234, -611, 2600, 3792, 1704, 2757, 1456, 3414, 4338, 5176, 4562, 5128, 4379, 4499, 7056, 5170, 6859, 4481, 4032, 7438, 4820, 7148, 3264, 2816, 6602, 3842, 6041, 1187, 666, 4649, 2801, 2942, 2185, -3294, 1847, 2180, -28777, 3045, -6235, -819, 1672, -245, 2564, -3208, -2505, 535, -232, 1386, -2964, -3465, -1451, -786, 438, -2538, -942, -1457, -669, -469, -1540, 1080, -175, -2370, -2226, -1040, 1762, 391, -11488, -4907, -976, 1432, 604, -1869, -5408, -1245, 210, 656, -377, -5487, -1874, -1962, 337, -1040, -7097, -2851, -5836, -747, -4168, -6759, -4504, -9064, -2438, -6163, -4278, -8112, -4473, -1415, -2795, -2837, -5584, -3074, 223, -2270, -2149, -2984, -3286, 756, -3321, -1587, -2331, -5584, 356, -5906, -846, -2378, -12319, -710, -10284, -286, -1996, -5195, -2247, -11629, -341, -776, -3580, -5152, -7644, -1509, 500, -2709, -9284, -4536, -4946, 1008, -1621, -3225, -2841, -2102, 543, -1136, -2386, -2075, 960, -628, -1855, -4500, -2111, 2341, -1690, -4286, -4940, -3112, 2706, -2705, -12776, -2372, -5202, 2177, -4738, -6615, -2807, -4327, 689, -9695, -4295, -5247, -2340, -1011, -6528, -3460, -2610, -1849, -776, -3592, -3482, -1296, -2954, -621, -3225, -4718, -2172, -7335, -1218, -4486, -7644, -6411, -7603, -1245, -5360, -7542, -5576, -4858, -559, -5214, -5630, -3112, -6288, -321, -5202, -4587, -3417, -11945, -932, -4564, -4097, -5286, -6973, -2536, -4307, -4315, -6856, -6692, -5097, -5097, -5240, -5273, -8982, -5353, -7445, -5735, -2914, -10704, -3597, -28777, -4408, -2203, -6885, -2507, -10526, -3301, -3951, -4199, -2107, -9284, -3291, -8034, -2779, -2259, -6928, -4923, -2902, -2630, -2743, -5465, -10899, -2016, -3860, -3331, -5429, -7097, -3391, -6457, -4056, -5346, -5494, -8220, -7842, -4991, -4616, -5422, -6870, -9022, -5253, -5020, -4774, -3920, -17034, -3910, -6602, -3927, -2772, -9022, -2550, -5079, -3441, -2510, -7281, -1973, -3665, -3563, -3140, -6528, -2169, -4028, -3748, -4764, -6553, -2960, -6278, -2954, -6469, -8304, -3717, -7730, -2132, -6103, -14784, -3433, -5678, -2176, -5924, -11004, -2855, -5109, -3339, -6411, -9284, -3042, -5960, -6103, -7019, -9238, -4134, -9106, -14784, -8009, -10362, -5145, -9429, -9873, -10210, -12776, -4853, -5260, -7389, -7842, -9585, -4774, -3644, -6278, -4874, -6870, -5906, -3438, -5576, -3380, -5509, -9238, -4438, -4733, -2918, -5584, -7247, -5979, -3843, -3347, -7464, -4361, -5793, -3266, -4625, -10001, -3638, -5091, 1053, 8110, 8914, 8307, 6042, 624, 7849, 8377, 7697, 6023, 614, 6830, 6761, 5694, 5584, 1187, 4282, 4227, 1468, 3982, 547, -3409, 2171, -3076, 110, -1225, 2598, 2072, -3543, 1042, -665, 4111, 1684, -506, 2658, -964, 3751, -446, 2235, 1984, -7146, 2103, -7936, 2601, -337, 2168, 462, -1580, 2579, 1717, 5343, 1916, 1908, 4177, 4251, 6921, 4386, 3752, 5080, 5244, 7424, 5647, 4202, 4292, 4783, 6883, 5311, 2971, 305, 2614, 5111, 2609, -777, -620, 3635, 1736, -4464, 1146, 2544, 5977, -629, 2458, 2514, 1870, 6709, -634, 3097, 1606, -2359, 6413, -2823, 2131, -1302, -3342, 5643, -7623, 316, -6773, -908, 4793, -5487, -2306, -13049, -1451, 3640, -3151, -4555, -9695, -3574, 1736, -2908, -5234, -6388, -5592, -904, -4759, -9238, -3996, -3723, -2510, -17034, -4274, -2615, -2599, -1828, -5394, -2601, -1887, -1611, -2331, -2945, -3496, -1453, -538, -7752, -2242, -4464, -1450, 44, -1051, -2606, -2166, -1784, 49, 1245, -3773, -1528, -2204, -388, 1328, -4429, -2473, -3158, -1272, -587, -3686, -3594, -5085, -2728, -7081, -2881, -4123, -7408, -5202, -3215, -2132, -5339, -11629, -8982, -1488, -1471, -5031, -4940, -4299, -1189, -1473, -4923, -1805, -1452, -797, -2510, -4010, -677, -91, -222, -4545, -2633, -1019, 204, -349, -6666, -3563, -2386, -385, -1899, -6183, -11356, -1821, -1716, -3036, -4620, -3710, -342, -3817, -531, -4149, -2615, -216, -4386, 781, -4013, -4518, -1874, -2895, 948, -3194, -4010, -6590, -2019, 322, -2008, -1979, -4344, -670, -624, -1414, -2191, -2979, 628, -990, -1710, -4597, -4071, 1114, -976, -3110, -8982, -8754, 807, -1502, -7665, -6914, -7984, -33, -2829, -6045, -7179, -5170, -977, -4620, -2677, -7299, -4336, -1666, -5743, -2254, -6183, -3319, -2350, -5615, -3647, -5853, -2339, -3933, -5539, -7130, -5158, -2069, -8423, -5546, -8903, -4438, -2690, -10069, -4640, -7644, -4403, -4149, -7865, -3586, -7213, -4784, -5494, -12319, -2897, -5686, -4940, -4985, -8485, -2608, -4108, -4847, -4130, -5247, -3027, -3239, -5133, -3940, -4064, -4935, -2950, -6553, -4532, -3683, -10526, -2933, -10613, -5951, -3927, -5735, -3038, -11945, -8333, -5037, -3930, -3433, -7730, -11232, -7146, -3647, -4473, -6016, -13049, -6719, -3629, -6083, -5451, -14195, -4940, -3299, -7960, -6083, -13365, -4331, -3172, -10526, -8304, -17034, -4733, -3843, -15615, -10069, -9695, -6113, -5584, -15615, -9149, -6492, -8220, -7230, -12319, -11004, -5195, -7960, -6123, -6719, -17034, -4759, -6615, -4907, -5043, -9193, -4523, -6376, -3748, -5584, -7644, -4523, -7081, -2651, -7484, -6113, -4698, -8192, -2111, -6640, -4438, -5195, -8363, -2429, -5145, -3795, -6914, -7842, -3843, -4067, -4408, -13049, -7936, -6469, -3840, -5988, -5638, -8718, -8718, -4940, -7708, -3201, -9812, -7936, -7960, -4748, -6653, -4769, -7050, -7603, -6332, -6615, -4513, -7019, -5942, -7299, -6388, -4869, -7774, -4805, -6225, -5879, -5710, -6828, -5429, -5654, -6388, -6590, -4460, -11356, -5879, -8582, -7113, -3680, -5710, -6842, -7960, -7796, -4157, -3375, -7819, -6469, -8333, -5253, -3296, -7445, -6928, -7774, -6528, -4620, -6870, -8247, -6640, -7708, -7445, -6528, -8754, -6153, -8247, -14784, -5844, -9812, -6602, -8009, -11629, -5415, -9753, -8333, -7603, -9193, -5306, -7464, -17034, -7146, -8790, -5554, -5569, -8718, -6786, -7774, -7066, -4482, -5818, -5933, -5569, -8304, -3415, -6064, -4795, -3247, -4890, -1853, -13049, -3291, -1092, -1488, -282, -2670, -1180, 441, 194, 903, 44, 464, 1064, 369, 1400, 853, 1121, 561, -758, 998, 249, 726, -1463, -2859, -374, -1779, -805, -6988, -4679, -2714, -4863, -3757, -5401, -4923, -5784, -5367, -7335, -3383, -5055, -8942, -5374, -6343, -3744, -5951, -12534, -6045, -5638, -5524, -7050, -12534, -6365, -5960, -7730, -6914, -7484, -6516, -7842, -6973, -5879, -5654, -6602, -11488, -6026, -5509, -5085, -6173, -7353, -6602, -5933, -5312, -6045, -6235, -8649, -6422, -6113, -6814, -6928, -11004, -6083, -5888, -8276, -8615, -10284, -5073, -4659, -9380, -8582, -6745, -4238, -4442, -9753, -7865, -4733, -4153, -6083, -9238, -7644, -3954, -4800, -12776, -8582, -6628, -4071, -5686, -9064, -8192, -5079, -4728, -6074, -7464, -8982, -3937, -5189, -5810, -8393, -10613, -3512, -5026, -5509, -11004, -8549, -3954, -5109, -5394, -17034, -7113, -5654, -6434, -5061, -15615, -6666, -9479, -11004, -4438, -11488, -6288, -7353, -9753, -4064, -9695, -6422, -4918, -8485, -4373, -8454, -8060, -4089, -13049, -5408, -8165, -9022, -4226, -6988, -6376, -9331, -6422, -5465, -4482, -6885, -13738, -5623, -8485, -4246, -8276, -10799, -6666, -8718, -5646, -11629, -8423, -10613, -7281, -8363, -13738, -7960, -10899, -9149, -8112, -13365, -8304, -8582, -11945, -6653, -15615, -8138, -9193, -7034, -6235, -11356, -7464, -10069, -5726, -6800, -8615, -7389, -7796, -5743, -8423, -7264, -7774, -6310, -6516, -10442, -7179, -7264, -5776, -7687, -11232, -7819, -6343, -5686, -7445, -9064, -8138, -6123, -5827, -6422, -6870, -7912, -6256, -6278, -6278, -5988, -8165, -6590, -7097, -7004, -6343, -9380, -6745, -8615, -8304, -7562, -11781, -6480, -11115, -10526, -7503, -11356, -6376, -10069, -15615, -7050, -10210, -7353, -7819, -11781, -7960, -9639, -9753, -7162, -10799, -11356, -9380, -10799, -7936, -14784, -15615, -9380, -10284, -10069, -11356, -12776, -8903, -11945, -10210, -8192, -12123, -8903, -13738, -9639, -7130, -8192, -11004, -9380, -11629, -6928, -5853, -11488, -7888, -11356, -7389, -5115, -9193, -8138, -9238, -8790, -5678, -10001, -10362, -9531, -12123, -7230, -11115, -28777, -11356, -28777, -8683, -8903, -10284, -11488, -14784, -8683, -8615, -7960, -10362, -12776, -7984, -10362, -7179, -9380, -11781, -3117, -6870, -7644, -4630, -5247, -3659, -11232, -6016, -7146, -6422, -5561, -12319, -5026, -6457, -8754, -10362, -7130, -4679, -5103, -17034, -5801, -5158, -5346, -5176, -8903, -3801, -4674, -6914, -6842, -6692, -3668, -5195, -7819, -14195, -6719, -4874, -6133, -8112, -8304, -8112, -6288, -6602, -9331, -6054, -8423, -6354, -6093, -8034, -6267, -7774, -6814, -5286, -6899, -7113, -7708, -6842, -4847, -7213, -6045, -7583, -6422, -5103, -6842, -5726, -7066, -7213, -6640, -5437, -7034, -6870, -7708, -13365, -5145, -8790, -6914, -7162, -6928, -5531, -8790, -6153, -6814, -4929, -6054, -6615, -4880, -5055, -5554, -11004, -3296, -2813, -2438, -4230, -4082, -524, -733, -656, -1370, -833, 1182, 493, -67, -185, 223, 1807, 608, -783, -417, -86, 1336, -519, -3058, -2075, -1452, -316, -3094, -6988, -5694, -3417, -3130, -5871, -7603, -7936, -5189, -4963, -6516, -6388, -6885, -6705, -4698, -6299, -4918, -7562, -9812, -4616, -4649, -4348, -8649, -12776, -4518, -4060, -5333, -9695, -10210, -4258, -4344, -9149, -10210, -11945, -4195, -4679, -7796, -9284, -8165, -4912, -4460, -5152, -8009, -5546, -7371, -4035, -4869, -6943, -4532, -12319, -3989, -6074, -6516, -4282, -6343, -4601, -6469, -6786, -4504, -4635, -5759, -4611, -7583, -5133, -4464, -6615, -3751, -8790, -6602, -4790, -6332, -4184, -10899, -10704, -4997, -6365, -6103, -13738, -10799, -6388, -7936, -11488, -12319, -6640, -17034, -13365, -10069, -9812, -5306, -6856, -11004, -7034, -7426, -5008, -4963, -9064, -5646, -5997, -5286, -5465, -6828, -4451, -5710, -6035, -8683, -4754, -3509, -6553, -7389, -11356, -4064, -3194, -8034, -10704, -6842, -4774, -3680, -7162, -13738, -5702, -7213, -5085, -5266, -8034, -5458, -11356, -7371, -4290, -6528, -5444, -11945, -10210, -4258, -6123, -5569, -28777, -9331, -5170, -5836, -6007, -9022, -6958, -6943, -5444, -7097, -6759, -5623, -8903, -5735, -9873, -6480, -5079, -9585, -7644, -10284, -6958, -5103, -9149, -14784, -7019, -6679, -5702, -8034, -9106, -5735, -5554, -6814, -7066, -7353, -5554, -4764, -7708, -6899, -7562, -6332, -4425, -7066, -7353, -8865, -7464, -4455, -6516, -8034, -10613, -6856, -4863, -7004, -8754, -10613, -5836, -5592, -8276, -10069, -8549, -5836, -6153, -9873, -13738, -6732, -6719, -6590, -11356, -12123, -5844, -7603, -7162, -13365, -8165, -5997, -8247, -7752, -10799, -6885, -7389, -9284, -8009, -9106, -7113, -10362, -11488, -8333, -9284, -8718, -14195, -14784, -9380, -10799, -11115, -13365, -11232, -9585, -11781, -10799, -12776, -10284, -8582, -10362, -9331, -13365, -11004, -8333, -9106, -8903, -13365, -10284, -8333, -9193, -9331, -9585, -9380, -8333, -10001, -9936, -7730, -9429, -9238, -8942, -10069, -7523, -8649, -11004, -8247, -9331, -8754, -8454, -12776, -9380, -8220, -11629, -10799, -28777, -14784, -7583, -11356, -14784, -11488, -13049, -8086, -9531, -9022, -9380, -11356, -10899, -9064, -7562, -9873, -7081, -9429, -2805, -8718, -6899, -6800, -10899, -4226, -6653, -7179, -5718, -8827, -8517, -5401, -9193, -5638, -6480, -7034, -4518, -9531, -6133, -4946, -5306, -3804, -6246, -6732, -3830, -5759, -3444, -4527, -5933, -3014, -8192, -3485, -4344, -4138, -2827, -9238, -4056, -5387, -3203, -3523, -5915, -5480, -7162, -3352, -5152, -4282, -6565, -10442, -4649, -6958, -3316, -5437, -11232, -6943, -7665, -2574, -4592, -7081, -7213, -7445, -2163, -4395, -6492, -6376, -7113, -2312, -4460, -8276, -7583, -7146, -3191, -4578, -28777, -8790, -5801, -5183, -4559, -9193, -6885, -5127, -12776, -4545, -6516, -6828, -4769, -5292, -3920, -3900, -3447, -1899, -1621, -1802, -1198, -706, 111, 92, -225, 391, 418, 753, 503, 157, 682, 253, 191, -422, -702, -432, -1141, -1561, -3304, -2975, -3615, -3853, -4532, -7603, -6759, -10284, -7503, -7389, -4901, -7426, -4688, -12123, -7623, -5458, -6928, -3546, -10613, -7299, -9238, -8086, -3482, -7196, -6800, -9106, -11356, -4053, -6469, -6434, -7130, -11356, -5531, -7503, -7353, -7247, -7066, -7752, -11488, -11232, -8903, -5576, -7196, -9380, -11004, -9064, -6153, -6267, -7464, -9380, -5638, -9531, -6225, -8903, -11488, -3592, -10704, -6153, -28777, -9585, -2642, -10069, -5678, -8582, -7179, -2483, -12123, -5516, -8393, -6615, -2912, -6376, -5818, -11945, -7562, -3879, -4323, -6388, -8865, -10704, -4912, -3876, -6553, -7426, -8982, -4774, -4555, -6332, -8034, -6354, -4115, -6399, -6540, -7130, -5592, -4075, -10069, -7774, -5374, -6103, -4640, -10799, -10284, -4985, -7281, -5751, -7888, -12776, -5670, -8138, -7542, -7113, -11488, -5853, -7819, -9531, -7888, -11945, -5008, -7281, -9022, -8615, -28777, -4774, -7371, -7912, -7445, -11115, -5810, -8276, -7213, -6773, -7960, -8615, -10899, -7179, -6565, -6035, -15615, -10442, -8060, -6204, -4759, -15615, -7113, -9873, -6083, -4153, -9429, -6376, -10210, -6422, -4447, -7213, -7960, -10138, -6504, -6074, -6194, -10362, -11232, -5960, -10442, -5234, -6786, -9429, -5630, -12319, -4597, -5768, -7179, -5979, -10799, -4912, -6133, -6026, -7196, -12123, -6376, -6133, -5743, -9380, -8086, -8865, -5415, -6343, -11004, -5793, -9695, -5176, -7583, -10442, -4935, -8423, -5164, -8220, -9531, -5127, -8247, -5164, -7936, -8333, -6310, -9380, -5702, -8333, -6988, -8582, -10704, -6973, -8192, -5897, -12534, -9873, -8485, -7004, -5561, -28777, -8549, -9331, -6800, -6225, -12534, -7888, -10526, -8247, -7281, -11232, -7888, -14195, -11781, -7162, -17034, -8517, -28777, -10704, -6885, -10613, -10001, -17034, -8754, -7196, -8009, -11232, -11004, -8247, -7708, -8247, -8683, -8165, -8790, -7796, -8582, -7162, -7247, -8549, -7687, -6602, -6943, -7796, -7730, -7730, -5784, -7730, -9064, -7936, -8165, -6577, -9429, -8333, -9106, -9936, -9380, -11781, -7066, -10069, -11115, -14195, -11356, -6602, -9429, -7247, -8982, -9429, -6653, -8903, -5735, -7984, 10044, 12648, 12998, 9252, 6231, 9325, 12187, 12390, 8700, 5681, 6793, 10765, 10421, 7132, 3998, -1825, 8281, 6402, 5122, 1148, 3219, 4758, 1900, 3557, -2152, 4456, 1711, 3145, 2012, -3412, 3991, 1942, 1400, 204, -5079, 2605, 2961, -1604, -3856, -5020, 1397, 3208, -3417, -3557, -71, 1218, 2542, -2979, -39, 2241, -2135, 353, -2745, 1046, 3469, -1404, -6856, -1711, 2768, 4068, 1609, 1799, -53, 4306, 4109, 1189, 4070, -76, 4861, 3454, 671, 4427, -2467, 4441, 2259, 1918, 3028, -3788, 3064, 2550, 1989, -1738, -1385, 411, 3822, 681, -1108, -1853, -4693, 4093, -654, 1442, -5979, -2592, 3171, -213, 1945, -4064, -520, 1371, 312, 1726, -2731, 491, -451, 514, 673, -4172, 1095, -4067, 545, -219, -3140, 1267, -3468, 233, 1160, -1015, 1002, -20, -487, 2224, -2, 267, 293, -1090, 2237, 417, -1484, -1315, -949, 1348, 442, -6399, -5152, -560, -150, 79, -6399, -4038, -1063, -1862, -811, -3961, -1042, -3078, -3600, -2512, -4491, 588, -1589, -6153, -4420, -6528, 1425, 177, -5374, -5133, -10284, 1468, -12, -1979, -4847, -6480, 442, -2155, -888, -3274, -3468, -2145, -4403, -1535, -3281, -1610, -2664, -1884, -3529, -7004, -258, -546, -685, -5539, -6235, 641, 7, -525, -6856, -3087, 948, -599, -815, -3659, -3047, 583, -2345, -1077, -2153, -5145, -396, -6235, -1402, -2756, -7162, -1909, -5979, -2105, -3910, -4583, -3996, -3094, -2743, -1780, -4957, -5085, -2401, -2268, -343, -15615, -4616, -2809, -1703, -181, -4509, -5380, -3105, -1949, -1173, -2628, -6235, -2039, -3087, -3465, -2982, -5509, -391, -4491, -8060, -4035, -5827, 967, -4918, -9331, -3944, -7796, 1574, -4774, -3798, -3540, -9429, 1143, -5394, -1564, -3490, -6064, -731, -7752, -671, -3748, -3551, -3738, -5437, -746, -3889, -2417, -1854, -2714, -1722, -3521, -2465, -738, -1511, -3910, -2918, -3286, -1072, -1174, -8060, -2807, -4382, -2477, -1487, -7464, -3817, -6016, -4826, -2521, -5726, -6679, -8034, -7542, -4395, -5539, -10526, -12319, -6828, -5979, -6256, -6480, -6123, -4918, -5584, -5862, -3933, -2470, -4038, -4816, -4071, -2659, -1201, -4303, -4592, -2883, -2589, -1456, -5793, -6035, -2460, -4028, -3042, -7984, -11781, -2988, -7230, -5751, -8138, -4491, -5227, -5043, -7865, -7523, -2336, -6590, -3916, -6553, -7426, -1857, -3170, -5299, -5031, -7230, -2367, -1790, -10362, -4985, -6054, -3674, -1497, -7583, -6204, -4935, -6256, -1909, -7162, -5751, -4733, -6225, -2686, -10001, -4097, -5646, -3695, -2793, -28777, -3757, -8649, -2722, -1804, -11232, -4800, -7984, -2733, -812, -9695, -4464, -4357, -3196, -222, -9936, -3005, -3025, -3399, -19, -6719, -3529, -2975, -3094, -215, -4831, -8060, -3659, -3218, -1018, -4541, -4097, -3975, -3947, -2937, -4491, -1958, -3487, -4134, 7316, 10225, 10623, 7748, -1098, 6444, 9621, 10019, 6996, 330, 3271, 7799, 8140, 4473, -135, 1316, 4928, 4844, -755, -2958, 3602, 1795, 905, -1315, -4578, 3296, -1449, -120, -2182, -543, 2161, -5133, 69, -4108, 879, 2607, -1265, -838, -5164, 1283, 3323, 2438, -72, -4365, 1191, 3383, 3844, 822, -5299, 1048, 2823, 4299, -288, -2566, 1369, 1264, 4253, -757, -248, 1858, -2958, 3479, 1529, -219, 1962, -613, 1344, 2185, -1117, 1743, 2218, -4821, 1460, -1255, 1702, 3058, -2541, 806, -793, 2155, 2695, -548, 1142, 382, 2651, 1144, -873, 1061, 1030, 2641, -1772, -2039, 567, 433, 1850, -1000, -2305, 388, -1616, 94, 759, -1155, 220, -5524, -2779, 1119, -359, -388, -10899, -3128, 900, -437, -1029, -9149, -1604, 812, -1352, -970, -4518, -1346, 688, -3425, -397, -1838, -1963, 276, -4455, 54, -450, -2752, -201, -922, 230, -180, -3003, -514, 990, 258, -1194, -2776, -737, 1673, -29, -3391, -3191, -772, 1287, -1143, -2430, -5487, -663, -184, -3641, -919, -10704, -869, -2573, -9695, -833, -5286, -739, -4790, -5662, -1888, -3846, 539, -5654, -2054, -3289, -4486, 1249, -8009, -517, -4003, -6640, 580, -10442, -43, -6183, -2065, -2142, -4805, 189, -6194, -122, -14195, -3130, 952, -2241, -240, -3769, -2325, 2173, -986, -2333, -2605, -1918, 3172, -964, -2885, -3222, -2003, 3383, -1800, -835, -3850, -2724, 2442, -3811, -587, -2578, -3824, -47, -4564, -2234, -1983, -3083, -1844, -2789, -8276, -2234, -1771, -329, -2622, -4606, -2673, -1662, -251, -4112, -2457, -3860, -3425, -1346, -7371, -2355, -6083, -7196, -2443, -11781, -3168, -4929, -2754, -1961, -9331, -3760, -4238, -1298, -1088, -6083, -3130, -5299, -1543, -916, -4344, -2309, -6457, -2969, -1777, -3951, -2170, -5145, -5394, -3850, -4348, -2918, -3509, -9695, -6016, -4991, -4784, -2406, -9022, -5451, -6602, -8138, -1928, -5480, -5387, -6235, -10362, -1952, -4592, -6278, -2902, -7523, -2291, -5599, -5960, -1404, -4907, -2952, -6480, -5121, -990, -3817, -4327, -4968, -5286, -1119, -4254, -7687, -4957, -6457, -1582, -5055, -12123, -7371, -8086, -2442, -4067, -6973, -15615, -8423, -3707, -3422, -5871, -8304, -7050, -5183, -3773, -5516, -5437, -6267, -7888, -4573, -5451, -3518, -7179, -9585, -4837, -5408, -2683, -9380, -3714, -4545, -5844, -2918, -5599, -1799, -4779, -8649, -3846, -3863, -1524, -6225, -8165, -3985, -3600, -2374, -8718, -4541, -3449, -4021, -3447, -9149, -3344, -3635, -4630, -3937, -9639, -3329, -4564, -5818, -4795, -7162, -4089, -4616, -6469, -5776, -4067, -5221, -3886, -4378, -4028, -2320, -5897, -4134, -3110, -2399, -1634, -5801, -5662, -2855, -1746, -2036, -5458, -9531, -2724, -1821, -3624, -4003, -7113, -1902, -2417, -5615, -2626, -3698, -1022, -3235, 2765, 10743, 11015, 7835, 5167, 2573, 10288, 10453, 7230, 4978, 1899, 8926, 8676, 5477, 4404, 431, 6717, 5342, 2971, 3601, -2510, 4089, 826, -759, 2738, -1116, 2331, 280, -2247, 1585, 1335, 1862, -849, 2278, 958, 2037, 1137, -1499, 3142, 1914, 2121, -359, -1606, 2056, 2766, 2493, -1087, -3067, -531, 3083, 2981, -162, -2845, 1494, 2837, 3208, 1678, 256, 2898, 1355, 2995, 3017, 1510, 2431, -5353, 2078, 3266, 983, 412, 1537, 495, 2329, -2220, -1382, 4611, 45, 753, -3692, -1259, 6111, 41, 850, -150, -1056, 6663, -1833, 1379, 313, -442, 6245, -1875, 1210, -688, -234, 4738, 1059, 939, -2566, -954, 2413, 2204, 1007, -4013, -2999, 1451, 2071, 1366, -3296, -7984, 1487, 869, 1630, -1712, -3840, 921, -915, 1398, -1065, -1305, -226, -2019, 816, -2412, -412, -1913, -2990, 328, -8865, -255, -3626, -5214, -124, -1636, -262, -8009, -10138, -168, 335, -17, -4482, -14784, 497, 609, 795, -1324, -17034, 752, -8, 1509, -1330, -7583, 127, -1352, 1536, -3714, -3417, -922, -4438, 861, -2962, -956, -1306, -9695, -311, -1326, 369, -1134, -4601, -2112, -830, 420, -911, -6376, -5164, -172, -1578, -598, -4880, -1971, 136, -5286, -43, -182, 497, -448, -712, 141, 1578, 1353, -1463, -152, -869, 1793, 1056, -1937, -2879, -3883, 367, -338, -2367, -7353, -7230, -3760, -2299, -3354, -2711, -7644, -1205, -1284, -5008, -3989, -10210, 633, 187, -4754, -7335, -4127, 682, 458, -2353, -3213, -2992, -90, -576, -1166, -1239, -3876, -1210, -2589, -1417, 41, -6577, -3225, -1869, -3316, 408, -13365, -7353, -451, -3827, -439, -9238, -4060, 7, -1758, -2403, -5844, -2334, -20, -1021, -2962, -4555, -2334, -169, -989, -2364, -4046, -3504, -466, -932, -3279, -3856, -5735, -1293, -626, -6565, -4161, -12534, -3003, -228, -8649, -4386, -7066, -3961, 29, -5592, -4071, -4536, -2517, -22, -4327, -4258, -4885, -1637, -541, -3723, -5097, -5494, -1446, -1642, -3689, -5678, -3083, -1635, -3085, -4115, -6064, -1838, -2204, -3523, -4100, -7371, -1822, -2881, -3096, -3833, -11004, -2730, -2391, -2975, -4250, -11115, -4578, -1473, -3105, -5784, -8982, -8060, -1479, -2754, -8138, -9284, -10899, -2883, -2100, -8754, -4425, -7583, -5097, -2042, -6870, -2015, -5121, -3005, -2716, -3999, -1423, -3546, -1384, -3054, -2741, -2403, -3342, -965, -2557, -3194, -4880, -5253, -1343, -2505, -4606, -4733, -11629, -2238, -3184, -4307, -3326, -5139, -3401, -4395, -3393, -2979, -4038, -4601, -6163, -1689, -2849, -4784, -5818, -7335, -26, -2541, -5776, -6577, -5260, 622, -2262, -6278, -6173, -4270, 176, -2344, -8485, -4395, -5164, -1242, -3154, -9064, -2849, -8034, -3225, -4912, -4940, -2698, -8034, -4611, -5646, -3286, -5240, -7665, -2419, -6615, -3482, -1846, -3281, -626, -3304, -2130, -2175, -3569, -105, -1262, -1182, -2008, -3566, -743, -1087, -1198, -1819, -3225, -2300, -2635, -2576, -1603, -3257, -4060, -7146, -3626, -1013, -4438, -5437, -7936, -2214, -312, -9238, -7708, -5997, -2372, -132, -4957, -6666, -6958, -5862, -837, -2285, -3566, -10613, -5049, -2419, -1986, -1772, -13365, -1771, -3680, -3837, -688, -7752, -1085, -3624, -5906, -101, -5844, -1654, -3683, -2975, -80, -5067, -3108, -4336, -2094, -818, -3653, -4071, -4399, -2458, -2770, -2002, -2608, -3158, -3163, -8423, -1108, -1685, -2458, -3751, -6204, -1100, -2282, -2364, -4010, -3210, -1825, -4769, -1646, -3237, -2445, -2762, -5240, -595, -1689, -2711, -3840, -3751, -258, -376, -3744, -6745, -4738, -699, 97, -5367, -9812, -10613, -1406, -557, -6256, -3866, -7796, -1864, -2613, -5008, -1892, -6528, -2502, -5915, -3961, -1087, -9585, -4365, -5387, -3766, -939, -8549, -9753, -3092, -4323, -1217, -6153, -8827, -1828, -5444, -1731, -6246, -7984, -1501, -6745, -2312, -6492, -7230, -1312, -7335, -2475, -4923, -5374, -1098, -7081, -1852, -3586, -4395, -1695, -7842, -1203, -3354, -3992, -3412, -9873, -1341, -4654, -5026, -4382, -8982, -2635, -8649, -8247, -4403, -9022, -4907, -10799, -5801, -6434, -11004, -4858, -9284, -4644, -13049, -8086, -3537, -8060, -5623, -10526, -6469, -3049, -6173, -8683, -28777, -5607, -3119, -4968, -28777, -9753, -5273, -3900, -4161, -13049, -8276, -5437, -6540, -3833, -11232, -5214, -4831, -10526, -3760, -8517, -2564, -4592, -6814, -3386, -5818, -1433, -6528, -7317, -2829, -4082, -1436, -14784, -11945, -2726, -3085, -2257, -8582, -11488, -3365, -2514, -3656, -10799, -11629, -4482, -2470, -4985, -8333, -28777, -4611, -3554, -4597, -5319, -12319, -4361, -7730, -3785, -4858, -13738, -5026, -6773, -4104, -5408, -8942, -5784, -3362, -6615, -5768, -6214, -5451, -2619, -12534, -6026, -5221, -5127, -3054, -5415, -7130, -4951, -5319, -3954, -3927, -8220, -4940, -6590, -3920, -4246, -7936, -5333, -8549, -2853, -6759, -7888, -7213, -6553, -2364, -12319, -5801, -28777, -4863, -3415, -5576, -3668, -6759, -3641, -8517, -3741, -2813, -4764, -2541, -5615, -2982, -3177, -4518, -1999, -2945, -2505, -4918, -4963, -2257, -2580, -2165, -9429, -5158, -3309, -3096, -2128, -11488, -5020, -4929, -3529, -2610, -7960, -5189, -5615, -3927, -3827, -8517, -6204, -4460, -4718, -5678, -13365, -8827, -3455, -5623, -7389, -11945, -13738, -3135, -6388, -9429, -9753, -9479, -3319, -7644, -7503, -10138, -7752, -3583, -10442, -4723, -11945, -7562, -3635, -28777, -3735, -17034, -8517, -3804, -9585, -3906, -12319, -9639, -4282, -7247, -4640, -9531, -9022, -4042, -5942, -5437, -8363, -8582, -3038, -4912, -6492, -7774, -7774, -2550, -4207, -8060, -7335, -7019, -2895, -4024, -10362, -7603, -7936, -4172, -4532, -14195, -9812, -13365, -6786, -6153, -9380, -6365, -2564, -2516, -966, -3968, -5607, -4513, -2347, -2244, -4991, -3339, -8304, -2545, -4968, -7317, -2173, -4764, -3215, -5097, -14784, -2146, -4278, -5037, -4323, -9812, -2937, -6054, -9479, -3662, -8903, -4408, -4728, -9936, -2453, -8827, -7034, -2265, -7426, -2132, -5429, -4929, -1286, -6422, -3182, -3776, -2223, -1296, -5888, -5502, -3196, -1202, -1811, -5793, -6256, -2943, -1328, -2093, -6480, -6133, -2835, -2396, -2184, -7162, -8754, -2781, -4199, -3110, -4028, -12123, -2592, -5638, -5630, -1975, -6759, -2487, -4837, -4847, -1230, -5487, -2758, -3999, -2492, -1394, -4138, -3523, -4718, -1697, -2239, -2191, -4935, -10138, -2014, -3671, -654, -8112, -5951, -3362, -6074, 198, -10284, -3029, -5531, -11629, 268, -4164, -2677, -5743, -12319, -477, -2062, -4038, -4640, -8333, -1868, -1537, -4963, -4060, -6422, -3038, -2447, -3910, -3110, -5240, -2929, -5164, -4550, -2166, -3957, -2080, -7819, -8649, -2393, -3112, -1543, -4907, -7004, -4748, -3357, -1671, -2475, -4649, -12776, -5079, -2528, -1033, -4278, -4123, -8942, -3893, -933, -4640, -2488, -5561, -3583, -2696, -4805, -2419, -3087, -2260, -9639, -4344, -3094, -2082, -1644, -3624, -3923, -3018, -2107, -1825, -1752, -4046, -2219, -3201, -2922, -1724, -4821, -1952, -5584, -5726, -2803, -5871, -2374, -6679, -8138, -4718, -6183, -3114, -5286, -4795, -6773, -5158, -3580, -4759, -3337, -8304, -4242, -3420, -3222, -2967, -9873, -3468, -3083, -1514, -3916, -8942, -2737, -3196, -851, -7213, -7371, -2628, -4290, -1397, -8220, -5031, -3441, -6565, -3518, -8517, -2924, -5306, -7623, -9639, -7936, -2083, -6666, -7730, -7623, -4199, -2509, -3910, -10526, -5871, -3420, -3331, -2225, -5279, -6113, -4307, -3147, -2053, -2893, -7335, -5879, -3314, -3463, -2398, -8393, -6870, -4980, -7542, -3314, -5915, -7484, -8683, -11115, -5979, -4420, -10442, -15615, -7389, -12319, -4319, -9695, -10284, -6973, -5924, -5227, -5862, -5997, -7162, -3720, -6615, -5133, -4323, -6786, -3023, -7230, -5853, -4336, -5623, -3650, -7179, -7730, -5115, -4974, -5862, -7687, -13049, -4153, -5818, -5997, -8247, -10210, -2795, -8754, -3618, -5836, -6928, -2115, -6332, -2590, -3686, -6343, -1878, -4246, -2450, -2675, -7371, -1699, -4067, -2889, -2369, -11004, -1353, -5678, -4017, -2450, -11781, -1020, -12123, -6745, -2751, -8247, -1076, -6615, -8165, -3114, -7426, -1890, -4056, -4616, -3412, -7960, -4046, -3571, -3707, -3883, -8485, -10069, -4754, -4386, -5079, -6786, -5662, -8423, -6732, -7865, -4957, -3373, -7281, -14195, -9753, -3906, -2778, -5152, -8982, -5784, -3501, -3058, -4748, -5853, -3961, -3641, -3707, -4429, -4616, -3227, -4086, -4274, -3487, -4587, -3154, -4559, -4918, -2617, -5735, -3507, -4880, -6074, -2248, -8034, -4307, -5109, -7335, -2512, -9064, -5924, -5292, -8086, -3463, -8276, -8754, -5502, -7299, -5170, -8393, -9639, -6204, -5646, -5638, -4606, -2845, -6278, -11115, -8718, -5008, -3045, -1236, -9106, -4946, -4323, -2920, 372, -6540, -2630, -1996, -2108, 535, -6123, -2531, -1262, -1384, -353, -4842, -3879, -2378, -1149, -2111, -3078, -3910, -5561, -1536, -4319, -2291, -2204, -4134, -2692, -6288, -2541, -1237, -2711, -4199, -8649, -3375, -1152, -2827, -4142, -11004, -3729, -1662, -3744, -3720, -5176, -3523, -2288, -5599, -4286, -2929, -3856, -3194, -7960, -5988, -2138, -5387, -5710, -4963, -10362, -2385, -6492, -28777, -3114, -7299, -3850, -3624, -7146, -2550, -4644, -7583, -1693, -6800, -2875, -4097, -5286, -1039, -9064, -4064, -3615, -2458, -1752, -12319, -6679, -1793, -1298, -4336, -5888, -8165, -202, -1070, -6828, -3449, -5686, 616, -1634, -4664, -3074, -4821, 710, -2984, -5145, -4810, -4425, 164, -4664, -10899, -8192, -5014, -985, -3856, -6870, -4464, -8790, -2733, -2241, -4433, -2904, -8485, -4890, -1319, -4754, -2799, -5561, -6399, -1020, -7264, -3626, -5360, -7730, -1508, -9812, -4946, -6113, -9429, -3215, -8827, -5924, -7984, -5502, -6692, -9284, -6480, -12123, -3989, -5387, -8649, -6786, -8247, -4985, -3609, -6653, -7562, -6267, -9695, -3594, -4460, -9106, -5487, -4013, -5662, -3119, -5726, -5670, -2075, -11781, -2709, -2931, -7004, -1868, -4805, -2964, -1551, -6422, -2709, -2941, -3504, -1157, -4134, -4464, -2254, -4161, -1587, -3487, -7317, -2155, -4810, -2900, -4460, -8754, -2803, -4826, -5751, -6590, -7146, -3889, -4504, -28777, -7213, -5768, -3692, -5085, -5933, -5906, -4532, -3161, -6653, -3729, -3814, -3504, -3971, -7623, -2557, -2758, -2924, -7081, -8112, -1713, -3179, -2924, -6705, -8790, -1219, -4863, -3566, -3968, -9149, -1239, -4611, -5158, -3357, -9380, -1735, -3342, -9106, -4344, -7353, -2398, -3518, -9380, -6943, -5654, -3014, -5561, -6321, -6064, -4365, -3944, -12319, -5710, -4611, -3526, -5710, -8485, -5444, -5312, -3474, -8549, -7004, -4395, -10899, -4382, -14195, -5539, -3729, -6007, -6354, -14784, -3732, -4262, -2947, -6988, -12776, -3108, -6504, -2071, -4940, -7665, -3644, -11629, -2495, -3804, -4541, -4748, -8903, -4082, -3624, -2947, -5152, -7752, -6973, -3900, -2166, -4416, -7146, -10899, -4112, -1940, -3644, -6016, -8138, -4644, -2419, -3853, -5524, -5319, -6492, -3795, -5810, -5997, -4053, -8754, -5933, -13738, -7542, -3896, -6299, -6828, -6093, -10899, -4455, -5353, -5145, -3837, -17034, -5253, -5710, -3860, -3184, -9812, -6399, -6705, -3479, -2956, -7936, -8865, -7146, -3964, -2407, -7371, -14195, -5979, -5208, -2008, -7484, -10899, -5109, -7162, -2302, -7603, -8903, -5214, -10001, -3428, -6480, -8060, -5584, -11781, -5654, -5227, -7335, -5408, -15615, -7865, -4858, -6204, -5176, -8304, -5214, -5751, -5043, -5266, -4963, -3804, -8718, -4153, -5292, -3769, -3951, -8034, -3407, -4951, -3840, -5702, -5091, -2760, -4688, -4616, -10442, -4168, -2538, -5170, 2924, -234, 1360, 6807, -8942, 2066, -2370, 4384, 6357, -5810, -141, -2316, 6118, 5078, -3900, 1102, 864, 6272, 3574, -2939, 2871, 2029, 4982, 2947, -2191, 3429, 2929, 1313, 2390, -2148, 2957, 3148, -353, 643, -5437, 1123, 2033, 3041, -4403, -2204, -4885, -1104, 3754, -2053, 1954, -1183, -6719, 3043, 205, 3676, 1865, -4172, 491, -267, 4413, 2821, -3653, -7752, -1049, 4868, 2344, -1888, -199, 1694, 5207, -359, -9, 972, 3120, 5050, -1632, 595, 83, 3046, 3874, 1955, -1268, -1515, 1653, 578, 2733, -2034, -634, -75, -912, 1786, 2552, 214, 1121, 2255, -864, 3972, 473, 2128, 2530, -2273, 3661, 640, 1934, 1253, -825, 1861, 457, 1079, -446, 292, 123, -219, 514, -4874, 1881, 460, -1259, 630, 63, 3071, 42, -3388, 1278, 3589, 3387, -516, -9639, 1572, 4619, 2800, -265, -1659, 633, 4027, 1366, -817, 320, -2517, 1686, -799, -2762, 270, -7665, -3930, -3968, -4713, -1864, -3692, -3304, -8718, -6299, -8363, -1474, -2526, -3249, -5234, -3128, 612, -2094, -1855, -1449, -2152, 1371, -497, -3147, -19, -3518, 798, 62, -7562, -156, -7317, -391, -900, -2639, -1790, -4858, -388, -3518, -1365, -3726, -2659, -173, -2541, -1549, -2762, -1254, -1080, -837, -1402, -3177, -87, -3883, -672, -1136, -3546, 612, -14195, -1556, -2185, -1011, 683, -5189, -3092, -3299, -127, 255, -4810, -4674, -1074, -408, 469, -5158, -5810, -458, -152, 1380, -2644, -7730, -1654, -81, 1634, -864, -9193, -1208, -2163, 1154, -51, -2672, 674, -4991, 832, 155, -175, 1435, -1433, 1013, -131, 761, 1314, -1182, 998, -1065, 724, 444, -1811, 564, -3135, 65, -1033, -1320, -218, -5221, -1064, -2295, -1850, -1008, -2359, -3001, -2817, -4985, -1698, -306, -5472, -3717, -3147, -3766, 626, -2825, -5915, -875, -8517, 689, -1373, -9695, -643, -1522, 110, -1799, -10284, -1952, 328, -645, -4550, -8393, -5158, 462, -1073, -10704, -4880, -6958, -523, -1486, -3526, -2364, -4800, -1611, -3433, -1904, -806, -4017, -1034, -5607, -2280, -95, -3671, 811, -744, -5607, -347, -3247, 2261, 644, -6480, -1863, -3210, 2734, 110, -1799, -5103, -4810, 2098, -2285, 184, -4659, -28777, 205, -6692, 1041, -2109, -4049, -3264, -9531, 934, -473, -1838, -10704, -5037, -22, 605, -915, -4630, -2875, -1556, 1152, -403, -688, -2859, -2705, 1070, -564, 939, -4733, -2610, 57, -1773, 1155, -6814, -2105, -2377, -3521, 70, -4006, -1277, -6842, -3920, -2624, -2128, -785, -7230, -2054, -4800, -1131, -268, -5480, 427, -2743, -550, 863, -1591, 1982, -1959, -690, 1399, 994, 2627, -2102, -2931, 751, 2205, 2455, -2624, -3235, -981, 2081, 1425, -2661, 732, -2168, 111, -357, -1579, 1804, -2049, 4113, 8691, 7936, 8773, 6012, 3561, 8072, 7149, 8102, 5618, 2114, 6090, 4494, 5874, 4286, 385, 2467, -1467, 1335, 1442, 105, 335, -1512, 891, -3557, 1448, 19, -294, 1187, -653, 1670, 457, 2284, -59, 86, -162, 3511, 3895, 1882, -446, -6310, 5241, 4882, 3950, -804, -1085, 5595, 5534, 4332, 72, 356, 4540, 5713, 2430, 2068, -210, 2264, 5244, -849, 3407, -2129, 3099, 3913, 3563, 3660, -2831, 4469, 1707, 4593, 2972, -179, 4352, 1895, 3800, 1685, 2669, 2937, 3096, 1376, 261, 4384, 420, 2850, -1704, -616, 4854, -2821, 1300, 224, 367, 4011, -3808, -1286, 1808, 2210, 2310, -734, -2758, 2566, 3511, 3004, 259, 414, 3084, 3724, 3945, -255, 2119, 3767, 2385, 3371, -1544, 2519, 4192, -706, 1226, -2429, 2071, 3811, 1582, 282, -1773, 1347, 2525, 3374, 1664, 379, 898, 1309, 3933, 1804, 2168, 288, 1062, 3877, 646, 3217, -1270, 233, 3216, -1975, 3667, -4164, -1948, 1802, -2098, 3631, -8333, -6113, 150, 474, 3106, -8790, -8220, -278, 1453, 1924, -3837, -2977, -114, 1011, 19, -2664, -1399, 94, -1305, -645, -4176, -949, 577, -9064, 109, -5988, -689, 1392, -3321, -468, -1586, -771, 2221, -2843, -2881, 62, -2235, 2652, -4847, -3319, 490, -8304, 2491, -3296, -2752, 628, -4119, 1624, -1343, -3792, 1106, -1913, -182, -769, -3468, 1773, -1367, -3732, -871, -2650, 2176, -909, -5394, -1065, -2475, 2162, -896, -2016, -1130, -4299, 1644, -2359, -556, -1455, -6422, 532, -5037, -201, -2679, -824, 28, -2585, -882, -4451, 369, 777, -1683, -2733, -3365, -473, 747, -3401, -5387, -1928, -1848, -261, -6692, -6365, -1282, -987, -1277, -1773, -4270, -1254, -573, -2485, -30, -2253, -1887, -1288, -5897, 664, -1411, -4299, -3025, -8718, 914, -1321, -6528, -4620, -6973, 688, -1803, -1524, -3971, -5121, -178, -4003, -500, -3689, -2490, -1697, -8112, -1699, -3574, -1091, -3811, -2169, -4250, -3142, -530, -6928, -593, -4357, -3040, -547, -7842, -284, -8138, -3349, -1001, -5195, -504, -3089, -3996, -1679, -4620, -1564, 149, -5561, -2452, -6064, -5333, 1287, -5960, -3624, -12534, -6640, 1418, -2448, -5915, -6133, -2910, 947, -686, -5979, -2606, -2756, -117, -344, -3409, -751, -4266, -2165, -1087, -2391, 30, -7960, -4119, -1837, -1825, -57, -11356, -3225, -1303, -1099, -336, -8549, -3779, -1152, -668, -39, -9022, -8517, -2114, -534, 504, -3420, -7484, -3543, -1040, 1034, -1859, -5415, -3301, -3321, 1024, -2789, -4985, -1226, -3566, -591, -7281, -2912, 223, -1232, -11781, -3479, -1176, 639, -825, -757, -1218, -333, 583, -482, 1616, -476, -729, 900, 508, 2382, -451, -3326, 1327, 1147, 2418, -949, -4473, 1318, 1271, 1921, -2132, 6050, 7975, 8032, 3262, 3201, 5282, 7235, 7407, 4445, 2276, 2882, 4845, 5384, 5737, 1543, -1581, 449, 1204, 6321, 2762, -4365, -1218, -3344, 6202, 1952, 697, 1027, -807, 4913, -3001, 1699, 2207, -634, 394, 156, 1344, 1875, -264, 1794, -994, 1845, 390, 450, 4710, 1510, 2609, -843, -70, 5194, 4848, 2799, 63, -4254, 4680, 5567, 2411, 370, -2308, 3521, 5001, 1114, -894, 1299, 1143, 4606, -326, -3257, 2247, -1267, 4612, 1278, -6666, 1843, 1748, 4153, 2514, -7819, 240, 2820, 3522, 2479, -2283, -3457, 2246, 3871, 1252, 316, -4963, -251, 4898, -861, 2145, -449, -4184, 5257, -1712, 3381, 1314, 194, 4585, -2030, 4337, 2095, 1821, 3929, -4491, 5204, 2646, 2246, 5191, -8220, 5754, 3360, 2008, 6461, -3023, 5697, 3878, 1433, 6915, -40, 4936, 3757, 724, 6530, 1680, 3604, 2780, -300, 5228, 2082, 1923, 676, -2526, 2835, 897, -653, -3668, -5103, -394, -2621, -5853, -5176, -921, -537, -1319, -3142, -1849, 1016, 1414, 647, -2320, -801, 1527, 2562, 925, -3433, -294, 822, 2712, 282, -4842, 242, -1181, 1703, -850, -2309, 769, -1463, -1062, -781, -1052, 1003, 651, -1707, 543, -2061, 541, 1790, 194, 1207, -2345, -1065, 2238, -233, 958, 605, -1566, 2360, -3110, -13, 1942, 931, 2335, -4238, -883, 2114, 2319, 2134, -1013, -851, 1496, 2564, 1534, 32, -915, 278, 1735, 223, -847, -1878, -919, -350, -1991, -4403, -3606, -914, -2020, -3996, -3729, -3729, -993, -544, -4340, -3279, -2585, -2173, -113, -5266, -7774, -2133, -2378, -1091, -6113, -3526, -2512, -1154, -2937, -5458, -1749, -3840, -1378, -2273, -4929, -1987, -5646, -3798, -779, -5286, -2500, -4223, -4698, -480, -5979, -1443, -1889, -2670, -1206, -3674, -34, -395, -3515, -2195, -1741, 739, 45, -10613, -2889, -1006, 747, -929, -6163, -4176, -1250, -63, -3677, -7353, -4800, -1811, -1627, -2330, -4378, -2793, -1310, -2519, -720, -535, -1182, -200, -1823, -1173, 333, -240, 992, -1736, -3930, -823, 254, 1875, -2877, -14195, -4327, 429, 1936, -5827, -6504, -7523, 100, 813, -9531, -2797, -14784, -1054, -2146, -3889, -581, -4420, -3133, -14195, -1062, 378, -1799, -3269, -5465, 192, 678, -927, -1330, -3866, -7, 821, -670, 64, -2156, -1573, 914, -1065, 811, -1184, -1349, 635, -1633, 984, -1702, 282, -463, -217, 855, -4344, 555, -2393, 1105, 618, -4805, -601, -3294, 1347, -242, -3110, -3362, -1070, 658, -2683, -4420, -8615, 1182, -686, -3766, -8086, -7708, 2334, -1922, -1963, -3096, -3438, 2464, -2055, -2703, -1314, -1462, 1785, -1641, -7865, -740, -628, 493, -1010, -5702, -958, -332, -1390, -484, -3337, -2440, -311, -4017, -811, -2766, -4013, -576, -2857, -601, -209, 1245, -2673, 1298, 661, 654, 252, -3543, 2971, 1013, 516, 721, -1936, 3338, 131, -1375, 1236, 68, 3018, -2696, -3785, 1177, 1327, 2426, -9479, 78, 947, 1651, 1838, -2398, 1391, 788, 1071, 1239, -1269, 853, 440, 207, 422, -2348, -1860, -494, -280, -847, -6943, -6679, -1943, -1402, -2452, -3386, -2319, -2529, -4097, -2941, -1127, -1404, -1853, -3172, -1189, -1047, -1489, -1293, -1244, 742, -1659, -1798, -999, -860, 1749, -437, -1694, -812, -1739, 1622, 713, -542, -1050, -4649, 172, 485, 468, -2975, -4469, -2941, -1694, 432, -6943, -1207, -3695, -9064, -1197, -156, -526, -2305, -1646, -6842, 2017, -2334, -1990, 112, -4635, 2738, -3665, -1633, -169, -2789, 2674, 337, -998, -2152, -2605, 2265, 1508, -769, -989, -1740, 1727, 820, -1605, 824, -1331, 879, -2153, -4486, 998, -2066, -701, -5726, -7984, 154, -2473, -3347, -1741, -3680, -452, -1129, -5988, -295, -2648, 89, -513, -7912, 518, -2935, 827, -1335, -6973, 1122, -3586, 1136, -4013, -3137, 1470, -3014, 998, -3760, -1580, 1242, -1921, 720, -1046, -2050, 383, -1482, 581, -225, -6828, -213, -2076, 381, -1055, -3856, -468, -4669, -379, -4119, -941, -1887, -8086, -1652, -10001, -525, -5319, -2455, -1481, -5686, -1408, -8865, -498, -429, -4764, -3586, -6988, 264, -220, -4340, -10899, -2564, -67, -1095, -4790, -4145, -1311, -2416, -2619, -7752, -1577, -1593, -10442, -2425, -6814, -1118, -1611, -2668, -1617, -2906, -1637, -1051, -2626, -1753, -1652, -1893, -945, -4769, -2670, -1755, -2032, -746, -1679, -4130, -2514, -1775, 111, -362, -5871, -2797, -574, 893, -1074, -6800, -2849, -138, 908, -3609, -5531, -4003, -1267, -211, -3094, -3923, -7542, -5208, -2813, -1256, -3373, -15615, -4963, -6692, -761, -4184, -9479, -2522, -8517, -1169, -5979, -6856, -2100, -11232, -2406, -6870, -5458, -1852, -8942, -4112, -5924, -4089, -900, -7146, -3294, -5002, -1823, 169, -4784, -1973, -5638, -466, 480, -2480, -2023, -9753, -169, -562, -1384, -3373, -7819, -484, -3529, -1255, -4242, -5793, -726, -2587, -1207, -3507, -5960, -532, -732, -1140, -3689, -5531, -269, -583, -1970, -4805, -4896, -342, -1430, -4010, -4089, -5630, -886, -2861, -5097, -2887, -7281, -1953, -4728, -4042, -2988, -7936, -3518, -7408, -2683, -4901, -7230, -4425, -10799, -2119, -8582, -4974, -4064, -10799, -3194, -4486, -3365, -3757, -10069, -8220, -2703, -2653, -3603, -9149, -4718, -2659, -2714, -3249, -8086, -1904, -4378, -3665, -2720, -6870, -1067, -10284, -5718, -2090, -5480, -1219, -6480, -8718, -1369, -4104, -2034, -3975, -9331, -729, -3105, -3286, -2929, -7484, -376, -2741, -4723, -2309, -7665, -337, -3261, -6411, -2066, -9812, -478, -5091, -8517, -2555, -5152, -695, -9873, -6679, -709, 749, 1073, 789, -4541, 740, -577, 904, -1058, -8549, 1156, -3551, 870, -2166, -4386, 753, -10001, 436, -1854, -2253, -719, -4433, -1178, -2129, -1395, -3856, -3428, -5888, -2566, -1168, -8363, -2084, -7562, -2633, -1356, -4616, -531, -5942, -3401, -2072, -258, 85, -6183, -5810, -3054, 1888, -54, -3161, -11781, -3119, 2511, -246, -2468, -7644, -2450, 1853, -121, -3147, -6278, -2181, -247, 11, -3612, -7066, -2650, -5299, -127, -3151, -10284, -4038, -6445, -541, -1998, -6173, -4527, -3045, -1063, -1405, -3321, -2004, -2385, -1916, -2125, -2698, -337, -3695, -3870, -4395, -3023, 292, -6045, -4863, -5502, -1621, 209, -1432, -3023, -4172, -233, -193, 118, -2617, -4299, 0, -488, -440, -2986, -5768, -739, -495, -3142, -2155, -5333, -2004, -517, -1988, -821, -2964, -2662, -907, -31, 89, -1550, -1799, -1979, 87, 592, -1302, -483, -3498, -1293, 585, -2385, 208, -2361, -4738, -436, -5170, -160, -283, -7097, -4053, -8220, -2018, 734, -3827, -4635, -7730, -3386, 706, -3060, -911, -8060, -798, -471, -4067, -11, -7912, 597, -3827, -9531, 182, -6480, 923, -4578, -5437, 365, -5429, 456, -925, -1790, 118, -5394, -811, 63, -111, -1167, -6064, -3532, -400, 533, -3989, -7213, -10526, -2068, 359, -6422, -10138, -2003, -4071, -239, -3110, -10069, 33, -3732, -1289, -949, -4361, 77, -3266, -4464, -87, -2066, -2130, -4056, -7019, -314, -1101, -13365, -6628, -2339, -1238, -1084, -3460, -15615, -1271, -2168, -1814, -3509, -10001, -1096, -3409, -2799, -8683, -8247, -1614, -4874, -3360, -6885, -6653, -2813, -1683, -3244, -5127, -4592, -2119, 410, -2815, -5607, -2984, -1017, 1034, -2849, -4718, -2339, -1382, 479, -3621, -2865, -2699, -3227, -1015, -4659, -1931, -4149, -5623, -2973, -5037, -2545, -7389, -5353, -5997, -5189, -6256, -6074, -3352, -5306, -6457, -7317, -2653, -2153, -1521, -8304, -3496, -1321, -1957, -14, -6899, -2977, -1733, -2514, 171, -5933, -3723, -4425, -3744, -520, -5008, -4946, -2383, -5299, -1011, -3349, -5472, 306, -3824, -392, -1729, -4344, 1274, -1784, 296, -718, -2797, 1281, -1105, 520, -301, -2020, 748, -1867, 155, -361, -2268, -138, -4649, -1076, -1074, -3468, -1559, -11115, -3370, -2871, -5312, -4112, -4620, -3449, -6256, -7665, -8982, -2952, -1940, -11488, -9753, -5960, -2522, -1542, -15615, -8192, -4390, -2945, -1807, -14195, -4412, -4115, -4620, -2347, -10210, -1902, -4075, -7888, -2982, -5509, -675, -3999, -5240, -3449, -3098, -513, -3982, -3792, -3249, -1768, -1423, -4031, -3923, -2986, -1088, -3837, -3493, -2879, -3624, -915, -10704, -2670, -1344, -5810, -1065, -8247, -2505, -1144, -9022, -1416, -7389, -3147, -2672, -7912, -2207, -9284, -3971, -7562, -8112, -3779, -7179, -4153, -7264, -10001, -5844, -5319, -3853, -6204, -2741, -1903, -147, -1215, -9380, -3463, -862, 2102, -2152, -7247, -632, -530, 3003, -3222, -3889, 647, -1274, 2930, -3201, -3563, 860, -3294, 2001, -1062, -5997, 307, -6035, 89, 314, -7426, -960, -5480, -2146, 416, -3436, -3007, -4295, -1282, -359, -2462, -4108, -4172, -637, -1090, -2999, -2728, -4853, -1076, -1717, -3485, -1733, -3686, -1728, -2482, -2156, -1543, -1748, -1637, -2655, -1439, -1873, -858, -793, -2897, -2606, -1940, -1012, -339, -3375, -7004, -1064, -1882, -1002, -4718, -2574, -63, -2596, -3474, -5465, -942, 266, -3837, -6434, -2720, -1802, -687, -9106, -1718, -2477, -5915, -5026, -1501, 50, -5247, -3540, -3177, 1141, 87, -3487, -1670, 33, 2131, -1875, -1046, -1908, 910, 2149, -3886, -485, -2378, 1063, 1523, -375, -819, -1366, 804, 560, 919, -1498, -714, 76, -571, 758, -2396, -1143, -510, -2152, -573, -3776, -2192, -1300, -4564, -2908, -6016, -2500, -4373, -6194, -4951, -9936, -2613, -8549, -7004, -4728, -10899, -3792, -3515, -7912, -2312, -6590, -6388, -2443, -5979, -383, -3996, -6679, -2241, -5422, 538, -2018, -4698, -3393, -6332, 634, -883, -4149, -8423, -7445, -6, -973, -2641, -6773, -9479, -1308, -2745, -347, -4053, -14195, -3140, -7113, 920, -3114, -7503, -4654, -6914, 1292, -2040, -6204, -1914, -7299, 1184, -1188, -5615, 295, -8718, 830, -897, -4295, 986, -5458, -97, -1002, -3512, 450, -3354, -2265, -1050, -3529, -858, -2170, -5751, -827, -3760, -2152, -1726, -3038, -749, -3804, -3773, -1651, -663, -1448, -3906, -5888, -1802, 726, -3982, -4060, -4108, -2247, 1211, -7353, -3526, -2184, -2785, 685, -2774, -2952, -1182, -3014, -1072, -2000, -3860, -1123, -3142, -4266, -4056, -10138, -1974, -4038, -4395, -7912, -4238, -2404, -7130, -3103, -2256, -1768, -1397, -10284, -3603, -916, -1850, -798, -6565, -6310, -1300, -4536, -1077, -5509, -5437, -3175, -5960, -1790, -3274, -2552, -7034, -2596, -1533, -1529, -1532, -13738, -1816, -679, -836, -1527, -8942, -2083, -526, -1005, -2541, -6786, -2910, -1432, -1894, -6899, -8333, -5020, -3597, -3455, -4831, -5607, -11945, -7130, -5623, -1396, -2879, -6422, -6225, -6299, -824, -2887, -5152, -3893, -4764, -1813, -4630, -4784, -2783, -3754, -3951, -2653, -3551, -2612, -3087, -5176, -1005, -2781, -3347, -2534, -3244, -877, -2825, -4929, -2350, -1650, -1693, -3433, -4779, -2696, -1063, -2150, -4769, -3076, -3452, -1459, -1511, -7445, -2646, -4403, -2964, -1259, -9193, -3714, -5097, -6332, -2214, -8615, -6399, -4940, -13365, -5091, -10001, -7960, -4918, -7335, -11356, -13049, -6235, -5429, -8060, -5367, -9753, -4523, -3903, -8138, -3621, -6914, -2847, -2291, -3521, -3144, -6163, -1782, -2057, -1672, -3535, -7004, -1395, -3130, -1264, -4482, -7842, -1332, -5002, -1865, -5465, -7984, -1394, -5776, 9769, 6855, 9619, 7873, -3078, 9177, 6752, 9152, 7200, -1055, 7333, 6116, 7837, 4981, 348, 4069, 4419, 6083, 1119, 1049, 119, 1465, 4351, 1858, 1673, -395, 163, 2094, 2644, 1980, 500, 1204, -1384, 2232, 1923, -56, 1983, -1361, 1315, 1625, 5, 2429, -92, 134, 947, 2500, 2451, -816, -968, 213, 4231, 2225, -1921, -654, 1059, 5210, 2732, 574, 95, 2593, 5428, 3905, 1860, 549, 3684, 4655, 4581, 1394, 1347, 4413, 2737, 4293, -2031, 1791, 5014, 1532, 2643, -494, 881, 5499, 2091, -1937, 2910, -2235, 5614, 1513, -798, 3929, -1957, 5017, 1211, 1418, 3626, 37, 3356, 2627, 1121, 2149, 162, 263, 3491, -1133, -964, -645, -2483, 3994, -6299, -5951, -1007, 677, 4492, -6745, -2576, -229, 3384, 4505, -3089, -2109, 219, 4694, 3663, -587, -3254, -430, 4865, 2234, 59, -4447, -1858, 4118, 1442, -1265, -3632, -1008, 2796, 1035, -4451, -2447, 231, 1771, 52, -1766, -3049, 359, 1503, -253, -28, -6492, -305, 1201, 696, 906, -1032, -1226, 422, 1320, 1853, 1128, -576, -569, 1342, 2422, 1451, 1376, -663, 898, 2146, 613, 2591, -229, 323, 491, -535, 2781, -729, 332, -5139, -770, 1932, -3034, 880, -1125, -904, -161, -7113, 1135, 1081, -2159, -4097, -4513, 594, 806, -5662, -7371, -3449, -813, -1595, -10899, -7066, -3012, -2521, -2262, -4683, -4597, -2924, -3058, -570, -2429, -2622, -3135, -2624, -941, -1569, -2289, -2967, -2924, -2677, -2184, -2869, -2228, -5726, -2550, -4863, -3085, -1432, -8086, -1446, -8333, -3189, -1390, -2975, -1159, -4145, -4748, -2608, -1704, -1385, -2234, -8649, -5026, -1918, -1864, -1439, -6365, -5014, -2857, -2550, -1763, -5942, -4569, -3294, -3296, -2954, -8009, -6516, -3683, -3726, -3254, -7623, -5326, -5152, -4262, -2592, -5784, -2538, -6640, -6007, -2288, -5260, -2069, -7019, -8165, -2334, -6246, -3744, -13049, -6666, -2601, -5979, -8754, -5997, -6565, -2720, -3487, -8034, -3163, -6814, -2534, -2499, -7665, -2601, -4254, -2698, -2969, -5784, -3449, -2380, -3665, -4997, -5247, -5429, -1660, -5415, -9531, -6899, -8165, -1889, -6773, -8220, -5509, -8982, -3121, -5509, -5561, -4078, -6504, -5569, -3474, -4412, -4399, -4246, -9812, -2548, -4119, -6445, -3020, -14784, -2606, -4082, -5133, -2853, -9479, -2988, -3978, -2267, -3388, -6773, -3291, -4504, -1141, -3154, -4831, -3632, -6666, -1165, -2105, -3554, -4089, -8393, -1857, -1498, -3124, -4795, -5638, -2644, -1553, -3873, -5906, -4311, -3276, -2347, -6434, -7389, -2920, -3846, -4299, -7213, -7752, -1706, -3476, -9284, -3194, -5008, -933, -2935, -9284, -941, -2543, -461, -3339, -5827, 185, -1084, -645, -4373, -4880, 258, -545, -1922, -4184, -5623, -864, -852, -4545, -2571, -10704, -3014, -1778, -8363, -777, 3635, 4384, 1687, -227, 2784, 3471, 4154, 4135, -37, 2584, 2680, 3439, 5566, 480, 2660, 359, 2276, 5339, 1050, 3081, -3546, 859, 3326, 1143, 3028, 373, -932, -2956, 435, 2454, 1205, -2433, 1387, 454, 1202, 35, -1587, 3163, 1920, -1775, -2811, 337, 3076, 2428, -7752, -6246, 2418, 1908, 1587, -5576, -198, 4141, -330, -500, -1397, 2932, 5306, -2173, -3518, 1349, 4328, 5803, -968, -4486, 2056, 4561, 5567, -2273, -1465, 946, 3988, 4576, -1794, 1865, -2495, 3117, 2839, 2138, 4000, -1786, 2268, 392, 3583, 4893, -155, 1083, -3105, 3671, 4613, -186, -471, -7247, 2895, 2933, 226, -2122, -812, 1924, -1329, 1588, -6786, 1411, 1640, -888, 2786, -3391, 1831, 1708, 652, 3294, -1073, 817, 1269, -1542, 2676, -1802, 1615, -347, -745, 171, -5079, 3858, -4738, 2705, -10138, -2724, 4731, -5195, 3710, -1281, -1320, 4285, -3326, 3817, 496, -1303, 2613, -4683, 4140, 1152, -981, 266, -5266, 4415, 1026, -591, 143, -4545, 3915, 175, -1142, 1680, -5020, 2466, -375, -2482, 2820, -4523, 624, 506, -2887, 3223, -4523, -28, 1665, -1000, 2880, -4234, -139, 2264, 731, 1805, -1455, -680, 2045, 1351, 251, 232, -1189, 946, 817, -297, 610, -1208, -155, -841, 144, -186, -1581, -113, -3496, 22, -2140, -3326, -461, -5183, -444, -5176, -3457, -1548, -4912, -760, -7264, -489, -2770, -4779, -1446, -5743, 929, -4738, -3870, -2353, -4738, 1264, -4842, -3449, -2497, -4669, 861, -3893, -4784, -1963, -5638, -160, -5145, -6914, -1119, -9064, -1499, -4683, -5031, -849, -9064, -1748, -2772, -4006, -1664, -5014, -1656, -2716, -3717, -1998, -3615, -2504, -4748, -3208, -611, -3316, -2483, -6516, -2253, -227, -3927, -1044, -4583, -1548, -1515, -5988, -241, -5569, -1716, -4219, -6786, -118, -10210, -2982, -3695, -4620, -555, -4703, -3471, -3677, -4821, -1762, -3460, -2817, -6492, -8903, -4219, -4067, -3837, -8086, -6870, -4821, -5234, -7213, -5008, -3754, -2370, -3830, -4743, -3474, -2236, -1043, -1611, -3773, -2659, -1469, -546, -485, -5183, -3020, -1864, -786, -695, -8942, -5061, -3785, -1819, -2730, -5422, -5415, -4863, -3309, -8549, -2685, -2799, -3294, -3334, -4049, -1298, -1514, -2941, -1864, -2835, -819, -1047, -3975, -666, -3074, -938, -987, -6745, -243, -2578, -1491, -806, -6602, -575, -1707, -2417, -263, -5333, -1176, -1434, -3668, 77, -8903, -1542, -1819, -5615, -327, -5451, -1773, -2916, -8615, -1697, -1753, -1809, -4348, -9022, -4207, -614, -1748, -4331, -5960, -8754, -801, -2046, -3804, -4006, -12534, -1666, -2893, -3944, -3468, -9531, -2319, -4086, -4703, -4021, -11356, -3038, -4031, -5152, -5487, -8112, -4784, -2420, -4234, -9873, -4491, -2608, -1307, -4067, -8982, -2578, -325, -1029, -5561, 2080, 5215, 106, 2922, 2841, 3014, 5221, 172, 2269, 4181, 4165, 5141, 2035, 2117, 5452, 4538, 4770, 3580, 3754, 5490, 4196, 3956, 3785, 4526, 3901, 3537, 2557, 2738, 4043, -932, 2591, 269, 703, 2291, 1136, 458, -2306, -1136, -365, 2445, -4555, 45, -577, 826, 1757, -4031, 1951, 1058, 3043, 3471, -2994, 2842, 1736, 4276, 5582, -12, 3222, 1102, 4634, 6587, 1515, 3365, -537, 4061, 6540, 1412, 3187, -369, 2224, 5179, 512, 2445, 532, -1320, 1188, 389, 926, 4, -310, -1679, 422, -1736, -2046, 1038, 2003, -644, -3957, -3179, 699, 2666, -3080, -385, -2058, -1343, 3228, -5394, 1313, -1268, -15615, 3414, -8615, 1454, -339, -1452, 2847, -1385, 980, 822, 629, 1934, 1523, 1624, 1683, 733, 1499, 2381, 2301, 1903, -531, 1708, 1669, 2042, 1588, -2626, 1667, -601, 1059, 1265, -2390, 326, -2688, -727, 972, -1036, -5638, -1495, -4199, 37, -371, -735, -1308, -2012, -371, -271, 1794, -3417, -1298, 900, -525, 1968, -4035, -4046, 1326, -799, 465, -1141, -2648, 552, -834, -1868, -967, 96, -976, -816, -1463, -3040, 1115, -2933, -1254, -476, -2918, 1369, -6278, -2399, 238, -440, 928, -5906, -1975, 454, 118, 163, -3007, -295, -71, -1624, -79, -549, 188, -1409, -9106, -364, 849, -588, -2843, -907, -671, 917, -2383, -2450, 312, 221, 113, -3261, -1683, -1227, 1036, -36, -1566, -969, -10613, 1015, 105, -454, -418, -1932, 620, -840, -350, -629, -864, 409, -3156, -802, -2172, -2226, -97, -5735, -1373, -5422, -5801, -1458, -5374, -2366, -5686, -7603, -3621, -4980, -4500, -5615, -4282, -5451, -5509, -4578, -6035, -2720, -5091, -5933, -2382, -6256, -2559, -4679, -6007, -1722, -12319, -3438, -4420, -4625, -2339, -5531, -4327, -5253, -2594, -3436, -3321, -5387, -28777, -1814, -2631, -3339, -8138, -3324, -2372, -1339, -4378, -7562, -854, -3415, -992, -4885, -8683, -247, -2984, -1777, -5387, -10069, -818, -2282, -3804, -9149, -4743, -2475, -1983, -7562, -6692, -3710, -5189, -1753, -28777, -3463, -4625, -6007, -1887, -7335, -2960, -7888, -4784, -2910, -3662, -3954, -8393, -3811, -5121, -1665, -5319, -5037, -3124, -7583, -941, -4764, -3551, -3441, -8754, -1377, -3311, -2442, -5678, -28777, -2803, -3274, -1479, -10362, -6553, -4659, -5346, -1108, -7796, -3422, -5844, -4738, -1702, -4100, -2047, -5240, -2448, -3170, -890, -1210, -3600, -1640, -3665, 753, -627, -2344, -1449, -2829, 1092, -773, -2008, -1364, -2458, 217, -1782, -2875, -1402, -2453, -1925, -2336, -5234, -1950, -2683, -4625, -2229, -8754, -3213, -3886, -6163, -3509, -7523, -4460, -7196, -12123, -4644, -5836, -4134, -4042, -5897, -2203, -4957, -3603, -1553, -3175, -1107, -4733, -3910, -755, -2407, -1088, -5326, -5202, -6577, -2509, -2453, -7034, 339, -3108, -1198, -1880, -4611, 522, -1729, -1155, -1035, -4093, -162, -1394, -2205, -734, -4997, -1186, -1895, -4601, -1124, -6615, -1296, -3428, -7936, -1670, -8060, -843, -7179, -5509, -1585, -8423, -717, -8942, -4028, -1123, -5115, -886, -5387, -2975, -822, -2891, -1418, -4469, -1714, -1076, -1874, -3045, -3441, -1076, -2173, -1815, -6388, -2205, -1487, -3940, -2799, -3103, -1495, -2825, -4816, -4880, -1481, -1315, -2566, -4611, -3650, -1877, -1534, -854, -4659, -1245, -4438, -1843, 29, -5152, -156, -9238, -2306, -47, -6225, -106, -5208, -3509, -1227, -8827, -1007, -4006, -5043, -4425, -10899, -3062, -4119, -4901, -6973, -6035, -6553, -5133, -5584, -3707, -4145, -5670, -4858, -10210, -3237, -3769, -4270, -2587, -9193, -3149, -4464, -4438, -1303, -6183, -2316, -4929, -5623, -1301, -4759, -1826, -3417, -5367, -2683, -3016, -2108, -2034, -3535, -5793, -1842, -3069, -1681, -2369, -6445, -1514, -4331, -2621, -1698, -4918, -1800, -5195, -5422, -1742, -4420, -2125, -5115, -10526, -3284, -3978, -2004, -4486, -6786, -8942, -3930, -2014, -3846, -5751, -8333, -5189, -2939, -3337, -6074, -8865, -10799, -5776, -2990, -6553, -8086, -6321, -12776, -3042, -4826, -3738, -3606, -5266, -3352, -3119, -2979, -3569, -3689, -3947, -2644, -4172, -6163, -3430, -5554, -3227, -7687, -9479, -3103, -5387, -4378, -9331, -6163, -1904, -3347, -4997, -4968, -5897, -969, -2984, -4331, -2747, -6278, -912, -4278, -3563, -1466, -6332, -1704, -7796, -3220, -1170, -6745, -2935, -12123, -3112, -2130, -8276, -3896, -7264, -3903, -5079, -9284, -4597, -7050, -7583, -7562, -7299, -5429, -10899, -5810, -3603, -4382, -7066, -6800, -2811, -2087, -2317, -8192, -4242, -2045, -1884, -1615, -5444, -3689, -2297, -3012, -2181, -4195, -3971, -2937, -6288, -3876, -4286, -4295, -3798, -9753, -7523, -5227, -4907, -5115, -5127, -8423, -6928, -5844, -5115, -3049, -3449, -8112, -5085, -4089, -1868, -1882, -6814, -4403, -4056, -1379, -1733, -6354, -5561, -4869, -1489, -2331, -7583, -9585, -5988, -2086, -2914, -10526, -7247, -7623, -3083, -2637, -11004, -6083, -9193, -4473, -1753, -8138, -7503, -9064, -6026, -1228, -6267, -6759, -8942, -4837, -1526, -5879, -4578, -8393, -3393, -2933, -6113, -3913, -8138, -3422, -6103, -4869, -4242, -9331, -5037, -17034, -3788, -5097, -11781, -6133, -6653, -4028, -5888, -11115, -4597, -4138, -5997, -6016, -7603, -4112, -2997, -13365, -5576, -4853, -4759, -2861, -9380, -5152, -3455, -5480, -3436, -7408, -5227, -3163, -5253, -4315, -7665, -6173, -3798, -5429, -5726, -8649, -8827, -4826, -7542, -7113, -8138, -7542, -4991, -28777, -5049, -6899, -4769, -4800, -7936, -3916, -6719, -3944, -5960, -7213, -4187, -8165, -4611, -11945, -9106, -5422, -10899, -6928, -7264, -12534, -6786, -8009, -10799, -4266, -11488, -7317, -6445, -8790, -3370, -8582, -7865, -5326, -1923, 445, -1426, -4795, -4847, -2690, 167, -2256, -2211, -6480, -5630, -872, -3276, -1275, -8423, -5279, -2445, -4130, -1697, -5494, -2369, -4429, -4464, -2703, -4683, -1072, -7503, -4086, -2482, -6064, -546, -9429, -3133, -2452, -5367, -837, -6183, -2417, -4587, -2292, -2488, -4929, -2435, -11488, -959, -6399, -4056, -3399, -3683, -1087, -5735, -3532, -5061, -2276, -3054, -4795, -3833, -4683, -2465, -12776, -6411, -4307, -3189, -3689, -4089, -8903, -3306, -2969, -5718, -2326, -8865, -1875, -4486, -5970, -2785, -10138, -1058, -5678, -4112, -5394, -10704, -986, -3468, -3449, -9479, -9149, -1589, -3142, -4491, -6457, -7050, -2855, -5183, -7984, -5942, -6035, -5055, -6214, -7503, -6759, -5139, -6786, -2931, -7665, -6123, -3968, -4149, -1355, -8485, -3996, -3824, -2482, -812, -3856, -2655, -5002, -2176, -1260, -1868, -2128, -4693, -3274, -3227, -845, -2239, -2988, -6267, -10284, -485, -2859, -2531, -8485, -5654, -959, -3710, -3051, -6267, -4826, -2011, -4420, -3975, -6653, -5312, -2865, -4708, -4683, -9022, -2411, -4373, -4698, -4901, -8549, -892, -6422, -4523, -3975, -10069, -684, -2960, -4108, -2791, -9064, -1157, -1516, -3856, -2325, -3947, -1793, -1693, -4369, -2791, -2102, -2478, -3137, -4395, -4282, -1538, -3194, -5234, -3239, -6267, -1655, -3792, -5326, -2733, -5718, -2198, -4733, -4460, -2994, -4042, -3624, -7050, -4523, -3600, -3133, -8333, -8086, -5818, -4134, -3286, -6814, -4373, -7730, -3910, -4997, -3788, -2737, -6786, -3569, -9022, -3526, -2536, -6615, -3954, -6183, -4698, -3748, -7912, -4805, -4262, -5014, -6885, -4630, -5718, -3365, -3597, -7097, -2336, -7819, -2472, -2997, -4790, -1603, -13049, -1875, -3485, -3978, -2115, -9284, -2236, -4810, -3893, -3964, -9022, -3535, -6732, -4469, -8276, -12123, -3425, -10362, -6759, -8304, -9380, -2873, -14784, -12319, -5437, -6388, -4307, -10442, -5879, -4805, -4968, -9193, -6376, -5073, -4486, -4390, -4199, -4282, -5942, -3034, -4138, -2601, -4086, -4951, -1771, -4104, -2847, -5472, -4290, -1703, -4382, -4659, -7842, -4541, -3388, -4403, -8549, -8649, -3632, -6235, -3329, -5367, -7484, -3244, -3177, -2453, -3089, -7445, -4464, -1921, -2560, -2260, -9479, -5465, -1873, -3814, -2337, -8827, -4478, -2213, -6103, -3264, -8754, -4408, -3007, -6842, -4592, -13738, -5584, -4748, -6007, -3856, -6528, -7542, -4869, -6123, -2351, -4541, -6692, -3409, -7230, -1662, -4473, -4569, -3135, -9429, -1779, -5615, -3067, -3856, -11356, -2540, -7687, -2231, -4991, -10001, -3680, -11115, -2276, -5630, -8549, -4790, -12534, -3386, -5768, -7665, -5599, -6679, -5871, -6225, -7389, -6332, -4451, -12319, -6679, -6064, -7004, -4067, -10138, -5253, -4266, -6602, -5862, -7665, -3944, -3501, -5888, -17034, -7752, -3833, -3496, -5942, -5960, -8865, -5049, -3425, -6666, -4412, -8903, -7819, -3239, -7408, -5037, -7687, -13365, -1137, -2559, -1426, -6299, -6773, -2512, -3158, -1682, -5109, -7730, -3886, -3940, -2182, -4250, -10069, -3964, -4513, -3198, -5810, -9149, -4134, -4980, -3474, -11115, -6565, -4250, -7146, -2964, -3732, -6123, -3999, -8276, -3007, -1831, -6615, -3788, -4578, -2322, -1531, -7097, -3726, -3103, -1208, -2194, -7523, -3853, -2533, -1122, -3773, -8192, -2969, -2809, -2204, -7960, -9479, -1736, -4035, -3707, -6828, -12534, -1417, -5801, -3940, -2853, -10899, -2083, -6411, -3269, -1472, -9585, -3624, -3707, -3067, -1500, -10442, -6074, -1999, -4559, -3010, -6045, -9429, -1872, -8649, -5346, -3710, -11356, -3259, -4482, -3281, -2531, -9022, -5145, -3347, -2011, -1359, -6640, -3025, -5014, -2111, -419, -5623, -885, -9695, -3080, -238, -5670, 387, -3463, -4416, -812, -5951, 943, -1497, -5702, -1848, -7066, 897, -952, -7247, -2997, -12123, 607, -1319, -12534, -4238, -9479, 547, -2557, -7230, -5888, -6842, 461, -4403, -4509, -8790, -6113, -341, -4258, -4491, -28777, -5020, -2248, -3092, -7562, -10613, -3804, -4021, -2849, -5273, -9695, -3903, -2533, -3444, -2191, -8454, -6246, -1432, -3923, -1086, -4578, -7371, -1526, -3415, -994, -2309, -5367, -2815, -3182, -1505, -1452, -5784, -3944, -3933, -2242, -1813, -6842, -3449, -5694, -2891, -3074, -5776, -3674, -7796, -3407, -4082, -4361, -5253, -6732, -3975, -4654, -3108, -8086, -4195, -4769, -6343, -2264, -10284, -2543, -5853, -8086, -1987, -8060, -1844, -7066, -6133, -2216, -6399, -1868, -8517, -5584, -2578, -6016, -1864, -10362, -7066, -2487, -7317, -1236, -10210, -12123, -1979, -11945, -479, -6759, -7230, -1711, -7230, -266, -4180, -4935, -2328, -4644, -981, -2559, -4234, -4718, -3342, -2958, -1860, -4541, -11781, -2242, -6457, -2057, -5836, -5176, -1033, -6828, -3130, -7503, -3957, -168, -4963, -4532, -8034, -4693, -21, -4238, -4874, -6469, -6814, -643, -4816, -4963, -4592, -8165, -1863, -6480, -4991, -4352, -7213, -2982, -7819, -3535, -6153, -5906, -3269, -7464, -2111, -5020, -4408, -3425, -4640, -1471, -2707, -3916, -3668, -3010, -1532, -2277, -5234, -3386, -3027, -2238, -3452, -9585, -3279, -4513, -3430, -6343, -6411, -4659, -7097, -4307, -9380, -5286, -7888, -8649, -3592, -8485, -7130, -5678, -6988, -2737, -9284, -11488, -5202, -5026, -2416, -14195, -5997, -6745, -3795, -2051, -8718, -4733, -5312, -3331, -1759, -6299, -4698, -3487, -3788, -2305, -5623, -4089, -2847, -5367, -4274, -5339, -3163, -3117, -7426, -7353, -4907, -3056, -3957, -7730, -7034, -4336, -4130, -5312, -8615, -7097, -3879, -6870, -8549, -9149, -7623, -3444, -15615, -12123, -7408, -7299, -2933, -11356, -7335, -7687, -7213, -2813, -10704, -6856, -12319, -7687, -3296, -9238, -5942, -9106, -8754, -3856, -7130, -4425, -6310, -8754, -3856, -6332, -3723, -5751, -8112, -3933, -6321, -3668, -5951, -8615, -4597, -5836, -3766, -5827, -8942, -5776, -4082, 15079, 1996, 10173, 9749, 8284, 14678, 5449, 9501, 9080, 10074, 13441, 6789, 7260, 6834, 10033, 11279, 6239, 2289, 1501, 9131, 8396, 4271, 379, 853, 8032, 7499, 1618, 725, 1957, 6314, 8352, 35, -328, -609, 3415, 8633, -837, 177, -7019, 5102, 8143, -501, -542, -380, 5954, 6802, 1346, 1343, 1246, 4327, 4699, 3374, 3619, 2342, -3430, 3032, 4847, 4777, 2973, 1407, 3215, 5570, 5121, 3062, 1920, 4733, 5418, 4779, 2581, -1020, 5585, 4180, 3864, 1055, -6773, 4934, 1705, 2704, -2482, -3741, 2161, 513, 1702, -3133, -2997, -1296, 1091, 825, -1759, -4896, 1491, 453, 65, -1928, -2165, 1940, -1082, -638, -2567, -645, 977, -2097, -1932, -6173, -178, -1760, -1270, -4157, -3879, 1276, -5827, -543, -4104, -904, 2354, -3018, -950, -3820, -853, 2725, -2578, -2445, -6565, -1860, 2679, -3512, -2155, -6988, -956, 2077, -6577, -713, -4550, -176, 74, -6928, -394, -5158, -589, -9064, -1549, -1189, -5339, -1860, -1729, 496, -3284, -4046, -2935, -333, 1063, -7774, -3754, -2238, -1078, 587, -28777, -3401, -946, -1641, -483, -9812, -3161, -315, -1799, -1278, -5214, -3999, -675, -3441, -1319, -3465, -5189, -2244, -5472, -1206, -3326, -6365, -3863, -4382, -1671, -4373, -10799, -2475, -5615, -3269, -6007, -9429, -1656, -8754, -4620, -6628, -8683, -2049, -3674, -3286, -5979, -12534, -3177, -2743, -2646, -5333, -8086, -4238, -3600, -2829, -5554, -5266, -6256, -5139, -3321, -6943, -3635, -10001, -6074, -3738, -8034, -3087, -4951, -4323, -4123, -6786, -3840, -3526, -2317, -4635, -6719, -5055, -3860, -1154, -4929, -9429, -3347, -5380, -554, -4630, -11629, -2049, -7299, -448, -4161, -6899, -2022, -7371, -976, -3996, -5451, -2807, -6615, -2339, -4541, -4664, -3476, -6973, -5061, -6035, -4403, -3647, -8615, -9531, -7644, -4896, -4089, -8333, -7865, -6973, -6074, -5494, -6246, -7542, -6411, -7230, -9380, -4373, -7034, -7445, -7317, -9106, -3005, -6083, -11629, -6225, -5569, -2430, -4974, -9936, -5055, -4733, -2701, -4130, -6376, -4307, -5429, -3741, -4340, -4323, -4078, -7281, -5247, -5743, -3130, -4274, -10284, -6267, -7644, -2817, -4625, -14195, -5793, -7687, -3309, -4649, -9531, -5465, -6800, -4395, -4649, -9064, -6565, -8649, -5480, -5509, -12319, -9193, -8903, -5818, -8333, -11115, -8009, -3612, -5970, -13365, -8454, -6540, -1952, -6299, -8754, -8165, -6577, -1671, -6343, -7523, -9331, -7842, -2169, -5801, -7687, -9479, -9639, -3396, -5061, -7281, -8485, -9380, -5827, -4880, -5710, -8718, -9639, -11629, -5853, -4980, -10362, -13365, -9873, -7708, -5158, -11004, -13738, -7004, -6422, -5879, -9753, -9106, -5906, -4573, -6943, -9429, -7752, -5067, -4336, -8276, -9331, -7774, -3683, -6445, -10210, -8582, -8423, -2869, -12776, -9380, -7264, -8138, -3291, -6800, -7445, -6332, -7299, 8604, 3945, 6864, 8571, 7383, 7855, 3964, 6139, 8137, 7006, 5364, 3619, 3539, 6914, 5897, -274, 2199, -7523, 5283, 4622, -5240, -1046, 484, 3958, 4359, -3119, -1418, 512, 3032, 4121, -662, 1403, -3342, 1925, 3168, -599, 3199, -151, 3, 2474, -3054, 4122, 1936, -3827, 3063, -7081, 4206, 3093, -8683, 3985, 714, 4162, 4738, -2758, 4335, 3758, 4887, 6199, 115, 3745, 5275, 5632, 6833, 1408, 2127, 5620, 5737, 6451, 1162, -254, 4831, 5174, 4797, 469, -1992, 2837, 4148, 1409, 2100, -1279, 135, 2813, 989, 3339, -287, -241, 872, 2252, 3304, -571, 65, -1625, 1699, 2089, -2726, -411, -245, -88, -215, -6745, -1345, 1370, -2047, -2749, -3498, -2432, 1928, -3498, -4486, -2320, -2672, 1882, -5743, -3824, -2580, -1515, 1601, -6640, -2564, -3609, -797, 1335, -5933, -3824, -4669, -1195, 1133, -7353, -5702, -4460, -3244, 810, -14784, -1836, -3078, -10069, 47, -6943, -506, -2064, -6173, -1304, -4946, -315, -1832, -3735, -2182, -4486, -667, -2311, -2621, -1766, -4299, -2057, -3177, -2264, -1648, -3551, -7281, -3738, -2849, -1826, -3597, -4664, -3886, -4395, -1638, -6143, -1424, -3824, -6577, -1468, -5862, -165, -3698, -7865, -1752, -3187, 485, -3720, -5906, -2541, -3430, 761, -4130, -3529, -3817, -6246, 486, -5694, -2200, -5615, -6133, -790, -11356, -1873, -7644, -4630, -4486, -8790, -2473, -7162, -5133, -6814, -6577, -4078, -5360, -5008, -2217, -6411, -7247, -4606, -3309, -1123, -5133, -11115, -4784, -2452, -1197, -3937, -6640, -5319, -2845, -2043, -4266, -4816, -6299, -4997, -3362, -7230, -4929, -11232, -9695, -4112, -11004, -7842, -7146, -6016, -3092, -5546, -11004, -3837, -5133, -2020, -4327, -6288, -3187, -5951, -1836, -4331, -5970, -4123, -6163, -2664, -5121, -7774, -4842, -5718, -4523, -5988, -10899, -3824, -7097, -7752, -6457, -8112, -3662, -28777, -13365, -7019, -6745, -5103, -7603, -9429, -7371, -7050, -8942, -5853, -8549, -6914, -8790, -9149, -6278, -11488, -6457, -8192, -7146, -7408, -10704, -6958, -6016, -6615, -6814, -6235, -9429, -4532, -6719, -6173, -4693, -9639, -3674, -7865, -6870, -4331, -6745, -3714, -11945, -9106, -4597, -6256, -4816, -10899, -11781, -5170, -7730, -6885, -7464, -11629, -5853, -13049, -8454, -6577, -10362, -6143, -8582, -7687, -7213, -8615, -5735, -5592, -6540, -10001, -7644, -4974, -4573, -6628, -28777, -7281, -4564, -4795, -7842, -10069, -7179, -4728, -6434, -9149, -8942, -7299, -5158, -11629, -13365, -10069, -7542, -5480, -8582, -9531, -11781, -7162, -5607, -5049, -6615, -8517, -6615, -5067, -3729, -6214, -6958, -6235, -4348, -3729, -6553, -7097, -5933, -4226, -5240, -6299, -8517, -6133, -4708, -9284, -5979, -10362, -7317, -5686, -8982, -5924, -11115, -8112, -7066, -7583, -5960, -10526, -7842, -7774, -9531, -6163, -10069, -9429, -7213, -12776, 4310, 2708, 6990, 7471, -15615, 3226, 1575, 6534, 7170, -5319, -565, -1330, 5369, 6403, -1790, -1323, 1284, 4390, 5600, 1713, -1967, 2902, 4127, 4938, 4045, -6163, 3210, 3792, 3977, 5217, -1403, 2642, 2997, 2856, 5416, -3629, 1050, 1590, 2355, 4620, -1743, -1913, -605, 1507, 2126, 2935, -3040, -3168, -1542, -3626, 4946, 1173, -948, -2146, 2887, 5787, 4314, 1140, 1218, 4354, 5668, 5813, 1252, 2007, 3854, 4538, 5779, -493, 2074, 2001, 2451, 3882, 611, 2980, 2509, 942, -3210, 2276, 3721, 4021, 702, 231, 1892, 3317, 4409, -103, 1213, -609, 1603, 4021, -608, -1343, -4495, -1340, 3247, -650, -9429, -6540, -6540, 2242, -958, -2698, -6093, -5871, 719, -927, -2102, -2073, -2619, -1591, -356, -1857, -1686, -2222, -1594, 196, -1391, -3626, -2175, -136, 147, -1688, -11356, -1900, 259, -920, -2887, -6246, -2314, -224, -3656, -4234, -3863, -3866, -1571, -10001, -4176, -3259, -5516, -3729, -4527, -3187, -3635, -4021, -4299, -3996, -2847, -5008, -3314, -2316, -7708, -4093, -7912, -5121, -761, -4759, -6299, -13738, -6870, -336, -1613, -2912, -12776, -2495, -1371, -860, -1158, -7562, -1300, -4199, -1588, -863, -5176, -1625, -4532, -3463, -1439, -4784, -2737, -3071, -4053, -2289, -5509, -4010, -2447, -3242, -3225, -5524, -5509, -1953, -3671, -4974, -6093, -7603, -2178, -5286, -7445, -9429, -9022, -3444, -6246, -6885, -7335, -9695, -4532, -6399, -6928, -6026, -12123, -3971, -7623, -9639, -8247, -6590, -4219, -9331, -12319, -9753, -3422, -6988, -9429, -8454, -4469, -2002, -9753, -8615, -5853, -3005, -1741, -5646, -7299, -4142, -3119, -2416, -6310, -5979, -3814, -4138, -3618, -11232, -4946, -4885, -4688, -3571, -5008, -4226, -5554, -4442, -2670, -3707, -3840, -4176, -5067, -2688, -4918, -3680, -3644, -8865, -3886, -11356, -3580, -4307, -6354, -5646, -7603, -3683, -5784, -2825, -6602, -5584, -4473, -7503, -1782, -7146, -6235, -6653, -8982, -2195, -7426, -9753, -11629, -7708, -3913, -6679, -11781, -9873, -6411, -7353, -5091, -7603, -9106, -6214, -8220, -3846, -6553, -8363, -7281, -5871, -3436, -6719, -6973, -10613, -5751, -3798, -8060, -6759, -7644, -7371, -4821, -10210, -7888, -5299, -9873, -6214, -9064, -9873, -4831, -9753, -7353, -7113, -11629, -5584, -9479, -8790, -5793, -11781, -7081, -9812, -11232, -5374, -10442, -8649, -9753, -7484, -6457, -8903, -9238, -10069, -5183, -11945, -8247, -8454, -10442, -4464, -7708, -8423, -7113, -8517, -4679, -4513, -9149, -6411, -6870, -4997, -3621, -9380, -6235, -6376, -4951, -4086, -9284, -5735, -6528, -5415, -5524, -9695, -4759, -7066, -6914, -7353, -10613, -4168, -8649, -7335, -8333, -10899, -4013, -11629, -6354, -7687, -9284, -4010, -8827, -6732, -8192, -8192, -3947, -6565, -9331, -13049, -8333, -3773, -5818, -9149, -9331, -9531, -3785, -6321, -6773, -7623, -5139, -5897, -6973, -6074, -7230, -7281, -6365, -7912, -6256, -7842, -4587, -6288, -10799, -6628, -8454, -2613, -5768, -10526, -6504, -8754, -2219, -5970, -9149, -5561, -7445, -3540, -6528, -9873, -4946, -5879, -6914, -6288, -8517, -5266, -5133, -5576, -5183, -8138, -6628, -5214, -3916, -4060, -11945, -8790, -6343, -3549, -3386, -11004, -10899, -9639, -3801, -3409, -7865, -10799, -14195, -4215, -4157, -6973, -8903, -8827, -4078, -5539, -6914, -7752, -8942, -3551, -7730, -9022, -7912, -12319, -3751, -7865, -12123, -8517, -14195, -4654, -6204, -7445, -7912, -10362, -4957, -4478, -5202, -9639, -7774, -4093, -2210, -3027, -6814, -3580, -2316, -69, -818, -1828, -467, -735, 1194, 803, 382, 1201, 75, 1347, 1438, 1068, 1630, -57, 377, 925, 464, 862, -1274, -1599, -921, -1469, -1321, -3863, -4031, -4774, -5121, -5686, -8615, -5997, -8827, -12319, -8942, -15615, -6602, -6492, -10001, -7603, -12319, -6204, -6434, -7179, -6899, -11115, -5844, -7888, -6163, -6194, -10613, -6183, -11629, -5888, -5970, -9284, -7464, -11781, -5997, -5897, -8423, -8790, -8393, -6577, -6035, -7484, -8423, -7146, -7960, -6719, -6007, -7912, -7464, -10284, -7960, -5422, -6773, -9936, -11781, -8982, -6469, -5139, -10362, -11232, -9639, -11629, -4211, -7888, -11488, -11356, -8009, -4097, -7623, -13365, -15615, -5055, -4369, -8942, -14784, -14195, -4286, -4616, -11629, -11356, -10799, -4853, -5152, -11945, -9064, -8865, -6628, -6083, -9284, -8304, -9022, -7774, -7019, -7912, -8903, -12319, -6745, -8790, -7708, -10442, -13365, -6256, -17034, -8683, -9106, -9149, -6885, -9753, -10799, -6899, -8165, -8247, -7752, -13738, -5942, -8060, -7213, -8582, -17034, -6246, -8615, -5853, -13365, -28777, -8454, -9936, -6204, -14195, -17034, -13365, -12534, -8982, -11356, -13738, -8683, -10613, -11945, -9064, -12534, -8247, -8865, -9193, -7484, -12776, -10613, -9531, -9936, -7247, -17034, -14195, -11004, -14195, -8060, -13365, -11232, -8423, -9695, -9149, -10210, -11488, -7353, -7644, -9238, -9064, -13049, -7583, -7484, -8220, -9106, -11945, -8304, -7408, -6988, -9695, -10284, -8754, -6113, -6615, -9639, -9238, -8865, -4929, -7408, -9639, -8363, -8903, -4307, -9284, -9639, -8276, -8754, -4495, -10362, -8827, -9064, -8615, -5888, -9022, -8393, -10362, -9064, -8754, -7665, -8582, -11781, -9936, -8582, -6828, -8903, -14195, -10442, -6528, -6615, -9193, -12123, -10210, -5888, -6973, -9429, -8982, -10001, -6540, -7562, -9753, -7888, -10001, -9022, -7730, -10613, -8220, -10362, -17034, -7730, -12319, -10362, -11488, -15615, -8582, -12534, -28777, -13049, -15615, -11004, -9429, -14195, -12776, -9380, -13365, -7865, -12776, -11945, -7146, -10799, -8009, -14784, -11945, -6411, -8754, -10001, -12534, -12534, -6828, -8423, -12534, -10899, -11945, -8192, -9812, -10899, -10138, -10526, -9585, -12776, -10799, -10362, -9585, -9695, -13365, -12776, -11356, -9936, -9429, -10442, -13049, -10799, -11945, -6602, -9331, -17034, -6692, -7960, -7113, -8754, -11781, -6745, -6504, -8165, -9331, -13365, -7196, -5988, -11115, -10899, -14195, -7066, -5444, -9585, -9585, -10001, -6343, -4743, -6958, -7603, -9873, -6235, -4168, -6376, -6666, -12123, -7281, -4006, -7230, -6553, -13738, -10526, -4361, -9380, -7230, -11488, -15615, -5306, -12534, -8754, -8615, -9531, -6480, -9585, -8903, -6842, -7752, -6958, -6745, -7196, -6590, -7408, -6759, -6064, -6434, -8086, -8393, -6577, -7353, -6602, -13365, -10210, -6504, -10526, -6376, -12123, -11945, -6732, -12534, -5387, -8790, -15615, -6565, -9106, -5942, -9479, -7687, -5576, -4923, -10362, -7752, -3535, -3840, -1920, -2664, -2432, -788, -1616, -269, 35, -115, 743, 13, 29, 912, 614, 1152, 624, -1164, 438, 96, 421, 120, -4541, -1426, -1563, -1617, -1613, -12123, -5279, -4215, -5183, -4644, -8649, -28777, -7179, -6800, -7842, -8649, -11629, -9106, -6719, -7730, -6856, -11115, -9238, -7842, -6540, -5121, -9639, -7353, -9064, -6615, -4303, -8718, -6083, -9585, -7264, -4713, -8718, -6343, -9238, -7019, -6376, -9873, -8393, -9149, -6943, -7426, -13049, -10210, -10210, -8060, -7213, -28777, -7426, -14784, -11356, -8718, -14195, -6153, -11488, -14195, -12534, -15615, -6143, -8112, -11004, -7389, -17034, -6988, -7050, -10613, -5380, -10001, -8549, -7335, -12123, -5097, -7936, -11004, -8582, -12319, -6615, -7130, -15615, -9429, -9064, -14195, -7281, -15615, -8009, -8276, -8485, -8517, -11115, -6064, -9429, -6422, -11945, -9585, -5422, -11488, -6628, -15615, -8982, -6469, -12123, -7623, -10613, -8982, -11004, -11629, -7960, -9585, -9022, -9106, -9331, -7819, -9429, -8549, -6516, -8165, -8138, -9022, -7281, -6163, -8903, -9479, -8138, -6411, -6899, -11781, -10799, -7484, -6310, -8333, -10362, -10362, -7523, -6856, -9639, -7644, -10442, -8423, -7299, -9022, -6343, -12123, -10210, -7019, -8517, -5924, -14784, -12123, -6914, -9873, -6434, -28777, -13365, -7644, -15615, -8009, -13365, -12534, -9380, -14784, -10001, -9531, -10899, -11781, -12534, -10526, -8112, -10799, -13049, -10001, -10613, -7842, -13049, -11945, -8865, -9022, -7936, -28777, -11356, -10138, -7888, -8165, -10442, -12319, -14784, -7687, -8903, -8865, -17034, -12776, -8034, -11232, -8009, -12123, -17034, -7796, -15615, -6973, -9429, -11629, -7196, -9753, -6745, -8485, -8517, -7281, -8485, -7730, -8549, -8393, -8060, -8865, -9380, -9331, -9812, -9331, -10001, -9639, -10799, -10613, -10138, -12319, -10210, -13365, -10138, -10613, -15615, -11629, -17034, -10210, -11488, -11781, -10704, -15615, -10613, -12776, -10526, -10526, -11356, -11356, -28777, -11488, -12123, -9639, -11781, -12319, -28777, -14195, -9064, -11115, -9873, -10069, -15615, -9531, -11004, -10138, -7687, -15615, -10899, -12776, -11945, -7317, -11232, -13049, -28777, -12776, -8363, -9429, -12123, -11945, -12534, -11232, -8865, -10526, -9812, -11945, -14195, -9022, -9429, -9695, -11004, -14784, -10442, -9238, -11004, -11629, -10069, -4104, -8333, -5801, -9149, -9429, -4447, -14784, -5554, -9106, -8060, -4654, -13365, -5871, -6399, -6299, -4985, -10613, -6745, -5472, -5253, -5326, -10069, -8086, -5678, -5026, -5234, -10526, -10613, -6434, -5422, -4625, -9531, -13365, -7408, -6143, -3937, -6628, -8982, -8423, -7019, -3507, -5312, -7019, -9284, -8247, -3546, -5073, -5951, -9936, -10526, -4127, -5353, -5584, -11488, -14784, -4728, -5743, -6026, -11781, -15615, -4447, -6565, -7146, -9936, -10613, -4180, -8754, -8009, -9284, -8790, -5234, -12123, -8009, -9639, -8827, -8517, -8865, -8220, -11488, -8549, -9812, -6093, -6679, -11629, -5061, -5670, -3237, -3656, -4826, -2012, -1978, -693, -1030, -1746, -188, -34, 920, 530, -283, 484, 425, 1414, 892, -63, 72, -546, 703, -42, -1096, -1479, -3375, -1434, -2578, -3738, -4234, -11781, -4774, -8060, -10069, -7179, -8333, -5279, -15615, -8060, -7665, -8009, -6183, -17034, -6365, -7665, -9753, -9873, -11004, -5906, -8165, -8549, -8247, -8942, -5339, -10138, -5988, -7213, -8192, -4800, -13738, -5014, -8942, -7353, -4863, -9193, -5360, -14195, -6773, -5524, -8454, -6640, -7960, -6943, -6267, -10613, -8276, -6143, -7708, -6457, -12776, -8942, -5915, -8304, -6732, -7774, -8615, -6745, -9106, -7644, -6007, -8549, -8247, -10899, -8903, -6016, -9695, -9022, -13049, -9873, -7865, -12319, -8903, -12123, -12776, -11629, -10069, -9064, -9331, -12123, -9695, -7912, -8942, -7050, -8754, -9022, -7196, -7960, -5801, -8220, -9479, -7912, -7281, -5554, -10001, -9106, -10704, -7389, -6288, -17034, -8333, -28777, -8649, -7819, -10526, -7936, -28777, -12319, -8982, -8454, -7408, -13049, -15615, -9193, -8165, -6422, -8423, -10899, -10704, -8982, -5623, -7196, -10799, -14784, -10442, -5286, -8138, -14784, -9331, -12123, -5266, -10799, -15615, -7583, -12319, -5516, -7603, -10362, -7464, -10613, -6445, -5247, -9639, -7687, -9695, -8615, -4336, -10613, -7687, -10526, -12776, -4295, -13365, -8034, -17034, -28777, -4733, -12123, -9022, -10362, -15615, -5286, -9812, -10799, -7842, -11488, -5768, -8683, -14784, -7353, -9873, -6045, -8333, -14195, -8582, -8683, -6332, -8615, -9479, -13049, -7774, -7230, -9639, -7752, -17034, -7247, -8683, -12534, -7299, -12776, -7445, -8009, -17034, -7503, -11356, -8393, -6814, -11004, -8060, -9695, -10284, -6590, -9812, -9380, -8754, -13365, -7179, -10210, -11945, -8165, -14784, -8582, -11232, -13738, -8363, -12776, -11232, -10613, -15615, -9753, -10704, -28777, -10442, -15615, -11781, -9531, -11781, -10704, -11115, -10210, -8615, -9429, -9064, -9284, -8903, -7912, -9193, -7503, -8683, -8582, -7819, -9753, -6504, -9193, -8942, -8582, -9873, -6064, -10704, -9873, -10284, -9873, -6235, -13049, -11781, -14784, -11232, -7097, -13049, -14195, -14784, -13365, -8982, -11781, -17034, -10362, -11356, -13738, -11945, -10899, -8827, -9380, -15615, -13049, -8827, -8333, -8393, -12319, -13365, -8549, -8363, -8304, -14784, -13738, -9585, 8691, 10305, 10541, 8363, 6601, 7910, 9849, 9903, 7804, 6059, 5271, 8450, 7889, 6106, 4381, 2415, 6066, 4679, 3269, 1449, 3746, 3056, 3635, -135, -1732, 2977, 1488, 2915, -2326, -3242, 1084, 2377, 314, -3227, -10362, 1812, 3353, -1552, -1758, -9, 2880, 3452, -1317, 255, 2692, 2860, 2480, -2229, 1058, 3712, 1121, -330, -3824, 1567, 3828, -1906, -2217, -5784, 3306, 3465, -906, 2508, -5367, 4815, 2717, -2032, 4277, -3779, 5221, 1198, -297, 4506, -3801, 4428, -1244, 1773, 3323, -4874, 2258, 699, 1762, 222, -3574, -1859, 2634, -210, -3474, -1026, -4230, 2955, -6786, -395, 729, -3103, 1975, -3235, 766, 1489, -3182, 25, -913, 1107, 1108, -3036, -3247, -458, 987, -859, -2470, -3695, -1216, 718, -5214, -1939, 724, -3490, 430, -3417, -674, 1651, -3034, -301, -1909, 543, 121, -1499, -2123, -570, 478, -8220, -2148, -6422, 845, -1650, -2236, -1663, -7665, 1426, -28777, -1095, -287, -3016, 1119, -2076, -1716, -1664, -1746, 342, -150, -677, -8517, -2730, -131, 258, 982, -354, -7408, -391, -114, 1613, 886, -5109, -628, -244, 676, 383, -4412, -501, 496, -4067, -910, -6565, -777, 1177, -1882, -2829, -4412, -2807, 1366, 1056, -7960, -3401, -15615, 993, 1442, -4541, -2871, -2735, 13, 377, -1948, -930, -955, -888, -2300, -1862, -33, -836, -284, -10069, -3493, -756, -1612, 337, -5853, -4831, -1978, -2877, 10, -4500, -3692, -220, -4089, -1151, -4089, -2716, 1032, -5346, -2460, -2605, -2490, 888, -5646, -3606, -1341, -3621, -652, -3147, -5879, -839, -8112, -3903, -1432, -14195, -1252, -7445, -8165, -824, -8865, -2881, -4112, -13365, -1057, -7484, -5670, -3704, -5055, -1760, -6321, -6773, -4728, -2445, -2448, -4021, -9695, -5576, -1677, -2988, -2416, -8790, -4100, -1923, -3375, -1634, -4597, -3187, -2762, -2935, -1601, -3062, -3674, -4010, -2057, -2430, -2516, -5240, -5333, -1733, -4290, -2943, -6899, -5164, -2188, -6376, -4420, -13365, -4274, -3094, -5735, -6422, -6278, -4176, -3808, -4901, -8485, -3586, -5079, -4262, -4640, -11945, -3557, -6856, -4635, -4357, -7464, -6173, -8454, -4800, -3951, -5546, -13049, -7865, -4968, -3686, -5253, -6183, -6214, -5214, -3683, -5793, -5759, -5458, -5049, -3978, -6692, -8683, -6103, -4336, -4482, -7623, -10210, -8304, -3840, -4997, -8086, -5569, -11356, -4250, -5888, -7371, -4378, -9695, -5487, -7484, -6332, -4442, -7081, -6516, -9022, -6113, -5367, -6480, -6388, -9753, -6885, -7034, -7230, -6173, -9531, -9284, -9429, -7912, -6899, -8718, -14195, -28777, -8138, -10442, -8649, -10362, -7936, -8683, -11781, -11781, -10613, -5401, -8615, -8683, -8247, -9873, -4708, -7213, -8615, -5170, -7936, -5164, -6143, -9106, -4382, -6988, -6445, -5906, -9022, -4940, -5465, -8363, -6365, -8649, -6540, -4089, -5646, 5776, 7356, 3662, -4733, -891, 4819, 6828, 3205, -2859, 332, 1246, 5321, 1950, -203, -938, 82, 3287, -24, 509, -5103, 1880, 1533, -2011, -545, -3311, 673, -508, -1247, -2386, -1726, 81, -8517, -1443, -5299, -1130, 1969, 499, -263, -3964, -234, 2762, 3183, 1844, -1575, 614, 2807, 4262, 2043, -974, 942, 2151, 4793, -92, 1499, 666, 24, 4919, 621, 3218, 66, -5031, 4265, 3095, 3609, -451, 562, 2416, 3298, 3098, -804, 2856, -732, 1155, 2234, -976, 3584, -1030, -11945, 1723, -486, 3028, 96, 444, 1906, 586, 914, 578, 1841, 1995, 1404, -2605, 808, 1760, 1269, 1355, -1232, 521, 1411, -642, -42, -377, -578, 1605, -4723, -3383, -871, -1250, 2108, -9531, -3824, -2795, -475, 2321, -4559, -3168, -3526, -563, 1969, -3714, -4250, -1292, -2276, 950, -3316, -5380, -1071, -5266, -620, -2173, -6343, -3067, -3698, -2121, -1644, -5615, -7708, -1516, -2692, -2690, -6719, -3741, -222, -2179, -5960, -8982, -1137, 155, -1559, -5097, -3615, 536, -715, -1587, -3769, -1940, 1480, -4086, -1873, -4478, -1514, 1701, -7066, -1580, -7004, -1689, 1130, -2935, -1197, -12534, -2581, -372, -3468, -1499, -10526, -5319, -3175, -6256, -2664, -4550, -3748, -11004, -2422, -4049, -1393, -977, -6074, -513, -4215, -142, -642, -3843, -126, -2155, -431, -2592, -4149, -813, 157, -2058, -7179, -8247, -2589, 1296, -3417, -4123, -5145, -6183, 1086, -3378, -3968, -1775, -7371, -866, -4258, -3215, -509, -3985, -7984, -6388, -1246, -78, -2958, -3523, -9193, -662, -246, -3490, -1799, -11004, -1445, -1325, -5353, -2192, -11629, -3367, -3906, -4486, -3496, -12534, -5844, -6026, -2701, -4831, -12776, -7796, -4693, -2236, -5662, -10613, -6553, -5183, -2350, -6225, -9106, -5853, -6388, -2388, -6899, -9284, -7213, -6235, -2458, -8363, -8454, -9429, -5759, -2839, -11004, -6773, -9193, -4569, -3689, -7146, -6365, -11629, -3529, -4826, -5494, -7179, -12534, -3365, -5516, -6445, -8718, -7984, -3876, -4649, -11781, -9380, -5584, -4654, -3117, -7730, -11356, -4097, -5286, -2355, -5888, -15615, -3521, -5897, -2443, -5710, -8423, -3860, -7317, -2999, -5853, -6899, -5292, -9753, -3383, -5768, -7113, -8393, -11232, -2979, -5437, -8517, -11488, -14784, -2084, -4957, -10799, -7819, -9812, -1522, -4559, -11781, -6480, -7081, -1630, -4478, -8517, -6399, -6540, -2505, -4795, -6516, -7130, -7389, -4230, -5306, -5897, -7644, -9238, -6143, -5827, -6388, -7146, -10899, -5380, -6870, -7603, -6666, -9936, -4219, -9479, -8086, -6759, -8009, -3785, -12123, -7583, -7464, -6457, -3710, -8304, -7542, -8790, -5630, -3701, -7936, -8649, -8903, -5360, -3910, -10899, -13049, -6214, -5494, -4679, -11004, -11232, -4795, -5862, -6321, -7562, -7484, -4478, -6288, -9331, -7130, -6492, -4901, -6113, -12776, -8549, -6457, -2505, -4842, 2010, 3905, 962, 931, -1150, 2331, 2455, 4825, 2939, 1276, 2948, -12123, 6643, 3103, 2313, 3325, 1971, 6810, 1326, 2360, 3195, 3111, 5724, -1206, 1605, 2525, 1581, 3512, 149, 81, 1509, 532, 1417, -60, -2447, 528, 2746, 835, 1160, -4805, -479, 2964, 1023, 3140, -3042, -3788, 1231, 2606, 3882, 269, -2610, 1012, 3180, 3560, 2815, 1979, 2340, 1817, 2254, 3991, 3427, 1267, 245, -174, 3757, 3255, -3526, 2637, -1163, 1815, 1866, 974, 3641, 347, -1141, 667, 2125, 4254, 427, 760, 598, 835, 5135, -1214, 1375, -187, -3487, 5450, -4168, 602, -1979, -7687, 4788, -1616, -490, -3554, -4153, 3180, 491, -645, -4274, -3927, 1757, 1151, -23, -3232, -5933, 2244, 860, 300, -1203, -9429, 2633, 495, -227, 95, -3069, 1981, 450, -1686, 478, -1450, -36, -83, -3830, -208, -1324, -4644, -1547, -6045, -2422, -1701, -6310, -3964, -8485, -6590, -855, -2226, -7019, -6628, -3571, 705, -1452, -7542, -4184, -1956, 1596, -3042, -5915, -3420, -1749, 1607, -5576, -4592, -3827, -2578, 742, -2460, -3203, -4611, -4810, -1168, -1341, -1930, -4361, -12123, -6214, -2116, -1302, -3853, -5768, -4307, -7130, -1501, -4191, -2182, -743, -4416, -1949, -4455, 17, 415, -2943, -2045, -3103, 1169, 582, -6267, -2578, -2211, 1153, 183, -2608, -3025, -2472, -375, -695, -344, -2277, -4089, -3014, -1815, -394, -2603, -10899, -1472, -1127, -2189, -5253, -4425, -875, 327, -5145, -15615, -1682, -2442, 743, -4708, -11629, -1515, -5615, 166, -3540, -11115, -3971, -4340, -688, -2787, -9639, -10799, -4184, -1343, -2785, -13365, -3744, -7389, -2690, -4093, -6246, -2950, -7523, -5509, -7066, -4303, -3600, -3161, -7562, -6814, -4348, -4451, -1787, -8060, -5827, -5776, -4601, -1865, -7623, -5897, -7464, -4495, -3365, -4907, -5339, -6928, -4946, -7583, -3817, -3808, -5844, -5793, -9585, -3692, -2564, -5380, -5273, -6516, -3425, -2257, -5524, -4104, -7730, -3001, -2971, -6194, -3457, -10613, -3433, -4161, -6928, -3342, -6773, -5718, -4373, -7113, -3763, -5970, -8363, -3889, -6786, -5152, -6988, -4635, -3830, -6590, -8865, -8982, -3482, -4683, -7004, -12534, -10210, -3656, -6376, -8718, -8165, -10284, -4399, -6354, -11488, -7230, -8112, -5085, -5189, -7562, -7247, -6083, -5836, -5133, -5415, -8034, -5494, -6615, -6173, -4842, -9936, -6343, -6745, -7819, -5472, -12123, -7281, -6074, -8827, -6943, -11945, -5751, -5472, -8363, -8247, -10284, -4564, -5710, -7281, -8034, -8865, -4207, -7130, -6343, -7247, -8112, -4348, -8942, -5844, -7081, -7665, -4382, -8517, -5599, -7708, -7130, -3873, -8220, -5451, -9380, -6692, -3071, -8982, -6204, -14784, -6759, -2517, -9429, -9429, -11945, -7113, -2597, -7842, -14195, -8517, -7603, -3624, -7034, -10799, -7936, -8220, -6054, -7644, -13365, -10284, -7196, -9106, -9193, -3674, -8086, -7445, -9812, -10799, -4541, -5997, -6153, -8086, -7426, -7623, -5020, -4504, -6814, -5451, -7299, -4573, -3501, -6759, -4779, -4473, -4266, -3306, -7542, -5306, -3920, -4046, -3766, -8454, -7097, -4940, -4142, -4635, -8683, -10138, -7687, -4907, -5451, -8549, -10210, -10526, -6540, -6434, -7984, -8192, -7936, -6640, -8549, -7213, -7230, -7281, -4929, -11004, -7066, -7623, -8718, -4323, -7888, -8615, -9812, -9331, -5073, -5970, -11945, -15615, -6577, -7796, -5037, -8615, -13738, -5437, -28777, -4611, -7230, -12776, -5623, -8192, -4513, -6745, -12534, -6973, -6492, -5273, -6173, -11232, -10284, -6235, -7484, -4963, -9695, -12123, -7179, -8790, -3853, -9193, -7097, -11115, -7984, -3701, -9873, -5319, -11004, -10001, -4805, -12319, -5115, -8112, -15615, -7230, -12319, -6267, -8009, -8683, -9531, -10526, -9022, -8485, -7213, -9812, -8827, -14784, -9380, -7130, -10899, -7426, -28777, -14784, -7888, -11781, -6759, -12534, -9479, -9238, -12123, -6692, -10138, -6267, -11356, -10526, -7146, -8517, -5061, -13365, -8903, -8549, -7583, -4853, -12319, -9331, -12123, -7389, -5444, -9936, -10899, -12776, -8060, -7004, -8754, -9064, -9193, -9639, -7562, -9695, -7842, -8393, -11232, -6064, -13049, -7819, -8423, -11356, -5615, -9331, -8247, -8615, -10613, -6469, -6719, -9193, -10069, -9331, -7353, -5208, -10442, -10362, -8304, -6602, -4620, -9812, -8393, -7819, -5879, -4985, -7708, -8304, -8034, -5686, -6256, -6267, -9695, -9022, -5638, -8485, -5960, -10613, -11781, -5654, -10613, -6773, -9531, -17034, -5743, -8549, -8683, -8454, -11004, -5592, -6615, -10526, -9106, -10138, -4874, -5924, -8942, -13365, -10799, -4112, -6246, -7730, -10704, -10899, -3893, -7426, -7623, -8423, -9695, -4433, -8192, -8454, -8086, -9193, -5862, -7774, -10704, -8138, -9639, -7708, -8086, -13049, -8060, -10613, -7730, -10704, -10001, -8220, -10613, -7162, -13365, -8683, -8942, -9479, -7484, -9429, -9193, -10138, -8718, -8247, -8582, -11488, -11004, -8718, -8649, -8827, -11945, -10704, -8615, -8549, -9193, -11115, -10069, -8754, -8220, -10284, -11629, -9479, -10210, -7426, -14784, -12319, -8942, -11945, -6628, -11629, -12776, -8615, -10442, -6434, -7708, -17034, -8517, -10442, -7213, -6480, -17034, -8393, -14195, -9695, -6504, -12534, -8192, -14195, -13365, -7281, -13738, -7687, -10069, -9639, -8333, -28777, -7230, -9380, -8517, -9479, -10210, -7113, -9695, -9064, -11232, -8192, -7299, -10526, -9284, -12319, -7960, -7426, -12534, -7984, -11004, -9193, -7819, -28777, -7730, -9695, -11488, -8903, -14195, -8718, -9585, -14784, -11356, -14784, -10138, -10704, -13365, -15615, -12319, -12534, -13049, -10362, -28777, -9936, -28777, -12534, -9238, -28777, -9479, -10799, -11004, -9238, -17034, -10001, -9585, -11004, -9812, -14195, -10704, -10799, -11945, -11629, -12776, -11781, -28777, -10799, -14784, -12534, -13738, -17034, -8982, -14195, -14784, -15615, -11629, -8192, -13049, -17034, -17034, -5554, -5502, -11115, -10284, -6759, -6153, -5472, -9531, -8790, -7371, -6973, -6492, -8220, -8138, -7562, -8112, -8718, -7562, -7936, -7050, -9022, -9873, -7819, -8086, -7542, -9284, -8423, -8683, -8790, -9022, -9064, -6958, -9479, -9753, -9380, -8942, -6074, -10138, -10001, -8790, -8220, -5997, -11629, -9479, -8485, -7353, -6540, -9429, -9106, -8517, -7752, -7371, -6786, -7912, -9585, -10704, -8582, -5862, -6577, -11232, -15615, -12123, -6492, -6163, -12534, -10704, -12319, -9380, -6615, -12776, -10704, -8942, -28777, -7371, -12776, -11232, -8086, -9812, -7687, -11945, -10526, -6914, -7888, -8138, -10799, -10442, -5879, -6928, -9639, -11781, -8827, -5853, -6332, -10362, -13365, -6870, -6602, -5970, -8333, -8790, -5988, -7984, -5818, -7583, -7523, -6016, -11115, -5942, -8718, -7865, -6653, -9380, -6692, -12534, -8363, -7426, -7445, -9429, -13049, -7523, -7665, -8034, -12776, -13049, -6469, -7665, -9585, -7865, -17034, -5979, -8192, -8060, -7335, -14784, -6434, -9479, -7665, -9149, -11629, -7408, -10613, -9193, -15615, -10069, -7081, -10210, -12776, -15615, -8942, -6653, -9531, -14195, -11356, -8276, -7281, -9064, -17034, -8423, -7730, -8165, -8683, -12776, -6928, -6943, -7888, -8138, -9380, -6973, -6422, -7562, -7542, -8615, -9064, -6516, -8220, -7484, -10001, -13049, -7146, -9936, -8165, -13738, -10526, -8086, -9695, -9149, -11945, -11115, -8790, -7865, -9479, -9531, -12776, -8903, -7130, -8485, -7503, -9753, -8517, -7774, -7644, -6376, -7865, -7888, -10069, -7888, -6204, -6719, -7371, -28777, -9936, -6958, -6615, -7583, -10069, -11488, -8582, -7912, -8827, -8034, -8086, -11232, -10284, -11629, -7912, -6842, -28777, -10284, -28777, -9531, -6914, -10704, -9936, -17034, -9585, -8112, -7960, -10362, -14195, -7912, -10799, -7819, -10442, -12776, -7888, -13738, -10210, -9149, -12776, -9873, -9106, -15615, -8363, -12776, -12776, -7353, -11232, -9284, -12123, -10899, -7389, -10526, -14784, -10799, -9149, -8485, -10799, -12319, -9639, -8192, -7464, -13365, -9238, -9531, -7774, -6422, -12776, -8615, -11004, -7960, -6828, -9585, -8615, -14784, -8865, -8517, -9585, -8827, -17034, -10526, -10362, -12123, -9639, -12123, -9873, -10138, -17034, -11629, -9331, -7796, -9149, -12776, -13365, -8086, -6705, -9429, -11488, -11629, -8060, -6705, -11232, -11115, -11004, -9022, -8165, -15615, -11232, -11115, -10526, -13049, -28777, -13738, -11781, -12534, -11488, -28777, -28777, -11629, -28777, -9531, -13738, -11115, -10799, -12319, -9873, -12123, -9639, -9639, -9531, -10210, -11945, -10001, -9064, -8982, -9531, -11232, -11115, -9106, -10069, -8363, -8982, -9812, -9331, -12776, -7865, -7503, -7984, -9238, -17034, -8485, -6899, -7113, -9695, -14195, -10362, -7081, -7019, -11488, -11115, -11232, -7819, -7542, -15615, -9936, -10210, -8982, -8683, -17034, -9753, -9585, -10799, -10704, -17034, -10210, -9106, -15615, -13365, -17034, -10899, -8790, -12776, -13365, -14784, -11356, -9022, -9429, -13365, -13049, -12534, -9531, -9331, -9695, -11629, -10362, -11945, -10001, -13738, -14195, -12776, -11004, -7034, -14784, -14195, -9106, -12776, -5960, -10069, -9873, -7353, -28777, -6035, -8649, -6828, -6332, -9753, -5970, -9238, -5531, -5759, -7426, -5726, -14784, -5109, -5897, -6745, -6492, -9531, -5299, -6745, -7081, -8982, -6553, -5702, -7623, -8649, -11945, -5654, -6113, -7503, -9753, -11945, -5888, -7034, -6045, -7687, -11115, -7317, -9284, -4901, -6457, -8276, -11356, -11488, -4759, -6026, -7019, -12123, -9531, -5630, -6045, -7004, -8009, -8827, -7464, -6365, -7644, -6842, -9106, -10210, -6492, -8582, -7213, -9695, -15615, -5988, -9812, -7708, -9639, -13365, -5480, -9695, -6256, -7730, -8582, -5085, -7623, -5472, -6225, -6640, -4693, -6958, -6354, -6113, -6204, -4464, -8304, -8454, -7960, -6828, -4460, -14195, -8333, -10899, -8086, -4759, -11781, -8393, -8718, -9284, -5569, -9064, -8903, -9479, -9639, -7019, -7796, -7066, -15615, -8754, -8942, -6653, -5933, -10799, -8034, -11356, -5879, -6026, -8649, -7353, -28777, -6064, -6786, -7353, -7034, -9585, -7583, -7247, -6759, -7912, -6528, -9639, -6800, -7130, -11356, -5516, -9429, -6225, -8165, -12534, -5853, -10069, -6204, -8827, -10613, -6842, -11781, -6870, -8649, -14784, -7665, -13365, -7960, -8393, -10613, -9149, -14784, -8220, -8683, -6914, -10069, -11781, -8009, -9479, -5678, -8060, -10138, -9193, -8549, -5726, -7752, -10613, -11356, -6828, -6870, -9639, -13365, -9753, -6007, -8615, -9873, -28777, -9238, -6299, -8649, -8393, -12319, -8485, -7730, -8423, -9429, -9284, -6745, -9873, -9429, -13049, -7445, -5718, -11488, -11115, -11232, -6388, -5561, -12776, -13738, -10138, -6083, -6026, -12319, -12319, -10442, -6267, -6692, -10799, -9429, -8903, -6565, -6732, -10284, -9149, -7264, -6928, -5951, -10284, -11004, -6615, -7936, -4885, -10069, -15615, -6745, -9936, -4180, -10899, -11004, -7247, -12776, -4250, -17034, -9531, -7644, -15615, -5286, -11232, -9812, -7984, -11781, -7213, -8683, -11781, -8790, -9695, -8112, -8754, -17034, -9106, -8982, -7912, -11629, -12534, -8754, -8485, -8683, -14195, -10799, -9238, -7984, -10704, -11629, -9873, -9531, -7936, -12319, -12776, -9106, -9479, -7912, -12534, -14784, -9022, -11945, -7984, -14784, -12534, -9639, -15615, -8363, -28777, -10138, -9639, -9936, -9064, -12776, -8304, -9479, -8549, -8517, -11356, -7299, -10210, -8034, -7623, -11004, -7179, -11115, -7523, -7842, -10001, -7796, -10613, -7408, -9695, -9380, -9531, -10526, -7912, -14195, -9812, -13738, -11356, -10001, -28777, -11781, -17034, -13738, -28777, -28777, -14195, -11945, -28777, -9429, -13365, -12123, -10138, -14784, -7708, -12534, -10001, -9106, -12776, -7936, -17034, -9022, -8790, -11356, -9479, -14195, -9022, -9380, -10704, -11629, -10613, -10001, -10613, -10526, -11115, -10362, -12123, -10799, -10284, -9531, -11629, -13738, -10138, -10284, -8827, -15615, -11629, -10704, -10704, -9284, -17034, -11004, -12319, -11629, -10613, -12123, -12534, -12319, -11488, -12534, -7912, 8129, 8421, 4616, -91, -5208, 7667, 8075, 5018, 389, -3412, 6217, 7030, 5460, 639, -1710, 3433, 5274, 5332, 427, 1114, -2217, 2927, 4709, 850, 3155, -662, 578, 3903, 1078, 3852, 970, -1786, 2948, -412, 2963, 594, -8393, 1261, -3701, -587, -1247, -2245, -2217, 919, -951, -2749, 439, -2153, 2934, 1518, -1398, 1739, -17, 3694, 1447, 72, 2577, 49, 3955, 134, 1663, 2943, -1025, 3872, -1774, 2634, 2519, -565, 3053, -2194, 2594, 766, 973, 632, -985, 1323, -4518, 1671, -1203, -1142, -2094, -979, 1525, 2144, -2555, -5183, 1761, 946, 3236, -3748, -1343, 2641, 1113, 2723, -8549, -981, 2386, 2234, 930, -3067, -1508, 953, 3135, -57, 413, -727, -2273, 3407, -346, 1639, -181, -8192, 3019, -5061, 1671, -1185, -7113, 1992, -1153, 673, -3436, -10799, 44, 2113, -1646, -1458, -4278, -4527, 3050, -5444, 107, -2885, -2182, 2826, -4064, 295, -3540, 293, 1696, -1480, -95, -2478, 637, -295, -243, -21, -812, 326, -1317, -374, 306, -1037, 1164, 100, -1299, 74, -4901, 2180, 1009, -1759, -752, -3763, 2296, 1240, -832, -1872, -349, 1388, 1079, 676, -3339, 2, -304, 441, 1219, -6064, -1645, -1207, -1156, 393, -7230, -5531, -861, -4640, -1244, -2071, -3543, -1275, -7603, -1078, 108, -2222, -3080, -4097, -773, 777, -2339, -5979, -2231, -2156, 148, -2924, -7004, -1341, -6958, -2383, -3947, -5458, -1268, -7583, -11232, -4195, -3471, -1645, -5026, -3344, -2294, -2049, -2220, -4123, -2877, -1233, -1253, -2783, -2232, -5472, -1025, -1301, -2756, -872, -10284, -589, -2064, -2294, -487, -8247, 466, -3187, -1788, -1037, -6958, 1229, -5480, -1302, -2305, -3225, 1182, -5139, -1156, -3566, -1562, 155, -1846, -1830, -5008, -1327, -2032, -539, -3886, -6679, -2234, -5487, -243, -6235, -4784, -4157, -5176, -421, -4669, -3641, -6528, -3220, -884, -4442, -3751, -8112, -2661, -1820, -5592, -5014, -8718, -3404, -3316, -6800, -7936, -8754, -5214, -3518, -7865, -7984, -10210, -6054, -2198, -10899, -8086, -14195, -5554, -1443, -11004, -14195, -9936, -4455, -1409, -6553, -6705, -8982, -2877, -1998, -3798, -5247, -10001, -1698, -3056, -1842, -6103, -11232, -1157, -3830, -744, -9429, -13738, -1310, -3612, -526, -13365, -9873, -2330, -3121, -1324, -7426, -5654, -4307, -2992, -3422, -4821, -3701, -4790, -3306, -6267, -3704, -2889, -3360, -3883, -5879, -3971, -3089, -2819, -4323, -6113, -5451, -4532, -3201, -4373, -7583, -6422, -7984, -4278, -4331, -7687, -6054, -13049, -5844, -4664, -6885, -5299, -13738, -6074, -6045, -5768, -4315, -8865, -4649, -10210, -4764, -3937, -6640, -4089, -11232, -4869, -4303, -6256, -4286, -7445, -6800, -5247, -6759, -4327, -6256, -15615, -6679, -8276, -4145, -5055, -7081, -8276, -12319, -4509, -4286, -5031, 5810, 2751, -3003, 7114, -1794, 5418, 2238, 3725, 6585, 1614, 4093, 685, 5400, 4857, 2891, 1271, 812, 4932, 2564, 1994, -6143, 2495, 2201, 3529, -1765, -4078, 2793, 446, 4063, -5646, -2043, 1563, 3779, 2944, -1987, -73, -741, 4886, 951, -3641, 1109, 535, 4795, 682, -9380, 1309, 2366, 3656, -273, -2364, 977, 3028, 1304, -5924, -327, 785, 2696, 784, -983, 822, 1122, 2017, 3220, 1278, 1077, 1885, 2691, 4575, 1727, 180, 2938, 3463, 4949, 1296, -1754, 3983, 2996, 4442, 255, -2783, 4638, 729, 2959, -985, -1745, 4593, -3589, 119, -174, -1396, 3498, -1326, -3201, 2031, -2305, 626, -854, -706, 3390, -4017, -1043, -2162, 473, 3675, -6786, 1434, -4863, -47, 3198, -6914, 1734, -11488, -1307, 2907, -2245, 728, -2637, 106, 2779, -1092, -103, -201, 1108, 1615, -884, 94, 218, 542, -373, 777, 109, -1231, -1205, 134, 1873, 98, -2015, -1610, 41, 1161, 808, 797, -1238, -2432, -2831, 1786, 2177, -2685, -10526, -3615, 2351, 2540, -3112, -6504, -1518, 2203, 2385, -201, -5480, -4352, 1230, 1832, 710, -5776, -4679, -322, 609, -284, -9238, -2265, -1097, -1628, -4564, -10442, -2677, -516, -4230, -4460, -6814, -1613, 538, -4810, -1797, -7503, -42, 1397, -6064, -2071, -10001, 538, 1530, -11356, -3814, -2455, 176, 566, -5465, -5109, 413, -1173, -2320, -3175, -3957, 1652, -3060, -13738, -3301, -2560, 1715, -3896, -3933, -4759, -1663, 636, -4262, -3641, -3449, -1377, -1990, -4336, -5121, -2095, -1987, -7299, -4064, -6225, -2019, -3763, -4795, -3479, -5437, -3154, -4115, -3618, -2863, -4123, -6016, -2204, -3776, -3058, -3656, -8615, -1599, -4089, -3873, -4307, -7019, -2412, -4195, -3529, -6565, -7687, -5014, -4713, -2694, -12123, -8903, -9936, -6653, -2657, -4795, -8754, -5444, -11629, -3347, -2709, -9531, -3751, -8304, -4478, -2605, -9812, -3237, -7004, -5494, -4078, -5458, -3286, -7019, -5702, -4688, -3609, -4161, -7019, -5401, -3010, -3449, -6958, -6628, -5516, -1701, -4473, -8982, -5970, -6399, -549, -6299, -8393, -5509, -7623, 134, -8086, -8363, -5662, -7523, 20, -8549, -3560, -6064, -6310, -985, -7708, -2178, -5853, -5638, -2893, -5451, -3085, -6411, -5743, -5615, -4527, -5472, -9936, -6133, -9106, -5827, -2956, -11945, -5970, -13365, -12319, -1656, -6885, -5273, -13738, -9585, -1994, -4319, -4951, -10442, -7730, -3644, -2833, -5710, -7247, -6299, -6842, -2720, -6565, -5380, -5306, -28777, -4315, -5546, -4644, -5702, -8423, -9149, -5279, -4659, -7796, -6133, -6842, -6885, -4698, -7842, -5662, -5444, -11781, -4161, -5654, -6602, -6988, -9531, -3465, -5164, -6705, -10210, -7623, -3324, -6016, -4810, -6615, -7034, -4180, -7752, -4060, -5408, -6885, -6183, -8754, -4683, -5576, -7066, -8982, -7730, -6540, -6577, -7426, 7775, 3486, -3409, 6394, 8147, 7302, 2951, -449, 6089, 7915, 5722, 1586, 1184, 5311, 7244, 2010, 796, 1186, 4451, 6152, -1259, 1258, -143, 3733, 4391, 3176, 1783, -1680, 2617, 2593, 4027, 2024, -818, 940, 4178, 3651, 1508, 642, 1854, 4899, 3008, -50, 1485, 2837, 3291, 2594, -1202, 1176, 2496, -949, 1762, -714, -1098, 1766, 3303, -217, -906, -9193, 1214, 4537, -4536, -1948, -20, 431, 4869, -3051, -3428, 2048, 862, 5421, 9, -5654, 2373, 1696, 5574, 1413, -4912, 1299, 1275, 5145, 1772, -1607, -880, -945, 4881, 977, 366, -679, -4644, 4832, -1743, 1576, 555, -2873, 4192, -3360, 2583, 878, -1392, 2959, 293, 3527, 613, -306, 2757, 1714, 4104, 309, -101, 3943, 2141, 4010, 797, -980, 4874, 1935, 3045, 1596, -2488, 4965, 1063, 1165, 1614, -3301, 3808, -674, -618, 227, -2893, 170, -3163, -1216, -4382, -2688, -1249, -2943, -2112, -4060, -3407, 1858, -1005, -1935, -613, -2294, 1852, 326, -1055, 170, 94, 143, 1129, -904, -427, 1297, -2583, 1531, -1292, -2635, 1298, -3665, 1668, -2020, -7730, -15, -2960, 1607, -2366, -12123, -3208, -2994, 1257, -2372, -7196, -4491, -4108, 349, -1875, -2801, -2228, -5312, -1377, -277, -804, -1556, -4754, -2490, 165, 258, -1644, -2973, -1534, -1685, 980, -2268, -1210, -632, -6666, 1193, -3923, -272, -311, -1448, 502, -7960, -698, -1348, -619, -1335, -4357, -3680, -5836, -1920, -3479, -2168, -7230, -5801, -3846, -3417, -2079, -2309, -3396, -3523, -3808, -3776, -2241, -4226, -3738, -4601, -7335, -4912, -6235, -3606, -4254, -8363, -3158, -6278, -2698, -4723, -6278, -739, -4569, -3433, -7230, -3644, -133, -3792, -7503, -9936, -2613, -839, -4555, -5988, -9106, -3357, -2545, -6504, -4654, -7984, -6103, -3208, -4764, -6225, -6365, -5401, -2424, -2701, -6899, -6800, -3316, -2280, -2060, -6628, -13365, -2724, -2745, -2776, -6745, -7583, -2871, -3360, -5444, -3735, -4985, -3254, -4211, -14784, -2288, -4219, -3078, -6214, -6310, -2404, -4010, -2121, -10362, -5049, -3913, -3957, -1096, -9193, -5273, -7097, -3840, -438, -9936, -6399, -12319, -3326, -169, -11232, -8615, -11945, -2688, -95, -10001, -10210, -11488, -2409, -150, -14195, -8138, -11115, -2670, -566, -5924, -7523, -10613, -3354, -1602, -3430, -7774, -10001, -3940, -3354, -2922, -7408, -10284, -3947, -5662, -3589, -6113, -9429, -4112, -8517, -4064, -5109, -6988, -5067, -13738, -4089, -4907, -5879, -6628, -12319, -5394, -5718, -6540, -7408, -10799, -8138, -8009, -9429, -7317, -10284, -5546, -14784, -7179, -8304, -7888, -4064, -8754, -4606, -10210, -6885, -4100, -6163, -3665, -7146, -7687, -5319, -5292, -3837, -5444, -11781, -8454, -5444, -4997, -5444, -10284, -13365, -6528, -6411, -6679, -6928, -8423, -8865, -7113, -7960, -5827, -8034, -8393, -8903, -5516, -4659, -4713, -8982, -7464, -6492, -6480, -5422, -11232, -8363, -6856, -7426, -6842, -6666, -11488, -6745, -5494, -8485, -4438, -28777, -7196, -4718, -8827, -3766, -12123, -8827, -5170, -7888, -3856, -8615, -10613, -6814, -7034, -4024, -6457, -10284, -10138, -7004, -4145, -5127, -8754, -13365, -7484, -4901, -4826, -7426, -11488, -6958, -7066, -6035, -7335, -10704, -5694, -12776, -10442, -7445, -9695, -5091, -13365, -9479, -6640, -8517, -5158, -9695, -6457, -6035, -7542, -5844, -7335, -5592, -6225, -6958, -7408, -6173, -5678, -7796, -6602, -9193, -6745, -6411, -11781, -6786, -11629, -10362, -6666, -6163, -7960, -8790, -4869, -4536, -2833, -6422, -3989, -2273, -2716, -1138, -3641, -1965, -1694, -2068, -603, -2534, -1450, -2610, -2617, -1166, -2945, -2211, -4416, -4311, -2994, -4963, -4455, -5133, -5818, -6692, -9238, -8582, -5592, -5339, -10362, -13049, -10704, -7335, -5465, -8718, -11781, -11115, -9585, -6928, -9380, -10284, -14195, -9064, -8165, -11115, -10442, -17034, -8423, -6640, -10799, -13365, -13738, -8827, -5401, -9331, -11781, -13365, -8754, -5353, -8220, -9193, -15615, -8034, -6800, -7984, -8138, -13049, -8276, -9331, -8363, -7960, -12534, -9873, -9753, -7066, -8192, -14195, -12319, -10138, -5888, -8009, -14784, -12776, -10362, -6074, -8615, -13049, -9479, -7819, -7665, -12319, -15615, -7162, -6759, -10526, -11004, -17034, -6194, -7464, -12776, -8903, -14784, -6183, -9331, -10210, -10442, -28777, -6288, -9479, -8454, -15615, -10001, -6143, -8393, -8582, -14784, -7665, -6083, -7523, -10526, -17034, -7752, -6653, -6615, -17034, -10526, -10799, -8790, -5960, -12123, -9149, -11232, -12534, -6183, -8333, -9479, -7503, -8034, -7774, -6516, -9873, -6343, -6719, -11781, -5554, -10799, -6045, -6828, -8517, -5121, -14784, -6204, -7796, -6411, -5103, -14195, -6388, -9695, -6246, -5662, -11945, -6422, -10284, -7603, -7034, -11945, -6828, -8086, -10613, -9022, -11115, -8485, -6973, -13738, -10284, -9873, -14195, -7034, -28777, -11356, -9238, -11488, -7687, -12319, -13049, -8942, -8423, -8138, -9479, -11781, -8982, -7842, -8333, -9193, -9193, -9531, -8423, -9022, -10613, -8192, -10526, -9695, -9812, -11945, -8304, -11356, -8982, -9695, -10362, -8982, -10613, -7888, -9238, -9380, -8942, -9193, -8276, -9193, -8827, -8363, -8086, -11356, -10138, -8247, -7865, -8009, -17034, -12776, -8060, -7912, -9380, -11945, -14195, -9022, -8827, -13365, -13738, -12319, -11945, -10069, -15615, -17034, -12319, -28777, -9695, -13738, -10899, -11629, -15615, -8982, -15615, -10284, -9812, -15615, -9479, -17034, -12123, -8615, -12776, -10526, -14195, -17034, -8304, -11356, -11115, -10799, -28777, -9149, -11356, -12319, -8982, -15615, -11232, -11356, -15615, -8276, -12534, -13049, -11115, -17034, -8903, -12123, -14784, -11356, -13365, -11356, -13738, -15615, -13738, -10284, -28777, -28777, -14195, -17034, -8683, -12534, -17034, -11488, -12776, -8485, -11004, -13365, -10899, -11004, -9429, -10613, -11781, -10069, -6553, -8903, -8865, -7353, -9284, -6332, -9812, -14784, -7281, -7708, -7842, -8942, -8982, -9064, -6343, -11115, -8517, -7281, -8393, -5933, -7819, -8903, -7644, -4901, -6786, -6615, -8942, -10210, -3833, -9022, -7353, -8485, -13365, -4469, -11488, -9531, -8649, -9429, -6856, -9479, -12123, -9695, -8582, -8423, -6628, -10284, -9936, -9531, -6365, -4985, -8009, -9238, -12319, -5810, -4319, -6973, -9193, -17034, -6457, -4238, -7196, -9531, -15615, -8192, -4327, -8790, -8276, -10442, -14195, -4327, -12123, -7004, -7464, -9695, -4395, -14784, -6411, -6354, -6434, -5133, -10799, -5437, -6321, -5607, -8220, -5888, -3589, -5888, -6828, -8649, -2902, -1778, -3641, -8276, -3989, -1348, -695, -2039, -4082, -2509, -972, -555, -1717, -2545, -2517, -1735, -1415, -2737, -2841, -3707, -3804, -3373, -4555, -4826, -5888, -7644, -6469, -4527, -8517, -8138, -17034, -10442, -4203, -13365, -10442, -12534, -12319, -5085, -9531, -11781, -8865, -11781, -7162, -7426, -9022, -7130, -10362, -10799, -7542, -7196, -6246, -8827, -28777, -9531, -6504, -6457, -8247, -28777, -14784, -6842, -8276, -9380, -11004, -14784, -7912, -13049, -17034, -7230, -11115, -8865, -11356, -10001, -5630, -10001, -9479, -9695, -7665, -5584, -9936, -9022, -9639, -7583, -6914, -10069, -7335, -9429, -9022, -8942, -7819, -6153, -8865, -9936, -9639, -6035, -6143, -8942, -9022, -9753, -5502, -7774, -9429, -8649, -8060, -5997, -12776, -10069, -8333, -6973, -7264, -11488, -10613, -7562, -7162, -8718, -9812, -10001, -6988, -8454, -10069, -10362, -9380, -7034, -10613, -11945, -11232, -8304, -7888, -14195, -10899, -11488, -6856, -9753, -14784, -9380, -11629, -6235, -11356, -11004, -9639, -12319, -6814, -9284, -9284, -10704, -14784, -9331, -7230, -8718, -10442, -28777, -15615, -6103, -8423, -11356, -12776, -8903, -5970, -8165, -17034, -12534, -7389, -7019, -8304, -13738, -14784, -7752, -9531, -8790, -11115, -12123, -8790, -9585, -8865, -10442, -10138, -8517, -8086, -8549, -9936, -9149, -8220, -7888, -8363, -8865, -7960, -8423, -8247, -8827, -7796, -7179, -8060, -8615, -10526, -7503, -6800, -7264, -9106, -14784, -8517, -6679, -7162, -9873, -13738, -12123, -6719, -8009, -10138, -11488, -14195, -6958, -9753, -9531, -11004, -9429, -7583, -11004, -8982, -11232, -8754, -9193, -10210, -8393, -11945, -9639, -13365, -10362, -7819, -12319, -10442, -13049, -12319, -8112, -13738, -10704, -9936, -28777, -9753, -14784, -12123, -9479, -17034, -14784, -12776, -13738, -10069, -14784, -14195, -11356, -11781, -11488, -14195, -12123, -10210, -9022, -14195, -11356, -12534, -9193, -7445, -11232, -8982, -13365, -8718, -7130, -8393, -7842, -11945, -9022, -8060, -7644, -7936, -10704, -9873, -9812, -8454, -9585, -9531, -9238, -11232, -10899, -13738, -8942, -8165, -12534, -14195, -28777, -9064, -7865, -13738, -11488, -15615, -9585, -8363, -15615, -9479, -15615, -9753, -9753, -15615, -8982, -17034, -10613, -11781, -13049, -10001, -15615, -12534, -12776, -12776, -13049, -8138, -7865, -5554, -10001, -8649, -9193, -7842, -5818, -9429, -6653, -9936, -7888, -6679, -7426, -6628, -10526, -7162, -8517, -6640, -7523, -8060, -5615, -11629, -6299, -7335, -7912, -4336, -12776, -5615, -8276, -10442, -3923, -11232, -4274, -28777, -8220, -4611, -9284, -3137, -7464, -6235, -6870, -8165, -2801, -5539, -5751, -11232, -7842, -3311, -5592, -5933, -11781, -7097, -4532, -7034, -6235, -10069, -6540, -6163, -9936, -6194, -7066, -7445, -7865, -13365, -5862, -5387, -10526, -8649, -13049, -5678, -5055, -11232, -8454, -11945, -5818, -5897, -8517, -8615, -10526, -6773, -7317, -6411, -8220, -7335, -7796, -6007, -4149, -5584, -3982, -4616, -3930, -2168, -3281, -2036, -2698, -2823, -1128, -1967, -1420, -2253, -2741, -1185, -1613, -2040, -2889, -3920, -2462, -2334, -3971, -4336, -6365, -5234, -4386, -7562, -6267, -6278, -10138, -7623, -14784, -7503, -5599, -9479, -6773, -13738, -6074, -6856, -7281, -5924, -11004, -4880, -10362, -5451, -6565, -9531, -4664, -28777, -4299, -8423, -8790, -5380, -17034, -4075, -9873, -8549, -7066, -28777, -4946, -9936, -8304, -9531, -28777, -7196, -10442, -8363, -8903, -15615, -11945, -8363, -8903, -6973, -14195, -14195, -6365, -10210, -6143, -14195, -9193, -5576, -10526, -6083, -12776, -7130, -5662, -9531, -6365, -9695, -6310, -6577, -9284, -6628, -7730, -6504, -7708, -9331, -7019, -6856, -7562, -7445, -8683, -8060, -6800, -8790, -7389, -8112, -10138, -7066, -8138, -8086, -8112, -12123, -7179, -7066, -8086, -8220, -11115, -7426, -6492, -8865, -7936, -9380, -7888, -6310, -14784, -7081, -8423, -8582, -6653, -10442, -6422, -8138, -9873, -7562, -8009, -6434, -8276, -8790, -8517, -7687, -7213, -8086, -6899, -9479, -8138, -8247, -7371, -6469, -11488, -8393, -8683, -6343, -7687, -28777, -7984, -9022, -5429, -11488, -13365, -7730, -9531, -4957, -11004, -10799, -7865, -9639, -5061, -9238, -9531, -8220, -9873, -5853, -9531, -8754, -8582, -11945, -7603, -10799, -9193, -9284, -14195, -10284, -9695, -11356, -10799, -10362, -11115, -8454, -12319, -12319, -9064, -9238, -8582, -11004, -11781, -8649, -8034, -10442, -12319, -10613, -8517, -7464, -13049, -14784, -9639, -8363, -7665, -11629, -11629, -9149, -8454, -9331, -10442, -10001, -9149, -8754, -28777, -9106, -9531, -9531, -8718, -9238, -8423, -10526, -11232, -8247, -7247, -8517, -14195, -15615, -8192, -7774, -9106, -10704, -11945, -8865, -11232, -10442, -8363, -10442, -10704, -11945, -14195, -7960, -11115, -13049, -10138, -28777, -8649, -13049, -12123, -11781, -14784, -10442, -17034, -12776, -14195, -15615, -12534, -28777, -28777, -12123, -15615, -11232, -15615, -12319, -12319, -13365, -10210, -13738, -9936, -13365, -10899, -10362, -11488, -9479, -13365, -9380, -11629, -10526, -10210, -12776, -8982, -13365, -11356, -11488, -11781, -9753, -15615, -12123, -13365, -11232, -12319, -28777, -11781, -17034, -11945, -17034, -17034, -10799, -28777, -14195, -12123, -12123, -9639, -28777, -28777, -10526, -10001, -10284, 4117, -1741, 9439, 9312, 2929, 4284, 3780, 9089, 8741, 3537, 3546, 5573, 8139, 6969, 2777, 77, 5538, 6789, 3793, -832, 507, 4484, 5032, -1375, 2805, 1841, 4026, 2905, -4071, 3685, -490, 4578, 1425, -2758, 2398, 458, 4783, 2331, -3201, 1941, 2624, 4456, 3865, -749, 2661, 2622, 3622, 4037, 2250, 1839, 2018, 2369, 2478, 3507, 644, 2440, 1644, -681, 3310, 3949, 3087, 2569, -214, 2662, 6229, 3034, 3999, 1167, 3524, 7221, 2032, 4742, 2237, 4177, 7205, 1220, 4302, 3191, 3378, 6255, 1632, 2944, 3826, 324, 4266, 755, 3572, 3941, -5662, 652, -3412, 4796, 3351, -770, -8165, -3357, 4906, 1831, 557, -985, 358, 4203, -1154, 1485, 947, 3721, 3249, -5266, 2252, 1828, 5710, 2217, -2133, 3012, 2522, 6438, 254, -589, 3494, 3352, 6161, -3589, -192, 3259, 3915, 5106, 963, -496, 2047, 3842, 3530, 3031, -504, -223, 2924, 1435, 3332, -164, -1337, 954, -1360, 2077, -599, -29, -2297, -866, -1878, -2659, 1208, -4373, -668, -883, -9531, 2301, -707, -6504, 1977, -3968, 3284, 981, -403, 2637, -1710, 3956, 1025, 2695, 1865, -885, 4103, 302, 3660, -1123, -897, 3684, 222, 3544, -3586, -1897, 2782, 35, 2671, 818, -4331, 1276, -1210, 1024, 1553, -6773, -1669, -2617, -1780, 71, -4527, -4478, -2152, -2730, -5670, -3860, -1207, -1155, -566, -2241, -4123, -442, -263, 373, -511, -3007, -1201, 340, 491, -918, -1462, -3367, 250, 208, -2363, -759, -6759, -1057, -143, -3065, -858, -4795, -4550, -870, -2470, -1504, -2823, -9873, -2795, -2651, -2312, -1758, -7936, -5374, -4215, -3254, -1158, -6299, -2873, -5085, -4923, -1030, -3927, -1384, -3594, -8304, -1410, -3342, -940, -2659, -8827, -1766, -3583, -1076, -1906, -6705, -1193, -4049, -1614, -1075, -5726, -683, -5221, -2495, -660, -4795, -1190, -6553, -3583, -1224, -4262, -3252, -6163, -4679, -3641, -4429, -10001, -5960, -5306, -9193, -4564, -4134, -5836, -4295, -5085, -4270, -1272, -5234, -3135, -5458, -4386, -361, -4718, -2859, -9812, -4630, -674, -4664, -3744, -6745, -2861, -1711, -5472, -5312, -5109, -1241, -2348, -8304, -4991, -4425, -891, -1728, -5818, -4738, -4278, -1773, -806, -3342, -5221, -6214, -3968, -556, -2918, -3989, -10138, -7542, -1268, -3856, -2881, -4826, -11232, -3067, -4974, -3175, -3760, -8865, -6153, -4713, -5465, -4473, -5531, -8942, -3720, -12776, -6388, -3662, -7464, -3069, -5726, -8517, -2941, -5014, -3378, -3650, -8827, -3294, -3076, -5061, -3274, -8192, -4123, -1979, -8086, -4683, -8086, -3937, -1515, -8683, -9936, -9064, -3546, -1564, -5818, -4616, -8982, -3523, -1957, -3741, -1935, -7484, -3319, -2576, -2992, -1060, -6814, -3227, -3629, -3638, -1564, -6365, -3404, -3479, -6615, -3879, -6235, -3566, -2186, -9531, 6803, 9364, -4743, 4275, 9806, 6092, 8981, -377, 4063, 9215, 3944, 7910, 1949, 3178, 7333, 886, 6396, 2910, 2059, 3891, 539, 4752, 3404, 2191, 1230, 2443, 3137, 3821, 2050, 2253, 2887, 2212, 3979, 886, 2908, 935, 2848, 3917, -157, 2637, -1532, 3687, 3734, -219, 1128, 1752, 3753, 3302, -985, -1205, 2359, 2832, 2821, -2288, -2016, 1916, 716, 2936, 264, -266, 2262, -3396, 3667, 1652, 1017, 2916, -293, 4315, 1773, 1691, 3217, 2884, 4483, 1961, 2831, 3601, 4208, 4235, 2651, 3658, 4113, 4035, 3815, 3109, 3289, 4379, 1922, 3346, 2946, 1350, 4232, -4258, 2606, 1940, -2472, 3801, 545, 1129, 540, -4968, 3411, 1727, -1748, 1032, -6235, 2953, 1598, -4698, 1944, -4693, 2074, 634, -4513, 1989, -2300, 757, -121, -4486, 2266, 700, -1212, 2880, -918, 3610, 2747, -1140, 4536, 460, 4539, 3819, 1327, 4779, 542, 4573, 4236, 2028, 4032, 1154, 4013, 4197, 881, 2632, 1796, 3564, 3842, -3010, 736, 1195, 3340, 3341, -3692, -1967, -945, 2819, 2825, -1001, -7335, -3729, 2154, 2324, -172, -9585, -3404, 2086, 1895, 379, -9753, -2977, 2253, 1590, 868, -7464, -4184, 1805, 1304, 925, -4382, -4230, 159, 876, 240, -5067, -2104, -4336, 667, -1389, -4810, -1882, -2749, 1094, -3201, -1576, -3606, -125, 1286, -2071, -437, -4654, 30, 482, -1386, -1085, -2873, -1636, -1678, -2569, -4455, -2055, -2859, -5014, -7050, -6914, -1747, -1120, -6016, -5630, -2958, -1727, -1106, -7299, -2686, -3668, -2101, -3342, -9284, -1620, -8192, -2082, -5494, -7066, -1754, -1736, -1399, -3515, -6870, -3149, 466, -749, -3449, -5751, -6800, 1016, -236, -4826, -3662, -8276, 385, -15, -5374, -2675, -3147, -1336, -179, -3339, -2437, -1522, -3808, -489, -2068, -2378, -1380, -5326, -975, -2128, -2409, -2273, -4991, -2112, -3903, -2815, -3785, -4184, -4625, -8220, -3748, -5115, -4142, -11004, -7097, -3893, -5176, -6143, -4764, -6653, -2510, -4403, -9479, -2203, -7730, -1546, -3833, -4708, -1125, -5429, -1141, -4049, -3766, -1216, -2813, -684, -4703, -4733, -2958, -1710, -160, -4299, -5020, -9106, -2054, -124, -3512, -3401, -6113, -3741, -712, -3560, -2661, -5367, -6083, -1682, -4433, -2673, -9284, -7464, -2952, -5202, -3040, -9873, -7603, -5253, -5139, -3779, -6943, -5960, -7484, -4764, -5115, -6628, -3606, -5451, -3951, -8165, -5253, -1947, -4847, -3412, -7603, -3154, -1143, -5502, -3744, -4089, -1949, -1174, -7264, -5049, -2926, -1984, -2088, -7583, -6973, -2964, -2871, -3101, -5260, -7317, -3529, -3383, -2129, -4504, -6814, -3937, -4153, -1065, -5451, -7665, -4086, -6828, -1231, -7912, -8393, -4946, -5208, -2937, -12776, -6988, -6973, -3714, -4191, -7146, -6434, -5422, -5097, -2644, -4238, -7464, -3490, -13738, -2661, -4157, 5486, 3550, 4844, 8175, 8460, 5170, 3253, 3870, 7568, 8093, 4392, 2279, 1352, 5729, 7079, 3654, 309, 2109, 3368, 5881, 3139, -3668, 2386, 2603, 5308, 2364, -8718, 25, 1314, 5027, 954, -4592, -1019, -1668, 4008, -1091, -5694, -124, -885, 1579, -2493, -5401, -2617, 1393, 2270, -812, -468, -3650, 2522, 4231, 1549, 1044, -4078, 2252, 4803, 3187, 1508, -2751, -310, 5157, 3896, 2408, 242, -2160, 5623, 3491, 2656, -224, 2457, 5488, 1534, 1314, -926, 3846, 4459, -2553, 733, 1956, 3667, 2790, -1379, 1855, 2803, 2220, 1933, -639, 1429, 1960, 41, 2406, -1353, 895, 35, -1813, 2323, -2060, 2131, -1625, -13049, 1137, -1410, 2833, -2186, -281, -752, 498, 2583, -1550, 2102, -2289, 2368, 1526, -1194, 2105, -1291, 3310, -269, -1906, -200, 423, 2948, -2686, -3580, -5988, 1673, 944, -6035, -5227, 44, 2718, -748, -8549, -4336, 1949, 3219, 624, -3420, -2696, 2753, 3215, 240, -1534, -1060, 2976, 3404, -2350, -1011, 456, 2636, 3995, -3354, -1177, 1455, 1662, 4339, -1947, -1081, 1825, 307, 4072, -2610, -688, 1728, -275, 3103, -5097, -1049, 1468, -274, 1509, -4145, -2833, 1249, -1048, -3, -1979, -5694, 910, -2216, -152, -1130, -4127, 189, -751, -208, -1515, -2531, -918, 877, -835, -4262, -2002, -1690, 1630, -395, -4395, -1661, -840, 1837, 461, -897, -621, 139, 1759, 545, -180, 34, 72, 1428, 226, -1002, -608, -1502, 841, 222, -1966, -2914, -4847, 164, 579, -1713, -4451, -3612, -274, 639, -1577, -4319, -2460, -340, -86, -1999, -7865, -3054, -164, -1470, -2859, -8009, -4127, 94, -2163, -4433, -4303, -2969, 286, -2071, -7097, -2997, -1438, 197, -2385, -8086, -2427, -750, -224, -3085, -6411, -2945, -831, -647, -3757, -5615, -5630, -1552, -668, -4290, -5897, -6628, -3189, -624, -4963, -7984, -2752, -7034, -1196, -5531, -7162, -2084, -11488, -2897, -3860, -3399, -3433, -7687, -5429, -1557, -1965, -3365, -4795, -4644, -287, -2211, -1878, -2088, -3354, 54, -4664, -2297, -765, -3352, -291, -11488, -4963, -507, -5768, -1282, -3707, -4399, -1078, -6577, -3203, -2057, -1956, -2407, -2091, -3992, -1900, -1040, -4769, -717, -1906, -2507, -1232, -8790, -824, -740, -2735, -2528, -6163, -2170, -543, -2407, -4234, -5546, -5638, -1051, -2666, -4108, -8790, -7426, -2071, -3853, -4153, -5502, -2971, -2943, -5576, -5576, -2823, -1522, -2783, -6653, -5888, -2222, -1382, -2201, -6332, -4447, -2897, -2361, -1945, -5615, -4172, -4142, -4901, -2239, -5743, -4635, -4262, -8790, -3237, -7603, -4348, -3978, -5554, -4997, -8754, -3632, -3261, -4130, -6666, -4447, -2597, -1600, -3535, -6288, -2571, -1420, -776, -3560, -4869, -2213, -1073, -1289, -5326, -2952, -3149, -2082, -3218, -8247, -1549, -6719, -5997, -3763, -2377, -3992, -3662, -4254, -4985, -5202, -2762, -2493, -2635, -11356, -6113, -3760, -2419, -1961, -4907, -3076, -4659, -2787, -2257, -2323, -2555, -1855, -2967, -3487, -2100, -3266, -850, -2670, -5897, -3856, -5061, -1705, -2414, -9585, -5408, -10138, -4842, -2644, -7865, -2825, -6133, -9639, -3757, -6457, -1792, -3449, -10362, -6321, -6814, -1902, -2835, -7752, -8112, -10362, -2628, -3436, -3653, -4491, -8165, -3930, -5061, -2342, -2330, -4238, -6411, -7146, -2232, -1533, -2910, -5623, -7247, -2560, -2306, -3184, -3027, -6828, -2813, -6278, -5319, -2311, -6469, -2641, -4743, -7503, -3465, -4469, -1841, -1353, -3704, -4968, -1794, -867, -386, -1854, -2222, 59, -291, -631, -1258, -1011, 840, -452, -1650, -1797, -1335, 566, -1607, -3069, -3883, -2512, -619, -4211, -4764, -9380, -3641, -2355, -7774, -6376, -9695, -5818, -4282, -5718, -6225, -8827, -11629, -4968, -4816, -5429, -10362, -4064, -3165, -5853, -4559, -6354, -2305, -1973, -10362, -3665, -3916, -2135, -1928, -6705, -3289, -3261, -2754, -3036, -3388, -4042, -3903, -3566, -4104, -2140, -7113, -4559, -4270, -3621, -2326, -10704, -4460, -4352, -3893, -3886, -5408, -5678, -3714, -5569, -7066, -4003, -11945, -3683, -4863, -11356, -3723, -8363, -5043, -3441, -7730, -4130, -6388, -8549, -3626, -7335, -5374, -5686, -6504, -5247, -8060, -8220, -4460, -4112, -7583, -4311, -17034, -3650, -3194, -8192, -2510, -6786, -3543, -3007, -7371, -2286, -3975, -3766, -3276, -7960, -3087, -2610, -3947, -3824, -8192, -3999, -2271, -4408, -4500, -4769, -5127, -2739, -5472, -5152, -3126, -9238, -3779, -6692, -5367, -2837, -8423, -4748, -6528, -4764, -3476, -5394, -4795, -6246, -4357, -4769, -5784, -4733, -6914, -4974, -6204, -8865, -5630, -7708, -6653, -6310, -11115, -8086, -7213, -7523, -5592, -9695, -11232, -5836, -6267, -5592, -9022, -8649, -4703, -4336, -6814, -6445, -6885, -4238, -3144, -6943, -3886, -6256, -4112, -3362, -4348, -2540, -6870, -4112, -5451, -2793, -2488, -7317, -4918, -5408, -2306, -3732, -5176, -7503, -3056, -2690, -6278, -3638, -9380, -2420, -4049, -10138, -2859, -7004, -2865, -6026, -8517, -2594, -7335, -3741, -5827, -5638, -2885, -12776, -4282, -5326, -5152, -3923, -8034, -4195, -5988, -6504, -5879, -5710, -4164, -6732, -7299, -9479, -6103, -4997, -7213, -6143, -12123, -8138, -7130, -8333, -6026, -9585, -9064, -8903, -9479, -6719, -10362, -11115, -10210, -8363, -7066, -17034, -12534, -12534, -6504, -6214, -11232, -8754, -7371, -5292, -4896, -7936, -8086, -5988, -5020, -4108, -5906, -7644, -6007, -5759, -4207, -4869, -6759, -6204, -7796, -5260, -4923, -6016, -5654, -9022, -7230, -6434, -5183, -4759, -7464, -8034, -10704, -4460, -4270, -7264, -6705, -6590, -4352, -4625, -8192, -6310, -3913, -4863, -5933, -8827, -7445, -2891, -5915, -7912, -8304, -12319, -2992, -7484, -7960, -7213, -10138, -9380, -3198, -4853, -4295, -8247, -5208, -4573, -3269, -5286, -4901, -2557, -9106, -3225, -4863, -2065, -1252, -7542, -3662, -5561, -1290, -945, -4390, -4583, -6928, -994, -1398, -3222, -6928, -6800, -747, -2217, -2823, -28777, -4683, -983, -3344, -2512, -6540, -3242, -1728, -6354, -2286, -4420, -3471, -2276, -8827, -2631, -4104, -6016, -2254, -3543, -3827, -4416, -8615, -2257, -1908, -5702, -4145, -6842, -2597, -1442, -7426, -3846, -8827, -3412, -1750, -6163, -4089, -28777, -5227, -2910, -4433, -4412, -9331, -9873, -4880, -3913, -4583, -5401, -5654, -6445, -5127, -5234, -3870, -2733, -8942, -7644, -7097, -4357, -1243, -7960, -2900, -4940, -3049, -371, -2897, -697, -2018, -369, 88, -1191, -128, -795, 869, 184, -1080, -729, -956, 933, -136, -2139, -2060, -2672, 54, -1031, -3735, -3042, -7774, -1542, -2696, -4482, -3367, -7264, -3399, -5374, -4478, -3820, -4935, -5360, -9380, -4369, -4504, -5888, -8060, -14784, -4142, -5429, -8393, -9639, -15615, -3324, -5638, -5202, -10284, -28777, -2351, -4003, -3266, -8363, -12123, -2019, -2683, -2657, -6153, -8827, -2455, -2333, -3352, -5862, -8247, -2631, -2492, -6278, -5871, -5801, -1885, -2223, -8683, -4115, -3683, -1462, -1820, -4935, -2724, -3309, -1690, -2053, -4024, -2566, -4513, -2232, -3080, -4064, -4024, -5253, -2517, -4451, -4286, -8086, -3714, -2739, -4784, -4728, -4625, -2716, -4060, -3951, -6267, -2622, -2462, -8485, -3254, -13365, -2336, -2751, -8165, -3003, -5465, -2941, -3521, -6732, -2766, -2605, -3754, -4743, -8942, -2455, -1535, -4157, -6528, -17034, -2562, -1482, -4336, -7503, -11232, -3239, -2075, -4620, -5726, -7583, -3754, -3128, -4541, -4089, -4460, -3940, -4429, -4616, -3271, -2875, -4759, -5346, -6256, -3352, -2730, -6814, -5109, -8903, -4460, -3782, -10138, -4606, -5801, -7146, -4597, -13738, -4997, -4759, -17034, -4145, -12319, -5043, -5061, -8754, -4164, -10362, -3515, -5988, -7034, -4810, -11004, -2789, -7687, -7034, -4985, -12534, -3391, -8423, -6246, -4649, -12534, -5584, -7562, -4464, -4478, -9936, -11945, -7484, -3653, -3732, -6615, -8112, -6988, -3896, -2578, -5374, -5374, -6719, -4708, -2130, -5853, -4683, -7888, -5546, -2867, -8333, -5801, -10284, -6958, -5408, -15615, -11232, -8827, -8683, -10442, -12123, -7687, -7912, -6399, -7603, -9479, -5801, -8790, -4907, -7562, -6885, -6773, -8827, -4901, -9479, -5437, -10442, -6310, -6299, -11004, -5401, -8615, -5061, -9284, -9531, -7066, -7464, -5127, -13049, -7936, -12319, -6943, -6615, -13049, -7796, -11115, -5234, -10138, -11488, -9106, -7230, -3992, -8865, -11356, -11356, -5031, -3686, -7097, -11781, -11356, -3804, -4093, -7130, -11232, -8304, -3741, -4713, -8582, -9193, -6123, -5195, -4754, -12534, -7960, -4842, -9479, -4006, -13049, -8304, -4311, -8903, -3191, -9873, -11356, -4504, -7213, -3025, -8982, -10069, -5862, -8333, -3863, -8718, -6870, -5247, -4654, -6411, -3069, -1035, -7730, -4555, -7819, -1087, -1342, -5793, -2967, -4473, -272, -2170, -2918, -2353, -2538, 8, -3001, -1487, -1935, -1790, -342, -3540, -1089, -1391, -1646, -1800, -4266, -1343, -995, -1936, -3040, -5735, -1846, -942, -2416, -1246, -7445, -2502, -1150, -2128, -392, -7081, -4060, -1581, -1503, -831, -7317, -6445, -2747, -1493, -2198, -8304, -4067, -5879, -2066, -3692, -7213, -2385, -13738, -2741, -4382, -5451, -1823, -8454, -3304, -4693, -4078, -1647, -7842, -3961, -5026, -3906, -1611, -7503, -4184, -5494, -4469, -2280, -8865, -3814, -5253, -3334, -5014, -10526, -5686, -4821, -2962, -4963, -4779, -5793, -6143, -5509, -1939, -1962, -893, -5339, -5801, -1399, -953, 636, -2308, -2420, -2447, -1412, 543, -889, -1892, -3827, -3210, -730, -471, -3133, -3080, -5793, -2355, -653, -6577, -2703, -7562, -2999, -1036, -7644, -4017, -8865, -3334, -1310, -4923, -6399, -10210, -3788, -1838, -4703, -4748, -9812, -3717, -3144, -6988, -3916, -9936, -3266, -4583, -8393, -3689, -8247, -3201, -3957, -5793, -3252, -6504, -3441, -3128, -7389, -3158, -5768, -3457, -3119, -6914, -3281, -5759, -2950, -4093, -3047, -3242, -6590, -2303, -6692, -2143, -2924, -9284, -2162, -11356, -3069, -1932, -12534, -2743, -6093, -5735, -1068, -6759, -3751, -4234, -8192, -985, -4597, -4664, -3444, -6457, -1686, -3314, -5227, -2646, -5299, -2897, -2437, -5253, -2032, -4718, -4559, -1932, -4559, -2176, -4142, -7445, -1959, -3367, -3051, -3378, -28777, -2960, -2257, -3840, -2677, -6988, -5888, -1494, -3889, -2366, -4262, -7371, -1097, -3279, -2641, -2988, -4968, -1021, -2743, -3249, -2762, -5326, -1308, -3184, -3428, -3409, -7034, -2049, -5437, -3087, -3850, -7264, -3208, -15615, -2939, -3321, -8034, -4207, -6745, -3698, -3244, -11004, -4157, -4597, -6083, -4203, -12776, -4119, -3529, -9238, -5844, -11945, -5292, -2458, -11232, -6692, -6988, -9812, -1581, -11115, -5615, -4679, -8363, -1255, -6856, -4013, -4203, -4985, -1556, -7752, -3065, -5524, -4219, -2495, -11356, -2926, -9695, -4923, -3961, -5127, -3347, -12534, -7299, -5221, -3580, -3779, -13738, -11115, -5394, -3704, -3735, -8790, -6457, -5487, -5346, -3485, -5879, -3493, -5751, -11004, -3311, -4800, -2051, -5401, -7523, -3276, -4097, -1771, -4399, -5008, -3493, -3249, -2398, -3569, -4569, -4164, -2488, -3490, -3474, -4654, -5176, -2023, -4336, -4482, -4357, -5951, -2102, -4784, -7389, -4049, -5979, -2962, -5401, -9238, -4115, -5776, -4382, -7213, -6354, -4064, -6267, -5759, -12319, -5897, -3798, -7936, -8485, -12534, -6943, -3933, -9639, -11945, -8982, -8582, -4478, -10284, -6828, -6870, -8363, -4754, -11629, -6074, -6183, -7503, -4863, -10442, -6914, -7019, -7146, -5516, -7730, -8333, -8276, -7004, -5818, -6278, -8790, -7130, -6204, -5109, -6214, -7960, -6445, -5067, -5214, -7213, -7050, -7113, -4564, -6653, 8198, 5825, 565, 6157, -726, 8211, 6039, 937, 5454, -1500, 7961, 5718, 1930, 2821, -1419, 6996, 3610, 3491, -2125, 778, 5105, -701, 4384, 2225, 1888, 2860, 2874, 3799, 2570, 1659, 1944, 3990, 757, 6, 290, 2955, 3960, -313, -4550, 736, 4407, 3787, 2482, -13, 2463, 4907, 3661, 2428, 1038, 3412, 4593, 3283, 160, 2893, 3943, 4378, 2556, -6653, 4867, 4183, 4084, 3063, -2468, 5775, 4065, 2255, 4607, -936, 5456, 3534, -2251, 5324, -1104, 3646, 2312, 637, 5050, -2286, 152, -54, 1147, 4049, -2288, 1191, -2440, -34, 2488, -1036, 2116, -2567, -18, -227, -804, 1244, -4290, 1057, -7113, -1859, -1124, -6516, 1512, -4416, -3569, -5055, -2477, 1477, -1324, -3920, -6054, -589, 1325, 33, -2380, -4064, -160, 762, -497, 55, -1526, -1123, -42, -3455, 1225, 705, -3501, 694, -2492, 1104, 1705, -2016, 1467, -1420, 769, 1596, 43, 1437, -4223, 1187, 339, 402, 1444, -1094, 918, -3930, -1041, 1311, 1932, -814, -2984, -3964, -87, 2749, -571, 483, -760, -4067, 1963, 1360, 691, 598, -11781, -884, 1887, -1220, -117, -9193, -5292, 1071, -1963, -2268, -7081, -2286, -1614, -180, -1212, -3618, -2590, -10210, 186, -399, -1580, -3367, -1739, -271, -1497, 119, -1307, -209, -666, -2229, 1094, 208, -312, -470, -27, 1304, 583, -1302, -130, 1320, 1171, -440, -1944, -270, 1714, 1237, -3624, -1451, -1228, 1456, 1535, -2159, -400, -2783, 980, 1626, -77, 549, -3580, 757, 1075, 81, 654, -3140, 555, -480, -854, -543, -2197, -50, -3856, -1857, -3220, -1787, -894, -11115, -1628, -2835, -2587, -1603, -4311, -553, -1333, -3695, -2292, -3056, 260, -1349, -2020, -2916, -2982, 472, -2470, -460, -3080, -3140, 130, -3557, 129, -3126, -2797, -666, -2879, -131, -4100, -2022, -2007, -1925, -1522, -7984, -1648, -4473, -1732, -5862, -9022, -1961, -9331, -2541, -5516, -6163, -2875, -7004, -4693, -1872, -7034, -4203, -5888, -9873, -937, -7484, -6354, -6577, -6628, -914, -6422, -8192, -6256, -3523, -1178, -6399, -4853, -4587, -2443, -1405, -6885, -3543, -3603, -2986, -1479, -7888, -3985, -3574, -6035, -1498, -7912, -6054, -4254, -8138, -1556, -5686, -7984, -5189, -5043, -1677, -4254, -5630, -6321, -5810, -2093, -3827, -3701, -7562, -11115, -3005, -4464, -2432, -7389, -8060, -4625, -6153, -1654, -6828, -7019, -7819, -6679, -1536, -8247, -8393, -17034, -5360, -2342, -9695, -7389, -7984, -5103, -4203, -5638, -6194, -7353, -6679, -5279, -4918, -7299, -8718, -14784, -5164, -6732, -11781, -8718, -8034, -6388, -12776, -7389, -9106, -6528, -8827, -13365, -5686, -17034, -7865, -14784, -13365, -5793, -9873, -17034, -8865, -9531, -6828, -8549, -8454, -5942, -8333, -7796, -9331, -5183, -5387, -8903, -7503, -9380, -3754, 1488, 4732, 5435, 3299, 860, 2075, 3934, 4830, 2558, 1286, 2330, 1112, 2417, 1071, 1434, 1165, -8363, -3886, 2056, 1478, -1660, -4616, 2254, 3008, 2384, -1958, -10362, 2932, 2279, 2697, -718, -3479, 629, -65, 1658, -270, -1728, 11, 1675, 800, 77, -2100, 3171, 3169, 2379, -347, -1384, 4349, 2465, 3936, -3521, 511, 5009, 619, 5251, -852, 2031, 5436, 3324, 6009, 2604, 3193, 5140, 4662, 5949, 3812, 3872, 3587, 3984, 5094, 3644, 3951, -497, 399, 3731, 2084, 3418, -3961, 651, 2635, -1610, 2150, -303, 3766, 2558, -978, -292, -478, 4689, 2681, 720, -2050, 274, 4780, 1965, 118, -1257, 2008, 4519, -164, -2843, -2743, 2550, 4088, -4184, -7004, -3179, 1817, 3563, -3798, -3860, -1303, 299, 3029, -3076, -3940, -2207, 505, 2487, -4115, -6469, -6235, 1721, 1771, -5214, -7213, -5394, 1936, 830, -4606, -2642, -6800, 615, -7, -4042, -706, -3289, -4299, -335, -1880, 224, -629, -1722, -274, 326, 795, 420, 779, -327, 1319, 1012, 995, 639, -702, 1040, 654, 1419, -1532, -1244, -445, -207, 1283, -1665, -1869, -2528, -804, -170, -231, -2112, -2962, -937, -5401, -1052, -2047, -1992, -1880, -2900, -3944, -2583, -605, -2653, -581, -2295, -3704, 611, -1237, -618, -710, -4451, 1218, -912, -1821, -88, -3085, 1122, -2241, -2902, 337, -823, 645, -5091, -1728, 559, 342, 452, -7081, -194, 312, 296, 440, -3393, 847, -706, -910, -13, -696, 1511, -3036, -3067, -868, 661, 1809, -6565, -4089, -1280, 971, 1570, -4532, -3222, -1412, 392, 500, -3698, -2879, -2223, -1051, -1976, -3689, -3707, -3554, -3563, -8220, -2958, -5662, -4545, -7708, -6153, -2225, -5686, -5055, -8165, -5031, -2030, -4863, -4816, -8582, -6870, -2188, -5480, -4764, -17034, -15615, -2677, -7034, -5387, -7299, -10526, -3618, -8683, -6225, -6653, -13365, -4784, -7960, -7464, -9238, -8549, -5735, -6828, -8718, -6299, -4693, -6083, -7081, -6745, -3569, -3329, -5997, -6628, -5554, -2073, -3242, -6343, -5726, -6692, -1243, -4089, -8138, -5260, -9936, -1058, -5686, -11629, -4064, -5630, -1614, -6988, -9639, -2895, -3863, -3023, -7097, -10899, -2377, -3425, -5827, -7264, -6914, -2443, -3754, -9695, -7665, -3184, -2885, -4532, -5326, -7281, -1505, -3407, -5240, -3668, -6288, -1109, -3896, -5810, -3779, -5531, -1808, -4569, -5801, -5836, -5319, -3409, -5164, -5170, -8363, -5879, -4564, -5380, -4923, -4968, -7264, -4195, -5810, -4991, -3940, -8423, -4108, -6492, -5020, -4649, -7562, -4779, -6705, -5189, -7066, -5933, -5561, -6083, -5853, -10799, -5214, -5472, -5531, -7019, -8333, -5569, -5176, -5623, -8454, -6225, -6705, -5646, -6504, -9429, -5292, -8333, -7019, -8192, -10001, -5326, -12123, -8790, -10526, -9479, -5997, -12534, -9479, -11115, -7299, 6416, 2356, 4664, 4031, -5299, 5458, 1289, 4241, 3522, 3198, 1889, 1076, 3307, 2987, 5682, -4035, 3271, 3179, 3621, 6467, 59, 4035, 3779, 3662, 5954, 1569, 3567, 3884, 2134, 4082, 2618, 1938, 3351, 1349, 1174, 1829, -1816, 2461, 3482, -75, 696, -2000, 1162, 3919, 2162, 3512, 195, -3866, 2144, 3865, 5329, -174, 928, 1771, 3107, 5968, 2492, 4503, 4015, -511, 5618, 4771, 5457, 3596, 3888, 4171, 5142, 4513, -1174, 5022, 1539, 3408, 845, 2442, 3508, 593, -4985, 461, 4277, 1141, 911, 1157, 2545, 3506, 3875, -508, 2441, 2172, 332, 4892, -2675, 1350, 582, -8615, 4703, -1820, -1203, -755, -6321, 3747, -788, -3971, -398, -7464, 2446, -422, -4918, 387, -3692, 1952, -274, -5394, 804, -1739, 1899, 15, -7984, 865, -494, 1162, -218, -28777, 590, -50, -82, -1703, -8827, -114, -985, -533, -4795, -6163, -1497, -4119, -419, -5710, -4226, -4134, -1442, -325, -5319, -3792, -13049, 877, -304, -5444, -4688, -5360, 1446, -1034, -1832, -3843, -2853, 881, -1636, 495, -1986, -2173, -539, -513, 1571, -1239, -2722, -2480, -15, 1774, -952, -3996, -5026, -761, 1241, -701, -5346, -8060, -1784, -104, -1099, -7179, -4266, -891, -2424, -2472, -4176, -2655, -268, -4307, -3557, -1370, -2465, -664, -2546, -2875, -335, -2845, -877, -605, -1921, -770, -3067, -707, 113, -1986, -2306, -2276, -1312, -1001, -2125, -2260, -961, -2552, -6800, 205, -1553, -26, -3680, -3230, 1694, -2138, 262, -6411, -1366, 1734, -2295, 14, -6759, -2095, 468, -1256, -340, -2545, -4219, -1418, -1221, -522, -1363, -7050, -2198, -2366, -1086, -1909, -10362, -3119, -3306, -2743, -4258, -6856, -5451, -2386, -6214, -8276, -6692, -7299, -1541, -8942, -7936, -12534, -6321, -1470, -6163, -8517, -7019, -4968, -2194, -4172, -11232, -4134, -4386, -3769, -3465, -11781, -3409, -5437, -6602, -3923, -6194, -3735, -7097, -11488, -4307, -4403, -4447, -3782, -12534, -3487, -4295, -5091, -1998, -10899, -3058, -5121, -5924, -1595, -6422, -4053, -5951, -7888, -2160, -4968, -8247, -6235, -12123, -3532, -5458, -6692, -6679, -8517, -5458, -7984, -3465, -8454, -6590, -7665, -13365, -2592, -9106, -6064, -10001, -15615, -2795, -7019, -6814, -6035, -12776, -3577, -6225, -9873, -3856, -8454, -4555, -5202, -8754, -3294, -7687, -5415, -3827, -6194, -3951, -8754, -5888, -3140, -5836, -5531, -8276, -5516, -3276, -6628, -6194, -7708, -4774, -3910, -7623, -5195, -10442, -4683, -4698, -7752, -4482, -10210, -5759, -5906, -7888, -4219, -6590, -8393, -8165, -9936, -4319, -5988, -9585, -15615, -28777, -4929, -6759, -6973, -9149, -9585, -6553, -7034, -5924, -6828, -7888, -11004, -5793, -6759, -6083, -6007, -9106, -4790, -11945, -5615, -4527, -6434, -4620, -8034, -5480, -4238, -6214, -5273, -5480, -6343, -6343, -9238, -6773, -8009, -3386, -8683, -7960, -7113, -7213, -3776, -8009, -7162, -10362, -7708, -4536, -5339, -7665, -11356, -10069, -5031, -4195, -9873, -7819, -11629, -4997, -4199, -12319, -8034, -9936, -5208, -4382, -10526, -10284, -9106, -6123, -4035, -8982, -12776, -9479, -7665, -4180, -7960, -14195, -13049, -7796, -5546, -7865, -10613, -10069, -6388, -8304, -8754, -7464, -6565, -5465, -11781, -9429, -5879, -5546, -4896, -13049, -10069, -5970, -6214, -5014, -8549, -7687, -7097, -8649, -5924, -9936, -6288, -7281, -13738, -6480, -8790, -5031, -6988, -8220, -5458, -10284, -6492, -9284, -12776, -9936, -304, -622, 154, -394, 27, 3828, 3713, 4003, 3698, 4086, 5846, 5794, 5951, 5755, 6050, 6437, 6405, 6546, 6426, 6623, 5763, 5698, 5893, 5839, 5941, 3711, 3461, 3829, 3848, 3851, -232, -1519, -371, -255, -389, -8865, -5630, -10362, -11115, -14784, -11232, -3671, -7113, -7426, -6973, -15615, -5458, -12123, -10284, -11488, -11781, -7484, -10442, -7774, -12123, -8034, -7708, -7081, -8086, -10284, -7408, -8009, -5312, -9639, -8790, -8718, -10442, -5115, -14784, -8649, -9479, -13738, -6133, -11004, -9064, -7408, -11781, -8393, -8247, -9585, -6310, -12776, -10704, -7542, -9639, -6958, -8683, -10210, -7888, -9479, -9639, -6256, -11356, -8790, -10210, -17034, -5202, -17034, -8683, -13365, -14784, -5031, -15615, -7842, -28777, -13049, -5360, -10613, -7708, -17034, -12123, -6183, -8247, -8790, -14784, -12319, -7583, -8304, -11488, -10799, -14784, -9380, -11629, -11781, -8165, -15615, -10899, -14195, -10704, -7264, -11232, -11004, -10001, -11945, -7687, -8649, -9479, -9429, -13365, -9284, -7113, -8423, -9812, -9149, -10899, -6445, -8423, -10704, -7408, -10362, -6786, -9284, -11356, -6899, -9331, -8423, -9149, -9531, -7247, -8718, -11945, -8423, -7665, -8683, -8363, -11356, -8165, -6679, -11232, -8247, -9064, -7984, -6814, -10704, -8304, -8454, -8086, -8454, -10069, -8827, -9331, -8582, -10362, -9873, -9193, -11629, -9284, -8754, -9479, -8517, -11629, -9936, -8517, -9531, -8138, -10284, -11232, -10069, -10704, -8790, -10138, -15615, -13738, -13049, -10138, -9531, -13049, -15615, -14784, -10362, -8112, -10799, -15615, -12776, -9639, -7281, -10362, -15615, -11232, -9753, -7542, -8903, -13365, -10138, -11488, -8454, -7984, -12534, -9812, -28777, -8790, -8485, -14784, -10069, -14195, -9531, -10210, -28777, -10001, -11115, -12319, -11356, -12776, -9479, -9936, -17034, -11356, -11232, -8942, -9873, -14784, -11488, -11004, -8754, -11004, -14784, -11945, -11488, -9238, -15615, -11781, -11781, -11781, -11356, -13365, -10613, -12319, -12776, -28777, -10799, -10899, -13365, -13049, -13049, -11356, -11629, -13738, -11356, -11781, -15615, -10704, -14195, -10704, -13049, -28777, -9873, -13365, -10899, -14784, -28777, -10210, -11004, -12123, -14195, -14784, -11781, -10613, -15615, -13365, -14195, -14195, -11115, -14784, -13049, -17034, -13049, -11945, -12123, -11356, -28777, -12319, -11781, -11004, -9753, -14195, -6365, -9753, -9238, -7113, -5810, -6492, -8903, -8615, -5115, -5751, -6745, -8276, -8009, -4541, -7842, -6153, -7623, -8363, -4858, -12319, -5599, -6332, -10613, -5836, -7196, -6321, -5079, -12776, -7708, -5702, -8718, -4569, -10442, -10704, -5422, -10069, -4831, -8790, -11945, -5531, -11356, -5630, -8138, -13365, -5818, -12123, -6480, -7936, -7796, -6640, -10284, -7019, -7687, -5079, -8247, -11356, -7247, -7445, -4021, -8903, -12319, -8942, -8615, -4157, -6943, -9695, -12776, -10613, -5055, -5776, -11356, -10001, -8112, -6973, -7665, -8393, -7066, -5599, -7644, -8304, -17034, -7842, -10362, -10704, -10899, -463, -258, -579, -346, -735, 3740, 3829, 3777, 3803, 3715, 5796, 5856, 5835, 5855, 5858, 6417, 6453, 6427, 6491, 6529, 5751, 5747, 5709, 5866, 5905, 3657, 3566, 3521, 3875, 3843, -577, -903, -882, 30, -296, -28777, -15615, -8982, -7130, -7081, -7004, -6943, -8615, -10284, -7623, -9479, -5662, -11488, -11004, -7230, -11945, -5266, -9429, -10799, -6343, -10799, -6332, -9238, -15615, -8718, -10210, -8112, -8582, -10138, -11356, -11232, -11945, -8423, -9753, -11488, -12123, -17034, -7335, -11232, -11945, -12776, -10899, -6615, -17034, -13365, -17034, -8718, -6928, -28777, -12123, -13738, -8009, -8009, -28777, -7503, -9149, -8454, -8009, -13738, -5487, -7842, -9695, -6786, -10899, -4784, -8165, -10613, -6553, -10613, -5158, -10001, -10210, -7730, -11232, -6590, -10704, -9639, -9585, -10526, -9193, -9331, -8615, -9812, -9585, -12319, -8982, -8220, -9429, -9936, -14195, -8865, -9531, -9429, -12534, -17034, -8086, -13049, -10799, -28777, -13738, -8086, -10284, -13049, -14784, -10613, -8790, -9753, -10362, -17034, -7984, -7888, -12534, -8790, -13049, -6745, -7113, -14784, -7796, -11629, -6828, -7523, -12123, -7019, -11356, -8192, -8827, -11115, -6759, -11115, -10526, -10899, -10138, -7264, -10138, -11356, -11232, -9639, -8649, -9284, -9936, -11004, -10704, -10799, -9695, -9106, -11945, -12776, -13365, -11945, -9149, -10704, -11945, -17034, -28777, -9873, -8683, -10069, -17034, -13738, -10899, -8485, -9331, -12776, -12776, -11629, -9695, -9936, -11004, -14195, -11945, -11781, -12534, -10442, -28777, -12534, -13738, -14195, -10613, -17034, -12319, -14784, -10799, -11781, -12534, -10526, -14784, -8982, -14784, -11004, -9064, -13738, -8086, -12319, -10442, -8903, -13365, -8333, -10442, -10362, -10069, -13365, -10001, -10704, -10613, -13049, -14784, -14784, -12319, -11629, -28777, -17034, -13365, -12123, -14195, -14784, -17034, -11232, -11004, -28777, -13049, -13738, -11488, -11356, -17034, -11781, -12776, -13738, -13049, -17034, -11629, -11488, -17034, -12776, -17034, -12534, -10284, -15615, -11945, -17034, -14195, -9639, -15615, -12319, -28777, -14195, -9873, -28777, -13365, -15615, -12534, -11115, -28777, -14195, -12319, -12534, -13365, -14195, -14195, -11488, -13365, -15615, -13365, -14195, -12123, -14784, -15615, -15615, -13365, -14784, -15615, -14784, -17034, -11629, -28777, -17034, -13365, -28777, -10799, -17034, -15615, -5253, -8454, -6615, -5133, -8982, -7865, -28777, -7865, -6054, -28777, -9639, -10442, -8333, -8138, -10001, -8865, -13738, -8615, -9812, -7912, -9380, -10210, -8718, -9284, -7445, -8485, -7752, -8165, -9531, -8865, -8060, -8363, -6732, -12534, -12534, -9380, -9812, -5726, -13365, -8247, -8649, -9429, -5694, -9331, -6885, -7247, -8827, -6103, -7665, -6943, -7796, -8827, -6973, -6914, -7426, -9873, -9479, -8754, -7730, -8517, -10704, -8718, -9238, -14195, -10442, -9753, -6332, -7230, -10284, -8865, -11488, -6288, -6679, -10613, -10613, -8485, -6914, -6899, -7019, -7484, -9531, -6870, -6773, -6204, -8517, -466, -145, -95, -355, -422, 3651, 3885, 3750, 3753, 3830, 5698, 5914, 5730, 5808, 5899, 6308, 6529, 6341, 6438, 6532, 5592, 5882, 5697, 5793, 5904, 3327, 3857, 3651, 3756, 3930, -1577, -60, -461, -267, 173, -7796, -8649, -11629, -10001, -5951, -6899, -9695, -8060, -11232, -6870, -13049, -11488, -10001, -9193, -6786, -9284, -9238, -8393, -7213, -6745, -9531, -8333, -8942, -8615, -6602, -8086, -7665, -10799, -11781, -6103, -7097, -7113, -12534, -9380, -6278, -6615, -7066, -13049, -7936, -6814, -6705, -8276, -11945, -8718, -7353, -7264, -9812, -12534, -13049, -7865, -9331, -9284, -28777, -11945, -8754, -28777, -8790, -11004, -8827, -11781, -11004, -8982, -9106, -7912, -15615, -9284, -9753, -8683, -7888, -9585, -9106, -10526, -8454, -8982, -8333, -9585, -10210, -8247, -12319, -8903, -11488, -8718, -8517, -14784, -10362, -10799, -7665, -9695, -10210, -9106, -7960, -7730, -10069, -8423, -7819, -6732, -8790, -8754, -7687, -8009, -6745, -10001, -7842, -7984, -9873, -7819, -9639, -7503, -9585, -13365, -10362, -8454, -7603, -13365, -13049, -17034, -7542, -8060, -13738, -12776, -17034, -7050, -8865, -11945, -17034, -12776, -6732, -9812, -11781, -15615, -9639, -6540, -10526, -12319, -11356, -8754, -6773, -10442, -12776, -10210, -10362, -7408, -9639, -13049, -10210, -10799, -8247, -9284, -13738, -10526, -8333, -8903, -9695, -13049, -11629, -7426, -9106, -10899, -11781, -15615, -7523, -8982, -11781, -10526, -28777, -8333, -9064, -11115, -10284, -17034, -9639, -9753, -11004, -11004, -28777, -11004, -11356, -12319, -10704, -17034, -11115, -11945, -17034, -9695, -12123, -10613, -10704, -17034, -9753, -11356, -11004, -10001, -13738, -11004, -13049, -11629, -9639, -12319, -14784, -14784, -10799, -9812, -12319, -28777, -13738, -10069, -9812, -14195, -11945, -12319, -11004, -9106, -17034, -9812, -11781, -14195, -8790, -14195, -9106, -12534, -12776, -9695, -14784, -9753, -13365, -12534, -12123, -17034, -12319, -12319, -13738, -28777, -11945, -28777, -11356, -12123, -28777, -10613, -28777, -12319, -11488, -28777, -11115, -14784, -12123, -13049, -15615, -12776, -11115, -9639, -28777, -17034, -14195, -10613, -8582, -28777, -28777, -13049, -11629, -8247, -28777, -14195, -11004, -12319, -7912, -28777, -10899, -10799, -11781, -8009, -17034, -9936, -11781, -12123, -8649, -13738, -10284, -12534, -13365, -9585, 13663, 14366, 4813, 9113, 11708, 13034, 13853, 4611, 8494, 11025, 10985, 12278, 4030, 6553, 8801, 6567, 9566, 4556, 3159, 4258, 23, 5985, 5758, 1153, -1510, 4596, 3621, 5802, 1683, -3940, 4343, 4039, 4320, 489, -3597, 2011, 4334, 2002, -489, -2114, 583, 3693, 2781, 2757, 2647, 3150, 2999, 3816, 4459, 4923, 3320, 3110, 4217, 5034, 5775, 1425, 3950, 4379, 4757, 6105, -2950, 4772, 4336, 3451, 6336, -4779, 5028, 3919, 436, 6201, -1146, 4583, 3020, 206, 5210, 888, 3344, 2187, 2548, 2965, 1294, 1055, 2540, 2995, 508, 1023, -2831, 3195, 2080, 1107, 250, -3920, 3249, 899, 1211, -3422, -2881, 2700, 2154, 958, 1131, -3707, 1843, 3627, 1307, 4062, -4060, 550, 4293, 1474, 4927, -2178, -2010, 4267, 970, 4235, -928, -2791, 3646, 26, 1260, -346, -392, 2637, -1267, -3707, -201, 601, 1883, -1302, 1531, -1050, 632, 1692, 3, 1726, -1791, -271, 1323, -476, -535, 412, -2737, 283, -2330, -4810, 1448, -5227, -1626, 131, -5718, 1085, -2871, -4307, 1252, -4536, 95, -3425, -8454, 590, -364, -333, -2939, -7960, -143, 2446, -253, 306, -3792, 1164, 3844, -286, 1537, -2555, 1973, 3894, -777, 1300, -1574, 1533, 2500, -2628, -71, -1296, -489, -1166, -3121, -2726, -3433, -5670, -3792, -128, -8582, -8485, -6235, -58, 854, -7687, -2871, -6143, 1347, 377, -7730, -2181, -5759, 1924, -1303, -6183, -2034, -3184, 1734, -4352, -4901, -1175, -1961, 690, -6123, -6163, -380, -1114, -1276, -4134, -6434, -104, -255, -4373, -3757, -3147, -476, 242, -4180, -3269, -1111, -1338, 104, -2061, -2219, 166, -2512, -538, -1373, -1912, 685, -4003, -1385, -1579, -1990, 342, -4191, -2155, -2162, -1939, -832, -3269, -3213, -2741, -2222, -2703, -2967, -5960, -2692, -3177, -4837, -3360, -10138, -2100, -4946, -7464, -4119, -7264, -1641, -7960, -17034, -5208, -7912, -1717, -6457, -6163, -7603, -10526, -3117, -3422, -4688, -10362, -11629, -9873, -2331, -5694, -4713, -12123, -4805, -3354, -8220, -2881, -14195, -2801, -9380, -10442, -2935, -28777, -3447, -5569, -8423, -4078, -9149, -6445, -4630, -5853, -5031, -3927, -10362, -5208, -4369, -5818, -1274, -6123, -4115, -2705, -9238, -275, -4299, -4246, -1044, -6786, -542, -2567, -5085, -193, -2811, -1527, -2231, -4769, -594, -1943, -2416, -3638, -4795, -2257, -2841, -3760, -5607, -6354, -3386, -5115, -7445, -4826, -12123, -2664, -8982, -11945, -3455, -8485, -2128, -9873, -8304, -2768, -6814, -2460, -6786, -9531, -2829, -8790, -4532, -7034, -10210, -3428, -9873, -9639, -10613, -6480, -4238, -8112, -11232, -11115, -5623, -4386, -10799, -7408, -12123, -5319, -3916, -9106, -2730, -8034, -5103, -4319, -8393, -1135, -5539, -6332, -6093, -9936, -994, -4447, -7019, -10362, -8393, -1819, -4451, -8220, 8822, 6405, 7399, 8736, 8940, 8108, 6463, 6945, 8230, 8444, 6300, 5574, 5860, 6894, 6892, 4971, 1103, 5156, 5220, 4105, 3752, 1794, 5631, 3523, 308, 941, 4355, 6534, 2315, -1042, -1475, 3609, 7092, 1064, -262, 2831, 2053, 7104, -2149, 141, 5010, 3075, 6424, -2136, 967, 5572, 3899, 4428, -3080, 2160, 5193, 4063, -1720, -3971, 2729, 4869, 3813, 3597, 729, 2838, 5201, 3285, 5870, 2287, 2616, 5477, 3139, 6462, 2691, 1934, 5416, 3392, 6174, 2617, 1037, 5274, 2939, 5375, 2343, 409, 5104, 835, 4338, 1477, 20, 4546, -6434, 3082, -1333, -794, 3018, -3301, 1368, -551, -3161, -1070, -3110, 82, 2614, -7752, -1746, -8485, 427, 3135, -2280, 2055, -6928, 76, 1302, -39, 2952, -4674, -1500, -1419, 786, 2431, -367, -2659, 1626, 321, 516, 1682, -2716, 2762, -2399, -3096, 2207, -1478, 3437, -4842, -5170, 1807, 292, 3899, -40, -6480, 826, 1054, 3570, 669, -6422, -1270, 853, 2182, -1006, -2841, -10001, -349, -527, -1803, -1647, -1090, -4195, -5524, -187, -1622, 1487, -3321, -7752, -444, -1934, 2397, 37, -5576, -772, -613, 2402, 782, -4991, -122, 1514, 1893, 341, -4315, -382, 2946, 1275, -874, -2813, -1966, 3649, 905, -2939, -385, -2994, 3805, 447, -6705, 1507, -1546, 3452, -891, -8086, 2821, -1213, 2358, -2705, -4234, 3670, -2559, -119, -2245, -2073, 3915, -4115, -7179, -2847, -282, 3381, -3521, -2299, -6732, 646, 1818, -2195, -74, -2236, 308, -1558, -804, 581, -606, -1475, -5584, -561, 125, -1294, -3961, -1442, -2034, -1497, -2772, -3249, -499, -8138, -2528, -1841, -2152, -958, -3546, -1837, -1595, -2038, -2450, -634, -2030, -2883, -2504, -4258, 264, -2891, -5208, -2893, -4266, 104, -3498, -6786, -3304, -3571, -714, -4049, -6299, -5195, -3726, -1544, -3975, -5020, -8683, -3971, -2061, -3776, -3471, -3027, -2982, -3042, -4810, -2534, -1400, -2198, -5152, -5524, -3170, -1548, -2393, -8683, -4234, -6870, -3309, -3577, -7623, -2933, -6343, -6093, -5079, -5115, -1865, -4447, -4500, -5260, -4442, -1204, -4518, -4625, -3944, -4769, -918, -4215, -8649, -3393, -5333, -1063, -4234, -5020, -4038, -5759, -2000, -5871, -4500, -4659, -6267, -4108, -7865, -6173, -4491, -6814, -6870, -6204, -2407, -4386, -6679, -9429, -6256, -920, -5037, -6133, -7562, -5408, -1164, -3735, -5387, -4805, -4369, -2677, -2198, -5646, -4299, -4089, -5085, -2396, -6434, -5097, -3843, -6026, -4592, -5502, -6504, -4464, -5221, -6194, -5067, -6899, -7050, -5906, -3182, -5951, -5879, -14195, -10069, -2356, -7130, -5509, -5339, -7796, -3476, -8423, -5333, -2999, -3944, -5494, -15615, -5710, -2583, -1894, -5465, -9331, -8165, -3291, -989, -7665, -9149, -6540, -3370, -1182, -7730, -10526, -7353, -3507, -2797, -5933, -9238, 7163, 3687, 5260, 8213, 6927, 7099, 2930, 4980, 7774, 6104, 6680, 494, 4202, 6396, 3805, 5330, -2238, 3077, 4062, 3177, 2075, -2030, 1648, 2540, 3088, 1958, 913, -385, 3181, 857, 3995, 2958, -693, 3621, 2641, 4066, 3034, 1153, 3868, 3757, 3306, 881, 1696, 3399, 2009, 2354, -2000, 1067, 1075, -7335, 972, 1108, -542, -2813, 1110, -754, 2354, -2477, -681, 1451, -1726, 2622, 1049, -1597, 1460, -3038, 2053, 3143, 894, 2779, -4559, 424, 3398, 2886, 2453, 1076, -2425, 1810, 3045, 1969, 3164, -1512, -599, 1551, 4105, 3482, 703, 1603, -2733, 5065, 2147, 1542, 2633, -4086, 4530, -3331, 2566, 2539, -2406, 2913, 76, 3736, 2075, -5286, 2058, 3235, 4006, 1889, -3621, 2842, 4099, 3106, 2235, -1203, 3599, 3643, 834, 2223, -1038, 3658, 1940, -3701, 1122, -2016, 2423, -1124, -4357, -1084, -3574, 113, -4071, -4378, -1717, -5031, 1767, -2879, -5158, -511, -2135, 3054, -760, -1125, 505, 548, 3064, 974, -66, 1112, 2247, 2563, 2056, -524, 927, 3215, 1915, 2428, -1174, -555, 3404, 1122, 2253, -1849, -4064, 2614, 788, 1757, -2546, -4997, 329, 1078, 931, -3546, -2900, -5401, 1319, -44, -6422, -567, -2659, 1296, -811, -2208, 732, -833, 861, -1465, -1203, 497, -430, -227, -904, -3296, -324, -495, -1476, 583, -10899, 290, -957, -1272, 1293, -2485, 515, -2176, -1158, 596, -350, -718, -4438, -2345, -1813, 460, -2560, -5408, -2924, -2211, 262, -3230, -5487, -956, -522, -364, -4053, -4805, 120, -213, -522, -2793, -2733, -241, -1401, -573, -1804, -2594, -2897, -5387, -1062, -2271, -5020, -4640, -6856, -2235, -3257, -12319, -1258, -4460, -4509, -3215, -9479, -1044, -5214, -7247, -2801, -3944, -2756, -4038, -11629, -2226, -1211, -4754, -1913, -7583, -1734, -355, -4923, -1044, -4352, -2238, -647, -4640, -1345, -4640, -4728, -1616, -3396, -2811, -9380, -8304, -2655, -3490, -5516, -5638, -5862, -2514, -7146, -9106, -3215, -7230, -1398, -6163, -12534, -2817, -7281, -679, -3126, -9238, -3399, -4795, -641, -3618, -7034, -4010, -3577, -981, -8192, -6885, -4935, -2589, -1117, -7523, -9585, -7865, -2090, -989, -5818, -10613, -6577, -2225, -910, -7842, -7665, -5127, -2641, -1227, -10284, -7179, -5702, -2793, -2450, -7445, -7179, -6469, -3020, -5718, -5871, -6103, -6516, -3729, -10069, -4664, -5599, -6204, -4693, -6083, -3964, -6332, -5710, -5615, -6016, -3906, -7213, -5933, -6354, -6899, -4601, -6457, -6434, -7066, -7503, -6958, -5183, -6653, -8363, -10613, -11629, -4821, -7213, -8517, -7912, -5827, -5127, -9331, -7888, -5333, -5008, -3782, -10001, -6133, -5516, -5871, -3242, -8485, -4664, -7912, -6692, -5353, -11115, -4464, -9873, -7317, -28777, -8517, -4246, -5997, -9639, -9284, -7130, -3971, -4805, -11629, -9106, -5623, -3029, -4323, -5451, -6204, -4112, -4089, -4035, -3659, -5299, -4191, -5743, -5346, -4130, -4447, -7603, -7523, -8138, -5801, -3479, -8683, -7066, -8454, -7317, -3252, -6343, -5247, -6093, -13049, -4307, -8220, -3760, -5319, -7247, -6133, -8363, -3580, -5121, -4980, -6590, -10526, -5480, -4266, -5630, -6422, -11629, -8582, -5189, -6183, -8903, -6173, -4274, -10442, -5576, -5458, -3391, -2406, -4491, -5346, -6083, -9238, -5906, -4536, -6615, -3594, -4527, -5844, -2210, -2393, -5073, -4974, -5444, -4425, -7708, 1869, 1882, 1049, 1145, 1714, -6035, -8192, -4104, -7984, -7066, 8644, 8718, 8778, 8646, 8552, 12957, 12975, 12939, 12875, 12866, 15047, 15028, 14991, 14946, 14945, 15688, 15638, 15619, 15581, 15573, 15034, 14952, 14964, 14925, 14906, 12932, 12802, 12877, 12820, 12782, 8632, 8327, 8645, 8488, 8397, -6528, -2889, -3769, -8903, -5915, 1222, 2427, 1013, 1494, 1667, -7408, -2831, -4042, -6828, -5509, -3170, -7426, -2312, -3641, -2776, -10899, -6388, -4901, -11488, -7603, -7426, -2621, -4278, -6204, -4858, -10138, -3518, -6103, -10704, -6679, -5394, -5073, -7865, -8718, -13049, -8363, -4369, -7623, -5326, -12534, -7034, -3306, -4896, -3689, -10799, -7912, -4187, -6016, -4373, -9753, -14195, -6480, -8754, -4743, -4874, -10001, -8718, -9695, -5266, -4748, -9429, -9022, -11232, -6666, -8582, -10069, -8086, -12123, -7583, -9936, -11488, -9531, -10799, -10442, -6278, -9380, -10799, -8683, -9873, -5247, -7484, -8549, -9585, -10704, -5374, -6163, -6973, -8138, -13365, -7066, -5933, -6045, -6354, -12776, -9531, -6759, -5768, -6153, -11945, -10799, -10001, -5662, -7752, -11781, -6235, -9873, -4997, -8582, -9531, -4157, -7888, -5539, -8485, -7130, -4559, -9531, -8454, -9380, -5458, -6719, -11629, -10899, -6590, -4795, -7004, -7066, -8582, -4821, -5026, -6602, -5933, -8112, -4587, -6026, -7730, -6914, -8060, -5924, -8165, -9753, -8034, -8165, -9238, -11488, -10362, -6988, -8582, -11945, -9479, -10799, -8034, -8517, -10526, -9812, -12776, -15615, -9238, -9064, -17034, -13738, -10526, -10001, -9873, -11781, -9022, -9284, -9284, -13738, -10704, -7162, -8942, -10799, -17034, -11488, -6480, -6914, -28777, -12776, -10362, -6856, -6504, -10284, -11232, -9585, -9429, -8304, -7842, -28777, -9585, -14784, -9812, -6786, -10442, -10799, -8333, -12319, -6786, -9695, -11945, -8192, -14784, -7623, -8060, -8485, -10442, -11004, -9639, -6590, -7842, -11115, -11629, -13365, -6973, -9331, -10362, -13738, -12319, -8423, -11115, -8790, -10613, -12534, -10138, -8942, -6628, -7464, -10799, -10799, -7687, -5546, -8247, -7484, -11945, -9064, -6173, -17034, -5195, -28777, -13738, -9149, -11115, -4486, -17034, -10284, -17034, -11781, -5055, -11781, -8138, -15615, -14784, -5933, -10284, -7819, -11232, -10899, -6354, -11781, -9284, -8827, -8790, -6773, -15615, -12776, -8009, -7665, -7623, -14195, -28777, -8903, -7730, -9331, -12123, -28777, -10210, -11004, -4307, -6577, -6590, -7389, -5776, -4923, -13365, -6256, -8582, -6885, -6445, -11488, -6321, -11488, -11781, -7730, -9380, -7644, -6235, -6870, -6640, -11781, -6653, -5702, -4858, -8423, -6516, -6842, -6153, -3349, -8086, -4713, -15615, -5997, -2956, -5960, -4282, -10138, -5346, -3586, -6516, -4774, -8582, -3975, -3493, -5942, -5195, -5176, -4142, -2552, -9695, -2924, -3354, -8649, -2383, -11781, -1787, -2612, -5979, -8060, -4683, -5195, -4583, -9331, -4504, -1870, -3425, -3391, -3012, -7408, -8903, -9639, -4847, -7371, 1023, 1298, 733, 1225, 1518, -6235, -6732, -4935, -3870, -8649, 8697, 8728, 8774, 8757, 8620, 12889, 12938, 12926, 12920, 12889, 14951, 14991, 14962, 14962, 14956, 15584, 15612, 15572, 15578, 15579, 14929, 14946, 14892, 14903, 14907, 12833, 12834, 12757, 12777, 12785, 8538, 8507, 8347, 8410, 8461, -6553, -9585, -5158, -7752, -12534, 1497, 1372, 1741, 1370, 603, -4625, -8790, -6422, -5970, -8423, -7484, -2807, -3339, -2589, -2065, -5539, -7484, -9064, -6064, -3811, -3071, -8718, -5480, -7335, -2463, -5678, -8276, -7665, -10001, -4130, -6692, -4299, -11629, -7408, -6093, -6007, -5273, -13738, -9639, -7912, -3529, -7264, -13738, -5273, -9022, -3474, -6914, -6958, -5897, -8060, -4357, -5319, -4748, -7299, -7752, -4805, -5546, -5726, -6732, -11232, -4518, -7888, -9812, -7687, -9812, -4698, -10210, -10069, -9331, -7247, -6093, -9639, -9695, -6679, -7408, -7464, -11115, -9639, -6310, -7623, -8549, -12319, -7708, -8827, -7464, -8718, -8304, -7034, -14784, -8718, -8942, -7623, -8333, -12319, -10899, -8304, -6732, -10138, -8363, -9380, -8393, -5678, -10001, -8333, -10613, -8683, -5592, -7445, -10001, -15615, -8615, -7247, -7050, -10613, -11629, -9022, -13049, -8138, -8982, -7426, -8393, -12319, -8649, -6914, -6054, -7562, -8827, -8192, -5554, -5678, -7842, -7113, -8615, -5158, -6445, -10069, -6565, -8865, -5458, -8754, -14195, -7389, -7819, -5623, -8304, -14784, -8982, -7960, -5158, -7865, -14195, -9284, -9022, -4620, -8060, -13738, -10001, -9284, -4674, -7623, -11629, -9531, -8942, -5516, -7389, -10001, -8865, -8485, -6899, -8827, -11629, -9380, -8485, -7162, -10704, -8582, -7796, -7842, -6267, -8754, -6828, -6856, -7752, -6225, -9022, -7708, -7445, -9284, -7281, -9812, -10526, -7523, -10362, -7503, -9022, -11629, -7019, -10899, -6399, -10138, -10210, -7247, -14784, -6093, -28777, -10138, -8034, -10799, -7299, -9585, -11488, -10210, -9639, -10799, -7583, -10284, -13738, -9531, -14195, -7130, -7687, -9936, -9936, -9531, -6422, -5871, -10069, -10284, -7583, -6123, -5942, -28777, -10613, -8220, -7408, -7819, -10210, -11004, -12534, -8454, -8718, -8649, -10899, -12534, -7912, -7865, -9193, -10069, -11232, -8683, -8009, -11629, -9149, -11629, -10069, -9193, -17034, -9380, -11781, -10899, -11781, -9753, -9873, -11115, -10799, -14195, -8615, -10138, -9331, -9936, -14195, -8582, -9064, -8903, -9284, -11004, -6615, -4323, -5546, -7464, -7984, -6074, -4408, -7146, -8304, -6870, -6553, -3798, -6528, -7484, -7842, -8865, -3689, -7796, -5286, -10210, -6870, -4134, -8034, -4578, -10138, -6343, -4031, -4831, -2960, -7730, -9639, -2918, -3964, -1644, -6064, -6705, -2709, -4523, -2032, -6235, -4805, -3641, -5531, -3804, -7066, -4006, -3498, -5915, -3133, -8363, -3563, -3031, -13049, -2590, -4573, -3496, -2594, -6553, -2954, -6246, -14195, -4545, -6469, -8903, -3121, -3375, -4616, -2267, -3985, -4708, -3900, -3314, -5546, -5055, 1399, 1967, 2093, 896, 1351, -7623, -6928, -8549, -3824, -5743, 8664, 8640, 8637, 8910, 8824, 12887, 12912, 12897, 12993, 12948, 14942, 14968, 14952, 14998, 14964, 15560, 15579, 15567, 15588, 15559, 14886, 14896, 14890, 14893, 14870, 12760, 12763, 12765, 12748, 12730, 8405, 8412, 8417, 8354, 8329, -5924, -13365, -9022, -7562, -6103, 1189, 779, 1209, 1178, 1529, -7113, -4442, -7542, -12319, -7162, -2817, -1299, -3996, -2751, -3422, -7819, -5569, -12123, -9429, -9380, -5743, -7542, -4748, -6504, -5836, -14195, -6064, -10899, -14784, -9193, -6640, -5266, -6354, -6480, -6504, -7960, -5933, -9022, -7819, -8790, -7912, -5546, -10138, -13738, -10799, -7888, -7097, -8485, -9753, -12776, -10442, -13738, -6842, -6653, -9429, -9812, -12534, -6093, -7984, -9193, -6988, -8363, -7281, -10362, -9149, -6540, -7523, -8276, -7353, -7865, -7445, -7162, -7335, -6321, -6343, -7819, -8549, -8034, -6310, -5654, -6786, -17034, -8247, -7299, -5710, -7130, -10442, -6988, -8112, -5784, -10210, -10799, -7464, -7230, -5924, -13738, -10210, -7912, -7389, -6163, -8165, -7583, -8903, -11488, -5933, -5380, -5592, -10799, -10362, -5576, -4769, -5494, -8549, -9193, -7335, -5312, -6445, -5933, -8517, -8220, -5599, -6679, -4997, -8333, -6540, -5380, -5862, -4901, -9429, -7081, -5960, -5853, -5437, -10362, -8582, -7819, -7464, -7004, -9873, -9873, -9380, -9531, -8649, -11356, -9479, -7984, -8304, -8086, -13738, -7583, -6469, -7066, -8034, -8827, -8009, -6457, -7281, -10001, -9193, -14195, -7774, -7752, -10704, -9531, -7050, -8549, -6153, -10899, -8649, -6399, -9238, -4940, -8982, -9695, -9284, -11781, -5247, -6615, -7984, -17034, -9479, -7130, -6365, -5569, -10069, -8517, -9193, -8086, -5014, -9284, -8982, -8790, -10526, -6310, -10362, -8790, -7644, -10704, -10526, -11781, -7603, -7066, -14195, -10442, -9639, -6958, -7317, -17034, -8393, -7426, -7179, -8454, -14784, -8485, -6800, -7464, -10001, -13049, -8454, -7353, -7179, -10138, -12776, -8485, -8276, -6973, -9149, -12123, -9812, -9479, -7752, -9695, -9106, -12319, -14195, -10138, -10799, -7281, -12123, -10613, -13738, -7842, -6800, -11945, -8304, -14195, -6321, -7960, -14784, -9639, -13365, -6288, -10799, -14784, -15615, -13738, -7623, -13738, -13049, -28777, -14195, -10526, -15615, -12776, -17034, -14784, -12776, -14784, -17034, -15615, -13738, -11232, -11356, -14195, -28777, 12983, 8466, 12344, 11392, 6461, 12380, 8703, 11634, 10869, 5922, 10364, 8737, 9285, 9233, 4385, 5508, 8522, 4691, 6360, 3469, 3990, 8762, 3806, 2616, 4362, 6738, 8873, 3098, 927, 4760, 6552, 8370, 1133, 3740, 4637, 4825, 7566, 1153, 4516, 4528, 505, 6857, 585, 2372, 4276, 326, 6123, 1571, -416, 3811, 3583, 5147, 2412, 4610, 3586, 4122, 3992, 2286, 5935, 3851, 2898, 3285, 1987, 5780, 4498, -1384, 3170, 2228, 4459, 5196, -2026, 2326, 2240, 2699, 5702, 1171, 506, 1386, 3207, 5755, 1764, 2206, 904, 3826, 4887, 2222, 3757, 1995, 3129, 2468, 3180, 3870, 2658, 942, 52, 3634, 2839, 2456, 320, 976, 3623, 1191, 1604, 2480, -885, 4603, 1822, -525, 3460, -782, 5581, 2952, -7583, 3661, 1818, 5375, 2516, 1379, 3371, 1904, 3979, 1095, 3413, 2724, 295, 2803, 2173, 3843, 2163, -2385, 2485, 2834, 3487, 1736, -2409, 713, 1200, 2875, 930, -201, -2075, -2698, 2360, -206, 1030, -335, 1973, 2030, -1165, 1748, -562, 3507, 1755, -2140, 2111, -2956, 3447, 1208, -3479, 1329, -7774, 2264, -274, -2064, -2785, -4100, 446, -5810, -735, -425, 42, -35, -2204, -666, 2481, 1366, 911, 852, -333, 2815, 934, 1890, 1563, 554, 1385, -1336, 2567, 1102, 550, -1894, -6376, 2435, -70, -911, -2829, -2457, 958, -1321, -3425, -1625, 208, -495, -1875, -1609, -1192, 1831, 1443, -1879, 491, -833, 2715, 2199, -1954, 1279, -1153, 2768, 1427, -1787, 1024, -2191, 1800, -707, -1361, 429, -1825, -546, -3438, -1469, 132, -506, -3306, -3067, -2342, -434, 361, -1826, -2148, -2438, -1419, 693, -1060, -2789, -1291, -2326, 540, -1398, -5646, -281, -3230, 120, -2630, -11488, 255, -4086, -627, -5260, -6332, 89, -3741, -1594, -15615, -3076, -947, -2797, -1242, -8009, -1610, -2895, -2657, -440, -8192, -1745, -5759, -3449, -303, -10613, -3589, -10442, -3436, -614, -3603, -5997, -10613, -2567, -1078, -1281, -4863, -10138, -2612, -1569, -520, -4495, -7408, -3833, -1657, -926, -3920, -4923, -6388, -1532, -2597, -2969, -3811, -7523, -2140, -5735, -2642, -2462, -5569, -3792, -8903, -2857, -1095, -3814, -4282, -7081, -3203, -232, -2463, -3808, -4550, -3029, 77, -2125, -5353, -3463, -2450, -288, -2714, -5827, -3230, -2220, -1383, -3518, -3274, -3360, -2747, -3014, -3735, -2954, -3860, -4664, -4266, -3515, -4620, -5145, -10138, -4303, -3276, -8549, -7408, -11232, -4743, -3592, -13049, -7523, -7371, -5367, -4664, -12534, -4142, -4679, -4075, -4683, -7819, -1976, -3738, -2964, -3396, -6064, -914, -4863, -3261, -3286, -4100, -790, -9873, -5026, -4779, -2705, -1613, -4451, -5115, -7912, -2533, -3729, -2303, -3540, -8982, -3714, -8485, -2100, -3257, -5897, -6267, -6828, -3168, -4416, -3299, -5208, 6641, -9022, 10014, 6932, -1285, 6421, -1480, 9436, 7458, 1188, 5645, 2610, 7535, 8047, 2195, 4735, 4517, 3383, 7927, 1683, 5629, 4916, 677, 7040, 793, 6675, 4017, 3672, 5761, 24, 6487, 2575, 4180, 5137, 538, 5092, 2426, 3491, 5309, 924, 3984, 2299, 1425, 5228, -717, 3747, 2723, -1441, 4428, 616, 1867, 4179, 1667, 2892, 3293, 1701, 4930, 3607, 1086, 4534, 4106, 4823, 3888, 466, 5018, 4366, 4170, 2549, 1764, 4844, 2309, 3279, 1656, 3391, 3867, -3065, 2441, 3906, 4277, 2018, 2846, 1991, 5039, 4113, -508, 4320, 1427, 4954, 2669, -2954, 4298, -544, 3932, -1070, -4532, 3797, -1827, 2483, -3689, -4800, 3753, 796, 1513, 252, -2135, 4138, 1456, 1353, 1074, -456, 4171, 898, 1583, 871, -337, 3238, 175, 1024, 1179, -1526, 566, 287, -1177, 2338, -1895, -3903, 874, -4447, 3044, -501, -182, 686, -5702, 3154, 282, 680, -897, -3301, 3143, 548, 350, -3985, -1326, 3063, 734, 651, -5208, -1914, 2360, 1041, 1284, -2238, -6615, 387, 1321, 1603, -596, -3417, -4340, 1313, 2419, -419, -267, -6343, 929, 3345, -1096, 1233, -4509, 503, 3560, -2006, 1986, -4578, 421, 2957, -3375, 2159, -3137, 481, 1964, -2125, 1832, -2116, 563, 1390, 388, 1080, -2204, 597, 1090, 1687, -76, -3194, 23, 254, 1963, -1079, -834, -1623, -2399, 1268, -702, 1592, -3647, -6113, -443, 252, 2691, -4482, -453, -2270, 784, 2846, -3208, 1029, -1537, 470, 2426, -989, 1175, -343, -1194, 1835, -405, 404, 38, -5933, 1317, -1371, -1761, -562, -5784, 731, -2118, -4500, -1603, -3154, -261, -1164, -1740, -1446, -2731, -1899, -1024, -816, -1005, -2999, -3609, -1717, -1398, -1076, -3817, -3087, -2260, -3447, -1105, -5458, -1917, -2435, -7050, -742, -9429, -1559, -2653, -2837, -443, -5487, -2207, -2908, -1002, -616, -2232, -4184, -3210, -769, -1488, -1135, -9380, -3577, -1431, -3196, -1630, -5793, -4157, -2182, -4172, -4311, -2885, -4743, -2132, -2201, -11629, -1680, -4784, -1212, -723, -4270, -814, -4708, -487, -185, -3133, 428, -5784, -565, -483, -3220, 1544, -14784, -1568, -1605, -3515, 1989, -5524, -3415, -3294, -3600, 1609, -3452, -5997, -4774, -2975, 283, -4138, -9106, -4412, -1765, -2497, -3996, -12123, -1937, -904, -10799, -1660, -12776, -887, -837, -5429, -947, -9022, -1666, -1611, -4250, -1784, -8086, -3455, -3007, -5897, -3900, -6299, -2897, -3947, -17034, -6590, -4089, -2849, -3896, -5091, -9022, -3326, -4532, -4754, -3110, -5524, -3833, -6842, -11629, -3213, -3038, -3996, -8393, -4017, -5152, -1874, -2465, -9753, -476, -8138, -1381, -1210, -7523, 1019, -7389, -1357, -724, -4049, 1292, -5152, -1799, -1083, -1897, 459, -2644, -2716, -2390, -1028, -1522, -1132, -3989, 8639, 8433, -1228, 8965, 4876, 8228, 7718, 4726, 8594, 5063, 7076, 5210, 6354, 7458, 4833, 5526, -2424, 5894, 5453, 3010, 4164, 1836, 3901, 2248, -1123, 3075, 2791, 3507, -4997, 3103, 1547, 1485, 4525, -1727, 4722, -669, -1895, 4015, 660, 4281, -1112, -9812, 1797, 682, 357, 551, -7081, 203, -1030, 1809, 2363, -4805, 1729, -2295, 5573, 3098, 957, 1841, -1607, 6763, 2731, 3022, 246, -4138, 7010, 2067, 3062, -430, -1722, 6901, 1854, 751, 1400, 1568, 6515, 1354, -1704, 1351, 2000, 5632, 229, 1042, -1413, -132, 4024, -1084, 157, -2303, -5333, 1880, -3399, -11115, 231, -2480, 2450, -6615, 1257, 103, -8112, 4125, -1409, 3194, -1411, 408, 4623, 513, 3307, -3373, 2865, 3766, 1561, 2018, -3659, 3266, 886, 2293, -1206, -615, 2429, -1319, 2346, -2475, 1007, 750, 1659, 1237, -173, 1398, -1381, 1832, -1701, -92, 1144, -2637, -613, -9873, -1564, 975, -3933, -1284, -11356, -4097, 1184, -2793, 2481, -5079, -4620, 1234, 1121, 3869, -593, -2943, 907, 2930, 4064, 1427, -2205, 494, 3505, 3465, 2313, -2933, 318, 3319, 2384, 2448, -4587, 446, 2791, 1361, 1854, -2659, 610, 2286, 1592, 246, -1155, 575, 1779, 3000, -2831, -1207, 415, 890, 4033, -2644, -2430, 240, 52, 4175, -656, -4991, 246, 1121, 3334, 146, -8903, 865, 2385, 1424, 232, -1411, 1617, 2712, -1662, -424, 975, 1771, 2113, -4935, -1887, 1733, 1068, 756, -4042, -3817, 1432, -459, -953, -1926, -4336, 443, -1721, -2394, -605, -3133, -275, -1533, -3187, -620, -2311, -118, -1638, -3644, -2713, -2172, -356, -2204, -5109, -4733, -2364, -2047, -1807, -6553, -1473, -2793, -4447, -1011, -3526, -836, -3814, -2730, -825, -1912, -1361, -4713, -2764, -1393, -1556, -1480, -4195, -6719, -2564, -2201, -1628, -3999, -5686, -3843, -3430, -2891, -3732, -3144, -4946, -3047, -6321, -3289, -4071, -5079, -1706, -7004, -3824, -11004, -3433, -897, -2590, -3853, -6093, -2707, -684, -628, -2450, -4021, -3788, -1165, 208, -2008, -3951, -7819, -2500, 203, -2997, -4278, -6480, -4340, -338, -5020, -3850, -3388, -5776, -845, -4230, -2887, -1583, -8754, -1543, -2960, -2257, -490, -8942, -3168, -2522, -2334, -160, -4664, -3656, -1959, -3130, -648, -2910, -2090, -1419, -4211, -2229, -2087, -1033, -1469, -4664, -5906, -2068, -348, -2148, -4654, -7752, -3187, -275, -3163, -5662, -6103, -6332, -1275, -4010, -8363, -9753, -7523, -4038, -3732, -4738, -7796, -5539, -7960, -2495, -2902, -4361, -5793, -4640, -1578, -2839, -3396, -6856, -2698, -1377, -3396, -3108, -9193, -1689, -1841, -3557, -3357, -8247, -1904, -2670, -4491, -4130, -2811, -3618, -3729, -9284, -4108, -436, -3801, -5286, -6914, -3671, 602, -1820, -6457, -3964, -4149, 782, -1314, -4429, -4278, -7583, -1988, -2573, -3798, -3401, -6153, -1867, -1335, -4478, -2322, -4093, -2514, -1215, -7081, -1609, -4550, -2581, -2153, -6143, -1119, -10362, -2172, -4089, -3417, -1093, -5127, -2505, -5158, -2906, -1857, -2259, -3479, -3964, -4416, -3257, -1897, -4089, -2550, -8276, -3396, -3482, -3662, -1197, -6093, -2956, -5561, -3005, -405, -5516, -3860, -2622, -3133, -451, -5776, -8086, -1141, -4541, -1394, -3543, -6958, -915, -7936, -2776, -2172, -3319, -1323, -10799, -2906, -1923, -2242, -1740, -6235, -2445, -2545, -2337, -2102, -4226, -2470, -4149, -3449, -3112, -3321, -2437, -7484, -5662, -5592, -3479, -2050, -4509, -5176, -4929, -4679, -1811, -1759, -3147, -2711, -4853, -2040, -792, -2628, -2217, -4046, -3154, -1075, -3624, -2964, -4518, -5862, -1859, -6411, -4743, -4620, -6705, -1925, -9753, -6899, -3031, -4573, -1916, -7984, -7179, -2091, -4262, -2578, -6958, -7542, -2058, -5109, -3923, -6653, -8276, -2975, -5592, -5353, -6365, -6899, -5008, -4478, -5844, -5718, -6399, -5367, -3396, -5988, -5702, -5776, -3695, -2863, -6007, -5942, -4262, -3360, -2791, -6411, -5133, -3843, -3930, -3191, -7603, -3916, -5444, -4451, -4199, -7445, -3154, -9695, -5240, -6640, -7865, -3415, -5942, -7299, -14195, -15615, -4896, -5227, -6786, -4635, -6653, -6123, -6225, -4759, -2279, -3999, -5836, -5554, -4319, -1663, -3329, -7371, -4874, -4935, -2594, -4010, -8517, -5670, -5951, -6083, -5801, -3951, -7130, -6399, -7179, -5871, -2030, -6958, -5097, -3883, -4307, -1505, -5853, -3540, -3460, -3886, -2225, -4438, -2613, -4869, -4784, -4611, -3316, -1983, -8718, -7335, -12319, -3144, -1329, -6800, -14784, -8112, -4172, -971, -4532, -9149, -6492, -6469, -1242, -3954, -7842, -5569, -5897, -2128, -4469, -8276, -4669, -4473, -3286, -5592, -8582, -4674, -4282, -4500, -6246, -7888, -5480, -4460, -6278, -6113, -6870, -6143, -4382, -9331, -5374, -5970, -5429, -4365, -10526, -4759, -5793, -3773, -4518, -6705, -4486, -6692, -2902, -4215, -4569, -4021, -7819, -3098, -3537, -3760, -3609, -6899, -3717, -3225, -3930, -3754, -6745, -4149, -3748, -4451, -4282, -8247, -4386, -5759, -4573, -4800, -7960, -4495, -10210, -4420, -5458, -7230, -4901, -8454, -4482, -6943, -8718, -6214, -9479, -5516, -10899, -10899, -8304, -11781, -9064, -11004, -11356, -6914, -8034, -8790, -6759, -11781, -6074, -8112, -5793, -5339, -5997, -7523, -10704, -4896, -4991, -3452, -10284, -13738, -4644, -5353, -2605, -8790, -12319, -4664, -6183, -3156, -7503, -11232, -5073, -7623, -5394, -6354, -11232, -6246, -9873, -11232, -5346, -12776, -6692, -11356, -10442, -5079, -10613, -4951, -8549, -8718, -6026, -8393, -3886, -6445, -8485, -7389, -7389, -3985, -5394, -8304, -6516, -6842, -5227, -5253, -8363, -6123, -5960, -7752, -6434, -8192, -7371, -4769, -9695, -10613, -7299, -11232, -4234, -7865, -8304, -7213, -12534, -4940, -6719, -5607, -4097, -1277, -4093, -629, -5152, -4299, -2417, -3748, -1023, -6214, -3029, -3933, -2964, -2319, -8790, -1610, -4625, -3218, -4769, -6163, -842, -4211, -3641, -7162, -2624, -879, -4157, -3047, -5055, -1195, -1696, -5061, -2690, -3820, -1165, -3476, -5784, -3326, -3686, -2430, -7230, -4698, -3989, -4086, -5133, -7230, -3367, -3259, -4420, -7796, -4545, -2624, -2795, -4555, -7774, -3674, -2399, -3130, -5202, -6679, -3373, -2347, -4024, -6958, -4086, -3360, -2149, -5266, -7484, -2455, -3788, -1884, -7050, -4968, -1965, -4340, -1810, -11781, -3393, -2325, -4688, -2060, -9873, -2950, -3067, -5599, -2166, -6914, -4203, -4438, -9380, -1485, -6064, -8649, -8903, -8718, -856, -5133, -3589, -5623, -5127, -1114, -4282, -1720, -3334, -3430, -2282, -3889, -1959, -3244, -1872, -2597, -3540, -4395, -3609, -1138, -1833, -2787, -15615, -3391, -1660, -1713, -1877, -4708, -2941, -4013, -1927, -1303, -3518, -2364, -28777, -1980, -1443, -4504, -2414, -4625, -2305, -2499, -7687, -3689, -2969, -2867, -3586, -6321, -6194, -3415, -3187, -2863, -4134, -8982, -6064, -3201, -2422, -4180, -12776, -8683, -2528, -3274, -7603, -13049, -4532, -1939, -4779, -7708, -10362, -3103, -2490, -3571, -3927, -8942, -3031, -4858, -1898, -3621, -8060, -4286, -10799, -1147, -5630, -6480, -9331, -28777, -1127, -11004, -4779, -6528, -8393, -1725, -5103, -4134, -3005, -4352, -3071, -2831, -4821, -1917, -2809, -5970, -1917, -7484, -2166, -2728, -12123, -1922, -7426, -3656, -3866, -8060, -2875, -4038, -6153, -6173, -7644, -4527, -2514, -7583, -8827, -6007, -5380, -2143, -7484, -10069, -4006, -5623, -2831, -5638, -9149, -3117, -6899, -4482, -4319, -7389, -3045, -8304, -6445, -4161, -7196, -3741, -7542, -9873, -3916, -8485, -5827, -6445, -5915, -2758, -10526, -14195, -5516, -2969, -1825, -8220, -7113, -5158, -2289, -1682, -4974, -5133, -5374, -3386, -2433, -3357, -4784, -6035, -6214, -4230, -2986, -4748, -5247, -6343, -6814, -3656, -4587, -3036, -5422, -7130, -5127, -4606, -1727, -6113, -6054, -6434, -5380, -1586, -7665, -5387, -5524, -7213, -2316, -8304, -4974, -4282, -8086, -2943, -7081, -4874, -3903, -7335, -2924, -5915, -5480, -4644, -7445, -3566, -5127, -6565, -6988, -7004, -5759, -4500, -6705, -9585, -5615, -7299, -4075, -5970, -6679, -4378, -6411, -4299, -5002, -4869, -3804, -7936, -5933, -4669, -3870, -4412, -10138, -11781, -5879, -3612, -7484, -6113, -8683, -11232, -4191, -10613, -4795, -6828, -6640, -5253, -5844, -5109, -7888, -4153, -6411, -5472, -6973, -11232, -3594, -7665, -6445, -11356, -7583, -4108, -9193, -6814, -13049, -4545, -5176, -13738, -7317, -7445, -2939, -6332, -13365, -9022, -5646, -2470, -8138, -10442, -9106, -5654, -3089, -13738, -11232, -7066, -6943, -4805, -8615, -11488, -5844, -7842, -7583, -6411, -8333, -5623, -7179, -7984, -6692, -6745, -6173, -6628, -6343, -7888, -6376, -6800, -6973, -6194, -5630, -3504, -5152, 304, -2356, -5279, -3930, -4513, -717, -5924, -6469, -4290, -3215, -2268, -7562, -9873, -4769, -2571, -3833, -3468, -7066, -6267, -2463, -3785, -2490, -4738, -10442, -2478, -3476, -2926, -3785, -11356, -2457, -4357, -4550, -3247, -8615, -2642, -5546, -5444, -2900, -8790, -3309, -3996, -2730, -2979, -7936, -4573, -2752, -1042, -4138, -5576, -6492, -2429, -863, -8718, -4038, -8754, -2630, -2257, -5055, -3108, -5888, -3218, -5353, -2028, -2580, -2947, -4315, -5008, -1020, -2605, -1484, -5353, -3776, -923, -3729, -1239, -4693, -3609, -1018, -7484, -2447, -3463, -3259, -800, -8942, -6928, -2709, -2299, -601, -4611, -6045, -2361, -1372, -976, -3546, -3096, -2396, -920, -1943, -3896, -3189, -3007, -1016, -2869, -5718, -5306, -4790, -1264, -3337, -11781, -5630, -9812, -1020, -3889, -7247, -3873, -7130, -521, -4408, -4500, -3751, -4513, -359, -4319, -3632, -4985, -3668, -828, -3896, -3501, -6958, -3677, -2409, -3968, -3444, -8790, -4469, -7842, -5539, -3501, -7623, -5630, -4869, -13738, -3409, -6045, -6074, -1869, -5784, -2553, -4890, -5103, -1226, -3563, -1982, -3463, -3498, -1678, -3349, -2756, -2799, -2789, -2799, -4071, -6666, -3571, -3168, -4303, -4246, -5979, -6973, -3853, -5988, -3732, -2285, -9585, -4500, -7408, -3896, -1483, -4997, -6653, -6828, -4946, -2378, -3606, -11356, -4723, -6054, -5776, -2871, -6093, -3701, -5862, -9639, -2545, -3999, -4056, -4968, -4774, -2677, -2916, -5189, -4390, -4130, -3078, -2567, -5569, -4357, -4674, -3085, -2967, -6899, -4703, -5408, -3117, -4527, -9238, -4688, -6246, -4149, -11488, -4064, -4842, -7730, -5380, -5049, -1793, -6278, -9695, -3441, -2143, -734, -4654, -10613, -1937, -1323, -417, -1908, -6299, -1546, -1647, -674, -812, -4127, -2146, -2541, -1348, -1010, -3763, -3951, -3149, -2207, -2024, -5139, -4654, -3404, -2999, -2639, -9284, -2200, -3563, -3515, -2386, -14195, -1123, -3378, -3615, -2391, -11629, -1485, -2977, -3254, -3027, -11488, -3365, -2929, -2933, -4723, -8754, -7213, -3886, -2855, -9753, -7081, -8718, -6692, -2745, -7774, -5915, -7960, -6590, -2543, -4509, -4698, -8790, -4230, -2776, -3795, -3650, -9812, -3589, -4230, -4630, -2952, -9064, -3968, -7542, -5997, -2698, -7281, -4946, -5670, -5202, -2922, -5836, -6064, -4010, -4842, -3665, -5367, -7542, -3866, -5152, -4738, -6153, -10613, -4569, -4006, -5924, -7752, -9149, -6093, -2958, -6988, -6856, -6828, -8363, -3124, -7623, -5615, -6153, -6653, -4625, -8304, -5509, -6540, -4527, -6899, -7445, -6376, -8276, -3735, -7562, -5145, -8220, -13738, -3776, -8649, -3937, -8982, -11488, -4246, -12534, -3975, -7865, -8220, -5360, -12534, -5073, -7019, -6814, -7583, -11115, -7034, -6590, -6278, -6399, -11356, -9479, -6540, -6504, -4266, -28777, -14784, -7081, -7353, -3386, -11945, -10138, -7665, -7004, -3512, -9873, -6480, -8165, -5429, -4578, 6593, 3030, 1538, 6735, -3388, 6250, 2597, 1701, 6297, -1212, 5305, 1149, 1623, 5029, 852, 4075, -2288, 823, 3180, 2145, 3078, -7796, 216, 1115, 2889, 2249, -2043, 993, -2197, 2992, 943, -1459, 1852, -5133, 2263, 410, -1761, 2430, -72, 800, 819, -179, 2860, 1829, 553, -1209, 1652, 2740, 2877, 2116, 1362, 3020, 1299, 3377, 3701, 4582, 4225, -37, 3143, 5044, 5643, 5346, 2696, 1786, 5895, 5377, 6168, 3704, -242, 6002, 4448, 6394, 2690, 929, 5225, 3888, 5742, -526, 1833, 3773, 3467, 3792, 1936, 1358, 2873, 2329, -393, 3745, 94, 2228, 1512, 75, 3814, -1690, -93, 2392, 1020, 2661, -3612, -1816, 2772, -695, 969, -287, -583, 1903, -561, 232, 1779, -974, -475, 969, -1284, 2667, 1299, -5494, -222, -8393, 2952, 2553, -6988, -11115, 945, 2854, 1571, -5109, 688, 3075, 2353, -2945, -3071, 2798, 3446, 1365, 1195, -7, 3496, 2658, -465, 3161, 1703, 3593, 1298, -4625, 3128, 2164, 3229, 325, -1254, 1624, 1362, 2432, -48, 1774, -1066, -1865, 1408, 750, 3080, -3012, -3893, 411, 1726, 3408, -5312, 961, -517, 1730, 3047, -6332, 2111, -1748, 678, 2222, -3487, 1821, -2429, -403, 1194, -3814, 564, -382, -424, 331, -4842, -989, 817, -1142, -140, -2101, -939, 432, -2326, -365, -87, 378, -1663, -1107, -599, 1056, 1447, -3629, -744, -1047, 1613, 1991, -3142, -2698, -1760, 1621, 2080, -5380, -2630, -2714, 1089, 1814, -7162, -266, -3795, 104, 1204, -3391, -181, -3860, -1191, 177, -3213, -2232, -2369, -2751, -1324, -3893, -6590, -1126, -4578, -3365, -2383, -6640, -771, -4821, -5793, -834, -10362, -1288, -4021, -4378, 73, -7644, -2118, -4211, -2409, 533, -4386, -2004, -5615, -1627, 432, -3156, -1762, -6565, -1683, -450, -2336, -2546, -5531, -2115, -2312, -1854, -4180, -5079, -2083, -3860, -2130, -3751, -5145, -1793, -2752, -3883, -2356, -4748, -2251, -1627, -9193, -1781, -4053, -4464, -1368, -7665, -1781, -3798, -5360, -2297, -9106, -1923, -4728, -1756, -5031, -7264, -1875, -8165, -585, -11115, -3117, -1738, -8086, -1181, -7264, -2344, -1690, -5487, -3840, -5879, -3910, -1807, -4659, -17034, -5380, -8549, -2040, -4258, -6705, -5139, -3933, -2396, -4790, -5678, -5333, -2265, -3034, -7213, -5853, -5906, -2168, -4327, -7912, -5451, -6411, -3010, -6615, -5494, -4145, -6759, -4352, -7623, -5451, -2871, -8086, -4912, -6705, -8060, -2115, -17034, -4495, -7317, -11781, -2000, -8517, -4754, -10138, -7752, -2409, -6113, -5970, -12534, -9022, -3239, -6093, -7299, -8982, -7984, -4738, -7603, -7097, -6074, -4482, -8112, -9531, -5793, -4348, -3401, -8865, -9585, -4991, -3744, -3757, -5458, -7865, -5353, -4311, -4968, -4923, -5970, -7317, -6343, -6153, -6856, -4597, -9873, -10899, -6204, 1100, 6058, 1262, 2909, -8304, 2480, 5532, 2293, 2255, 1405, 3401, 3810, 3401, -217, 3985, 2749, 476, 3689, -7819, 4990, 398, -847, 3265, -284, 5012, 553, 668, 2244, 1759, 4306, 3124, 1150, 286, 2546, 2994, 4618, 1022, -4974, 2675, 810, 5369, 61, -3067, 2254, -2435, 5451, 1225, -1758, 1528, -3618, 5105, 4067, -62, 1110, -161, 5514, 5608, 3900, 1295, 2631, 6450, 5978, 5828, 1423, 3820, 6658, 5414, 6206, 1258, 3695, 5953, 4252, 5103, 2447, 2361, 4714, 2964, 1905, 4220, -153, 3574, 1759, -1407, 5231, -3373, 2705, -175, 986, 5531, -4713, 1455, -6083, 310, 5342, -4071, -1755, -483, -3218, 4798, -4821, -7842, 874, -10442, 3995, -4874, -3170, -946, -8649, 3129, -3744, -2666, -1948, -4769, 2334, -4713, -280, 1915, -440, 1301, -3311, 1086, 3469, 1578, -460, -1780, 1468, 3979, 2469, -1979, -2764, 1497, 3816, 2633, 65, -4086, 1528, 3136, 2198, 1650, -1067, 1651, 2419, 1097, 1922, -8, 1788, 2395, -647, 826, -665, 1778, 2654, -1939, -2472, -3354, 1547, 2531, -1566, -7603, -4442, 1264, 1722, -675, -1455, -575, 1309, -370, -272, -99, 1310, 1612, -1725, -852, -430, 2251, 1652, 1252, -2540, -1670, 2593, 1005, 2489, -4620, 217, 2450, -641, 2245, -4536, 2304, 1829, -3729, 548, -2219, 3283, 760, -5546, -3334, -639, 3546, -400, -2587, -14784, -60, 3408, -842, -471, -4991, -119, 3013, -117, 982, -638, -645, 2390, 931, 1808, 1517, -1510, 1431, 1485, 1993, 2218, -2069, -135, 1363, 1547, 1881, -2363, -1277, 650, 499, 1021, -3237, -583, -364, -1250, 259, -4795, -439, -978, -4145, -734, -6054, -1390, -930, -4270, -2990, -5888, -3014, -990, -2590, -7936, -5073, -4664, -1563, -3137, -10210, -4555, -5061, -2414, -7445, -6035, -4985, -4357, -3042, -7247, -2813, -6256, -3309, -3225, -4601, -1790, -5286, -2068, -3580, -5678, -2762, -3563, -1158, -5061, -6914, -7484, -3078, -849, -8454, -3704, -6928, -3913, -1121, -7317, -2083, -4319, -6246, -1507, -6504, -1624, -5073, -8903, -1521, -6666, -2095, -8942, -6988, -1499, -4963, -3490, -8903, -5121, -1668, -3441, -5810, -5437, -4311, -1918, -2900, -6773, -3971, -4640, -2062, -3650, -4826, -3476, -5584, -1869, -6321, -3237, -3893, -5630, -1827, -10138, -2213, -5109, -5273, -2617, -10704, -1868, -6492, -5569, -4630, -11232, -2455, -6565, -6183, -6943, -5221, -4447, -6123, -7230, -5415, -3386, -8790, -5836, -9873, -4089, -3184, -8615, -5539, -9753, -3840, -4369, -6705, -5380, -8517, -4935, -6528, -5524, -5408, -9873, -9479, -6133, -4951, -5751, -11232, -6267, -5979, -5266, -6628, -10799, -3321, -8393, -6246, -7888, -12319, -2666, -7819, -6973, -8363, -11232, -3422, -5933, -7050, -6204, -9936, -5509, -6565, -6679, -4447, -9639, -9064, -8454, -7865, 6384, 8433, 6336, -1661, 2254, 6190, 7798, 6460, 4567, 4610, 5623, 6069, 6709, 6674, 5012, 4822, 4554, 6703, 6995, 3751, 3834, 3798, 5914, 5827, 458, 2226, 1892, 3772, 2775, -1699, 919, -2082, 1070, 361, -1205, 1609, -7162, 1990, 1068, -4578, 1643, -3184, 1957, 2505, -3412, 715, -877, 2185, 5062, 1287, 500, -36, 3480, 6450, 3364, 1762, 233, 3873, 6837, 4204, 2522, 91, 2879, 6135, 3929, 2207, -1136, -383, 3287, 2281, 788, -5319, -6602, 1016, -1621, -2222, -1546, -911, 5163, -1417, -6399, 602, -1000, 6003, 314, -1749, 715, -2538, 5599, -180, -1145, -336, -3284, 5076, -2475, -3656, -1872, -3535, 4641, -7230, -3957, -3306, -1466, 3675, -14195, -678, -3571, -320, 2228, -8009, -95, -3269, -952, 907, -4451, -1287, -3529, -3311, 22, -3375, -4880, -2945, -5751, -427, -4100, -8276, -1433, -5458, -1026, -8009, -7034, -302, -5008, -1895, -6225, -5646, 172, -4403, -1174, -2648, -2351, 92, -4035, -23, -1707, -1615, -535, -3751, 230, -2340, -2964, -1887, -3140, -276, -3632, -5710, -3680, -2605, -1382, -2845, -4416, -4071, -3436, -4184, -1916, -2918, -2391, -6411, -5306, -1193, -2234, -422, -1541, -1468, 25, -2686, 676, 819, -617, 708, -4583, 616, 1322, -1187, 154, -4693, -595, 305, -2733, -2350, -2639, -810, -2528, -5346, -5109, -1642, 636, -12534, -2644, -2534, -1726, 1346, -3811, -352, -3600, -1944, 1705, -1487, 634, -2813, -585, 1998, -1370, 995, 746, 581, 1725, -3485, 1000, 1936, 794, 496, -12534, 578, 1525, 184, -1491, -6553, -574, -590, -981, -1893, -5387, -2650, -6434, -2317, -783, -4718, -5049, -5374, -3316, -217, -4361, -7708, -3763, -3677, -430, -4708, -14195, -5227, -3618, -1553, -4896, -7644, -8649, -3482, -3992, -4779, -6376, -5247, -3632, -7113, -4912, -6565, -3886, -4473, -5516, -5085, -5942, -4211, -6492, -4929, -5422, -4759, -5776, -9812, -5615, -6705, -4234, -7687, -8165, -6480, -8982, -4013, -7888, -5776, -7196, -7912, -3412, -7665, -4420, -9753, -6434, -2589, -7665, -3766, -15615, -5494, -2086, -6786, -3589, -8485, -4270, -2326, -5970, -3930, -7408, -3189, -3763, -6045, -5279, -8247, -2781, -7936, -6214, -9936, -9479, -3244, -8549, -6153, -7865, -9753, -4587, -4278, -6679, -4282, -9331, -6640, -2747, -7888, -3347, -8942, -7960, -2222, -8754, -4031, -8363, -8165, -2447, -7912, -6214, -5360, -8615, -3269, -6376, -6943, -4082, -8718, -4180, -5260, -5576, -4597, -8138, -4234, -4880, -4640, -6093, -8086, -3460, -5576, -4127, -6679, -9022, -2662, -7542, -4311, -7960, -11781, -2289, -7353, -5458, -9639, -13738, -2447, -7408, -7936, -7730, -8790, -3232, -11356, -10899, -7162, -7623, -4863, -5346, -8192, -8423, -8454, -7004, -3388, -6653, -14784, -10704, -7230, -3404, -6332, -11115, -10442, -7281, -8009, -3903, -7687, -12776, -5387, -5189, -3686, -6422, -9429, -4991, -4555, -3686, -6183, -7623, -5915, -4935, -3710, -6256, -6469, -8549, -5694, -3808, -5862, -6457, -7389, -7426, -4611, -5380, -7464, -6123, -8276, -6759, -5702, -6504, -6786, -5759, -11488, -7066, -4957, -7623, -4282, -13738, -9429, -4541, -7389, -3571, -10284, -11781, -5133, -7162, -3269, -8790, -11004, -6054, -6133, -3242, -8549, -8423, -6288, -5152, -3546, -8549, -7281, -6492, -4929, -4344, -7687, -6828, -7603, -5260, -6016, -7730, -6516, -8942, -5623, -10210, -8903, -6786, -8423, -5630, -11232, -8454, -7774, -8363, -5524, -7583, -7730, -9064, -9284, -5801, -7179, -6504, -9149, -11945, -6899, -8649, -5109, -6899, -10362, -8827, -11629, -4640, -5353, -6759, -8649, -11629, -5279, -5055, -5247, -7464, -9331, -7004, -5630, -4810, -7603, -6899, -8112, -5942, -5133, -9284, -5539, -6653, -5592, -6026, -12534, -5429, -5801, -6016, -6914, -11356, -6590, -5623, -8454, -7004, -9695, -8683, -5561, -11115, -6943, -8304, -10362, -5312, -7888, -7865, -6885, -9331, -5020, -7264, -10001, -5630, -7281, -4935, -8138, -9695, -4968, -6343, -5415, -10799, -7097, -5292, -6565, -6705, -28777, -5662, -6814, -7353, -7484, -9429, -5401, -8517, -7912, -6540, -7503, -6045, -7644, -8333, -6214, -7445, -7130, -7113, -8138, -6899, -8454, -7752, -7796, -7623, -8192, -9873, -7335, -8649, -7230, -9585, -10613, -6732, -7774, -7299, -10704, -9873, -6692, -5988, -8165, -10899, -8060, -7113, -4805, -9284, -10210, -7371, -7445, -4644, -8865, -9284, -8220, -7426, -5836, -8718, -7819, -11781, -6602, -9149, -8333, -6958, -14195, -5670, -9479, -7542, -7299, -10362, -5599, -7196, -7796, -8982, -8982, -6422, -6705, -10210, -9753, -7665, -8112, -6640, -17034, -8827, -6422, -10704, -6376, -9531, -9193, -5836, -10442, -6399, -8485, -11629, -6007, -8549, -7081, -9531, -13049, -6856, -8060, -8517, -13049, -11232, -7819, -9149, -10362, -28777, -10284, -8060, -13738, -10613, -14195, -8683, -8333, -11232, -9429, -11356, -7912, -9585, -8086, -8086, -8942, -8615, -13738, -7066, -7774, -7484, -12319, -28777, -7247, -8903, -7408, -14195, -12123, -8363, -13365, -9380, -9753, -12776, -10526, -12776, -13738, -8982, -12319, -12776, -11004, -7936, -9284, -8393, -13738, -13049, -6288, -9238, -6434, -13365, -10069, -6445, -8485, -5718, -11945, -7523, -8333, -8112, -5951, -10613, -6504, -12123, -8423, -7213, -10526, -6321, -9022, -9238, -9639, -10284, -7081, -7644, -9873, -12319, -9238, -9193, -8423, -10138, -12123, -9149, -12123, -11004, -10284, -14195, -10442, -12534, -10069, -10210, -28777, -12123, -10210, -9284, -10069, -12123, -12319, -8304, -11356, -11356, -10442, -10138, -7687, -14784, -28777, -9873, -8827, -7936, -10613, -13365, -9531, -8790, -8865, -9106, -11004, -8790, -10284, -10526, -9193, -10526, -8112, -13738, -14195, -10138, -10899, -7730, -28777, -28777, -10138, -11945, -7865, -17034, -13365, -10210, -10138, -8485, -15615, -12123, -6246, -4003, -9331, -11945, -9284, -5569, -5002, -9531, -9284, -13049, -4728, -7426, -10526, -7081, -9873, -4238, -8393, -11945, -5793, -7464, -4504, -7426, -11488, -5401, -6602, -5759, -6422, -9479, -5801, -5121, -7960, -5561, -8333, -6692, -4031, -10284, -5599, -7960, -7562, -4064, -12776, -6800, -8060, -8582, -5451, -11232, -8165, -8485, -8790, -9064, -8615, -8276, -8485, -6870, -11945, -7503, -7819, -6814, -6026, -8649, -7213, -7335, -5360, -6928, -8034, -7113, -7464, -5139, -10704, -8903, -6666, -8683, -5988, -11356, -12123, -5951, -11232, -5960, -7687, -12776, -5458, -13365, -5189, -6422, -9331, -5360, -10526, -5710, -6204, -8423, -5546, -9331, -7819, -6786, -8942, -5710, -8718, -8112, -8393, -9753, -5638, -6590, -7583, -10799, -8454, -5607, -4713, -10001, -9585, -7299, -5678, -4097, -11356, -8138, -6914, -5638, -4779, -5979, -7842, -7408, -5853, -6842, -4491, -7865, -8903, -6885, -10613, -4759, -7130, -10001, -7542, -28777, -6516, -6143, -9238, -5906, -12319, -8454, -5607, -7912, -4764, -9695, -8086, -5615, -6388, -4874, -9238, -8582, -5888, -5472, -6299, -9936, -9936, -6267, -5465, -10362, -11488, -8942, -6666, -6679, -12534, -14784, -8009, -7335, -10210, -8549, -11629, -8112, -9064, -11781, -8086, -9331, -8138, -11945, -7819, -8333, -9284, -7644, -12534, -6899, -8517, -10284, -6842, -28777, -7264, -9936, -9936, -6133, -9149, -8276, -10526, -9585, -6553, -6469, -9238, -7912, -8982, -9695, -5408, -10069, -6411, -7146, -11629, -5202, -11356, -5960, -6204, -7936, -5988, -13365, -6321, -6246, -7774, -7888, -11945, -7708, -6732, -8086, -7960, -10138, -9753, -7050, -7371, -6828, -9429, -9479, -6870, -6602, -6469, -9284, -8247, -6553, -6194, -6732, -9149, -8220, -6577, -6267, -7644, -9331, -8903, -7299, -7213, -9106, -10138, -9812, -8582, -9585, -10526, -13738, -10526, -8754, -13049, -12534, -14195, -11115, -8304, -10899, -28777, -9284, -11781, -8718, -9429, -11629, -7936, -12123, -10284, -8982, -10069, -8165, -12776, -13049, -9193, -11356, -9753, -14195, -28777, -10899, -17034, -10613, -13365, -13049, -12123, -17034, -8615, -9429, -11232, -8754, -13738, -7179, -7796, -11781, -7213, -9331, -6719, -7752, -14195, -7050, -7196, -7081, -8827, -11488, -7774, -6842, -8333, -10069, -9106, -8485, -8165, -10799, -10362, -9064, -8034, -12319, -28777, -10613, -11781, -7113, -28777, -12534, -12123, -11629, -6943, -13049, -10001, -14195, -8903, -8363, -11115, -9331, -12534, -8615, -12319, -10138, -9380, -10210, -9695, -13049, -10899, -9238, -8790, -10704, -12319, -11781, -9585, -7912, -9873, -11945, -10899, -10704, -7353, -8827, -9639, -10526, -9479, -7426, -7888, -8942, -11004, -7960, -8517, -7299, -10138, -12123, -7542, -10526, -7562, -14195, -12319, -8060, -10069, -9064, -12776, -11115, -9331, -9193, -12534, -10210, -11356, -10799, -10138, -17034, -9873, -12534, -11629, -14784, -15615, -10704, -11115, -12123, -13738, -14784, -11004, -9812, -11629, -10442, -12123, -10362, -10138, -10362, -4863, -7264, -8363, -10001, -8582, -7353, -10138, -7842, -11004, -7146, -7335, -12776, -8615, -12534, -5702, -5915, -10613, -10284, -28777, -6299, -5997, -11232, -12534, -11629, -9531, -8393, -13738, -12319, -10138, -8615, -10799, -9812, -11004, -13365, -6615, -6732, -7281, -11945, -13738, -6885, -5346, -5759, -28777, -9429, -9284, -5429, -4968, -15615, -8138, -13365, -7299, -4923, -12319, -7213, -8982, -11945, -5286, -10613, -7034, -7774, -8754, -5524, -9429, -8276, -7960, -7503, -5472, -9531, -12319, -8718, -7097, -5768, -13049, -10284, -9695, -6615, -7408, -10526, -7484, -10799, -6814, -11945, -7317, -6434, -9064, -8754, -17034, -6214, -6267, -7230, -10284, -12534, -5195, -6786, -6516, -7542, -7842, -3989, -8192, -6719, -7113, -6399, -3422, -11115, -7819, -8454, -6914, -3930, -11004, -8549, -9193, -8220, -5380, -8485, -7371, -8304, -8423, -6457, -7281, -6288, -8615, -8582, -6745, -6492, -5915, -9429, -9812, -7464, -5906, -6214, -8827, -11488, -9753, -5630, -6828, -7583, -10899, -14784, -5784, -6988, -6123, -11004, -7842, -6143, -6256, -4847, -9479, -6225, -6288, -5374, -4161, -7162, -6093, -6480, -4974, -4075, -6074, -6504, -6773, -5158, -4523, -5879, -6870, -7179, -5853, -5561, -6163, -7004, -8549, -7213, -7583, -6705, -7247, -12319, -9238, -9695, -6973, -8363, -11232, -9936, -8517, -6885, -11781, -8485, -8649, -8582, -7752, -13738, -7730, -7426, -11004, -11232, -10138, -7819, -7034, -13738, -14195, -10138, -7960, -7389, -13049, -10613, -12319, -7960, -7819, -13738, -9022, -12319, -8333, -8423, -13365, -7264, -11781, -9639, -9812, -17034, -6745, -14195, -11945, -10799, -12319, -7264, -14784, -12123, -12123, -8112, -8086, -9531, -10704, -11629, -6628, -8423, -6914, -10899, -8649, -6332, -8615, -5592, -11781, -7426, -6666, -9064, -5360, -13738, -6899, -7317, -9753, -6214, -17034, -6928, -8549, -10210, -8942, -10799, -7730, -10526, -10899, -28777, -8165, -9531, -10899, -12776, -9695, -7097, -12319, -10799, -11781, -8754, -7050, -28777, -13738, -9238, -10442, -7484, -12123, -14195, -8903, -13738, -7796, -8683, -11629, -11356, -10362, -7842, -7034, -12123, -15615, -9380, -8034, -6246, -11945, -9380, -10442, -8517, -6628, -10210, -8582, -13365, -9149, -8790, -9812, -9695, -13365, -9380, -13738, -10001, -11004, -11629, -9479, -13365, -9238, -10799, -10442, -10526, -10526, -8060, -11232, -10799, -13049, -7960, -7247, -12319, -12319, -14195, -6653, -6928, -12319, -15615, -13365, -6299, -7113, -12123, -28777, -12776, -6666, -7842, -11629, -28777, -10284, -7865, -9479, -12319, -28777, -8827, -10613, -13049, -14784, -28777, -8903, -17034, -28777, -17034, -14784, -10284, -13365, -13365, -12123, -11629, -12319, -14195, -12123, -11356, -9936, -13365, -28777, -11629, -11945, -9695, -11629, -14195, -11488, -12319, -10799, -10138, -13365, -11781, -10799, -13365, -9873, -14195, -11945, -10284, -12534, -11781, -14784, -12319, -11356, -11232, -28777, -13365, -11488, -17034, -11629, -11115, -10138, -9812, -13738, -13049, -9585, -8790, }; \ No newline at end of file diff --git a/sw/applications/transformer/tokenPosEmbeddingC.c b/sw/applications/transformer/tokenPosEmbeddingC.c new file mode 100644 index 00000000..39a63e40 --- /dev/null +++ b/sw/applications/transformer/tokenPosEmbeddingC.c @@ -0,0 +1,33 @@ +// +// Created by alireza on 10/6/23. +// + +#include "tokenPosEmbeddingC.h" + + +void createTokenPosEmbedding(TokenPosEmbedding* tokenPosEmbedding, quant_bit_width* pos_matrix, quant_bit_width* cls_token_vector, size_t seq_len, size_t input_dim, size_t pos_matrix_dim) { + tokenPosEmbedding->cls_token_vector_ = cls_token_vector; + tokenPosEmbedding->pos_matrix_ = pos_matrix; + tokenPosEmbedding->seq_len_ = seq_len; + tokenPosEmbedding->input_dim_ = input_dim; +} + +void clsConcatenate(TokenPosEmbedding* tpe, quant_bit_width* input, quant_bit_width* concatenated_input) { + // Copy cls_token_ into the concatenated array column-wise at the beginning + for (size_t i = 0; i < tpe->input_dim_; ++i) { + concatenated_input[i] = tpe->cls_token_vector_[i]; + } + // Copy the input array into the concatenated array + for (size_t i = 0; i < tpe->seq_len_ * tpe->input_dim_; ++i) { + concatenated_input[i + tpe->input_dim_] = input[i]; + } +} + +void posEmbedding(TokenPosEmbedding* tpe, quant_bit_width* input) { + for (size_t i = 0; i < (tpe->seq_len_ + 1); ++i) { + for (size_t j = 0; j < tpe->input_dim_; ++j) { + input[i * tpe->input_dim_+ j] += tpe->pos_matrix_[i * tpe->input_dim_ + j]; + } + } +} + diff --git a/sw/applications/transformer/tokenPosEmbeddingC.h b/sw/applications/transformer/tokenPosEmbeddingC.h new file mode 100644 index 00000000..9357a153 --- /dev/null +++ b/sw/applications/transformer/tokenPosEmbeddingC.h @@ -0,0 +1,24 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H +#define FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H + +#include "param.h" +#include "stdlib.h" + +typedef struct{ + quant_bit_width* cls_token_vector_; + quant_bit_width* pos_matrix_; + size_t seq_len_; + size_t input_dim_; +} TokenPosEmbedding; + + +void createTokenPosEmbedding(TokenPosEmbedding*, quant_bit_width* pos_matrix, quant_bit_width* cls_token_vector, size_t seq_len, size_t input_dim, size_t pos_matrix_dim); +void clsConcatenate(TokenPosEmbedding* tpe, quant_bit_width* input, quant_bit_width* concatenated_input); +void posEmbedding(TokenPosEmbedding* tpe, quant_bit_width* input); + + +#endif //FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H diff --git a/sw/applications/transformer/transformerBlockC.c b/sw/applications/transformer/transformerBlockC.c new file mode 100644 index 00000000..4d7a5fdb --- /dev/null +++ b/sw/applications/transformer/transformerBlockC.c @@ -0,0 +1,115 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include "transformerBlockC.h" +#include "multiply_cgra.h" + +SingleHeadSelfAttn global_selfatten [NUM_LAYERS * NUM_HEAD]; +Dense global_query_layer[NUM_LAYERS * NUM_HEAD]; +Dense global_key_layer[NUM_LAYERS * NUM_HEAD]; +Dense global_value_layer[NUM_LAYERS * NUM_HEAD]; + +Dense global_condense[NUM_LAYERS]; +Dense global_patch; +Dense global_FF[NUM_LAYERS * 2]; +Dense global_mlp; + +TransformerBlock global_transformer_block; +TokenPosEmbedding global_token_embedding; + +TransformerBlock* createTransformerBlock(size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, size_t num_heads, size_t ff_size, int32_t** weightVector, int32_t** biasVector, int32_t* clsTokenVector, int32_t* posMatrix) { + TransformerBlock* transformerBlock = &global_transformer_block; + transformerBlock->num_heads_ = num_heads; + transformerBlock->head_hidden_size_ = head_hidden_size; + transformerBlock->input_dim_ = input_dim; + transformerBlock->ff_size_ = ff_size; + + transformerBlock->addNorm = createAddNormalize(pre_seq_len, D_EMBEDDING, weightVector[0], biasVector[0]); + transformerBlock->patchEmbedding = &global_patch; + createDense(transformerBlock->patchEmbedding, D_EMBEDDING, D_MODEL, weightVector[1], biasVector[1]); + transformerBlock->addNorm2 = createAddNormalize(pre_seq_len, D_MODEL, weightVector[2], biasVector[2]); + transformerBlock->token = &global_token_embedding; + createTokenPosEmbedding(transformerBlock->token, posMatrix, clsTokenVector, pre_seq_len, input_dim, D_SEQ + 1); + + for (int l = 0; l < 4; l++) { + transformerBlock->transformer_layer_0_addNorm[l] = createAddNormalize((pre_seq_len + 1), D_MODEL, weightVector[l * 17 + 3], biasVector[l * 17 + 3]); + + for (int n = 0; n < num_heads; n++) { + transformerBlock->selfatten[l * num_heads + n] = &global_selfatten[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->query_layer = &global_query_layer[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->key_layer = &global_key_layer[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->value_layer = &global_value_layer[l * num_heads + n]; + + create_SingleHeadSelfAttn(transformerBlock->selfatten[l * num_heads + n], (pre_seq_len + 1), input_dim, head_hidden_size, weightVector + l * 17 + 4 + n * 3); + } + + transformerBlock->condense[l] = &global_condense[l]; + createDense(transformerBlock->condense[l], num_heads * head_hidden_size, input_dim, weightVector[l * 17 + num_heads * 3 + 4], biasVector[l * 17 + num_heads * 3 + 4]); + + transformerBlock->transformer_layer_1_addNorm[l] = createAddNormalize((pre_seq_len + 1), input_dim, weightVector[l * 17 + num_heads * 3 + 5], biasVector[l * 17 + num_heads * 3 + 5]); + + transformerBlock->feedForward0[l] = &global_FF[2*l]; + createDense(transformerBlock->feedForward0[l], input_dim, ff_size, weightVector[l * 17 + num_heads * 3 + 6], biasVector[l * 17 + num_heads * 3 + 6]); + + transformerBlock->feedForward1[l] = &global_FF[2*l + 1]; + createDense(transformerBlock->feedForward1[l], ff_size, input_dim, weightVector[l * 17 + num_heads * 3 + 7], biasVector[l * 17 + num_heads * 3 + 7]); + } + + transformerBlock->mlp_head_norm = createAddNormalize(1, D_MODEL, weightVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 8], biasVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 8]); + + transformerBlock->mlp_head_linear = &global_mlp; + createDense(transformerBlock->mlp_head_linear, D_MODEL, D_MODEL, weightVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 9], biasVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 9]); + + return transformerBlock; +} + + +void destroyTransformerBlock(TransformerBlock* transformerBlock) { + // Free dynamically allocated memory + + free(transformerBlock); +} + +void computeFixedPoint(TransformerBlock* transformerBlock, size_t seq_len, quant_bit_width * input, + quant_bit_width * input_normalized, quant_bit_width * output, + quant_bit_width* intermediate, quant_bit_width* qkv, void * kperf) { + + printf("\rStep 1\n"); + normalize(&transformerBlock->addNorm, input, input); + computeDense(transformerBlock->patchEmbedding, seq_len, input, output); // 120x400x16 + normalize(&transformerBlock->addNorm2, output, output); + + clsConcatenate(transformerBlock->token, output, input); + seq_len++; + posEmbedding(transformerBlock->token, input); + + printf("\rStep 2\n"); + for (int l = 0; l < 4; l++) { + normalize(&transformerBlock->transformer_layer_0_addNorm[l], input, input_normalized); + for (int n = 0; n < NUM_HEAD; n++) { + printf("\rStep 3\n"); + compute_SingleHeadSelfAttn(transformerBlock->selfatten[l * NUM_HEAD + n], input_normalized, + output + n * (seq_len * transformerBlock->head_hidden_size_), qkv, intermediate); +// destroy_SingleHeadSelfAttn(transformerBlock->selfatten[l * NUM_HEAD + n]); + } + printf("\rStep 4\n"); + multihead_transpose(output, intermediate, seq_len, transformerBlock->head_hidden_size_, transformerBlock->num_heads_); + + computeDense(transformerBlock->condense[l], seq_len +3, intermediate, output); // 121x16x16 + + add(input, output, seq_len, transformerBlock->input_dim_ ); + + normalize(&transformerBlock->transformer_layer_1_addNorm[l], input, input_normalized); + computeDense(transformerBlock->feedForward0[l], seq_len +3, input_normalized, intermediate); // 121x16x4 + activation(transformerBlock->feedForward0[l], seq_len * transformerBlock->ff_size_, intermediate, intermediate); + + computeDense(transformerBlock->feedForward1[l], seq_len +3, intermediate, output); // 121x4x16 + add(input, output, seq_len, transformerBlock->input_dim_ ); + } + printf("\rStep 5\n"); + normalize(&transformerBlock->mlp_head_norm, input, input_normalized); + computeDense(transformerBlock->mlp_head_linear, 1, input_normalized, output); // 1x16x16 +} + diff --git a/sw/applications/transformer/transformerBlockC.h b/sw/applications/transformer/transformerBlockC.h new file mode 100644 index 00000000..0663f92a --- /dev/null +++ b/sw/applications/transformer/transformerBlockC.h @@ -0,0 +1,48 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H +#define FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H + +#include +#include +#include "selfattentionC.h" +#include "addNormC.h" +#include "dense_layerC.h" +#include "tokenPosEmbeddingC.h" +#include "param.h" +#include "transposeC.h" +#include "cgra.h" + +typedef struct { + size_t num_heads_; + size_t head_hidden_size_; + size_t input_dim_; + size_t ff_size_; + SingleHeadSelfAttn* selfatten[NUM_LAYERS*NUM_HEAD]; + int32_t* multihead_out; + int32_t* condense_out; + int32_t* intermediateFF; + int32_t* intermediateFFBlockWise; + AddNormalize addNorm; + AddNormalize addNorm2; + AddNormalize transformer_layer_0_addNorm[NUM_LAYERS]; + AddNormalize transformer_layer_1_addNorm[NUM_LAYERS]; + AddNormalize mlp_head_norm; + TokenPosEmbedding* token; + Dense* condense[NUM_LAYERS]; + Dense* feedForward0[NUM_LAYERS]; + Dense* feedForward1[NUM_LAYERS]; + Dense* patchEmbedding; + Dense* mlp_head_linear; + #ifndef REARRANGE + int32_t* multihead_out_reshape; + #endif +} TransformerBlock; + +TransformerBlock* createTransformerBlock(size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, size_t num_heads, size_t ff_size, int32_t** weightVector, int32_t** biasVector, int32_t* clsTokenVector, int32_t* posMatrix); +void destroyTransformerBlock(TransformerBlock* transformerBlock); +void computeFixedPoint(TransformerBlock* transformerBlock, size_t seq_len, int32_t* input, int32_t* input_normalized, int32_t* output, int32_t* intermediate, int32_t* qkv, void * kperf); + +#endif //FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H diff --git a/sw/applications/transformer/transposeC.c b/sw/applications/transformer/transposeC.c new file mode 100644 index 00000000..2c27aa52 --- /dev/null +++ b/sw/applications/transformer/transposeC.c @@ -0,0 +1,31 @@ +// +// Created by alireza on 10/6/23. +// + +#include "softmaxC.h" + + +void multihead_transpose(const quant_bit_width * input, quant_bit_width* output, size_t seq_len, + size_t head_hidden_size, size_t num_head) { + const quant_bit_width * initial_input = input; + for (int i=0; i < seq_len; i++){ + for (int n=0; n< num_head; n++){ + input = initial_input + i*head_hidden_size + n*seq_len*head_hidden_size; + for (int j=0; j < head_hidden_size; j++){ + *output++ = *input++; + } + } + } +} + + +void transpose_quant(const quant_bit_width * input, quant_bit_width* output, + size_t width, size_t height) { + for (size_t i = 0; i < height; i++) { + for (size_t j = 0; j < width; j++) { + output[i * width + j] = input[j * height + i]; + } + } +} + + diff --git a/sw/applications/transformer/transposeC.h b/sw/applications/transformer/transposeC.h new file mode 100644 index 00000000..500c100e --- /dev/null +++ b/sw/applications/transformer/transposeC.h @@ -0,0 +1,22 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TRANSPOSEC_H +#define FVLLMONTITRANSFORMER_TRANSPOSEC_H + + + +#include +#include "param.h" + +// Replace class with struct +typedef struct { + // struct members +} Transpose; + +// Function prototypes +void transpose_quant(const quant_bit_width* input, quant_bit_width* output, size_t width, size_t height); +void multihead_transpose(const quant_bit_width * input, quant_bit_width* output, size_t seq_len, size_t head_hidden_size, size_t num_head); + +#endif //FVLLMONTITRANSFORMER_TRANSPOSEC_H diff --git a/sw/applications/transformer/weightsAndBiasesC.c b/sw/applications/transformer/weightsAndBiasesC.c new file mode 100644 index 00000000..2fd600f0 --- /dev/null +++ b/sw/applications/transformer/weightsAndBiasesC.c @@ -0,0 +1,181 @@ +// +// Created by alireza on 10/6/23. +// +#include "weightsAndBiasesC.h" +#include +#include +#include "data_cpp/data.cpp" + +void getWeights(quant_bit_width * weightVec[]){ + + int weightVectorIndex = 0; + weightVec[weightVectorIndex++] = to_patch_embedding_layer_norm1_weight; + weightVec[weightVectorIndex++] = to_patch_embedding_linear_weight; + weightVec[weightVectorIndex++] = to_patch_embedding_layer_norm2_weight; + + + /* *************************** Layer 1 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_0_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_0_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_0_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_0_1_fn_ff2_weight; + + /* *************************** Layer 2 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_1_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_1_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_1_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_1_1_fn_ff2_weight; + + /* *************************** Layer 3 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_2_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_2_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_2_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_2_1_fn_ff2_weight; + + /* *************************** Layer 4 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_3_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_3_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_3_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_3_1_fn_ff2_weight; + + /* *************************** MLP HEAD ***************************** */ + weightVec[weightVectorIndex++] = mlp_head_layer_norm_weight; + weightVec[weightVectorIndex++] = mlp_head_linear_weight; + +} + +void getBiases(quant_bit_width * biasVec[]){ + int biasVectorIndex = 0; + biasVec[biasVectorIndex++] = to_patch_embedding_layer_norm1_bias; + biasVec[biasVectorIndex++] = to_patch_embedding_linear_bias; + biasVec[biasVectorIndex++] = to_patch_embedding_layer_norm2_bias; + + /* *************************** Layer 1 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_0_0_norm_bias; + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_0_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_0_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_0_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_0_1_fn_ff2_bias; + + /* *************************** Layer 2 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_1_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_1_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_1_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_1_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_1_1_fn_ff2_bias; + + /* *************************** Layer 3 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_2_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_2_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_2_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_2_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_2_1_fn_ff2_bias; + + /* *************************** Layer 4 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_3_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_3_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_3_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_3_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_3_1_fn_ff2_bias; + + /* *************************** MLP HEAD ***************************** */ + biasVec[biasVectorIndex++] = mlp_head_layer_norm_bias; + biasVec[biasVectorIndex++] = mlp_head_linear_bias; +} + +quant_bit_width * getPosEmbedding(){ + quant_bit_width * posMatrix; + posMatrix = pos_embedding; + return posMatrix; +} + +quant_bit_width * getClassToken(){ + quant_bit_width * clsTokenVector; + clsTokenVector = cls_token; + return clsTokenVector; +} + + diff --git a/sw/applications/transformer/weightsAndBiasesC.h b/sw/applications/transformer/weightsAndBiasesC.h new file mode 100644 index 00000000..b16d6468 --- /dev/null +++ b/sw/applications/transformer/weightsAndBiasesC.h @@ -0,0 +1,15 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H +#define FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H + +#include "param.h" + +void getWeights(quant_bit_width * weightVec[]); +void getBiases(quant_bit_width * biasVec[]); +quant_bit_width * getPosEmbedding(); +quant_bit_width * getClassToken(); + +#endif //FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H From 2dc4e61b9abf41eba6eafcf7977b8c40de0bc336 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:31:40 +0200 Subject: [PATCH 12/27] add transformer example --- sw/applications/transformer/SYLT-FFT/LICENSE | 48 ++ .../transformer/SYLT-FFT/README.md | 59 +++ sw/applications/transformer/SYLT-FFT/config.h | 88 ++++ sw/applications/transformer/SYLT-FFT/fft.h | 423 ++++++++++++++++++ sw/applications/transformer/SYLT-FFT/fpmath.h | 139 ++++++ .../transformer/SYLT-FFT/intrinsics.h | 153 +++++++ sw/applications/transformer/SYLT-FFT/main.c | 74 +++ 7 files changed, 984 insertions(+) create mode 100644 sw/applications/transformer/SYLT-FFT/LICENSE create mode 100644 sw/applications/transformer/SYLT-FFT/README.md create mode 100644 sw/applications/transformer/SYLT-FFT/config.h create mode 100644 sw/applications/transformer/SYLT-FFT/fft.h create mode 100644 sw/applications/transformer/SYLT-FFT/fpmath.h create mode 100644 sw/applications/transformer/SYLT-FFT/intrinsics.h create mode 100644 sw/applications/transformer/SYLT-FFT/main.c diff --git a/sw/applications/transformer/SYLT-FFT/LICENSE b/sw/applications/transformer/SYLT-FFT/LICENSE new file mode 100644 index 00000000..f1c15f58 --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/LICENSE @@ -0,0 +1,48 @@ +MHG (MORAL HIGH GROUND) LICENSE + +This software is released under the UNLICENSE license under the single +condition that good moral standards are maintained in its use. + +The term "moral standards" is chosen because it is impossible to define +legally as it varies with cultural and individual values, principles and +ideas. Hence, the following may or may not apply. + +If you find this software useful - use it in any way you like, but +consider dropping the author a "thank you" message. + +If you want to use this software to earn money - please do, but +consider mentioning the authors name or making a donation. + +If you use this software - consider letting the author know. Simply +knowing it is being put to good use is often rewarding. + +You should consider maintaining open source licensing for software +that uses or is derived from this software. + + +UNLICENSE + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/sw/applications/transformer/SYLT-FFT/README.md b/sw/applications/transformer/SYLT-FFT/README.md new file mode 100644 index 00000000..530a2f31 --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/README.md @@ -0,0 +1,59 @@ +SYLT-FFT +======== +DEVSOUND (I)FFT(R) LIBRARY +------------------------------------- +And some other funky fixed-point maths like gray-coding and pow(2, f) + +**Optimized (C-level) for Keil C Compiler and GCC on Cortex-M4.** + +**Authors:** +* D. Taylor 2014 (gmail: senseitg) + +**License:** +* MHG (GPL compatible) - see LICENSE + +**Features:** +* FFT (Fast Fourier Transform) and IFFT (Inverse FFT) +* Fixed-point 32-bit, Radix-2 +* Complex or real (with slight conversion overhead) data +* No plan construction required before (I)FFT +* No reliance on other libraries (including libm if using precomputed tables) + +**Options (config.h):** +* DIT (decimation-in-time) or DIF (decimation-in-frequency) +* Rounding on divide (-speed, +accuracy) +* Saturating math (-speed, +stability) +* Table size vs. max. FFT length + +**Resource requirements:** +* Minimal memory requirements (in-place) +* Minimal stack use (non-recursive) +* Minimal twiddle tables (512 bytes for max N=512 FFT) + +**Notes:** +* Designed for optimal performance, not optimal accuracy + +**Caveats:** +* Care must be taken with input data to ensure no overflows +* Requires C99 (-std=c99 for GCC) + +**Performance:** +* Comparing against: CMSIS DSP arm_cortexM4I_math.lib(1.4.2) +* Platform: Freescale Kinetis K20 (Cortex-M4/ARMv7E-M) +* KEIL = Keil C Compiler 5.01 -O3 +* GCC = GNU Tools for ARM Embedded Processors 4.8.4 -O3 + +``` +Comparisons are of speed, +N% = faster than CMSIS, -N% = slower. +Please verify and do additional tests to add to the list. + + CMSIS-DSP SYLT-FFT N KEIL GCC +* arm_cfft_radix2_q31 fft_inverse 256 +25.6% +15.1% +``` + +**Thanks to:** +* [Wikipedia](http://www.wikipedia.org/) - for existing and taking donations +* [KATJA](http://www.katjaas.nl/) - for intelligible merge/split spectra algorithm +* [XCORE](https://github.com/xcore/) - for intelligible (I)FFT algorithm +* [CMLAB](http://www.cmlab.csie.ntu.edu.tw/cml/dsp/training/coding/transform/fft.html) - for intelligible FFT algorithm breakdown +* [BEVAN](http://web.ece.ucdavis.edu/~bbaas/281/slides/Handout.fft2.pdf) - for intelligible DIT vs. DIF, radix-2 vs. 4 overview diff --git a/sw/applications/transformer/SYLT-FFT/config.h b/sw/applications/transformer/SYLT-FFT/config.h new file mode 100644 index 00000000..a55673dd --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/config.h @@ -0,0 +1,88 @@ +// CONFIGURATION FILE +// D. TAYLOR 2014 + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#include "stdint.h" +#include "stdbool.h" + +#ifndef __INLINE +#if defined(__GNUC__) +#define __INLINE __attribute__((always_inline)) inline +#else +#define __INLINE __inline +#endif +#endif + + +/* == MATH CONFIGURE =============================================== */ + +#define FPOW2_FBITS 27 // Number of fractional bits (1...28) +#define FPOW2_LIMIT 8 // Limit accuracy to n fractional bits (1...FPOW2_FBITS-1) + +#define SINE_BITS 7 // Sine quality (2..14) vs. memory tradeoff +#define SINE_USE_TABLE 1 // Use pre-computed ROM table (vs. generate in RAM) +#define SINE_PRINTOUT 0 // Write sine table to screen (PC only) + +/* == FFT CONFIGURE =============================================== */ + +// Maximum FFT size: 4 << SINE_BITS (complex data points) +// Memory used by sine table: 4 << SINE_BITS (bytes) +// FFT is faster when SINE_USE_TABLE is 0 (located in RAM) + +#define FFT_DIT // Operation mode, FFT_DIT or FFT_DIF (slower) +#define FFT_ROUNDING 0 // Perform rounding when dividing (slower) +#define FFT_SATURATE 0 // Use saturating math where possible (slower) + +/* == WAVETABLE CONFIGURE ========================================== */ + +/* == GLOBAL DATA CONFIGURE ======================================== */ + +// PI +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// LUT for sine wave, first quadrant only +#if SINE_USE_TABLE +// == PLACE GENERATED SINE TABLE HERE ======================== // +// ROM +#if SINE_BITS != 7 +#error "sinetable[] size does not match SINE_BITS" +#endif +const int32_t sinetable[] = { + 0x00000000, 0x01921d1f, 0x03242abe, 0x04b6195d, 0x0647d97c, 0x07d95b9e, 0x096a9049, 0x0afb6805, + 0x0c8bd35e, 0x0e1bc2e3, 0x0fab272b, 0x1139f0ce, 0x12c8106e, 0x145576b1, 0x15e21444, 0x176dd9de, + 0x18f8b83c, 0x1a82a025, 0x1c0b826a, 0x1d934fe5, 0x1f19f97b, 0x209f701c, 0x2223a4c5, 0x23a6887e, + 0x25280c5d, 0x26a82185, 0x2826b928, 0x29a3c484, 0x2b1f34eb, 0x2c98fbba, 0x2e110a61, 0x2f875262, + 0x30fbc54d, 0x326e54c7, 0x33def287, 0x354d9056, 0x36ba2013, 0x382493b0, 0x398cdd32, 0x3af2eeb7, + 0x3c56ba70, 0x3db832a5, 0x3f1749b7, 0x4073f21d, 0x41ce1e64, 0x4325c135, 0x447acd50, 0x45cd358f, + 0x471cece6, 0x4869e664, 0x49b41533, 0x4afb6c97, 0x4c3fdff3, 0x4d8162c4, 0x4ebfe8a4, 0x4ffb654d, + 0x5133cc94, 0x5269126e, 0x539b2aef, 0x54ca0a4a, 0x55f5a4d2, 0x571deef9, 0x5842dd54, 0x59646497, + 0x5a827999, 0x5b9d1153, 0x5cb420df, 0x5dc79d7c, 0x5ed77c89, 0x5fe3b38d, 0x60ec382f, 0x61f1003e, + 0x62f201ac, 0x63ef328f, 0x64e88926, 0x65ddfbd3, 0x66cf811f, 0x67bd0fbc, 0x68a69e81, 0x698c246c, + 0x6a6d98a4, 0x6b4af278, 0x6c242960, 0x6cf934fb, 0x6dca0d14, 0x6e96a99c, 0x6f5f02b1, 0x70231099, + 0x70e2cbc6, 0x719e2cd2, 0x72552c84, 0x7307c3cf, 0x73b5ebd0, 0x745f9dd0, 0x7504d345, 0x75a585cf, + 0x7641af3c, 0x76d94988, 0x776c4edb, 0x77fab988, 0x78848413, 0x7909a92c, 0x798a23b1, 0x7a05eead, + 0x7a7d055b, 0x7aef6323, 0x7b5d039d, 0x7bc5e28f, 0x7c29fbee, 0x7c894bdd, 0x7ce3ceb1, 0x7d3980ec, + 0x7d8a5f3f, 0x7dd6668e, 0x7e1d93e9, 0x7e5fe493, 0x7e9d55fc, 0x7ed5e5c6, 0x7f0991c3, 0x7f3857f5, + 0x7f62368f, 0x7f872bf2, 0x7fa736b4, 0x7fc25596, 0x7fd8878d, 0x7fe9cbbf, 0x7ff62182, 0x7ffd885a, + 0x7fffffff, // <= space potato! +}; // <= sad monkey? +// == END OF GENERATED SINE TABLE ============================ // +#else +// RAM +int32_t sinetable[(1 << SINE_BITS) + 1]; +#endif + +// LUT for pow(2, fixedpoint) +// Only need to define up to FPOW2_LIMIT +const int32_t fpow2table[] = { + 0x6a09e668, 0x306fe0a3, 0x172b83c8, 0x0b5586d0, 0x059b0d31, 0x02c9a3e7, 0x0163daa0, 0x00b1afa6, +/*0x0058c86e, 0x002c605e, 0x00162f39, 0x000b175f, 0x00058ba0, 0x0002c5cc, 0x000162e5, 0x0000b172, + 0x000058b9, 0x00002c5d, 0x0000162e, 0x00000b17, 0x0000058c, 0x000002c6, 0x00000163, 0x000000b1, + 0x00000059, 0x0000002c, 0x00000016, 0x0000000b, 0x00000006, 0x00000003, 0x00000001, 0x00000001,*/ +}; + +#endif diff --git a/sw/applications/transformer/SYLT-FFT/fft.h b/sw/applications/transformer/SYLT-FFT/fft.h new file mode 100644 index 00000000..d6fb3ba7 --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/fft.h @@ -0,0 +1,423 @@ +// (I)FFT(R) +// D. TAYLOR 2014 + +#ifndef __FFT_H__ +#define __FFT_H__ + +#include "config.h" +#include "intrinsics.h" +#include "fpmath.h" + +/* == DECLARATIONS ================================================ */ + +// Fixed-point data type +typedef int32_t fft_t; + +// Complex number type +typedef struct { + fft_t r, i; +} fft_complex_t; + +// Readability macros +#define FFT_QCOS(K, SH) sinetable[(1 << SINE_BITS) - (K << SH)] +#define FFT_QSIN(K, SH) sinetable[K << SH] + +#if !((defined FFT_DIT) | (defined FFT_DIF)) +#error "Must define FFT_DIT or FFT_DIF" +#endif + + +/* == CODING STYLE DEFINITIONS ==================================== */ + +// GCC/ARMCC require different coding styles for optimal performance. +// These defines unify the different styles into one syntax. + +// # Optimal performance on ARMCC (Keil) # +#if defined(__ARMCC_VERSION) +// Declare complex, assign complex +#define FFT_DECLC(VAR, ASG) fft_complex_t VAR = ASG; +// Declare complex, assign real, imaginary +#define FFT_DECLR(VAR, R, I) fft_complex_t VAR = (fft_complex_t){ .r = R, .i = I }; +// Assign real, imaginary +#define FFT_ASSGN(VAR, R, I) VAR = (fft_complex_t){ .r = R, .i = I }; +// Access real, imaginary +#define FFT(VAR, SUB) VAR.SUB +#endif + +// # Optimal performance on GCC # +#if defined(__GNUC__) +// Declare complex, assign complex +#define FFT_DECLC(VAR, ASG) fft_t VAR##r = ASG.r, VAR##i = ASG.i; +// Declare complex, assign real, imaginary +#define FFT_DECLR(VAR, R, I) fft_t VAR##r = R, VAR##i = I; +// Assign real, imaginary +#define FFT_ASSGN(VAR, R, I) VAR.r = R; VAR.i = I; +// Access real, imaginary +#define FFT(VAR, SUB) VAR##SUB +#endif + +#if FFT_SATURATE +#define FFT_A(A,B) qadd(A, B) // A + B (saturating) +#define FFT_S(A,B) qsub(A, B) // A - B (saturating) +#define FFT_M2(W) qadd(W, W) // W * 2 (saturating) +#else +#define FFT_A(A,B) ((A) + (B)) // A + B +#define FFT_S(A,B) ((A) - (B)) // A - B +#define FFT_M2(W) ((W) << 1) // W * 2 +#endif +#define FFT_M(A,B) smmulr(A, B) // A * B +#define FFT_MA(A,B,C) smmlar(A, B, C) // C + (A * B) +#define FFT_MS(A,B,C) smmlsr(A, B, C) // C - (A * B) +#if FFT_ROUNDING +#define FFT_D2(W) (((W) + 1) >> 1) // W / 2 (rounded) +#else +#define FFT_D2(W) ((W) >> 1) // W / 2 +#endif + +/* == FORWARD AND INVERSE FFT ===================================== */ + +// Forward FFT transform +// Permutation must be performed prior to (DIT)/after (DIF) call +void fft_forward(fft_complex_t data[], unsigned bits) { + unsigned size = 1 << bits; +#ifdef FFT_DIT + unsigned shift = SINE_BITS + 1; + for(unsigned stride = 2 ; stride <= size; stride <<= 1, shift--) { +#else//FFT_DIF + unsigned shift = SINE_BITS - (bits - 2); + for(unsigned stride = size; stride >= 2; stride >>= 1, shift++) { +#endif + // Twiddle and combine for k = 0, having trivial (0 and 1) twiddle factors + for(unsigned a = 0; a < size; a += stride) { + unsigned b = a + (stride >> 1); +/* + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); + // # Radix-2 DIT/DIF trivial butterfly # + FFT_ASSGN(data[a], FFT_D2(FFT_ADD(FFT(A,r), FFT(B,r))), FFT_D2(FFT_ADD(FFT(A,i), FFT(B,i)))); + FFT_ASSGN(data[b], FFT_D2(FFT_SUB(FFT(A,r), FFT(B,r))), FFT_D2(FFT_SUB(FFT(A,i), FFT(B,i)))); +*/ + // Special case: GCC optimizes ARMCC style better here + fft_complex_t A = data[a], B = data[b]; + // # Radix-2 DIT/DIF trivial butterfly # + data[a] = (fft_complex_t){ .r = FFT_D2(FFT_A(A.r, B.r)), .i = FFT_D2(FFT_A(A.i, B.i)) }; + data[b] = (fft_complex_t){ .r = FFT_D2(FFT_S(A.r, B.r)), .i = FFT_D2(FFT_S(A.i, B.i)) }; + } + if(!(stride & 2)) { + for(unsigned a = (stride >> 2); a < (stride >> 2) + size; a += stride) { + unsigned b = a + (stride >> 1); + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT trivial butterfly # + FFT_ASSGN(data[a], FFT_D2(FFT_A(FFT(A,r), FFT(B,i))), FFT_D2(FFT_S(FFT(A,i), FFT(B,r)))); + FFT_ASSGN(data[b], FFT_D2(FFT_S(FFT(A,r), FFT(B,i))), FFT_D2(FFT_A(FFT(A,i), FFT(B,r)))); +#else//FFT_DIF + // # Radix-2 DIF trivial butterfly # + FFT_ASSGN(data[a], FFT_D2(FFT_A(FFT(A,r), FFT(B,r))), FFT_D2(FFT_A(FFT(A,i), FFT(B,i)))); + FFT_ASSGN(data[b], FFT_D2(FFT_S(FFT(A,i), FFT(B,i))), FFT_D2(FFT_S(FFT(B,r), FFT(A,r)))); +#endif + } + } + // Twiddle and combine + for(unsigned k = 1; k < (stride >> 2); k++) { + FFT_DECLR(W, FFT_QCOS(k, shift), FFT_QSIN(k, shift)); + for(unsigned a = k, b; a < size; a += (stride >> 2) + (stride >> 1)) { + b = a + (stride >> 1); + { // These two blocks prevent the compiler from confusing... + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT butterfly # + FFT_DECLR(BW, FFT_MA(FFT(B,i), FFT(W,i), FFT_M(FFT(B,r), FFT(W,r))), + FFT_MS(FFT(B,r), FFT(W,i), FFT_M(FFT(B,i), FFT(W,r)))); + FFT_ASSGN(data[a], FFT_A(FFT_D2(FFT(A,r)), FFT(BW,r)), FFT_A(FFT_D2(FFT(A,i)), FFT(BW,i))); + FFT_ASSGN(data[b], FFT_S(FFT_D2(FFT(A,r)), FFT(BW,r)), FFT_S(FFT_D2(FFT(A,i)), FFT(BW,i))); +#else//FFT_DIF + // # Radix-2 DIF butterfly # + FFT_ASSGN(data[a], FFT_D2(FFT_A(FFT(A,r), FFT(B,r))), FFT_D2(FFT_A(FFT(A,i), FFT(B,i)))); + FFT_DECLR(D, FFT_S(FFT(A,r), FFT(B,r)), FFT_S(FFT(A,i), FFT(B,i))); + FFT_ASSGN(data[b], FFT_MA(FFT(D,r), FFT(W,r), FFT_M(FFT(D,i), FFT(W,i))), + FFT_MS(FFT(D,r), FFT(W,i), FFT_M(FFT(D,i), FFT(W,r)))); +#endif + } + a += (stride >> 2); b += (stride >> 2); + { // ...register use resulting in more efficient code + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT butterfly # + FFT_DECLR(BW, FFT_MS(FFT(B,r), FFT(W,i), FFT_M(FFT(B,i), FFT(W,r))), + FFT_MA(FFT(B,i), FFT(W,i), FFT_M(FFT(B,r), FFT(W,r)))); + FFT_ASSGN(data[a], FFT_A(FFT_D2(FFT(A,r)), FFT(BW,r)), FFT_S(FFT_D2(FFT(A,i)), FFT(BW,i))); + FFT_ASSGN(data[b], FFT_S(FFT_D2(FFT(A,r)), FFT(BW,r)), FFT_A(FFT_D2(FFT(A,i)), FFT(BW,i))); +#else//FFT_DIF + // # Radix-2 DIF butterfly # + FFT_ASSGN(data[a], FFT_D2(FFT_A(FFT(A,r), FFT(B,r))), FFT_D2(FFT_A(FFT(A,i), FFT(B,i)))); + FFT_DECLR(D, FFT_S(FFT(B,r), FFT(A,r)), FFT_S(FFT(B,i), FFT(A,i))); + FFT_ASSGN(data[b], FFT_MS(FFT(D,i), FFT(W,r), FFT_M(FFT(D,r), FFT(W,i))), + FFT_MA(FFT(D,i), FFT(W,i), FFT_M(FFT(D,r), FFT(W,r)))); +#endif + } + } + } + } +} + +// Inverse FFT transform +// Permutation must be performed prior to (DIT)/after (DIF) call +void fft_inverse(fft_complex_t data[], unsigned bits) { + unsigned size = 1 << bits; +#ifdef FFT_DIT + unsigned shift = SINE_BITS + 1; + for(unsigned stride = 2 ; stride <= size; stride <<= 1, shift--) { +#else//FFT_DIF + unsigned shift = SINE_BITS - (bits - 2); + for(unsigned stride = size; stride >= 2; stride >>= 1, shift++) { +#endif + // Twiddle and combine for k = 0, having trivial (0 and 1) twiddle factors + for(unsigned a = 0; a < size; a += stride) { + unsigned b = a + (stride >> 1); +/* + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); + // # Radix-2 DIT/DIF trivial butterfly # + FFT_ASSGN(data[a], FFT_A(FFT(A,r), FFT(B,r)), FFT_A(FFT(A,i), FFT(B,i))); + FFT_ASSGN(data[b], FFT_S(FFT(A,r), FFT(B,r)), FFT_S(FFT(A,i), FFT(B,i))); +*/ + // Special case: GCC optimizes ARMCC style better here + fft_complex_t A = data[a], B = data[b]; + // # Radix-2 DIT/DIF trivial butterfly # + data[a] = (fft_complex_t){ .r = FFT_A(A.r, B.r), .i = FFT_A(A.i, B.i) }; + data[b] = (fft_complex_t){ .r = FFT_S(A.r, B.r), .i = FFT_S(A.i, B.i) }; + } + if(!(stride & 2)) { + for(unsigned a = (stride >> 2); a < size; a += stride) { + unsigned b = a + (stride >> 1); + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT trivial butterfly # + FFT_ASSGN(data[a], FFT_S(FFT(A,r), FFT(B,i)), FFT_A(FFT(A,i), FFT(B,r))); + FFT_ASSGN(data[b], FFT_A(FFT(A,r), FFT(B,i)), FFT_S(FFT(A,i), FFT(B,r))); +#else//FFT_DIF + // # Radix-2 DIF trivial butterfly # + FFT_ASSGN(data[a], FFT_A(FFT(A,r), FFT(B,r)), FFT_A(FFT(A,i), FFT(B,i))); + FFT_ASSGN(data[b], FFT_S(FFT(B,i), FFT(A,i)), FFT_S(FFT(A,r), FFT(B,r))); +#endif + } + } + // Twiddle and combine + for(unsigned k = 1; k < (stride >> 2); k++) { + FFT_DECLR(W, FFT_QCOS(k, shift), FFT_QSIN(k, shift)); + for(unsigned a = k, b; a < size; a += (stride >> 2) + (stride >> 1)) { + b = a + (stride >> 1); + { // These two blocks prevent the compiler from confusing... + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT butterfly # + FFT_DECLR(BW, FFT_MS(FFT(B,r), FFT(W,r), FFT_M(FFT(B,i), FFT(W,i))), + FFT_MA(FFT(B,i), FFT(W,r), FFT_M(FFT(B,r), FFT(W,i)))); + FFT_ASSGN(data[a], FFT_S(FFT(A,r), FFT_M2(FFT(BW,r))), FFT_A(FFT(A,i), FFT_M2(FFT(BW,i)))); + FFT_ASSGN(data[b], FFT_A(FFT(A,r), FFT_M2(FFT(BW,r))), FFT_S(FFT(A,i), FFT_M2(FFT(BW,i)))); +#else//FFT_DIF + // # Radix-2 DIF butterfly # + FFT_ASSGN(data[a], FFT_A(FFT(A,r), FFT(B,r)), FFT_A(FFT(A,i), FFT(B,i))); + FFT_DECLR(D, FFT_S(FFT(A,r), FFT(B,r)), FFT_S(FFT(A,i), FFT(B,i))); + FFT_ASSGN(data[b], FFT_M2(FFT_MS(FFT(D,i), FFT(W,i), FFT_M(FFT(D,r), FFT(W,r)))), + FFT_M2(FFT_MA(FFT(D,i), FFT(W,r), FFT_M(FFT(D,r), FFT(W,i))))); +#endif + } + a += (stride >> 2); b += (stride >> 2); + { // ...register use resulting in more efficient code + FFT_DECLC(A, data[a]); FFT_DECLC(B, data[b]); +#ifdef FFT_DIT + // # Radix-2 DIT butterfly # + FFT_DECLR(BW, FFT_MA(FFT(B,i), FFT(W,r), FFT_M(FFT(B,r), FFT(W,i))), + FFT_MS(FFT(B,r), FFT(W,r), FFT_M(FFT(B,i), FFT(W,i)))); + FFT_ASSGN(data[a], FFT_S(FFT(A,r), FFT_M2(FFT(BW,r))), FFT_S(FFT(A,i), FFT_M2(FFT(BW,i)))); + FFT_ASSGN(data[b], FFT_A(FFT(A,r), FFT_M2(FFT(BW,r))), FFT_A(FFT(A,i), FFT_M2(FFT(BW,i)))); +#else//FFT_DIF + // # Radix-2 DIF butterfly # + FFT_ASSGN(data[a], FFT_A(FFT(A,r), FFT(B,r)), FFT_A(FFT(A,i), FFT(B,i))); + FFT_DECLR(D, FFT_S(FFT(A,r), FFT(B,r)), FFT_S(FFT(B,i), FFT(A,i))); + FFT_ASSGN(data[b], FFT_M2(FFT_MS(FFT(D,r), FFT(W,i), FFT_M(FFT(D,i), FFT(W,r)))), + FFT_M2(FFT_MA(FFT(D,i), FFT(W,i), FFT_M(FFT(D,r), FFT(W,r))))); +#endif + } + } + } + } +} + + +/* == DATA SET PROCESSING AND MANIPULATION ======================== */ + +// Process complex data to produce real-only output +// This allows us to output N*2 point of real data using a N point complex (I)FFT +// Even/odd real data will be found in the real/imaginary parts of every output bin upon completion +void fft_convert(fft_complex_t data[], unsigned bits, bool permutated, bool invert) { + unsigned size = 1 << --bits; + unsigned shift = SINE_BITS - bits++; + unsigned n, z, nc, zc; + fft_t rsum, rdif, isum, idif; + fft_t itwiddled, rtwiddled; + for(nc = zc = size; nc; nc--, zc++) { + if(permutated) { + n = RBITS(nc, bits); z = RBITS(zc, bits); + } else { + n = nc; z = zc; + } + rsum = data[n].r + data[z].r; isum = data[n].i + data[z].i; + rdif = data[n].r - data[z].r; idif = data[n].i - data[z].i; + fft_t r = FFT_QCOS(nc, shift); fft_t i = -FFT_QSIN(nc, shift); + if(invert) r = -r; + rtwiddled = FFT_MA(r, isum, FFT_M(i, rdif)) << 1; + itwiddled = FFT_MS(r, rdif, FFT_M(i, isum)) << 1; + data[n].r = rsum + rtwiddled; data[n].i = itwiddled + idif; + data[z].r = rsum - rtwiddled; data[z].i = itwiddled - idif; + } + fft_t data_0_tr = data[0].r; + data[0].r = (data[0].r + data[0].i); data[0].i = (data_0_tr - data[0].i); + if(!invert) { data[0].r <<= 1; data[0].i <<= 1; } +} + +// Perform bit-reversal permutation on data set +// (Reverses address bits for all data points) +void fft_permutate(fft_complex_t data[], unsigned bits) { + unsigned size = 1 << bits; + unsigned shift = 32 - bits; + for(unsigned i = 1; i < size - 1; i++) { + unsigned z = rbit(i) >> shift; + if(z > i) { + fft_t + t = data[i].r; data[i].r = data[z].r; data[z].r = t; + t = data[i].i; data[i].i = data[z].i; data[z].i = t; + } + } +} + + +/* == "HIGH"-LEVEL FUNCTIONS ====================================== */ + +// Perform forward FFT (including permutation) +__INLINE +void fft_fft(fft_complex_t *complex, unsigned bits) { +#ifdef FFT_DIT + fft_permutate(complex, bits); +#endif + fft_forward(complex, bits); +#ifdef FFT_DIF + fft_permutate(complex, bits); +#endif +} + +// Perform inverse FFT (including permutation) +__INLINE +void fft_ifft(fft_complex_t *complex, unsigned bits) { +#ifdef FFT_DIT + fft_permutate(complex, bits); +#endif + fft_inverse(complex, bits); +#ifdef FFT_DIF + fft_permutate(complex, bits); +#endif +} + +// Perform forward FFT (including permutation, real output conversion) +__INLINE +void fft_fftr(fft_complex_t *complex, unsigned bits) { + fft_fft(complex, bits); + fft_convert(complex, bits, false, false); +} + +// Perform inverse FFT (including permutation, real input conversion) +__INLINE +void fft_ifftr(fft_complex_t *complex, unsigned bits) { + fft_convert(complex, bits, false, true); + fft_ifft(complex, bits); +} + + +/* == DATA SET CONSTRUCTION ======================================= */ + +// Magnitude and phase => complex FFT bin [index] +// A data set built with this method does not require fft_permutate before DIT IFFT +__INLINE +void fft_phase_magnitude(fft_complex_t complex[], unsigned bits, unsigned index, int32_t mag, uint32_t pha) { +#ifdef FFT_DIT + unsigned n = RBITS(index, bits); +#else//FFT_DIF + unsigned n = index; +#endif + complex[n].r = FFT_M(mag, sine(pha)); + complex[n].i = FFT_M(mag, cosine(pha)); +} + +// Magnitude, phase:0 => complex FFT bin [index] +// A data set built with this method does not require fft_permutate before DIT IFFT +__INLINE +void fft_magnitude(fft_complex_t complex[], unsigned bits, unsigned index, int32_t mag) { +#ifdef FFT_DIT + unsigned n = RBITS(index, bits); +#else//FFT_DIF + unsigned n = index; +#endif + complex[n].r = 0; complex[n].i = mag; +} + +// REAL Symmetric DC offset => complex FFT bin [0] (DC) +// A data set built with this method does not require fft_permutate before DIT IFFT +// A data set built with this method does not require fft_convert before IFFT +__INLINE +void fft_real_dc(fft_complex_t data[], fft_t r, fft_t i) { + data[0].r = r + i; + data[0].i = r - i; +} + +// REAL Symmetric magnitude and phase => complex FFT bins [index], [size-index] +// A data set built with this method does not require fft_permutate before DIT IFFT +// A data set built with this method does not require fft_convert before IFFT +void fft_real_phase_magnitude(fft_complex_t complex[], unsigned bits, unsigned index, int32_t mag_lo, int32_t pha_lo, int32_t mag_hi, int32_t pha_hi) { + unsigned size = 1 << bits; + unsigned shift = SINE_BITS - (bits - 1); +#ifdef FFT_DIT + unsigned n = RBITS(index, bits); + unsigned z = RBITS(size - index, bits); +#else//FFT_DIF + unsigned n = index; + unsigned z = size - index; +#endif + fft_t rsum, rdif, isum, idif, r, i; + fft_t itwiddled, rtwiddled; + r = FFT_M(mag_lo, sine(pha_lo)); + i = FFT_M(mag_hi, sine(pha_hi)); + rsum = r + i; rdif = r - i; + r = FFT_M(mag_lo, cosine(pha_lo)); + i = FFT_M(mag_hi, cosine(pha_hi)); + isum = r + i; idif = r - i; + r = -FFT_QCOS(index, shift); i = -FFT_QSIN(index, shift); + rtwiddled = FFT_MA(r, isum, FFT_M(i, rdif)) << 1; + itwiddled = FFT_MS(r, rdif, FFT_M(i, isum)) << 1; + complex[n].r = rsum + rtwiddled; complex[n].i = itwiddled + idif; + complex[z].r = rsum - rtwiddled; complex[z].i = itwiddled - idif; +} + +// REAL Symmetric magnitude, phase:0 => complex FFT bins [index], [size-index] +// This method works with permutated (bit-reversed) addressing +// A data set built with this method does not require fft_permutate before DIT IFFT +// A data set built with this method does not require fft_convert before IFFT +void fft_real_magnitude(fft_complex_t complex[], unsigned bits, unsigned index, int32_t mag_lo, int32_t mag_hi) { + unsigned shift = SINE_BITS - bits + 1; +#ifdef FFT_DIT + unsigned n = RBITS(index, bits); + unsigned z = RBITS((1 << bits) - index, bits); +#else//FFT_DIF + unsigned n = index; + unsigned z = (1 << bits) - index; +#endif + fft_t isum, idif, r, i; + fft_t itwiddled, rtwiddled; + isum = (mag_lo + mag_hi); idif = mag_lo - mag_hi; + r = FFT_QCOS(index, shift); i = FFT_QSIN(index, shift); + rtwiddled = FFT_M(r, isum) << 1; + itwiddled = FFT_M(i, isum) << 1; + complex[n].r = -rtwiddled; complex[n].i = (idif - itwiddled); + complex[z].r = rtwiddled; complex[z].i = -(idif + itwiddled); +} + +#endif diff --git a/sw/applications/transformer/SYLT-FFT/fpmath.h b/sw/applications/transformer/SYLT-FFT/fpmath.h new file mode 100644 index 00000000..9385d3c0 --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/fpmath.h @@ -0,0 +1,139 @@ +// FIXED POINT MATHS +// D. TAYLOR 2014 + +#ifndef __FPMATH_H__ +#define __FPMATH_H__ + +#include "config.h" +#include "intrinsics.h" +#include "fpmath.h" + +#define SINE_SIZE (1 << SINE_BITS) // Sine table size +#define SINE_FBITS (32 - 2 - SINE_BITS) // Fractional bits +#define SINE_FMASK ((1 << SINE_FBITS) - 1) // Fraction mask + +// Linear/box interpolation (30 bit precision) +// y1 is first point, y2 second +// mu is interpolation point 00000000-FFFFFFFF +// floating-point equivalent return y2 - y1 * mu + y1; +__INLINE +int32_t linear(int32_t y1, int32_t y2, uint32_t mu) { + return smmlar((y2 >> 1) - (y1 >> 1), mu >> 1, y1 >> 2) << 2; +} + +// Cubic interpolation +// y0...y3 need to be externally limited in range to prevent overflow +// y0...y3 are control points, interpolation is performed between y1 and y2 +// mu is interpolation point 00000000-FFFFFFFF +// floating-point equivalent return y1+mu/2*(y2-y0+mu*(2*y0-5*y1+4*y2-y3+mu*(3*(y1-y2)+y3-y0))) +__INLINE +int32_t cubic(int32_t y0, int32_t y1, int32_t y2, int32_t y3, uint32_t mu) { + mu >>= 1; + int32_t a = (3 * (y1 - y2) - y0 + y3); + int32_t b = 2 * y2 + y0 - (5 * y1 + y3) / 2; + int32_t c = (y2 - y0) / 2; + return smmlar(smmlar(smmlar(a, mu, b) << 1, mu, c) << 1, mu, y1); +} + +// Generate first quadrant (0 to PI/2) of sine wave +// Output table is in Q31 format, with 1 limited to 0x7FFFFFFF +void sine_init() { +#if !SINE_USE_TABLE + unsigned int n; +#if SINE_PRINTOUT + printf("// ROM\n"); + printf("#if SINE_BITS != 7\n"); + printf("#error \"sinetable[] size does not match SINE_BITS\"\n"); + printf("#endif\n"); + printf("const int32_t sinetable[] = {"); +#endif + for(n = 0; n <= SINE_SIZE; n++) { + uint64_t v = (sin(((double)n * M_PI) / (double)(SINE_SIZE * 2)) * 2147483648.0); + sinetable[n] = v > 2147483647 ? 2147483647 : v; +#if SINE_PRINTOUT + // Print table + if((n & 7) == 0) printf("\n "); + printf("0x%08x, ", sinetable[n]); +#endif + } +#if SINE_PRINTOUT + printf("// <= space potato!\n}; // <= sad monkey?\n"); +#endif +#endif +} + +// Sin by table lookup with interpolation +// pos = 00000000 to FFFFFFFF, corresponding to 0-2PI(less one) +int32_t sine(uint32_t pos) { + uint32_t fraction = (pos & SINE_FMASK) << (2 + SINE_BITS); + uint32_t index = (pos & 0x40000000) ? (0x40000000 + SINE_FMASK - (pos & 0x3FFFFFFF)) : (pos & 0x3FFFFFFF); + uint32_t indexa = index >> SINE_FBITS; + uint32_t indexb = pos & 0x40000000 ? indexa - 1 : indexa + 1; + int32_t sample = linear(sinetable[indexa], sinetable[indexb], fraction); + return pos & 0x80000000 ? -sample : sample; +} + +// Cos by table lookup with interpolation +// See sine +__INLINE +int32_t cosine(uint32_t pos) { + return sine(pos + 0x40000000); +} + +// Fast sin by table lookup +// Same as sine, but no interpolation +__INLINE +int32_t fastsin(uint32_t pos) { + uint32_t index = (pos & 0x40000000) ? 0x40000000 - (pos & 0x3fffffff) : (pos & 0x3fffffff); + int32_t sample = sinetable[index >> SINE_FBITS]; + return (pos & 0x80000000 ? -sample : sample); +} + +// Fast cos by table lookup +// See fastsin +__INLINE +int32_t fastcos(uint32_t pos) { + return fastsin(pos + 0x40000000); +} + +// Fixed point pow(2, e) +uint64_t fpow2(uint32_t e) { + uint32_t ipart = e >> FPOW2_FBITS; +#ifdef FPOW2_LIMIT + uint32_t fpart = (e >> (FPOW2_FBITS - FPOW2_LIMIT)) << (32 - FPOW2_LIMIT); +#else + uint32_t fpart = e << (32 - FPOW2_FBITS); +#endif + uint64_t final = 0x100000000; + if(fpart) { + uint32_t bit = clz(fpart); + uint32_t fcalc = fpow2table[bit++] >> 1; + fpart <<= bit; + while(fpart) { + uint32_t lzc = clz(fpart); + bit += lzc++; + int32_t fmul = fpow2table[bit++]; + fcalc += smmlar(fcalc, fmul, fmul >> 1); + fpart <<= lzc; + } + final += (uint64_t)fcalc << 1; + } + return final << ipart; +} + +// Convert binary to gray-code +unsigned bin2gray(unsigned bits) { + return (bits >> 1) ^ bits; +} + +// Convert gray-code to binary +unsigned gray2bin(unsigned bits) { + bits ^= bits >> 16; + bits ^= bits >> 8; + bits ^= bits >> 4; + bits ^= bits >> 2; + bits ^= bits >> 1; + return bits; +} + +#endif diff --git a/sw/applications/transformer/SYLT-FFT/intrinsics.h b/sw/applications/transformer/SYLT-FFT/intrinsics.h new file mode 100644 index 00000000..e2614bae --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/intrinsics.h @@ -0,0 +1,153 @@ +// INTRINSICS +// D. TAYLOR 2014 + +#ifndef __INTRINSICS_H__ +#define __INTRINSICS_H__ +#include "config.h" + +// issue warnings when not using full hardware acceleration + +#if defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__)) +#if (__CORTEX_M < 0x03) +#warning "Cortex-M core < M3 detected; hardware acceleration for math operations not supported" +#elif (__CORTEX_M < 0x04) +#warning "Cortex-M core < M4 detected; partial hardware acceleration for math operations supported" +#endif +#endif + +// reverse bits (ARM: RBIT) +__INLINE +uint32_t rbit(uint32_t x) { + uint32_t result; +#if defined(__ARMCC_VERSION) && ((__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300)) + __asm{ rbit result, x } +#elif defined(__GNUC__) && defined(__arm__) && ((__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300)) + __asm("rbit %0, %1":"=r"(result):"r"(x)); +#else + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + result = (x >> 16) | (x << 16); +#endif + return result; +} + +#define RBITS(W, BITS) (rbit(W) >> (32 - (BITS))) + +// count leading zeroes (ARM: CLZ) +__INLINE +uint32_t clz(uint32_t x) { + uint32_t result; +#if defined(__ARMCC_VERSION) && ((__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300)) + __asm{ clz result, x } +#elif defined(__GNUC__) && defined(__arm__) && ((__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300)) + __asm("clz %0, %1":"=r"(result):"r"(x)); +#else + x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; + x -= 0x55555555 & (x >> 1); + x = (0x33333333 & x) + (0x33333333 & (x >> 2)); + result = 32 - ((0x01010101 * (0x0F0F0F0F & (x + (x >> 4)))) >> 24); +#endif + return result; +} + +// 32-bit signed multiply -> 32-bit result, add 32-bit (ARM: SMMLAR) +// floating point equivalent: return c + a * b +__INLINE +int32_t smmlar(int32_t a, int32_t b, int32_t c) { + int32_t result; +#if defined(__ARMCC_VERSION) && (__CORTEX_M >= 0x04U) + __asm{ smmlar result, a, b, c } +#elif defined(__GNUC__) && defined(__arm__) && (__CORTEX_M >= 0x04U) + __asm("smmlar %0, %1, %2, %3":"=r"(result):"r"(a),"r"(b),"r"(c)); +#else + result = c + ((((int64_t)a * b) + 0x80000000) >> 32); +#endif + return result; +} + +// 32-bit signed multiply -> 32-bit result, subtract 32-bit (ARM: SMMLSR) +// floating point equivalent: return c - a * b +__INLINE +int32_t smmlsr(int32_t a, int32_t b, int32_t c) { + int32_t result; +#if defined(__ARMCC_VERSION) && (__CORTEX_M >= 0x04U) + __asm{ smmlsr result, a, b, c } +#elif defined(__GNUC__) && defined(__arm__) && (__CORTEX_M >= 0x04U) + __asm("smmlsr %0, %1, %2, %3":"=r"(result):"r"(a),"r"(b),"r"(c)); +#else + result = c - ((((int64_t)a * b) + 0x80000000) >> 32); +#endif + return result; +} + +// 32-bit signed multiply -> 32-bit result (ARM: SMMULR) +// floating point equivalent: return a * b +__INLINE +int32_t smmulr(int32_t a, int32_t b) { + int32_t result; +#if defined(__ARMCC_VERSION) && (__CORTEX_M >= 0x04U) + __asm{ smmulr result, a, b } +#elif defined(__GNUC__) && defined(__arm__) && (__CORTEX_M >= 0x04U) + __asm("smmulr %0, %1, %2":"=r"(result):"r"(a),"r"(b)); +#else + result = ((((int64_t)a * b) + 0x80000000) >> 32); +#endif + return result; +} + +// saturating add (ARM: qadd) +// floating point equivalent: return max(min(a + b, 1), -1) +__INLINE +int32_t qadd(int32_t a, int32_t b) { + uint32_t result; +#if defined(__ARMCC_VERSION) + __asm{ qadd result, a, b } +#elif defined(__GNUC__) + __asm("qadd %0, %1, %2":"=r"(result):"r"(a),"r"(b)); +#else + int64_t c = (int64_t)a + b; + if(c > 2147483647) c = 2147483647; + if(c < -2147483648) c = -2147483648; + result = c; +#endif + return result; +} + +// saturating subtract (ARM: qsub) +// floating point equivalent: return max(min(a - b, 1), -1) +__INLINE +int32_t qsub(int32_t a, int32_t b) { + uint32_t result; +#if defined(__ARMCC_VERSION) + __asm{ qsub result, a, b } +#elif defined(__GNUC__) && defined(__arm__) + __asm("qsub %0, %1, %2":"=r"(result):"r"(a),"r"(b)); +#else + int64_t c = (int64_t)a - b; + if(c > 2147483647) c = 2147483647; + if(c < -2147483648) c = -2147483648; + result = c; +#endif + return result; +} + +// 32-bit arithmetic shift right with rounding (ARM: ASRS + ADC) +// floating point equivalent: return v / pow(2, s) +__INLINE +int32_t asrr(int32_t v, int32_t s) { + int32_t result; +#if defined(__ARMCC_VERSION) + __asm{ asrs result, v, s }; + __asm{ adc result, result }; +#elif defined(__GNUC__) && defined(__arm__) + __asm("asrs %0, %1, %2":"=r"(result):"r"(v),"r"(s):"cc"); + __asm("adc %0, %1, #0":"=r"(result):"r"(result)); +#else + result = (v + (1 << (s - 1))) >> s; +#endif + return result; +} + +#endif diff --git a/sw/applications/transformer/SYLT-FFT/main.c b/sw/applications/transformer/SYLT-FFT/main.c new file mode 100644 index 00000000..cf59fcad --- /dev/null +++ b/sw/applications/transformer/SYLT-FFT/main.c @@ -0,0 +1,74 @@ +// BENCHMARKING FOR FRDM-K20D50M +// D. TAYLOR 2014 + +// * Do not build with operating system +// * Uses FTM0 as core clock cycle counter +// * Requires C99 standard + +#define BENCH_RUNS 100 // Not really necessary without OS + +#include + +#include +#include + +#include "config.h" +#include "intrinsics.h" +#include "fpmath.h" +#include "fft.h" + +static volatile unsigned count_hi; // FTM0 high counter +static volatile unsigned count; // Performance counter + +// FFT data structure +fft_complex_t complex[256]; + +// This function contains code to benchmark +static void benchmark(void) { + fft_inverse(complex, 8); +} + +// Initialize FTM0 +static void bench_init(void) { + SIM->SCGC6 |= SIM_SCGC6_FTM0_MASK; + FTM0->MOD = 0xFFFF; + NVIC_EnableIRQ(FTM0_IRQn); +} + +// Resets cycle counts, begins benchmarking +__INLINE +static void bench_begin(void) { + FTM0->SC = 0; + count_hi = 0; + FTM0->CNT = 0; + FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_TOIE_MASK; +} + +// Ends benchmarking, returns cycle count +__INLINE +static unsigned bench_end(void) { + FTM0->SC = 0; + return (FTM0->CNT | (count_hi << 16)) - 2; +} + +// FTM0 overflow counter +void FTM0_IRQHandler(void) { + FTM0->SC &= ~FTM_SC_TOF_MASK; + count_hi++; +} + +int main() { + bench_init(); + while(1) { + // Perform benchmark + unsigned ack = 0; + for(unsigned n = 0; n < BENCH_RUNS; n++) { + bench_begin(); + benchmark(); + ack += bench_end(); + } + count = ack / BENCH_RUNS; + // Count is reported here - use a breakpoint or add communication code + count = count; + } +} From 052c46b04479309d9de17c862d248ee5fa3c8fd9 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:19:32 +0200 Subject: [PATCH 13/27] reduced transformer example --- sw/applications/trans_versasense/SYLT-FFT | 1 + sw/applications/trans_versasense/addNormC.c | 71 + sw/applications/trans_versasense/addNormC.h | 26 + .../trans_versasense/cgra_bitstream.h | 12 + .../trans_versasense/data_cpp/array_output.h | 4803 +++++++++++++++++ .../trans_versasense/data_cpp/data.cpp | 104 + .../trans_versasense/data_cpp/signal.cpp | 5 + .../trans_versasense/data_cpp/signal_fft.cpp | 5 + .../trans_versasense/dense_layerC.c | 73 + .../trans_versasense/dense_layerC.h | 31 + sw/applications/trans_versasense/main.c | 143 + sw/applications/trans_versasense/main.h | 17 + sw/applications/trans_versasense/matMulC.c | 22 + sw/applications/trans_versasense/matMulC.h | 21 + .../trans_versasense/multiply_cgra.c | 178 + .../trans_versasense/multiply_cgra.h | 6 + sw/applications/trans_versasense/param.h | 26 + .../trans_versasense/performance.c | 62 + .../trans_versasense/performance.h | 64 + .../trans_versasense/selfattentionC.c | 99 + .../trans_versasense/selfattentionC.h | 35 + sw/applications/trans_versasense/softmaxC.c | 38 + sw/applications/trans_versasense/softmaxC.h | 17 + sw/applications/trans_versasense/stftVec.h | 3 + .../trans_versasense/tokenPosEmbeddingC.c | 33 + .../trans_versasense/tokenPosEmbeddingC.h | 24 + .../trans_versasense/transformerBlockC.c | 116 + .../trans_versasense/transformerBlockC.h | 48 + sw/applications/trans_versasense/transposeC.c | 31 + sw/applications/trans_versasense/transposeC.h | 22 + .../trans_versasense/weightsAndBiasesC.c | 181 + .../trans_versasense/weightsAndBiasesC.h | 15 + 32 files changed, 6332 insertions(+) create mode 160000 sw/applications/trans_versasense/SYLT-FFT create mode 100644 sw/applications/trans_versasense/addNormC.c create mode 100644 sw/applications/trans_versasense/addNormC.h create mode 100644 sw/applications/trans_versasense/cgra_bitstream.h create mode 100644 sw/applications/trans_versasense/data_cpp/array_output.h create mode 100644 sw/applications/trans_versasense/data_cpp/data.cpp create mode 100644 sw/applications/trans_versasense/data_cpp/signal.cpp create mode 100644 sw/applications/trans_versasense/data_cpp/signal_fft.cpp create mode 100644 sw/applications/trans_versasense/dense_layerC.c create mode 100644 sw/applications/trans_versasense/dense_layerC.h create mode 100644 sw/applications/trans_versasense/main.c create mode 100644 sw/applications/trans_versasense/main.h create mode 100644 sw/applications/trans_versasense/matMulC.c create mode 100644 sw/applications/trans_versasense/matMulC.h create mode 100644 sw/applications/trans_versasense/multiply_cgra.c create mode 100644 sw/applications/trans_versasense/multiply_cgra.h create mode 100644 sw/applications/trans_versasense/param.h create mode 100644 sw/applications/trans_versasense/performance.c create mode 100644 sw/applications/trans_versasense/performance.h create mode 100644 sw/applications/trans_versasense/selfattentionC.c create mode 100644 sw/applications/trans_versasense/selfattentionC.h create mode 100644 sw/applications/trans_versasense/softmaxC.c create mode 100644 sw/applications/trans_versasense/softmaxC.h create mode 100644 sw/applications/trans_versasense/stftVec.h create mode 100644 sw/applications/trans_versasense/tokenPosEmbeddingC.c create mode 100644 sw/applications/trans_versasense/tokenPosEmbeddingC.h create mode 100644 sw/applications/trans_versasense/transformerBlockC.c create mode 100644 sw/applications/trans_versasense/transformerBlockC.h create mode 100644 sw/applications/trans_versasense/transposeC.c create mode 100644 sw/applications/trans_versasense/transposeC.h create mode 100644 sw/applications/trans_versasense/weightsAndBiasesC.c create mode 100644 sw/applications/trans_versasense/weightsAndBiasesC.h diff --git a/sw/applications/trans_versasense/SYLT-FFT b/sw/applications/trans_versasense/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/trans_versasense/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b diff --git a/sw/applications/trans_versasense/addNormC.c b/sw/applications/trans_versasense/addNormC.c new file mode 100644 index 00000000..31828e28 --- /dev/null +++ b/sw/applications/trans_versasense/addNormC.c @@ -0,0 +1,71 @@ +// +// Created by alireza on 10/6/23. +// + +#include "addNormC.h" + + + +// Function implementations +AddNormalize createAddNormalize(int seq_len, int input_dim, quant_bit_width *weight, quant_bit_width *bias) { + AddNormalize addNorm; + addNorm.seq_len_ = seq_len; + addNorm.input_dim_ = input_dim; + addNorm.weight_ = weight; + addNorm.bias_ = bias; + // Initialize other fields as needed + return addNorm; +} + + + + +void normalize(AddNormalize *addNorm, quant_bit_width *input, quant_bit_width *input_normalized) { + for (int i = 0; i < addNorm->seq_len_; i++) { + quant_bit_width *input_ptr = input + i * (addNorm->input_dim_); + quant_bit_width *input_normalized_ptr = input_normalized + i * (addNorm->input_dim_); + + int sum = 0; + for (int j = 0; j < addNorm->input_dim_; j++) { + sum += *input_ptr; + input_ptr++; + } + + input_ptr = input + i * (addNorm->input_dim_); + quant_bit_width mean = (quant_bit_width)((float)sum / (float)addNorm->input_dim_); + + int64_t variance = 0; + for (int j = 0; j < addNorm->input_dim_; j++) { + variance += MUL_HQ((*input_ptr - mean), (*input_ptr - mean)); + input_ptr++; + } + + variance = SHIFT(variance); + float variance_float = (float)variance / (float)(addNorm->input_dim_); + variance_float = variance_float / (float)(1 << NUM_FRACTION_BITS); + float sd = sqrtf(variance_float); + float sd_inv = (float)(1 / (sd + 0.00001)); // prevent zero divide! + quant_bit_width sd_inv_int = (quant_bit_width)(sd_inv * (1 << NUM_FRACTION_BITS)); + + input_ptr = input + i * (addNorm->input_dim_); + input_normalized_ptr = input_normalized + i * (addNorm->input_dim_); + + for (int j = 0; j < addNorm->input_dim_; j++) { + *input_normalized_ptr = (quant_bit_width)MUL((*input_ptr - mean), sd_inv_int); + *input_normalized_ptr = (quant_bit_width)(MUL((*input_normalized_ptr), addNorm->weight_[j]) + addNorm->bias_[j]); + input_ptr++; + input_normalized_ptr++; + } + } +} + +void add(quant_bit_width *input, quant_bit_width *to_be_added, int seq_len, int input_dim) { + int32_t sum; + for (int i = 0; i < seq_len * input_dim; i++) { + sum = input[i] + to_be_added[i]; + if ((quant_bit_width)sum != sum) // In case of overflow in 16 bits + input[i] = (sum > 0) ? INT16_MAX : INT16_MIN; + else + input[i] = (quant_bit_width)sum; + } +} diff --git a/sw/applications/trans_versasense/addNormC.h b/sw/applications/trans_versasense/addNormC.h new file mode 100644 index 00000000..c2132867 --- /dev/null +++ b/sw/applications/trans_versasense/addNormC.h @@ -0,0 +1,26 @@ +// +// Created by alireza on 10/5/23. +// + +#ifndef FVLLMONTITRANSFORMER_ADDNORMC_H +#define FVLLMONTITRANSFORMER_ADDNORMC_H + + +#include +#include +#include "math.h" +#include "param.h" + +typedef struct { + int seq_len_; + int input_dim_; + quant_bit_width *weight_; + quant_bit_width *bias_; +} AddNormalize; + + +AddNormalize createAddNormalize(int seq_len, int input_dim, quant_bit_width *weight, quant_bit_width *bias); +void normalize(AddNormalize *addNorm, quant_bit_width *input, quant_bit_width *input_normalized); +void add(quant_bit_width *input, quant_bit_width *to_be_added, int seq_len, int input_dim); + +#endif //FVLLMONTITRANSFORMER_ADDNORMC_H diff --git a/sw/applications/trans_versasense/cgra_bitstream.h b/sw/applications/trans_versasense/cgra_bitstream.h new file mode 100644 index 00000000..014ee6b8 --- /dev/null +++ b/sw/applications/trans_versasense/cgra_bitstream.h @@ -0,0 +1,12 @@ +#ifndef _CGRA_BITSTREAM_H_ +#define _CGRA_BITSTREAM_H_ + +#include + +#include "cgra.h" + + +static uint32_t cgra_kmem_bitstream[CGRA_KMEM_SIZE] = { 0x0, 0xf01c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; +const uint32_t cgra_imem_bitstream[CGRA_IMEM_SIZE] = { 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4081ff4, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x850d0000, 0x0, 0x0, 0xc80000, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0x0, 0x0, 0x850d0000, 0x0, 0xab0000, 0xd0000, 0x8780001c, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a0d0001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xab0000, 0xd0000, 0xd0000, 0x87800018, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa5081ffc, 0x91c00000, 0x7a180004, 0x0, 0x5a080010, 0x8a0d0001, 0x7a181ff0, 0x1a181ffd, 0xd0000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x5080000, 0x0, 0x820d0000, 0x0, 0x820d0000, 0x2080000, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x2080000, 0x0, 0x0, 0x0, 0x5080000, 0x820d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x820d0000, 0x0, 0x3080000, 0x0, 0x820d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa5081ffc, 0x0, 0x91c00000, 0x0, 0x43180000, 0x0, 0x830d0000, 0x0, 0x830d0000, 0x4080000, 0x840d0000, 0x0, 0xab0000, 0xd0000, 0x0, 0x0, 0xf0000, 0x87800010, 0x8a0d0001, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x7a181ffc, 0x0, 0x0, 0xd0000, 0x7a180010, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x850d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x830d0000, 0x0, 0x2080000, 0x0, 0x830d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x0, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x3a080010, 0x0, 0x0, 0x0, 0x4080000, 0x830d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x4090000, 0x0, 0x0, 0x2080000, 0x0, 0x61180000, 0x910f0000, 0x0, 0x800005, 0x8080000, 0x8a0d0010, 0x8a081ff0, 0x91c00000, 0x0, 0x0, 0x0, 0x800003, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x8b90000, 0x0, 0x0, 0x0, 0x0, 0x2080000, 0x61180000, 0x910f0000, 0x8a0d0004, 0x0, 0x0, 0xa508000c, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x840d0000, 0x0, 0x800002, 0x0, 0xab0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x5090000, 0x0, 0x0, 0x3080000, 0x0, 0x61180000, 0x910f0000, 0x7a180010, 0x0, 0x0, 0x0, 0xa4080004, 0x91c00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad0000, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x5090000, 0x8b80000, 0x0, 0x0, 0x61180000, 0x910f0000, 0x0, 0x820d0000, 0x0, 0xa4080004, 0x0, 0x91c00000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x840d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + +#endif // _CGRA_BITSTREAM_H_ diff --git a/sw/applications/trans_versasense/data_cpp/array_output.h b/sw/applications/trans_versasense/data_cpp/array_output.h new file mode 100644 index 00000000..6e5f8182 --- /dev/null +++ b/sw/applications/trans_versasense/data_cpp/array_output.h @@ -0,0 +1,4803 @@ +int32_t prototypes[32] ={-1394, -5770, -6778, 762, 4001, -653, -5906, -20, 1220, 3795, -73, -3028, 635, -448, 7677, -6204, 5745, 3112, 1206, -1120, -3618, 1076, -649, 943, -3896, 2462, 4658, 2494, 3996, 1220, -1144, -1013, }; +int32_t STFT_rand_out[5008] = { + -12926, + -13872, + -27384, + -9514, + 16213, + -2431, + -29203, + 22796, + -13520, + -24530, + -1523, + -22165, + 6477, + -23668, + -32732, + 6528, + -20306, + -12571, + -5238, + -32626, + -32234, + -24604, + -25164, + -23058, + -284, + 22733, + 13211, + 30060, + 18770, + 14117, + -24215, + -20438, + -23294, + -23461, + -24059, + -30987, + 23538, + -18331, + -26582, + 26174, + 20, + -17686, + 14638, + 7688, + -28912, + -31479, + -4877, + -9303, + -25054, + 12141, + -30938, + -524, + 15610, + -20836, + -7851, + 14700, + 9746, + 31669, + -7502, + 1309, + 29525, + 3044, + -18198, + -15137, + -19411, + -14748, + -360, + -14208, + 956, + -1978, + -29616, + 29686, + -18651, + 6835, + 22417, + 11981, + -30352, + -4294, + 15146, + 15946, + -8216, + -2676, + -25568, + -22291, + 24059, + 28953, + -1211, + 20453, + -15372, + 15895, + -13367, + 8986, + -4597, + -24977, + 3325, + -2151, + 8144, + -22983, + -10167, + 24625, + -14559, + -9138, + 26672, + -5194, + 17718, + 24553, + -12199, + -26118, + -27912, + -15155, + -28038, + 4660, + -31609, + -14976, + 29967, + 26386, + 1921, + -5581, + -32130, + 28884, + 31773, + -30010, + -13952, + 12436, + 7435, + 31562, + -6612, + -20653, + 1799, + 29773, + -17425, + 7086, + 21604, + -15587, + 7938, + -12378, + 15944, + -28828, + -29045, + 12192, + 30536, + 27413, + -3130, + 15968, + 24829, + -19012, + -15131, + 30818, + -12319, + 20688, + 2459, + 11630, + 10578, + -13135, + 16621, + 23622, + -27873, + -128, + -8153, + -7040, + -3606, + 17172, + 16609, + 19012, + -20002, + 29911, + -23373, + -7789, + 24490, + 29616, + -19123, + -553, + 29523, + -27481, + 18250, + 28582, + 25602, + 29650, + 711, + 28687, + 25094, + -9118, + 21846, + 4730, + -12093, + 23850, + -13120, + 17772, + -18230, + -6716, + 14165, + 5818, + -11610, + -7149, + -29858, + -21764, + -5007, + 22148, + -15056, + -12084, + 29091, + -14694, + -20469, + -9607, + 31452, + 7223, + 27291, + -28384, + 10091, + -22522, + -32301, + -3436, + 2894, + -11292, + 21662, + 14254, + -24221, + -1471, + 11612, + 31030, + -32011, + -15252, + 10322, + 19696, + -16379, + 4097, + 25235, + -4789, + 18162, + 8046, + 9464, + -20778, + -16502, + 8426, + 9249, + -28464, + 7466, + -14803, + 4080, + -31337, + 27890, + 1109, + -18359, + 391, + 15794, + 15523, + -6939, + 9040, + 29810, + -25918, + -8188, + -32473, + -15855, + -15203, + 12229, + 12970, + 29248, + 15769, + -11288, + 3980, + 4350, + 10360, + 26227, + -16574, + -24206, + -6505, + 22774, + -7700, + -23171, + -11802, + 26384, + 829, + 14673, + -6318, + 29972, + 14680, + -22102, + -7816, + -13898, + 5003, + -4263, + 189, + -19916, + -30573, + -8535, + 14572, + -9936, + -26676, + 3818, + 19551, + 30529, + -21036, + 8479, + -8020, + -20934, + -25849, + 14758, + -17965, + -629, + -22446, + 1018, + -20110, + 16369, + 20661, + -5079, + 7605, + 15698, + 10295, + -17857, + 28680, + 30879, + -28659, + 16006, + 22443, + -12548, + 1079, + -1265, + -28915, + -12687, + 2561, + -13443, + 23795, + -24009, + 26699, + 19807, + -3974, + 3819, + -30149, + -13138, + 25042, + 12139, + -18304, + 26972, + -1278, + 4375, + 1559, + 21023, + 3144, + -19398, + -26570, + -30278, + 32403, + -32387, + -1201, + 31541, + 17157, + 22523, + 18062, + 21859, + 20875, + -28203, + 935, + -3875, + 13172, + -32117, + 32384, + -18546, + 17175, + 11073, + 14237, + -4578, + 11500, + 20778, + -23597, + -13751, + -9037, + -840, + -8845, + 2111, + -17705, + 4320, + 12398, + 7115, + -10940, + 12479, + -11251, + -8914, + 31198, + -31652, + 32222, + -21006, + -25725, + -15830, + 24105, + 15855, + -3554, + 9600, + 26493, + -28575, + -1343, + -16665, + -10363, + -17524, + 19543, + 7643, + -18020, + 103, + -5280, + -13700, + 21561, + 27066, + -8114, + -31694, + -1871, + -17244, + 18003, + -17684, + -14058, + 17243, + -32338, + -5711, + 25414, + -29426, + -17471, + 22764, + -31461, + -28346, + 18427, + 29733, + 21327, + 7675, + -16185, + -21765, + 23937, + 4319, + 30560, + -24889, + 22803, + 28266, + 5135, + -7171, + 12306, + 7275, + -11087, + -13001, + -25855, + -17021, + 19691, + -32077, + 12594, + -16956, + 13447, + -26358, + -28094, + 21711, + -2822, + 13881, + -2024, + 944, + -1531, + 7536, + -11819, + 17016, + 1231, + -19096, + 31141, + -8695, + -12215, + 18540, + 27486, + -13423, + 18368, + 31866, + -7847, + -27840, + -20034, + 17794, + -30598, + 5252, + 13117, + 8254, + 20551, + 22681, + -17080, + -23734, + -1381, + 22104, + -24321, + 23290, + 14593, + 30678, + 8077, + 5683, + 30824, + -26447, + -28041, + -7579, + 5396, + -25382, + -30830, + 16697, + -5651, + -5669, + 25066, + 7923, + -8602, + -7568, + 1428, + 2086, + 9646, + 9921, + 10236, + -32042, + -30188, + -26716, + -10819, + 29027, + 2685, + -17932, + 1562, + -23341, + 23106, + 25932, + -24468, + -31981, + -8134, + -7668, + -6548, + -26611, + -8569, + 13345, + -20035, + -13303, + -14140, + 15907, + -16570, + -27988, + 31993, + -2213, + 11074, + -2180, + 9844, + 27811, + -20876, + -10509, + 24415, + -19322, + -8885, + -15411, + 29585, + -6993, + -21218, + -22845, + 5612, + 27716, + 8629, + -25219, + 10020, + -14034, + -21978, + -22960, + -14756, + -1675, + -11142, + -22732, + -26001, + 2092, + -1875, + 12030, + 9584, + -22989, + -4438, + -8482, + 30341, + -26973, + -8167, + -1178, + 12006, + 11545, + 13723, + -10590, + -5866, + -3215, + 12424, + -3375, + 18216, + -16570, + 16557, + -20582, + 15267, + 15055, + 18366, + 25221, + -23012, + -2653, + 7591, + -28861, + -31688, + 20146, + -22097, + -12879, + -5398, + -1418, + 14383, + -4150, + 23361, + -1390, + 3437, + 32363, + 15952, + -1668, + -19674, + 3769, + -32241, + 28821, + 13149, + -20898, + -1144, + -2525, + -24219, + 5802, + -17669, + 8417, + 26592, + -32499, + 17422, + -16415, + -23919, + 25813, + -28040, + -22601, + 1468, + 14163, + -22315, + -19399, + 9767, + 4165, + -19977, + 20448, + -22779, + 27858, + -1766, + 190, + -29823, + -16505, + -312, + 17984, + -9076, + -5499, + 29803, + 15855, + 6888, + -8312, + 3644, + 11457, + 4317, + -17444, + 3618, + -16483, + -8324, + -6687, + 8008, + -3434, + -23048, + 27919, + 2579, + -29502, + -20626, + 21824, + 20815, + -1169, + -1207, + -22279, + 18567, + -15192, + -23546, + 9365, + 15236, + -22584, + 24237, + -6775, + -1604, + -29255, + 8637, + -30992, + -10225, + 2020, + 20887, + 19804, + -28826, + -30072, + 28908, + -4411, + 32426, + 7164, + 5822, + -1725, + 20672, + 16917, + -6359, + 3500, + -13522, + -8914, + -6762, + 20743, + -30579, + -20477, + -20467, + 11558, + -6449, + -20306, + -21134, + 15487, + -15471, + -24053, + -29166, + -1315, + 17110, + -15244, + 22264, + -13565, + -26278, + -16028, + -26056, + -6350, + -12235, + 21483, + -23531, + 19358, + 7130, + -32059, + 23141, + -24415, + 19150, + -15109, + -17892, + -6297, + -28771, + 16209, + -4271, + -26537, + -16272, + 11591, + -14254, + -32254, + 15310, + 823, + 7398, + -24978, + 14571, + -29863, + -24431, + -4741, + -22409, + 14211, + -15800, + -25283, + 18678, + 21516, + 1306, + 21711, + 6212, + 22652, + 3211, + 20137, + 3614, + 4884, + -8760, + 12156, + 8736, + -23901, + -7654, + 29454, + -28701, + 1372, + -30274, + 9245, + -4131, + 12660, + 24430, + 11885, + -3583, + -31465, + -19075, + -26439, + -27444, + 7611, + 25711, + 28562, + -10350, + -25209, + -44, + -246, + 23005, + -11649, + 15978, + 10954, + -32007, + 31528, + 9957, + -8472, + -2969, + 29444, + 18342, + 10286, + 15607, + 11175, + 3868, + -873, + 9145, + 27836, + -19491, + -3923, + 20283, + -15474, + 4602, + -10544, + 13227, + -18799, + -3933, + 8526, + -4283, + 20362, + 7916, + 19902, + -20909, + -27935, + -16588, + -10018, + -8697, + 14099, + 20353, + 8114, + -4313, + -4726, + -31223, + 5311, + -17836, + 3798, + -20855, + -22384, + 3853, + 31386, + -18671, + -20161, + -20365, + 7828, + 6194, + -17876, + -3789, + -12482, + 26049, + 30756, + 1624, + -23607, + -67, + 8234, + 9945, + 21991, + 16088, + -10949, + -12993, + 27470, + 10589, + -12914, + -20814, + -31527, + 12612, + -22618, + 30076, + 7623, + -1373, + 14940, + -15277, + 6239, + -5248, + 28330, + -5719, + 12498, + 20128, + 5951, + -27017, + -13972, + 14154, + -17057, + 27704, + 10260, + -21510, + 25282, + -19133, + 12855, + 4603, + -2540, + -23034, + -3444, + 6267, + -2050, + 20400, + 12632, + 20652, + -7784, + 28608, + -4574, + -15647, + -20918, + 8063, + 1380, + -22462, + -19797, + -16678, + -25455, + 13116, + -4254, + 13772, + -14514, + -21073, + 32215, + -21643, + 2234, + -14166, + 5989, + 25081, + 18193, + -8935, + -26880, + -21512, + 14120, + 26288, + 21949, + 5976, + 18263, + -19562, + -28544, + -25557, + -16054, + 19987, + -28919, + -23450, + -13752, + -142, + 18948, + 8016, + 17683, + 26106, + 7900, + 17129, + -8502, + 22918, + -222, + 25286, + -31723, + 29414, + 8981, + -5933, + -14804, + 27957, + -6932, + 30146, + 8780, + 29280, + -23551, + -19465, + 29136, + 9737, + 9423, + -22144, + 16994, + -19030, + -21959, + -20516, + 31318, + -15165, + -1926, + -4519, + -9911, + -27268, + -23693, + -30088, + -15882, + -17362, + -13610, + -21459, + 11450, + -20001, + 806, + 27803, + -1592, + -1921, + 30491, + -9089, + 13199, + 3121, + -12552, + -19748, + 5034, + 26832, + -7364, + 24822, + -1228, + 29969, + -17341, + -13771, + 15422, + -23654, + 30519, + -19522, + -7411, + -32217, + -7186, + -8460, + 24164, + -24242, + -15575, + -8817, + -16770, + -18115, + 12774, + 7283, + 11895, + 26604, + 13813, + 24503, + 4648, + -23794, + -23563, + 1540, + 14755, + -3952, + 11669, + -28719, + -25955, + -11327, + -15954, + 28998, + 9472, + -2640, + 13752, + 6110, + -32635, + 3994, + 1154, + 1062, + 19389, + -18507, + -18595, + -24942, + 25435, + -16418, + 12937, + 4484, + -9292, + 1542, + 25323, + 23974, + -851, + -13385, + 17634, + 3767, + -29321, + -23743, + 12892, + -11911, + -28602, + -15306, + 8265, + 25090, + -12893, + -11284, + 6771, + 19534, + -27508, + -13654, + 26431, + -14797, + -26522, + 25373, + -25186, + 26339, + -29076, + -21156, + -7491, + 662, + 14570, + 4017, + 4956, + 5625, + -2291, + 20084, + -6322, + 4178, + -1086, + 2845, + 11984, + 29728, + 28445, + -6334, + -22894, + 11882, + -31932, + 14479, + -8273, + -22357, + 16418, + 9629, + 14494, + -5474, + 2004, + -28421, + -7633, + -32593, + 14649, + -27248, + -25416, + 31207, + -10867, + 17056, + 9328, + -11393, + -15548, + 14491, + 7193, + 8976, + 32698, + -10663, + 15576, + 13468, + -7233, + 32191, + -24578, + -29265, + 13724, + -7798, + -21982, + 29458, + -16695, + -5112, + 30116, + -18229, + 32256, + -31105, + 10366, + 17352, + -19409, + -22627, + 26489, + -3397, + -13120, + 5892, + -12133, + -20494, + -17438, + -12904, + 20632, + 4620, + -3188, + 13035, + 9271, + -20508, + -15582, + 30194, + -3896, + -5875, + 17087, + -4642, + 2596, + -30774, + -28169, + -12836, + -29601, + -31933, + 7529, + 31727, + 23804, + -18745, + -25360, + -31984, + -20007, + 18958, + 25051, + -22946, + 13954, + -3433, + 5338, + -13253, + 9474, + -31657, + -21383, + -16332, + 3791, + -25995, + -26720, + 31381, + -2767, + -5544, + -18210, + 9802, + 2893, + 16027, + -25458, + 2588, + -30748, + 31841, + 31772, + -947, + 24253, + -16747, + -27878, + -11711, + -11232, + -30461, + -19297, + 7754, + -3692, + -28623, + -6470, + 25003, + -3018, + -2635, + 22110, + -21204, + 28172, + 24245, + -6436, + 5789, + 5033, + 18757, + 32734, + -6412, + 6661, + -26348, + 23245, + 19742, + 12484, + -29770, + 13231, + -19778, + 32134, + 30432, + 1711, + -1405, + -25460, + 20952, + -14839, + 14822, + 15058, + 387, + -8587, + 24075, + -26810, + 6238, + 3087, + 13858, + -8076, + -8035, + 28295, + -16319, + 32422, + -30336, + 29680, + 31549, + -3440, + -4836, + -24867, + -32580, + -16642, + -452, + -20522, + -11479, + 30274, + 25331, + -26794, + -12126, + 26384, + 4575, + -19603, + 27754, + 10030, + 11025, + 22409, + -20910, + -31261, + 6739, + 28485, + -31870, + 8008, + -32301, + 12501, + -21350, + 4827, + 8191, + 19014, + -5042, + 30378, + 15269, + -19243, + -7606, + 17847, + 4758, + -28221, + 24883, + -935, + 16814, + 19882, + -20138, + 6773, + -3465, + 15568, + 28970, + 27063, + -16146, + -4845, + -31466, + -23032, + 19539, + -19938, + 15081, + -19168, + -1772, + -20222, + 30477, + -15124, + 31138, + 29244, + -23799, + -1787, + -2402, + 2557, + 18066, + 21665, + 273, + 31356, + 24961, + -46, + -12004, + 22075, + -8247, + -22658, + 3319, + -20544, + -4627, + 21400, + -22468, + -4218, + -4614, + 32165, + 25085, + 24403, + 22056, + -5335, + 12221, + 4260, + -417, + 13161, + -11078, + -17987, + 30601, + 21746, + -3520, + 26524, + 29752, + -27132, + 5990, + 32151, + -28731, + -15158, + -12955, + -7175, + 12408, + -25179, + 13039, + 30575, + 6485, + 10091, + 4122, + 16561, + 15636, + 31879, + 20431, + 23641, + 2404, + -6978, + 1578, + 9882, + 15805, + -7268, + -8295, + 24751, + -16216, + -29265, + 6953, + -21638, + -760, + 15418, + 4705, + 10795, + 8484, + 9889, + -6534, + -26313, + 27547, + 23684, + 3051, + 29529, + -27271, + -14230, + 19598, + 16194, + 24811, + 9440, + 25198, + -13487, + -14366, + -14562, + -32019, + -20376, + 6307, + 31016, + -5684, + -12805, + 6899, + -32462, + -30377, + 6821, + -17468, + -15733, + -16858, + -9126, + 3805, + -8481, + -9922, + -117, + 19734, + -16565, + 13779, + -6598, + -22387, + -24676, + -6234, + 20923, + -31234, + -16711, + -24038, + -1650, + 25237, + -26163, + 14190, + -31528, + 22845, + -133, + -11481, + 1716, + -18717, + 28610, + 27821, + -15811, + 5921, + -26800, + -20475, + 8153, + 31161, + -15123, + 21737, + -17815, + 14942, + -8443, + -21714, + -19606, + -8758, + -2079, + 26819, + -16295, + 17875, + 3373, + -30090, + -20194, + -12153, + -6294, + -11457, + 3804, + -18013, + 26677, + -20561, + -20336, + -8213, + -12333, + -15033, + -20595, + -31189, + 1283, + 19090, + 12396, + -29655, + -16352, + -3835, + -16440, + 8393, + -16612, + 1450, + -7001, + -9612, + 20154, + 17629, + -21591, + 17749, + -21899, + 21434, + 20021, + 29224, + -23647, + 185, + -191, + -16313, + 28093, + 17988, + -28836, + -3361, + -1386, + 28917, + 18232, + 16934, + 30349, + -6187, + -21134, + -7227, + 4033, + 14959, + -22372, + 27307, + 15990, + 19888, + -30699, + 17069, + 5906, + -4745, + 22618, + 14868, + -5606, + -1017, + 5562, + -27631, + 2481, + 5119, + 16043, + -27820, + -6079, + -5943, + 26107, + 25053, + 30820, + -759, + -16771, + -19788, + 31293, + -7162, + -27354, + -13649, + 155, + -17202, + -15240, + -1641, + -21481, + -12221, + -30597, + -20401, + -29140, + -19725, + -28582, + -25561, + -29107, + -2794, + -11570, + -30295, + -25985, + -7807, + 13084, + -15407, + 13442, + 202, + -2920, + 27874, + -5452, + 32741, + -30999, + 20572, + -24423, + -2415, + -20483, + -6413, + 876, + 11308, + -8414, + 15965, + -13322, + 5015, + 4706, + 18947, + 29163, + 11125, + -20537, + -4709, + -24051, + 9000, + 17059, + -1815, + -31878, + 27531, + 17528, + -27836, + -7625, + 7321, + -21740, + -5938, + -25584, + -5971, + -32148, + -1936, + 22922, + -12822, + 16481, + -6077, + -2273, + 22957, + 28305, + -24327, + -20094, + -4520, + 14459, + 972, + 5493, + 18475, + -13063, + 21889, + -679, + 1106, + 22522, + -2734, + -1198, + -2633, + 1317, + -4737, + -9640, + 13005, + 7024, + -17304, + -26394, + 25019, + 5444, + 3160, + -4999, + 6061, + -498, + -4481, + 1786, + -29772, + 32393, + -5596, + 25671, + 14186, + 2319, + 26050, + -6425, + -23896, + -4901, + -27879, + 32547, + -19513, + 2201, + 16490, + -25466, + 6285, + 994, + -29623, + 1833, + 11296, + -13319, + -20454, + 30177, + 15710, + -32632, + 25127, + 30476, + 20218, + 9461, + -29997, + -16963, + -23392, + -29425, + 18800, + 11219, + 26983, + -31389, + 4104, + 24180, + -29356, + -2413, + 12084, + -637, + -1825, + 14935, + -19850, + 21759, + 22121, + 31784, + 5356, + 6279, + -20646, + 28671, + 18718, + 22659, + -9645, + -22867, + -27881, + -21000, + -22657, + 12444, + 6057, + -18890, + -14043, + 31001, + -29905, + 17887, + -10259, + -12294, + -24960, + -1395, + -1157, + -8299, + 18921, + 3132, + 27654, + 21021, + 32136, + 2292, + 15440, + -11878, + -24477, + 23384, + 11933, + 17924, + -11417, + -8881, + -7822, + -5662, + 1593, + 16171, + 28351, + 2099, + 28841, + 24173, + 9810, + 9446, + 30137, + -20304, + 28473, + 17544, + -10134, + -3219, + 31770, + 31700, + 19544, + -31513, + 10438, + 31105, + -510, + -17349, + 22193, + 26059, + 7061, + -1689, + -17780, + 9807, + -13457, + 32393, + 21934, + -7312, + 17552, + -20754, + 32109, + -12839, + -898, + 6463, + 25300, + -31702, + 13125, + 30947, + -16251, + 11241, + -31266, + -5503, + -31661, + 5316, + -24120, + 10330, + -11867, + 21681, + 32191, + -17765, + 9369, + 17110, + 15606, + 3328, + -31637, + 27046, + 3030, + 7312, + 11952, + 4350, + 6489, + 5357, + -18712, + 10434, + 7297, + -31474, + -8823, + -2061, + 15652, + 26916, + 3038, + 7204, + -2310, + 19032, + -405, + 30578, + -1841, + 16450, + 12313, + -15007, + 11867, + 30545, + -12509, + -23742, + -26152, + -25285, + -30891, + -9211, + 11895, + -14880, + 31183, + -8641, + -23833, + -31766, + 26667, + 23204, + 5919, + 23271, + 14702, + 19800, + 8336, + 21746, + 5668, + -14442, + 27718, + 13952, + -19565, + -16659, + -9324, + -26704, + 16520, + 2974, + 28763, + -31368, + 6866, + 10416, + 3057, + 14025, + -8811, + 619, + 7600, + -25045, + -81, + -15465, + -11178, + -21075, + -12590, + 9501, + 31377, + 13410, + -9971, + -11188, + 10408, + 18138, + 5441, + -8825, + 18634, + 242, + -6605, + 13494, + -6136, + 6221, + -18334, + 28717, + 8741, + -8591, + -18127, + -24926, + 5281, + 16456, + -24039, + 31477, + -21823, + -28908, + 26881, + 17063, + 11654, + -3806, + -32517, + 24636, + -17608, + 3563, + 18138, + 19514, + 4358, + 26422, + -31235, + 23556, + -23839, + 3188, + 8263, + -21065, + -19511, + -16428, + 15497, + -28022, + 3681, + 7575, + -5352, + -31470, + -904, + 13316, + -19449, + 23769, + 9114, + -15688, + 11921, + -2610, + 27056, + 30059, + -17766, + -461, + -2870, + 23002, + -13091, + -30710, + -3534, + -1615, + 2580, + 3166, + 20755, + -9085, + 10071, + -5996, + -22927, + -17783, + 21295, + 5436, + -6437, + 21464, + -20568, + 5687, + -10828, + 16960, + 16510, + 28260, + 4799, + -13820, + -22612, + 28801, + 32681, + 13272, + 27252, + 9994, + -11780, + -31239, + -6851, + 25434, + 17553, + -1306, + 14951, + 5478, + 14976, + -1291, + 27260, + -32600, + -24062, + 16891, + -26644, + -30453, + -1786, + 30624, + -2646, + -1889, + 6830, + 5280, + -25530, + 6703, + 19001, + -5247, + 11836, + -20542, + 2402, + -27979, + -29783, + 28854, + -17897, + 4450, + -6557, + 2534, + -26972, + 16775, + -22731, + -11158, + -9611, + 14091, + 11472, + -1801, + 22504, + 31496, + 23097, + 25120, + -13196, + -2926, + -30323, + 8116, + 11505, + -509, + -28817, + 18990, + -18969, + -10958, + -4868, + 18581, + 14899, + -97, + -29526, + 5061, + 32196, + 16508, + 15451, + -6057, + 21308, + -1808, + -28786, + 7039, + -21809, + 19356, + -16322, + 21801, + -27471, + -20285, + 8652, + -32439, + 23847, + 8729, + 19337, + -2706, + -31427, + -7567, + 15163, + 22443, + 3373, + -3519, + 4776, + 20993, + -12421, + 15805, + 13629, + 31494, + -25541, + -14912, + -21798, + -9385, + -31338, + -20114, + 30086, + -19046, + 569, + -12252, + 2680, + 13519, + 12913, + 20305, + -8343, + 3182, + -12645, + -27965, + -17266, + 19136, + -17735, + -19427, + -11582, + 5715, + -28660, + 28449, + -12008, + 28814, + 11800, + -24586, + -9964, + -17098, + -6883, + 32513, + 31076, + 12619, + 25007, + 16428, + -30987, + -16570, + -13140, + -4056, + -8683, + 22422, + 208, + -16498, + -4531, + -32511, + -23287, + -12511, + -12433, + -31960, + -18573, + -3116, + 20104, + -3302, + 8548, + 24761, + 11213, + 20581, + 26263, + -4523, + -6473, + -10026, + -23572, + -9292, + 20864, + 25639, + -20082, + -26970, + -8308, + 27823, + 31067, + 17360, + -2758, + 3722, + -8347, + -17822, + 27735, + -4058, + 11843, + -32569, + -8252, + -1406, + -20351, + 8444, + 13985, + 26823, + 17660, + 32537, + -3677, + 28147, + 6109, + -5323, + -5793, + -30753, + 313, + -6707, + -21434, + 13641, + 4593, + -5632, + -22032, + -12483, + -6846, + 29034, + 30200, + 3101, + -15596, + -15094, + 19396, + -902, + 5036, + 29210, + 8068, + -15588, + -6043, + -20025, + 6912, + 9485, + -10708, + -30148, + 16681, + -1480, + -914, + 15105, + -24048, + -23765, + -6351, + 10038, + 4744, + 28175, + -24604, + -17364, + 6433, + -24708, + 30363, + -11092, + 17307, + 30540, + 29292, + -8397, + -6026, + -18586, + 29260, + 9928, + 8926, + -29773, + -13907, + -14884, + -13470, + -10786, + 19573, + -1714, + -25584, + -5443, + -8193, + -30559, + -15812, + 29924, + 16933, + -29354, + 18494, + 13350, + -12685, + 18233, + -22180, + -25246, + 12614, + -14097, + -8289, + 1329, + -31409, + -12292, + -17050, + 18571, + -15497, + 32723, + -13907, + -19051, + 8854, + 20432, + 8895, + 30182, + 19490, + 3454, + 9296, + -4091, + -15856, + -31574, + 17032, + -28902, + 12291, + 22389, + 18365, + -18574, + -6823, + 8805, + -20616, + 4663, + -18946, + 13686, + -7551, + -19608, + 5996, + -17428, + 26255, + 26197, + 16942, + 9765, + -13583, + 11899, + 25401, + 32683, + -13685, + 29907, + -4591, + 20788, + 21856, + 24716, + -10040, + 31265, + 6997, + 27902, + 14429, + 19369, + 9664, + 283, + -12522, + -7197, + 13710, + -18276, + -20190, + 32329, + -31009, + 4458, + -14973, + -30533, + -30667, + 1219, + 7916, + -485, + 477, + 7397, + 8486, + 27823, + -18173, + -9924, + 25537, + -32390, + 12502, + 562, + 5523, + 2371, + -22045, + 25743, + -21455, + -19475, + -25795, + -32092, + 12595, + 23011, + -26185, + -27878, + 5730, + -29166, + -17077, + -20903, + 30397, + 29820, + -27627, + 15004, + -9696, + -12844, + 17280, + 3392, + 613, + 17529, + -31720, + 31964, + -22389, + -13007, + -27026, + 16474, + 2249, + -25043, + -23958, + 30946, + -12701, + 14311, + 7795, + -319, + 22662, + -32752, + -29149, + -25287, + -23718, + -13398, + 16705, + 4169, + 25506, + -29676, + 19942, + 8073, + -20889, + -25380, + -13437, + -24469, + 17744, + 12443, + -26467, + 30174, + -16684, + -26036, + -2121, + 11099, + 32008, + -13011, + -5703, + 10300, + 32364, + -20320, + -1108, + -20071, + 3726, + 15847, + -19846, + 15702, + 5437, + 21086, + 11306, + 31330, + 27044, + 30063, + -20659, + -18308, + -18229, + -31678, + 23102, + 31472, + -26485, + -19490, + 27158, + 3055, + -12970, + 15460, + -25964, + -1160, + -1480, + 21531, + -22358, + -32206, + 26121, + -23327, + 15822, + 12144, + 7861, + -9521, + 21118, + -30738, + -23460, + 9866, + 21720, + -23795, + -8807, + -25378, + 14641, + 9294, + 25501, + -32184, + -13288, + -18761, + -16494, + -32718, + -2645, + 13093, + -15519, + 24309, + -31699, + 1867, + 13615, + -9399, + -13578, + -29782, + 29679, + -21606, + -23140, + -31663, + -10985, + -2504, + -9184, + -25727, + -16582, + -13986, + 13046, + 11030, + 23113, + -25104, + -24538, + -16495, + 20754, + -31778, + 8608, + -1388, + -20146, + 14492, + 21394, + 21898, + -30159, + -23096, + -5640, + -12332, + 7882, + -13263, + -5703, + -11651, + 14111, + -9480, + 5539, + -23748, + -2357, + -22046, + -171, + 5236, + 9434, + 29683, + 1945, + 253, + 25846, + 19547, + 19369, + -17846, + -32478, + 17807, + 2195, + -4161, + -20586, + -10912, + 18650, + -7489, + -1873, + -22273, + 1411, + -18507, + -28923, + 24204, + 19456, + 7597, + 4597, + -5759, + -4795, + 30603, + 24010, + 11561, + -17946, + 24722, + 21301, + 7988, + 29551, + 6020, + -2676, + 10560, + 9739, + 14063, + 26914, + 5968, + 11042, + -21400, + 6278, + 2492, + 17347, + 16957, + -19172, + -27089, + 3363, + 14138, + -1231, + -32119, + -28040, + 18692, + -30250, + -1046, + -24636, + -27551, + -21287, + -13492, + 9955, + -16134, + -8631, + 28960, + -22670, + -10181, + -29227, + 2839, + -4446, + -26937, + 18411, + 16727, + 13226, + 16686, + 15364, + -22699, + 9478, + 6706, + 5071, + 12121, + -13331, + 25719, + -7867, + -8897, + 16422, + -7745, + -20635, + -15099, + 5728, + 30778, + 30371, + 6197, + 2508, + -25005, + -32640, + 13677, + -8523, + 28560, + -26013, + -4131, + -23329, + 15893, + -15707, + -6417, + 27365, + -7596, + 13670, + -10387, + 31439, + 20281, + -1065, + -17265, + 21415, + -4257, + -28864, + -19174, + 31007, + -25626, + -16170, + -25369, + 30362, + -12129, + -24970, + -11437, + -13794, + 16369, + -28930, + -8049, + 10540, + -20444, + -14602, + 9688, + 30656, + 9650, + -28726, + 31705, + 3895, + -28377, + 22778, + 21644, + -32489, + -1838, + -21788, + -1860, + 10465, + 2452, + 28774, + -29482, + 29754, + 22402, + -11603, + -32263, + -19885, + -20766, + -3914, + 7944, + -3088, + -20244, + 4423, + 31954, + -11080, + 15660, + 27860, + -7946, + -17478, + -18745, + 22932, + -18461, + -2431, + -7941, + -4933, + 3461, + -24455, + 15495, + 2182, + -6371, + 15268, + 25098, + 29884, + 18369, + 32109, + -2116, + 1036, + 13165, + 16965, + 13964, + -29307, + 21521, + -14078, + -17109, + -11791, + -8531, + -12171, + 3143, + 26382, + 30068, + 29017, + 25144, + 15083, + -12794, + -17955, + -25167, + -20515, + 19397, + -26157, + -31219, + 10553, + 4473, + 31278, + -19575, + 29119, + 27062, + 26960, + -21790, + 15328, + -7874, + 20539, + -29196, + 15541, + 3562, + -22275, + -11569, + -4989, + -11971, + -26025, + 682, + 10572, + 30798, + 28789, + -27517, + 7116, + 12200, + 824, + 32215, + 2947, + -10973, + 4331, + 7018, + -12469, + -13945, + 24913, + 15446, + 18146, + -21493, + -647, + 15304, + 18031, + 5142, + -1459, + -20671, + 9251, + -5207, + -3506, + -8505, + -32055, + 8094, + -28371, + -728, + 16437, + 25810, + 3165, + 10704, + -1559, + 5628, + -13422, + -15529, + 17678, + 14201, + 19386, + 3176, + 32187, + 2998, + 10738, + 4659, + 29248, + 10925, + 28420, + -30329, + 3736, + 9414, + -225, + -28089, + 11563, + -30476, + 7823, + 19755, + -19897, + 11009, + 31573, + -12567, + 12559, + -28919, + 6268, + 32012, + 10868, + -13321, + 26684, + 446, + 4515, + -2198, + -21277, + -13932, + -21164, + 7105, + 7889, + 20604, + 18721, + -15983, + 4578, + 3373, + 28065, + 21217, + 5774, + 1582, + 11856, + -27364, + 30627, + 31958, + 30936, + 26937, + 26079, + 22684, + -756, + -2001, + -11192, + 30812, + -4651, + -29460, + 9186, + -17831, + 4172, + 20484, + -31477, + 26656, + -17874, + -19952, + -23873, + -23325, + -26322, + 26977, + -13572, + 30378, + -4137, + -22003, + 7307, + -10046, + 23616, + -8584, + -2981, + 15313, + -22993, + -8689, + 6925, + 16352, + -22256, + 26936, + -31734, + -1902, + 28187, + 10042, + 8477, + 9923, + -1463, + 4896, + 9262, + -10316, + 1436, + -5245, + -2646, + -2287, + -26848, + -17603, + -24628, + 21392, + 25278, + -30847, + 19093, + -11197, + -19462, + -4538, + -11440, + -24280, + -24937, + -1381, + -1851, + 12850, + 1618, + 18426, + -21496, + 5292, + 23006, + -31329, + 24962, + 13005, + -7111, + 25007, + 21609, + -30581, + -16550, + 11038, + -8902, + 9773, + 13151, + -10772, + 2872, + 535, + 28977, + -7380, + 27685, + 27285, + -13468, + 8564, + -28486, + 25747, + -2007, + 11620, + 7808, + -30333, + -31454, + -9808, + 26075, + -10350, + 2450, + -23155, + 16331, + -11755, + 27688, + -18900, + -13797, + -29936, + -21668, + 10597, + -12089, + -14117, + 7868, + 5223, + -8849, + 16724, + -13663, + 713, + -12277, + -23956, + -3507, + -7914, + 28959, + 8617, + -29221, + -24897, + -22862, + 12132, + 5629, + -13648, + -11061, + 2824, + -8463, + 28542, + -22975, + -5975, + 9738, + 12120, + -30051, + 1128, + -1124, + -10629, + -26791, + 26293, + 25979, + 7626, + -15184, + -25175, + 23580, + 18285, + 7365, + -21688, + 25431, + -24972, + -11731, + -4868, + 28092, + 11300, + -14095, + 26955, + 31975, + 21723, + 2829, + 2795, + -24282, + -21332, + -23157, + -26240, + 20519, + -1709, + 15181, + -1430, + -21861, + -25094, + 14061, + -1934, + -9880, + 5352, + 29582, + 8033, + 22486, + -28762, + -6396, + 30612, + 8146, + -26141, + 23534, + -26055, + 3901, + -7402, + -9390, + 5725, + 14835, + 21368, + -25530, + 14556, + 30181, + -4371, + -23837, + -4004, + 14433, + -22422, + 1477, + -6363, + 1073, + -15040, + -8411, + 5838, + -1810, + 29826, + -24271, + 19039, + 11529, + 19458, + 23864, + -12640, + -22754, + 21138, + 934, + -5392, + 32187, + 24113, + 4447, + 17581, + 16187, + 31660, + 13069, + -18917, + -19194, + -26040, + 10600, + -31356, + 483, + 21817, + -29563, + 3251, + -26775, + -16627, + -24894, + 30894, + 25368, + 10133, + -29935, + -6434, + -2043, + 17591, + -7988, + -7402, + -10244, + 19370, + -12838, + 9649, + 30218, + -15436, + -24219, + -15648, + -22519, + -6935, + -7349, + 8799, + -2906, + -11429, + -20975, + -12087, + 25699, + 4715, + 15671, + 11640, + -5432, + 14774, + -12632, + 10004, + 21838, + 19177, + -5007, + 5202, + -21448, + 17899, + 32741, + -2928, + -29422, + -556, + -3339, + 1794, + -26910, + 31039, + -23384, + 7060, + -2267, + 17245, + -15842, + -32310, + -16436, + -11819, + 30957, + 13364, + 23888, + -31887, + -15152, + 32708, + -3065, + -29768, + -24135, + 5028, + 7992, + -28140, + -17074, + 2047, + -25760, + -6689, + 7437, + 22569, + -8681, + 9169, + 18585, + 27476, + -21264, + -14395, + 26128, + 14336, + -19778, + 17930, + 18385, + 5881, + 18099, + -5331, + -27646, + -27425, + 10683, + 30659, + -4472, + -15327, + 8781, + -8356, + -26789, + 12166, + 3889, + -22524, + 20478, + 27284, + 30353, + 6939, + 14015, + 23540, + -28410, + 2228, + -20263, + 24573, + -4217, + 32364, + 26185, + 32624, + -29472, + 10420, + 13781, + 7853, + 16422, + 7160, + -31960, + 280, + -14628, + 26779, + -26397, + 23611, + 24301, + -1879, + 10762, + 2380, + -7577, + -31843, + 29576, + 14238, + -9402, + -29679, + -11368, + 249, + 7535, + 21091, + -29998, + -10722, + 6003, + 28560, + -26939, + -10261, + -1633, + -6648, + -25954, + -27325, + 28140, + -28407, + -9466, + -15409, + 9808, + 3865, + -28355, + -5639, + 6560, + -15154, + 5169, + 11393, + -14431, + -15128, + 9247, + 9855, + -7614, + 26087, + 10439, + 6860, + 12605, + 21964, + -4567, + 31056, + 9973, + 23890, + 17259, + 9133, + -4993, + 31296, + -11294, + 7852, + 30093, + -17820, + 22848, + -6270, + 15523, + 28777, + -12550, + 23327, + -16757, + 14673, + 8014, + -22209, + 21947, + -13630, + -7832, + 11750, + -2130, + 4903, + -28941, + 22137, + 27338, + 29667, + -15806, + -16570, + 24799, + -929, + -11553, + 17739, + -22114, + 15187, + -16496, + -13073, + 11003, + 32671, + 23036, + 30190, + -11854, + 30422, + 673, + -15546, + -9882, + -24854, + 1269, + -26931, + 13687, + 14822, + 31198, + -22006, + -9413, + 20976, + -3602, + 20535, + -17726, + -13362, + -16687, + -28044, + 30299, + -27440, + 29000, + 17712, + -21049, + 23138, + 6592, + 17981, + -15969, + -8922, + -19433, + 19194, + -5185, + -11004, + 6600, + 19658, + -27323, + -21275, + 4879, + 30219, + -14986, + 3347, + -19769, + 31016, + -3246, + 20305, + -10468, + 31886, + 22978, + 19981, + 791, + 2229, + -16464, + -24170, + 21871, + -32004, + -24898, + -31690, + -1597, + 19708, + 2303, + -9114, + 29056, + 26524, + 32511, + 4352, + 7153, + -19674, + -29289, + 29723, + 10527, + 7337, + 30778, + -11169, + -10539, + -16132, + 6374, + 9404, + -15557, + 27513, + 25523, + 19139, + 6066, + -27930, + -18815, + -2275, + -3784, + -23, + 25083, + -6867, + -5690, + -5844, + 7569, + -14550, + -16648, + -12726, + 23041, + 3254, + -16206, + -14363, + 20774, + 26912, + -1861, + 15259, + 26088, + -23412, + -17287, + 21708, + 28426, + -18025, + -14780, + 16643, + -17353, + 20883, + 32133, + 1787, + -28525, + -28947, + -16338, + -17647, + 14082, + 32461, + 3989, + 32327, + 23769, + -31236, + -2262, + -16340, + 4356, + -5660, + -2186, + -29968, + 8170, + 31959, + -13507, + -10624, + 6089, + -18826, + 13324, + 5051, + 1142, + 11135, + 4451, + -20266, + 24324, + 30967, + -17719, + -12968, + 12953, + -24243, + -19818, + 22189, + 3534, + -25620, + 30352, + -30803, + -28773, + -19204, + 10030, + -4503, + 3971, + 10334, + 7407, + -17231, + -4636, + -17812, + 18819, + -15455, + -18127, + -9568, + -18800, + 5408, + 14234, + 17902, + 7068, + 25935, + 15403, + 2250, + 491, + -2786, + -25182, + -17189, + 3969, + 28999, + -1811, + -1322, + -14310, + -26807, + -25413, + -31700, + -25269, + -22921, + -8655, + 29454, + -24496, + 15552, + 883, + -13263, + -7236, + 11155, + 4681, + -1254, + 17935, + 25920, + 25586, + 20850, + -31218, + -29184, + -3887, + -993, + 7023, + 8483, + -28251, + -22655, + 29936, + 17033, + -24953, + -11401, + 30889, + 1798, + -5823, + 8147, + -15642, + 2867, + 7387, + 13206, + 8843, + 5977, + -26286, + 18253, + -11075, + -12287, + -30043, + 23806, + -6984, + -32094, + -6512, + 4827, + 7895, + 19841, + -10587, + -29033, + 27452, + 137, + 20520, + 3423, + 5854, + 11132, + -28819, + 12476, + 20719, + 26618, + -28690, + -6518, + -15341, + -8257, + -26315, + 6070, + -29803, + 31414, + 3179, + -4199, + 22469, + -26201, + -2022, + -3948, + 2333, + -16690, + -29336, + 11852, + -1411, + 9927, + 23312, + -19363, + 25344, + 17285, + 28300, + 31867, + -24391, + -14534, + 1762, + -1892, + 24135, + -14060, + -27733, + 4781, + 26548, + -18356, + -6463, + 29271, + 31188, + -12093, + 21719, + 21433, + 22161, + 21336, + -24752, + -496, + 28461, + 31954, + -16683, + 30633, + 4929, + -18627, + 24494, + 16386, + -20340, + -32460, + -10186, + -8979, + -26954, + -28624, + -17496, + 4274, + -4464, + 31949, + -22183, + -28694, + -27390, + -5140, + 4139, + 22447, + 17426, + 6330, + 12709, + -30172, + 324, + -10989, + 25247, + 524, + 24605, + 2892, + -17124, + -20586, + -25768, + 16674, + -26489, + -20432, + 3843, + -24273, + 16176, + 5752, + 16252, + -25818, + -32585, + -6786, + -24292, + 10967, + -13315, + 22982, + 31268, + -27812, + 6361, + 4412, + -2514, + -30880, + -26725, + 11005, + -28625, + 255, + 8641, + -19485, + -29328, + -29504, + 6152, + 28287, + 19427, + 17836, + 26188, + -31446, + 27331, + -14649, + 31518, + -13463, + -20200, + -22214, + 4400, + -9133, + -17530, + -5602, + -18148, + -15914, + -8394, + 19806, + -11227, + -24543, + 21153, + -14415, + 15184, + -3157, + 5135, + -20545, + -27172, + -1304, + -736, + 21164, + -31964, + 236, + 31398, + 20428, + 32643, + -15865, + -9117, + 9907, + -7091, + -1168, + 6550, + -9911, + 24926, + -17448, + -18033, + -22047, + -2248, + 5818, + 17096, + 2319, + 28713, + 17647, + 20071, + -8974, + 9467, + -10231, + -7553, + -3414, + -29149, + -4596, + 22673, + 8820, + 19354, + 10929, + 16044, + -17697, + 25121, + 9801, + -20583, + 26049, + -12069, + 12841, + 21062, + -19480, + -25913, + -26564, + -12011, + 30033, + -5204, + -11884, + 8347, + -7577, + -24098, + -16289, + 25664, + -21118, + 7682, + 26638, + 5318, + -3836, + 29311, + -160, + 30554, + -18779, + -23860, + 17085, + 277, + -8864, + -22609, + -22714, + 30884, + -20073, + -13394, + -5284, + -20648, + -833, + -5458, + 19186, + 13527, + 3479, + 6035, + -27270, + 18262, + 2327, + 6819, + 2679, + -29424, + -28080, + 13168, + 24892, + 25920, + 25203, + -17662, + -32516, + -28710, + -4557, + 19685, + -22622, + 4173, + 18686, + -19130, + 25652, + 32156, + -10585, + -11038, + -19583, + -31713, + -16913, + 16900, + 22646, + -25904, + 8386, + -5170, + -20261, + 6877, + 30864, + 26389, + -30602, + -8905, + -8803, + 27772, + 18626, + -25532, + -13984, + 1686, + -11136, + 5124, + 15510, + -18965, + 23930, + -12223, + -5932, + 17360, + -26459, + -15155, + 19932, + -26149, + 23267, + 10434, + -20354, + -28300, + 16515, + -31861, + -15085, + 23789, + -32575, + -27584, + -25770, + 9839, + -18370, + -28529, + -27862, + 25331, + 30138, + -28925, + -31229, + 20783, + 32523, + 17643, + -22040, + 29411, + 21484, + 18135, + -1245, + -10417, + -24807, + -24211, + 21891, + -28959, + -24633, + 14433, + -15239, + 6930, + 10036, + -20577, + 25681, + 16055, + 21738, + -24297, + -29909, + -7935, + 29356, + -23121, + -17544, + -27141, + -29746, + -28192, + 2053, + 28531, + 30601, + -7522, + -6060, + -23986, + 944, + 15242, + -32164, + -26318, + -3675, + 3143, + 12690, + -25461, + 19611, + -14118, + 7314, + -13543, + 7714, + -25508, + 28862, + -12051, + 32594, + 9691, + -29190, + 18444, + 12482, + 32350, + -10739, + 29427, + 1093, + -1117, + -21686, + -25362, + 20355, + 19957, + -16069, + 8173, + -962, + -7188, + 5109, + 24735, + 10053, + 17202, + 15162, + 5563, + 26942, + 10881, + 2250, + 12148, + 28196, + 17345, + 5006, + 13527, + -28531, + 29765, + 20220, + 17016, + 19436, + -12309, + -13906, + -24504, + 2599, + 21971, + 6049, + 21806, + 11662, + 28713, + 23033, + -6319, + -7004, + 19855, + -12675, + 3242, + -21589, + -29060, + -20720, + 5696, + 6467, + 15158, + -13791, + 6767, + 13048, + -16413, + 528, + 15506, + 24900, + 24513, + -14158, + -191, + 19261, + -18956, + -32621, + -25598, + -10325, + -16735, + 31200, + 21969, + 6872, + 30221, + 8461, + -24684, + -16046, + -29805, + -27925, + -25783, + 2442, + -5249, + 23407, + 16125, + -8204, + 12649, + -13026, + 1522, + -9539, + 4990, + 5784, + -3401, + 20710, + 21026, + -3774, + -3332, + -8476, + 23882, + 18702, + 22509, + 24852, + 21858, + 18036, + 11642, + -16853, + 2772, + 20653, + -22781, + 18122, + 22903, + 7682, + 1976, + -981, + -32262, + 348, + 4002, + -26202, + -17161, + 7261, + 8469, + -18437, + 2392, + 3364, + 5935, + -17196, + -30873, + 23667, + 11279, + 23440, + -32308, + 14427, + 4121, + 11050, + -8888, + -15100, + -12424, + 11204, + -29412, + -31451, + 5750, + -30633, + -830, + -5194, + 3464, + 22298, + -14517, + 3029, + 30735, + -11386, + 26180, + -7546, + -17816, + 15052, + -584, + 20201, + -12173, + -1770, + -17053, + 6334, + -1933, + 30676, + 26435, + -3878, + -16053, + 16698, + -7156, + -13392, + -3441, + 16174, + -30323, + -10477, + 26337, + 32066, + -28685, + -10890, + -20228, + 25107, + 3637, + 26911, + -17584, + 22506, + 3029, + 12387, + 21367, + -23844, + -30053, + -11777, + 7412, + 28777, + 13906, + 5226, + 17378, + 4882, + -14831, + -281, + -6193, + -27769, + 22032, + -32738, + 6100, + 3055, + -1080, + 3110, + -9934, + 20046, + 31464, + 24608, + -23051, + -10433, + -3605, + 5098, + 18041, + 9892, + 10215, + 31297, + 4880, + -21235, + -5237, + 4058, + -9186, + 26693, + 12023, + 2071, + -2544, + -28374, + 8017, + -4882, + 20240, + 12450, + 5102, + 29336, + -2023, + 31405, + 21260, + 27210, + 15541, + 22815, + 26372, + -43, + -18272, + -32646, + -3153, + -26195, + 3891, + 28717, + -4456, + 18365, + 29947, + -31716, + -17896, + 21573, + -190, + 16982, + 26928, + 25565, + 18763, + -2930, + -15822, + 571, + 20918, + 218, + -23365, + 18108, + 18919, + 26618, + 12055, + -8654, + -22169, + 2425, + 9782, + 13745, + 9414, + 863, + 3494, + 15610, + -24518, + 18053, + 26742, + 915, + -3285, + -29283, + -10292, + 26309, + -10935, + -26353, + -19439, + 29141, + -26052, + -12563, + -20875, + 10559, + -4367, + 1643, + 29375, + 27995, + -27063, + 32475, + 4497, + 4625, + -165, + -24069, + -22805, + -17281, + 549, + 17378, + 32149, + 3350, + 30397, + -15359, + 1376, + 5956, + -24807, + 21336, + 31935, + 30016, + -2603, + -18750, + 6106, + -17829, + -24196, + 28825, + 21131, + -21512, + -15936, + -14002, + -27599, + -3465, + -8021, + 17469, + 26146, + -9544, + -10950, + 18089, + -3073, + -7201, + 14933, + 28764, + -13903, + -4224, + -1827, + 20195, + 28220, + 20980, + 10238, + -2236, + -18762, + 17090, + 6769, + 31393, + -7483, + 886, + 23061, + 586, + -10262, + -32210, + -9870, + -32168, + -5196, + 15063, + 17303, + 6568, + 23220, + 3743, + -13883, + -4982, + -16495, + 9102, + -4573, + 13585, + -1532, + 17278, + 10255, + -605, + -2326, + 11505, + -12061, + 8175, + -29246, + -19816, + 20237, + -12680, + 22645, + 14709, + -2202, + -27591, + 13372, + 1980, + -795, + 12610, + 26575, + -8916, + 10899, + 32208, + -2241, + -10182, + 29498, + 14360, + -14879, + 4230, + -30434, + -3017, + -29321, + -10866, + -23683, + -7034, + -13141, + -27811, + 10185, + -10215, + 20492, + -20810, + 18202, + 31113, + 16160, + -6946, + -11682, + 28623, + 21630, + 20082, + 21865, + -32115, + -27274, + 27265, + -17526, + 17544, + 19465, + -16982, + 19707, + -15171, + -32179, + -24888, + 6039, + -31519, + -19985, + -17876, + -32632, + 1502, + 23273, + -19262, + 13131, + -4045, + 31959, + -27645, + -17506, + 4314, + 14570, + -5303, + -12313, + -12825, + -32475, + 6409, + -19032, + -10265, + -25443, + -24772, + -30683, + 9487, + -799, + 19791, + -797, + 8958, + 18410, + 16566, + -11063, + 7944, + 5878, + 5116, + 29000, + -31794, + -21015, + -2435, + -4233, + 11161, + -27439, + -8026, + 17337, + 9577, + -16860, + -17958, + -26397, + -23450, + -18343, + -18058, + 30446, + 18392, + -27634, + 31784, + 31393, + 32474, + -15104, + 31111, + 5344, + -16222, + -11282, + 24784, + -19582, + 18050, + 26475, + 5956, + -7837, + -19562, + 6463, + 32354, + -12577, + 8476, + -21573, + -31934, + 11834, + 3328, + 8526, + -11414, + 8126, + 19011, + -370, + -9109, + -25222, + 3142, + -6360, + -2082, + 14631, + -768, + -5816, + -31896, + 30709, + -6757, + -3471, + -21460, + -22459, + -21634, + 17498, + -17097, + 22691, + -13047, + 10624, + 8663, + -4977, + 31485, + -20960, + 1994, + -8778, + -2511, + 9503, + -32652, + -13975, + -28871, + 23411, + 24928, + -19231, + -2157, + 15663, + 30406, + 11435, + 9406, + -29697, + -3593, + 23188, + 18669, + -29593, + 25423, + -4865, + -7792, + 16792, + -21, + 30225, + -32020, + -3080, + 9714, + -22535, + -12995, + 15222, + -6281, + 7546, + -5444, + 10597, + 12345, + -20786, + 15355, + 5559, + -13133, + -1124, + 24319, + 19976, + 8649, + -2788, + 30159, + -8563, + -5145, + -25556, + -27310, + 22362, + -21020, + -8183, + -13650, + -22760, + 29563, + 10343, + 27236, + 31383, + -14883, + -8623, + -27570, + -17901, + 14, + 1823, + 25543, + 10345, + -17708, + 27569, + 2782, + 13589, + -22176, + 21059, + -28037, + -15619, + -9815, + 3525, + 24300, + -16126, + -29824, + -31068, + -1985, + -22850, + 18777, + -259, + -13696, + -22766, + 29488, + 6279, + -4442, + 31066, + -18923, + -10316, + 31721, + -13504, + 15775, + -24268, + 19888, + -22213, + -14299, + 7362, + -16221, + -27338, + -26287, + 1926, + 8792, + 26882, + 8627, + -7825, + 3660, + 19540, + -21838, + 24479, + 4289, + -25547, + -27538, + 23973, + -3876, + -28812, + -32376, + -18819, + -12868, + -4954, + -14322, + -29188, + -31148, + -10744, + 14785, + 8596, + 9330, + -25950, + 30333, + -20667, + -13499, + 23058, + 22842, + -3903, + -27493, + -22960, + 15024, + 19269, + -20932, + 14956, + -1989, + -26621, + 5320, + -16655, + -12986, + -12409, + -955, + 19404, + 30463, + 43, + 8419, + -24757, + 24615, + -21443, + 7408, + -4306, + -27433, + -14483, + -30115, + -23892, + 430, + 3589, + -5288, + -21, + -28991, + -28686, + 32721, + -18648, + 6865, + -7301, + -2033, + 30587, + -6814, + -26972, + -12451, + -13316, + -24353, + 11902, + -30958, + 15789, + -3630, + -3510, + 12138, + -6632, + 24678, + 14886, + 22026, + 16099, + 30781, + -2298, + 16298, + 3016, + -5435, + -32757, + -24106, + -9206, + 4715, + 12340, + 29423, + 28937, + 32111, + 1914, + 11692, + 19649, + -3719, + 22708, + -16573, + 19086, + 30158, + -29339, + -18642, + -9884, + -30469, + 20657, + -8414, + -30270, + 6257, + 7562, + -24389, + -31204, + -2410, + 1104, + -30585, + -13739, + 17744, + 3716, + -23546, + -9838, + -1195, + 2342, + 9729, + 9966, + -27503, + -3093, + 27960, + -22520, + 6146, + -29070, + -25396, + 30557, + 4637, + 31010, + 31516, + 11107, + -5095, + 27666, + 18556, + -8829, + 18211, + -18429, + -8768, + 14451, + 11867, + -10547, + 16388, + 10943, + 31737, + -12215, + -30181, + 31382, + 9073, + 31672, + -5733, + 22814, + 6202, + 14943, + -8238, + 14743, + -362, + 32001, + 21108, + 7627, + -10237, + -4093, + -22336, + 11554, + -347, + -27292, + -2835, + -28301, + -29891, + 19109, + 12051, + 27846, + 13804, + -1690, + 26402, + -21843, + -29160, + 18990, + -20997, + 14015, + -29243, + 27524, + -26881, + 22790, + -32595, + 27260, + 5020, + -21825, + 11866, + 28126, + 12486, + 6880, + -15966, + 27871, + 15036, + 30696, + 20369, + -24187, + 9101, + 19901, + -28563, + 31831, + -9023, + -10291, + 1359, + -3228, + 12297, + -25731, + -21019, + 14115, + 17892, + 18492, + 7790, + -27265, + -15383, + -15342, + -31969, + 28627, + -23689, + 31894, + 8910, + 181, + 29409, + -6435, + 2320, + -30854, + -15001, + 32181, + -5275, + -7917, + -16348, + -11614, + -2258, + -11292, + 11118, + 14064, + -17620, + -14531, + -4248, + -29614, + -7728, + 898, + 16048, + 7588, + -1094, + -27044, + 13650, + -15727, + 12887, + 31350, + 30967, + 6272, + -798, + 25293, + -8243, + 10571, + 28576, + -13109, + 12881, + 32301, + 22432, + 15379, + -15076, + -29832, + -20275, + 11016, + 437, + -12897, + -19306, + -32448, + -3203, + -19655, + 12602, + -21651, + 1403, + 17143, +}; \ No newline at end of file diff --git a/sw/applications/trans_versasense/data_cpp/data.cpp b/sw/applications/trans_versasense/data_cpp/data.cpp new file mode 100644 index 00000000..4e7efc7a --- /dev/null +++ b/sw/applications/trans_versasense/data_cpp/data.cpp @@ -0,0 +1,104 @@ +#include "stdint-gcc.h" + +int32_t pos_embedding[1936] = {-1383, 964, -5839, -3654, -5069, 4064, -1907, -3855, -3658, -8857, 316, -1245, -3385, 1368, -2997, 13377, 7049, -1252, 2205, -219, -1524, -1316, 4386, 3600, 244, 6103, 1171, 2736, -222, -10278, 728, -1065, 297, 490, 2032, 4887, 4769, -2205, -2950, 3033, 1045, -84, -924, -9504, 871, 6262, -6855, -7938, 3453, -1851, 2541, 741, 10731, 1307, 2100, -4055, -1536, 5267, -2867, -2898, 1939, 25, 3560, 3399, -2064, 139, -1077, 4781, -8273, -6488, 403, 439, 1265, 8417, -106, -211, -4182, 3988, 6307, 104, 3200, -2645, 2750, 1677, 5047, 1988, -368, 784, 2920, 1074, -3975, 322, 2831, -2976, -1221, 4132, -8774, -3231, -3688, -1704, 6092, 4813, -2799, -686, 6206, 460, 10634, 6885, -3182, 5878, 920, -1219, 461, 2684, -2039, -7031, -5283, -6447, 5388, 490, 692, -1467, 28, -72, -766, 6259, 2560, 9225, -6087, -4768, -285, 933, -5913, 6449, 840, -2466, 1073, 2144, 2515, -2408, -7375, 7211, -1006, 1794, -9011, -5, 2908, 3234, 891, -2127, 2135, 1420, -1477, -820, 486, 2927, 2929, -6034, -4795, 6535, 981, 1943, -2114, 112, 1866, 3449, 114, 4353, -3075, 722, 8027, -2035, -2310, 1004, -1842, 766, -193, -4143, -468, -10321, -641, -4879, -58, -4413, -6004, 1211, 2336, -7301, -2585, -2329, -2014, -9458, -2424, -2518, -2531, -1006, -11344, -79, 579, -2929, -3784, -115, 1487, 338, -6021, 6798, -3510, -1279, -584, 4754, 4306, 6089, 5313, -7733, -5283, -1086, -4182, -10, 1619, 7458, 4068, 3304, -3974, -2321, -3290, 1892, 4567, 3601, 3791, 6113, -2470, -1036, 3080, 2368, -84, -365, -3006, 2347, -2591, -3977, -5959, 1168, 475, -7409, 4234, -3694, -3462, -2384, -1386, 6249, 2631, -3582, -2584, -3016, -4120, -3507, 6681, 9170, -512, 2289, 437, -7173, -4825, -7726, -3024, 3, -152, 2356, -125, -793, 1257, 11753, 841, 689, -5175, 525, -30, 2126, 399, 4477, -6030, -8924, 6246, 2527, 4445, 3728, 3477, -4071, -2582, 265, 2704, 4541, 4935, -4722, -661, 2167, -1137, 4947, 484, -7557, 2390, -604, 5174, -1680, -7771, 5151, -2544, 4752, -5385, -5953, 6899, 1995, -3538, -1964, -2005, -2899, -3806, -2889, -875, -6668, 2421, 7852, -4135, 3480, -2472, 1312, -372, -1592, -4654, 2972, 6772, -1416, 1550, 956, 858, -2759, 3268, -2765, -4870, -2471, -794, 679, -6719, -659, -159, -987, -247, -3032, -1714, 232, -1652, -3874, -919, -7050, -1827, -5084, -771, -4296, 3897, -3539, 3699, 7776, -7566, 1318, -3243, -2937, -3200, 4591, 5992, -2227, -1440, 112, 4378, 5404, -8718, 279, -1468, -10044, 2330, -4613, -4171, 344, 3440, 8488, -3674, 51, 1177, 2204, -716, -1666, -1899, -2359, 4873, -2739, 1130, 1508, 492, -4401, 7262, -369, -4263, -383, -833, 4751, -292, 2986, -3862, 5871, 1335, 280, 2117, -4211, -2144, -2733, 1554, 2206, -3493, -6634, 491, 3879, 2548, 1455, 4467, 1138, 2686, 3161, 16872, -5, 1346, -7243, -3078, 757, 76, 647, 3155, -7469, 5539, -4297, 2788, -2706, -824, 9735, 227, -164, 1836, -2907, -902, 3414, 9070, 448, -365, 3590, 1785, 3155, -4327, 1762, -192, 5660, -4526, -2613, -5665, 4197, -7165, 6556, -575, -2809, 9670, -1455, 3162, 5698, -2530, 6970, -1283, 2194, 3080, 5368, -2841, 1661, -3814, 734, 2233, 1298, -2275, 2558, -663, 337, -1486, 5124, -4945, -705, 2226, 3647, 3922, -1636, -3246, -1121, 5034, 6748, 1672, -7449, 4429, 7100, -2473, 7379, -947, 96, 883, -571, 5956, 2154, -4363, -5640, 483, 4663, 4230, -1531, 4186, 8916, 2290, 2685, -3635, -2636, -10375, -359, -763, 3008, 1932, -3181, 4049, -2683, -1566, 218, 1499, -4272, 8315, -5687, -3909, -10107, -2763, 49, 4835, -3659, 5096, 2762, 1572, -1215, -1102, 1778, -304, -3823, -7065, -3514, 842, 1533, 3766, 7351, 2417, -4943, 3180, -1947, 1386, -76, 3659, -998, -3692, 1470, -4130, -4735, -920, -3834, -142, -1852, 1681, 1398, -1615, -395, -5920, 1152, 2867, -8946, -1574, -4741, 2136, 2927, -3393, 1605, 1767, 624, -161, -9984, -9672, -1855, -1974, 2349, -7959, 8138, 405, 3118, -5967, -400, -2649, 1157, 5872, 3428, 3737, -1628, 1432, 319, -1607, 1023, -2374, 3938, 1798, -3673, 1438, 3258, -753, -1809, 5015, 4319, -5591, 8596, 1887, -4751, -4368, 2422, -1443, -134, -788, -21, -2064, 1963, -10361, -3825, -3084, 10016, 2496, 7829, -1263, 10488, -6681, -2736, -3243, -2854, -5366, 4789, 3023, 5010, -1605, 818, 3508, 4327, 1620, 5211, 1638, -1602, -6396, -1011, -4742, -2177, -769, -7017, -5381, 6374, -434, 5859, -1740, -3273, -1150, -272, -4498, -1411, 3119, -2595, -3171, 2275, 4851, -2317, 9149, -5869, -470, -6065, -5685, -3181, -3491, 2468, 1930, -3545, -4076, 4313, -2524, -3857, -800, -2219, 3414, 477, -968, -2669, -3937, 7518, -421, -2605, -230, -2500, 1462, -3009, 1442, 3465, -1343, -4661, 9064, -1488, 2426, 4510, 5118, -6978, -8568, -3232, -803, 1624, -3680, -2136, -3299, -5547, -4491, -6242, 1845, 5622, -710, 3020, 5498, -3608, 1922, 1233, -851, 623, 1153, 2165, -5331, 5668, -4262, 6967, 5474, -86, 3346, -2149, 1429, 1485, 4000, 2078, 1875, 5851, -3715, 4393, 1652, 1144, 5240, 728, 1415, -864, 3615, 1811, 3974, -92, 4902, -8521, -4400, -627, 675, -3433, -3801, -2291, 3850, -6717, 0, -3766, -5335, -5421, -3057, 3809, -5880, 1665, 378, 4789, 3382, -5372, 4777, -1177, 329, -4118, -724, -6930, -1720, -1816, 436, 7447, -533, 4725, -2361, -1161, -3119, 4255, 8766, -1131, 22, 1182, 3252, 4970, -3812, -5076, 971, 7043, -2200, -4456, 3164, 707, -6497, -5324, -218, 9741, -6039, -8101, 6605, 6995, 2298, -10900, -9604, 14083, -2495, 1095, 6337, 1553, 636, 2874, -2222, -2863, 3775, 4896, 8593, -1049, -760, 1582, -720, 54, -1277, -493, -2055, -4673, 2164, -5176, -8766, 3986, 538, 1980, 3639, -5559, 2434, -6174, -2313, -933, 2087, 5489, 1018, -3362, 2350, 8964, 3414, -2611, 5676, -6438, -441, 4548, -3126, 454, 4305, -6046, -1526, 8867, -2809, -3597, 4805, 2720, 5284, -3439, -4167, -1973, -6302, -2436, 693, 2798, -3159, -3125, -1843, -9666, -2709, 6212, -2448, -2614, 9744, 7912, -2084, 6710, -519, -3216, -2973, 339, -1878, 5720, 1510, 3180, 2514, -516, -6191, 8129, -1176, 2473, -1280, -5885, 1885, 2574, 3670, -3595, 5584, 2165, -6515, 5554, -23, 9021, -1911, -881, 465, -2769, -1336, 4516, 781, 1487, 826, -239, 3450, -4089, 312, 4057, -1917, -4253, 2178, 3868, 2352, -96, 3171, 1883, -4054, 7586, -11703, -329, 4425, -6981, 5046, 3208, -4103, -112, -1376, 4341, -2181, -2487, -892, -589, 271, 3055, -346, -137, 741, 2066, 6128, 2551, -4083, -6775, -1311, -4114, 1237, 3796, -616, 3564, 352, -4720, -765, -1952, -3557, 4101, -1777, 4274, 887, 295, 951, -3343, -646, 5854, 4607, -1567, -3609, -4403, 6565, -7334, 109, 1943, 2694, -3486, 2950, -515, 2109, -4209, -3735, -7865, 324, -7742, 8839, 2293, -3205, -2644, 295, 1396, 861, -2310, -6156, -1106, 802, 3566, 486, -1692, 5686, 1646, -1695, 769, 2990, 5526, -2497, -3342, -533, -3074, -5231, 5510, 936, 4001, -324, 4587, 10056, 4353, 1130, -421, 674, -6294, 1722, 2558, 4, -2187, 6847, 2125, -6077, 2690, -719, 2561, 4669, -2845, 5001, 2939, -7002, 2354, 742, 2684, -799, -4004, -5759, 2889, -4625, -6648, 1569, 735, -553, 6963, 2696, 2508, -8183, 5055, -1470, 4075, -5437, -7301, 1969, 2904, 134, -4279, 6075, -1524, 355, -3125, 10803, 1276, -1346, 3689, 794, 742, 1634, 3327, 2022, -3683, 3090, 7283, 1861, -4229, 7780, 3606, -238, -4646, 5503, -2117, -1909, 1908, 6075, -6532, -1732, 5579, 3041, -3126, 4348, 4055, 692, -753, -4153, -1657, 2367, 6320, -235, -9175, -3784, -615, 2829, 2843, -2256, -1470, -5818, -6843, -196, -151, 1301, 2017, -4884, -203, 9959, -4350, 462, 3320, 4236, 1534, -4264, 699, 1578, 3318, 4140, 4835, 1014, -440, 8480, 1889, -706, -1703, 7888, -4966, 2139, 283, -2559, -1652, -1207, 999, 5663, 3620, -9024, 1337, -331, 4966, 1586, -5856, 6659, 4837, -3025, 1162, 204, -2217, -2655, -3015, 3457, -415, -10613, 4144, 4124, -2337, 4753, -2210, 6730, 5633, -4650, 6065, 1790, 4687, 1802, 5954, 3767, 1889, 3277, 1196, -3345, -50, -582, -976, 1391, 4427, -2472, 10868, 1423, -4134, 1687, 616, -5144, 3766, 7614, -3716, -2228, 8223, -4436, -49, 4142, 6244, 2533, 1008, 3650, 3387, 2705, 228, -1405, 1866, -2994, 6573, 6639, 2522, 892, -6028, -7974, -1034, -2814, -5937, -1890, -5217, -7161, -11827, 1492, -355, 5499, -1280, 6, -5161, -3852, 2855, -353, -2529, 999, -5875, 540, 690, 2957, 2639, -5606, 3065, -912, -8014, -2138, 11664, -2999, 3785, -3479, -443, 5357, 3674, 6408, 7416, -2708, -3874, 1420, -8040, 123, -5179, -1861, -68, 2909, 2095, 398, 3777, 2569, 10516, -3511, -10, -4321, -4616, 1167, -8103, 3211, -8598, -1242, -3099, 521, 3416, -4465, 1157, -5550, -219, -164, 3618, 795, -2932, -2417, -3135, 3185, -4072, -229, -5254, -9385, -2973, 7064, 1924, 6405, -2424, 2374, 3312, 1684, 46, 2385, 788, 6867, 1158, 1092, -1723, -3498, 1711, 106, -958, -2024, -2930, 8257, 7091, -1887, -2165, -1379, -4090, 3170, -1518, -1696, -461, -95, -1146, -3041, -486, -1225, 2840, 2454, -535, 4306, 4365, 1027, -7522, 6268, -3390, 1507, -4160, 3606, 4296, 844, 6481, 5322, 845, 1058, -2461, -770, 5714, -1310, 2248, -2115, 8250, -729, -3421, 4037, -2574, -1750, 5356, -6683, -4439, -2797, -5302, -5110, 398, -3725, -2597, 2897, -2513, 1987, -416, -2444, 6916, 349, -1110, -4154, -4623, 53, 3865, -993, -8210, -651, 1280, -4261, -4337, -7605, 2074, -413, -2321, 837, -2882, -3536, 8512, -3100, -751, -1466, -1352, -3046, 833, -538, -378, -5832, -2967, 3981, -608, -274, 39, 1911, -811, 6059, 1289, 6744, -3978, -2821, 2813, 3185, 1641, 4621, -5059, 5139, -4251, 7102, 2009, 4088, 13455, 3158, 2023, 845, -2790, -6827, -7613, 2793, 362, -2562, 7864, -4174, 2552, 30, -2629, -8870, 6764, 478, -2226, 1224, 1911, 2986, -6839, 750, -4442, 43, -4298, 2500, 1377, 4444, -1386, -903, 5267, 3429, 3397, -128, -314, -1175, 557, -1281, 3879, -6261, -2378, -4673, -4546, -9533, -434, -1251, 4867, -478, 6570, 1638, -6200, 2489, 1825, -3280, 2302, 529, 808, -1079, -932, -7550, 308, 5501, -2490, -1262, -503, 2525, 5519, -1882, -1477, -86, -9414, -1875, 3709, 9345, 696, -580, -4114, 3784, -1469, -2308, -7687, 7726, -5358, 2180, 198, -4601, 6568, -846, -743, 602, 3768, -8464, -2305, 1505, 3102, -1882, 1882, 2084, -5905, 10953, 1874, 4433, -4212, 9862, 845, -1182, 2011, -3850, -3034, 1874, 4546, 4268, 481, 5882, 2178, -797, 636, 195, -2742, -6500, -172, 6924, -2807, 1402, 1809, 4814, -6196, -4112, -489, 4513, -788, -1141, -1066, 6471, -366, 3895, -7083, -2192, -936, -4171, -3834, -2427, 60, -2176, 1471, -7225, 1075, -4612, 2404, 923, -6865, 3175, -2994, 3791, 3837, 4112, -2837, -2407, -1790, -135, -2982, 756, 2905, -3754, 3142, 4695, -4753, 3775, -3668, 2878, 58, 1401, -6116, -3778, -835, -1237, 4451, -486, -5649, -2662, -1359, 2480, 764, 6716, 1520, -3423, 3565, 6528, -5598, -2577, -5838, 3809, 4273, -5191, -6151, 856, -3401, 1877, 181, -3391, 6397, 521, 2696, -729, 2447, -2357, 71, 393, -4286, -3678, -3804, 202, 2483, -1495, -567, -351, -5601, 4345, 727, 2205, -446, -1712, 4245, -555, 2319, -1229, -4391, 1198, 3343, 6352, -3041, 3530, 2555, -2491, 3267, 5197, 7241, -5418, -196, -6974, 4126, -6772, -1952, -1254, 4365, -856, -7301, 2039, -3488, -1819, -5129, -8144, 1046, 9050, -2252, 3089, 1116, -3244, 3722, -6500, -2682, 6899, 999, -6970, 4962, 1942, -155, 205, 1988, 2059, -7244, 8643, -2080, -11003, -3558, 6445, 4859, 5428, 2292, 67, -996, 6220, 3174, -276, -9762, -1324, 1566, 3728, -677, 3279, -2624, 2045, 2832, -6470, 1538, -1687, -3169, -2649, -7823, -1285, 4916, 1915, 8069, -955, 3076, 5247, 6909, -1496, 6131, -4841, 8632, 495, -755, -1478, -1746, -5553, 6564, -2779, -3504, 639, -5842, 1703, 1079, 2635, 2315, 1960, -9291, 531, -1071, -1838, -2918, -399, 2394, -8068, -720, 31, -1530, -1179, 65, -4719, 5641, -1551, 5440, -2457, 6268, -5913, 3913, -6646, 188, -6885, 2757, -3601, 3880, -3979, -1443, 1375, -2572, -1632, 2321, 5070, -2172, 731, 481, 1710, -5181, 8850, -931, -3332, 3141, -1414, -2568, -3533, 728, -1683, 206, 907, 5058, 2523, -158, -1465, 1969, -5960, -1139, -7207, 991, 2704, -8160, -2148, -4477, 4621, -5992, 2561, -2189, 5366, 2138, 2017, -2125, -844, -6806, 3850, 3987, 2856, 2990, -6767, -2315, -721, -205, -672, -2231, -617, 4268, 4988, -1234, -2918, 5121, 4651, -2067, 629, 655, 2305, 490, 990, 598, 4562, 3404, 3903, -5174, 7998, -8369, -7167, -1066, 5288, -2154, 5324, -1541, -620, -3439, -4516, 6180, -8012, -1858, 1175, -2675, -2835, -3610, -7460, 10522, 3595, -4464, 1727, 2719, -2989, -2425, 2312, 1535, -2001, -4046, 3982, -3749, -1536, 2144, -68, 284, 1545, -2459, -6920, -2683, 3627, -1356, -188, 2040, 3459, 33, 6605, -1418, 5162, 2430, -1030, 3098, }; +int32_t cls_token[16] = {1579, -8312, -1543, 5366, -5637, -2872, -787, 5773, -2441, 5560, -195, -1606, -1795, -6080, 1247, 219, }; +int32_t to_patch_embedding_layer_norm1_weight[400] = {4133, 4145, 3757, 3886, 3959, 4157, 3936, 3941, 4085, 3902, 4116, 4193, 4064, 4147, 4075, 4082, 4012, 4029, 4116, 3960, 4010, 3944, 4027, 4086, 3719, 3979, 4088, 4002, 4053, 3642, 3885, 3881, 4070, 3980, 3861, 4118, 3899, 4082, 4035, 3967, 3992, 3993, 3975, 3960, 4044, 4026, 3964, 4104, 4141, 4203, 4335, 3950, 4260, 4394, 4250, 4142, 4046, 4265, 4355, 4162, 4026, 3882, 4271, 4276, 4216, 3970, 3983, 3922, 4114, 3907, 4105, 3924, 3986, 4032, 4059, 4209, 3959, 4090, 4356, 3975, 4122, 3986, 4208, 4332, 3799, 4094, 4119, 4180, 3884, 4095, 4133, 4137, 3932, 4225, 4114, 4111, 4032, 3875, 4169, 4247, 4040, 4016, 3875, 4170, 3953, 4202, 3919, 4007, 4077, 4003, 4305, 3842, 4027, 4056, 4142, 4325, 4154, 4097, 3973, 4237, 4355, 4214, 3867, 4227, 3953, 4371, 4289, 3955, 4040, 4009, 4349, 4107, 4081, 3992, 4066, 4087, 4143, 3998, 4267, 4175, 4172, 4379, 4104, 3944, 4301, 4158, 4079, 4004, 4215, 3903, 3995, 4349, 4114, 4170, 4144, 3863, 4146, 4371, 4222, 4055, 3768, 4143, 4415, 4017, 3835, 3989, 4230, 4134, 3999, 4111, 4047, 4056, 4048, 3949, 4234, 3900, 4057, 3988, 4199, 4106, 4042, 3996, 4172, 3837, 4434, 3947, 4334, 4126, 3984, 4289, 4126, 4312, 4083, 4108, 4197, 4109, 4378, 4341, 4190, 4026, 4163, 4292, 4392, 4021, 4034, 4101, 4160, 4278, 4369, 3999, 3936, 4324, 4048, 4162, 4044, 3925, 4438, 3960, 4227, 3866, 4002, 4304, 4042, 4232, 4019, 4004, 4256, 4206, 4115, 4146, 4098, 4208, 4202, 4077, 4139, 3819, 4197, 4112, 4082, 4096, 4123, 4186, 4242, 3938, 3958, 3854, 4033, 3863, 4125, 3973, 4049, 4200, 4256, 4168, 3976, 4109, 3891, 4326, 3963, 4095, 3989, 4003, 3975, 4060, 3839, 4141, 4158, 3988, 4027, 3942, 4172, 3919, 3789, 4114, 3849, 4044, 4072, 4189, 4027, 3988, 4126, 4168, 4252, 3919, 4101, 4337, 4444, 4213, 4265, 4097, 4241, 4310, 4159, 3999, 3960, 4176, 4212, 4061, 4151, 4209, 3865, 4062, 4143, 4250, 4240, 3844, 3949, 4000, 4163, 3924, 4031, 4240, 3901, 4130, 4081, 3980, 4027, 4228, 4179, 4012, 4004, 4040, 4259, 3998, 4100, 4036, 4036, 4179, 3997, 4013, 3999, 4269, 3892, 4237, 3970, 4001, 4144, 3987, 4286, 4028, 3876, 4163, 4167, 4266, 4089, 3886, 3843, 4096, 4022, 4139, 3774, 3958, 4185, 3968, 3734, 3858, 3944, 3847, 3897, 4437, 3900, 4063, 4092, 4064, 4184, 4036, 3915, 4042, 4022, 4221, 4130, 3789, 4108, 4215, 4273, 3804, 3838, 3820, 4098, 4179, 3893, 4165, 3959, 4077, 4066, 3950, 4334, 4204, 3915, 3767, 4120, 4262, 4153, 3926, 4022, 3947, 4106, 4003, 3883, 3666, }; +int32_t to_patch_embedding_layer_norm1_bias[400] = {-181, -150, -345, -240, -156, -149, -228, -310, -125, -193, -139, -95, -144, -184, -125, -137, -225, -204, -98, -170, -13, -175, -169, -127, -341, -168, -8, -182, -261, -380, -104, -230, -161, -206, -269, -152, -96, -4, -246, -37, -138, -182, -33, -64, 9, -50, -201, 66, 108, 50, 51, -30, 117, 88, 32, 40, 5, 73, 92, 7, -126, -116, 87, 86, 78, -51, -135, 5, 48, -15, -3, -54, -132, 77, -78, 44, -12, -133, -116, -105, 60, -27, -108, -166, -119, -68, -6, -132, -102, -68, 29, 94, -23, 58, -51, -35, -61, -28, 4, -114, -232, 9, -89, 23, -29, 46, -44, -122, 78, -82, 53, -36, 47, 62, -86, 50, 35, 90, 5, -70, 69, 105, 3, 113, -38, 42, -69, 2, 131, -44, 53, -59, -18, -111, -97, -18, -91, 9, -97, -53, -121, -103, -6, 42, -30, -55, -39, -11, 121, 8, -32, -27, 20, -58, 54, -76, -13, -34, -80, 83, -37, -57, -59, -4, 42, 97, -90, -39, 19, -59, 44, -68, 115, 80, -65, 13, 54, -46, 109, -21, -47, 11, -23, 136, 56, -34, -30, -40, -29, 47, -71, -89, -16, 112, -95, -71, -114, -57, 79, -70, -81, -76, -106, -18, -53, -66, -53, -52, -116, -127, -50, -104, -70, -36, 41, -56, -110, 104, -62, 132, -40, -73, -54, -24, -21, 37, -40, -59, -3, -65, -28, -87, -69, -37, 83, 40, -38, -35, -61, 59, -59, -72, -92, 118, -4, 36, 29, 133, -64, 135, 9, -33, 69, -76, 74, -28, 52, 68, 108, 95, -77, 156, 191, 69, 130, -58, 88, 141, -12, 89, -39, 256, 158, -6, 61, -118, 75, -15, -21, 99, -115, 205, -21, 50, 121, -88, 110, -40, -19, -30, -57, 110, 140, 152, -37, -56, 123, 128, 151, 87, 53, 95, -35, 89, 98, 91, 154, 25, 83, 6, 145, 102, 99, 186, -14, 51, 39, 103, 124, 140, 114, 130, 81, 120, 157, 129, 160, 152, 169, 144, 111, 104, 51, 11, 43, 156, 74, 234, 13, 193, 130, -45, 159, -14, 102, 205, 125, 137, 43, 169, 306, 142, 87, 182, 136, 216, 166, 198, 142, 88, 233, 165, 195, 49, 192, 104, 37, 200, 17, 189, 36, 134, 192, 224, 76, 272, 170, 180, 146, 85, 130, 69, 189, 142, 163, 142, 111, 130, 251, 186, -30, 128, 149, 264, 144, 72, 200, 147, 131, 210, }; +int32_t to_patch_embedding_linear_weight[6400] = {-173, 179, -273, -237, 19, 323, 124, -8, -4, -42, 39, -70, -3, -226, 215, -34, -120, 218, -189, -275, 21, -86, 42, 92, 209, -149, 196, 180, 164, -87, 49, 54, -54, 66, -83, 102, 32, 118, 140, -60, -96, -33, -165, -97, -141, -163, 34, 208, -214, 108, 22, -126, 151, -120, -195, 88, 21, 35, 157, -22, -12, -191, 82, 89, 183, 252, 17, -22, 206, -29, 22, 57, 40, -82, -285, 98, 46, 52, -16, 165, -125, 181, -157, -105, -129, 329, -88, 193, 218, -133, -27, 85, 294, -133, -127, -40, 114, 68, 18, -162, -98, 166, -117, -18, 74, 59, 92, -40, 56, -200, 122, -163, 199, -62, -49, 106, -136, 184, 136, -64, 52, -164, -255, 115, -58, 162, 245, -40, 34, -19, -127, -342, -173, 220, -44, 171, 124, -198, -144, -127, 27, 219, 7, -176, 314, -18, -43, 69, 75, 138, -23, 118, 163, -35, 69, 100, 208, 65, 126, 149, 100, 210, -48, -106, 9, 41, 43, -3, 43, -297, -324, -96, -51, 47, 126, 5, 116, 360, -299, -36, -50, 148, -155, 242, 64, -130, 69, -48, 210, -165, 54, 142, -59, 101, -64, -264, 80, -13, -111, 223, -145, -159, 47, -87, 141, 196, 57, -183, -11, 300, -304, -50, -157, 122, 34, -19, -83, -170, 70, -41, 12, -44, -60, -122, -85, 69, 38, -107, -205, -58, -122, 100, 155, -300, -175, -11, 326, 120, 131, -174, 152, 104, -46, -72, 122, -19, -161, 138, 61, -76, -343, -88, 176, -103, 148, -188, -129, 282, 65, -34, -61, 91, 111, 38, 114, -19, 95, 50, 206, -33, -113, 81, 323, -45, -34, -164, -122, 253, 186, 102, -5, -244, 88, 181, -58, 195, -30, -18, 155, 107, -108, -267, 72, -23, 125, 65, -204, -254, -238, 96, 159, 228, 71, 13, 223, 3, -192, -176, -65, -151, -115, 213, 122, 8, -130, 66, 144, 208, 63, -140, 193, -90, 104, -189, -59, -146, -39, -185, 172, 138, -264, -217, -88, 39, 39, 42, -61, 194, 123, -57, 156, 0, -172, -132, -221, -197, -165, 80, 110, -95, 50, 52, 244, 41, -58, -107, 145, 203, 212, 204, 112, -91, 45, -22, -26, -51, 34, -152, -205, 239, -88, -122, 203, -85, -69, -43, -190, -202, -248, 7, 189, 103, 137, 133, -63, 42, -115, 68, 129, 184, -192, 176, -118, 86, -1, 90, 210, 37, -40, 135, -45, -164, -175, 70, 283, 232, -219, -81, 66, -85, -171, 40, -67, 310, 164, -66, 32, -64, -64, -52, 172, -128, -229, -156, -273, 208, -107, -196, -176, 355, 43, -19, 48, 155, 74, -145, -28, -83, -128, 15, -101, -37, -54, 103, 278, 194, 154, -161, -342, 8, -187, -34, -149, 175, -73, -153, -1, -303, -197, -180, -29, -75, 9, -157, -75, 157, -66, -130, 112, -68, -26, 10, 117, 138, -104, -189, -81, 38, 138, 149, -52, -30, 110, -93, 153, -62, -116, 189, -67, -67, -94, -94, 17, 45, 122, -158, 177, 166, 101, 105, 52, 140, -115, -7, -184, -85, -249, 98, 19, 233, -100, 198, -165, 6, -73, -183, -133, 196, -146, 231, 42, -266, 70, -104, 50, -80, 281, -171, -331, -9, 168, -98, 177, 201, -234, -103, 79, -96, 112, -38, 170, 36, -86, 201, -132, 137, -9, 34, 105, 75, -234, -69, -34, -193, 78, -236, 205, -169, 96, -48, -191, 55, -261, -52, -100, -15, -261, 24, -68, -304, -137, -296, 240, -164, 185, -182, -111, -93, 149, -194, 264, -46, -231, -16, 168, 36, -202, -47, -68, -22, 69, -129, -157, -118, 251, 40, 0, 89, -44, 117, -149, -10, -241, 89, -199, -124, -32, 146, -178, 157, 64, -285, 11, 38, -75, -46, -83, -75, 159, 32, -141, 42, 196, -159, 43, -164, -143, -6, 23, -149, -263, -75, -223, -44, 15, -220, 94, 86, -157, 104, -62, 74, -249, -46, -210, 4, -253, 126, 104, 32, 60, 64, 266, -67, -87, 149, -87, 222, 24, 66, -40, 215, -20, 143, -77, 1, -33, 165, -16, -109, 49, -142, -4, -9, 154, 163, 9, -198, -177, 40, -27, 102, 171, -158, 128, 122, 203, -8, -163, -18, -20, -102, 190, 137, 37, -143, -97, 71, 0, 49, -174, -31, -124, -165, 106, 93, 123, -117, 44, -250, -306, 72, -93, 193, -33, -62, -94, 208, 88, 271, -74, -127, 237, -187, -189, -22, 68, 219, -145, 54, 153, 185, -118, -157, 52, -40, -169, 107, -163, 117, 10, 109, -303, -33, 179, 35, 63, 2, 41, -167, -6, 46, -175, -94, 144, 195, 60, -2, -157, 185, -250, -49, -170, -204, -103, -32, -46, 163, -96, -232, -64, 206, 273, -166, -227, -127, -12, -14, -248, -98, -145, 440, -51, 48, 212, -426, 140, 275, 314, -190, -270, -342, -139, 95, -110, 298, -114, -93, 16, 253, 150, -110, 390, 282, 180, -162, 121, 90, -170, 72, -83, 150, -353, -119, -5, 341, -89, 100, 61, 58, 1, 58, -203, -85, -28, 174, -126, -44, -31, -18, 12, 170, -88, -354, 326, 19, -1, -223, -124, -175, -270, 43, -54, 73, -345, 90, 19, 171, -40, -251, 332, 245, 259, -14, -85, -418, -299, 125, -324, 123, -124, 475, 153, 349, 205, -154, 290, 37, 45, -230, -81, -178, -215, 335, 40, 230, -357, 310, -126, 269, 58, -334, 131, 101, 254, -141, -235, 7, -240, 30, 35, -22, -147, 183, -16, 22, -100, -138, 154, -4, -158, 46, 154, -301, -147, -85, 155, -97, -275, 68, 84, 160, 151, -319, 105, 230, -179, -41, -105, -23, -445, 463, -29, -24, -255, 53, -256, 349, -126, -481, 341, 224, 239, -322, -302, -98, -143, 170, -279, 78, -369, 124, 106, 379, -65, -202, 393, 148, -31, 25, -257, -260, -217, 80, 35, 119, 1, 191, -242, 87, 342, 19, -120, -80, 241, -29, -76, -314, 1, -125, -219, 76, -167, 65, 3, 281, 24, -17, 22, -131, 295, -81, 80, -116, -56, -51, 148, -231, 80, 232, 28, 74, -219, -231, 383, 165, 165, -122, -124, 66, -237, 357, 1, 318, -54, 391, -175, 353, -331, -405, 247, 40, -27, -38, 86, -286, -118, 306, -253, 235, -210, 153, -77, 158, -217, -229, 177, 345, 145, 66, 29, -100, 30, 78, -155, 115, -13, 193, -136, 250, -6, -98, -10, -90, 112, 25, -141, -107, 71, -27, -156, 101, -137, 5, 65, 45, 23, -100, -15, -24, 151, 161, 80, -155, 250, -107, 40, -82, 127, 201, -110, 26, -257, 22, 154, -109, -13, -108, 95, -81, 14, -46, -278, 45, -130, 132, 94, 205, -57, -65, -42, 120, 273, 174, -8, -103, -170, 201, -323, 24, -205, 274, 49, 151, 39, -38, 43, 139, -92, -239, -203, 160, -41, -99, -9, -33, 89, 311, 125, 136, 31, -311, 64, 44, 168, -124, -45, 97, 155, 131, 33, 90, 211, 229, 155, 51, -27, 61, -229, -16, -166, 13, 256, -85, -69, -208, -125, 31, -174, 134, 266, 51, -182, 87, 98, -266, -75, 140, -39, -21, -70, 52, -230, -159, -113, -47, -17, -114, -101, -52, 216, -70, 88, -134, -306, -153, -56, 27, -294, 195, -114, -30, 17, 167, -14, 154, -62, -187, -246, 256, -154, 116, 76, 62, -133, -302, 237, 212, -25, 55, -65, -402, -140, 271, -144, -256, -117, -135, -160, 174, -27, -30, 193, 6, -118, 217, -177, -111, -148, 80, -6, 259, 249, -190, 226, -5, -133, -272, 180, 218, -133, -196, 200, 226, -8, -30, -163, 76, 271, 195, 28, -218, 44, 77, 153, 74, 48, -100, -69, 501, -408, -465, 15, 212, -400, 14, 196, -245, -36, 65, 7, 236, 267, -91, 228, 215, -49, -24, -133, 233, -121, -180, 13, -63, -266, -171, 79, -208, 52, 177, -430, -222, 51, 204, -65, -151, -83, -96, -124, -120, -276, 54, 20, -160, 204, 288, -350, -181, 14, 63, 4, 167, 200, -82, -104, 226, 167, 58, -47, 82, 47, -166, -114, 227, -217, -307, -342, 222, 88, 57, -26, -61, -30, -53, -52, -155, -46, -169, -263, 489, -78, -174, -117, 383, -120, 50, 350, -197, 5, -40, 220, 18, 138, -250, 479, 66, 91, 121, 70, -38, -25, -30, -128, -78, 73, -39, 63, -19, 154, -88, -254, -90, 150, 1, 76, 259, -271, -83, -86, -10, -77, 83, 26, -49, 158, 224, 26, -21, 24, 17, 192, 107, 280, -337, 91, 375, -147, -155, -224, -165, -25, -18, -204, 212, -191, -97, -198, 85, 42, 76, 17, -292, -19, -2, 200, -220, -81, -147, -412, -87, -45, -146, -28, 143, -206, -67, -32, -85, 79, -225, -57, 76, -78, -115, 60, 154, -159, 163, 197, 167, 25, -344, 67, -24, -36, 85, -298, 166, -209, 124, 37, -245, 222, 171, 153, 54, -143, -48, -53, -84, -41, 16, -193, 74, 24, 219, -78, -13, 146, -6, 208, -32, 214, -190, 217, 162, -32, -131, -246, -68, -163, 222, -219, 165, 113, 174, -198, -126, -21, -27, 59, 124, -165, -183, 62, -260, 93, -123, -66, -362, 349, 167, -79, -255, -165, 16, -249, 33, 64, 43, -281, 10, -295, -2, 114, 271, -300, 76, 156, 292, -146, 162, 49, -186, -123, -62, 163, 73, 95, 59, 235, -148, 48, -140, 236, 97, -293, -12, 213, -230, -266, 156, 192, 276, 206, 31, -149, 29, -84, -82, -16, 49, 87, 135, 290, -181, -121, 63, 111, -260, -131, 101, 26, 74, 57, 72, -166, -134, 33, 39, -144, 0, 29, -231, -93, 87, 282, -4, -401, 100, 293, 217, 146, -40, -168, -61, -19, 226, 46, -57, 102, 333, -213, 181, -159, 239, -167, -189, 68, 373, -270, 205, 287, -244, 29, -164, 117, -246, 236, -212, 191, 133, -31, -190, -13, 239, -67, 220, 9, -57, -230, 85, 21, 102, 158, 50, 21, 90, 140, 147, 179, 182, -65, -162, 18, 153, -103, 49, 35, -204, -94, 168, -32, -55, -69, 91, 159, -65, 94, -53, 120, -176, 102, -170, -28, 133, 1, 56, -181, -32, 260, -114, 138, -22, -412, 55, -106, -82, -166, -37, -256, 34, -222, 168, -79, -8, -54, -122, 176, 189, -242, -8, 38, 64, -132, 33, 120, -83, -122, 99, -103, -323, 256, 184, 90, -276, 51, -46, -42, 340, -145, -1, -42, -80, 58, 125, -53, 105, 32, 89, 142, -101, 132, 125, 208, 193, 137, 56, -238, -12, -205, 13, -169, -97, -30, 51, -269, 97, -141, -90, 231, -266, 191, -113, 86, -21, -72, -97, 99, -110, 180, -232, 98, 177, -208, -84, -86, -46, -61, 148, -49, 320, -32, 227, -334, 98, 88, 35, 38, 46, -360, -176, 73, -91, -121, -146, 9, 22, 75, 256, -42, -285, 346, 241, 81, -69, -89, -5, -386, 219, 218, -77, -171, 98, -226, 204, 97, -33, -112, 152, 152, 34, 66, 119, -155, -199, 43, 130, -137, -44, -96, 82, -288, -136, 180, 67, 58, 240, -51, -101, 89, 76, -165, -18, 136, 163, 147, 207, -95, -269, 174, 176, -33, 7, -154, 34, 31, 75, -125, -131, 170, 93, -5, 4, -255, -115, 28, -94, -301, 115, -40, 222, 64, -253, 17, -361, 297, -179, 34, -122, -332, -498, 281, 146, 81, -278, -275, -391, -361, 191, 223, -101, -58, 252, -214, 112, 303, -63, 104, 77, 83, -6, 261, 69, -349, 239, 101, 17, -165, -216, -167, -42, 214, -158, 43, -76, 196, -192, -289, -128, -184, 198, -114, 185, -211, 175, 193, -2, 42, 261, -80, -165, 59, -100, -91, -102, -10, 96, -207, -315, -50, 122, 73, 68, 25, 283, 43, 53, -269, 315, -203, 78, 271, -252, 254, -237, 276, -168, -30, -139, 91, -524, 353, 229, 57, -60, -142, -120, -139, 219, -241, 245, -152, 68, 18, 123, -110, -320, 281, 100, 94, -293, 137, 79, -199, 243, -207, 369, -253, 46, -218, -91, -102, -115, -243, -60, 208, 198, -75, 57, 190, 198, -45, -201, -9, -41, 151, 98, -128, -259, 201, -44, 148, -109, 113, -111, 66, 174, -262, 215, -231, 232, -61, 174, -299, 182, -137, -75, 8, 164, 17, 133, -65, -230, -86, -109, 27, -206, 6, 41, 46, -317, 478, 341, 236, -222, 232, -178, -364, 430, -294, 250, -320, -201, -10, 23, 124, 308, 72, -229, -361, 21, 459, 86, -109, -87, 81, 121, -40, -47, -2, -456, 50, 43, -181, 18, 150, -103, -124, 83, -96, 62, 188, -96, 53, -207, -160, -115, -81, -9, 272, -59, -43, 28, -176, 19, 103, 20, -150, -92, -52, 106, -100, 250, 2, -92, -80, -190, -220, -14, 237, -166, -25, -163, 175, -183, 239, -42, -23, 4, 439, -583, 218, 202, 110, -80, 443, -129, -302, 113, 154, -186, -221, -109, 8, -34, 41, 227, -91, -144, -77, 59, 159, 269, -36, 78, 290, -352, 152, -351, -88, -82, 261, -65, -69, 73, -90, 173, 403, 191, 157, -55, -106, -167, -20, -267, 102, -97, -53, 276, -127, -53, -155, 159, -99, -71, 90, -168, 150, -247, -75, 80, -235, -60, -57, 24, 17, -178, 96, 71, 187, 101, -97, 66, 192, -313, 211, -257, -349, -104, 251, 110, 38, 214, 378, -169, 154, 88, 233, 114, 34, -13, 48, -105, -173, -229, 30, 70, -119, -12, -167, 240, 139, -86, 214, -45, 185, -14, 325, -8, 240, -272, 183, 148, -4, 8, -260, -30, 75, -113, 3, -142, 35, -289, 2, -163, -137, 0, -361, 155, 6, -194, -268, 359, 145, -108, 299, -257, 134, -44, 273, -23, -218, -84, 36, 385, -189, -269, -151, -45, 27, 114, 125, 148, 136, -150, 91, -251, -310, 188, -184, 115, -332, -88, -139, 89, 200, 274, 301, 15, 14, -16, 122, 6, -111, -399, -73, 356, -280, -103, -216, 119, -56, 158, 364, -175, 40, -239, 365, -225, 284, -136, 81, 12, 67, 9, 22, 157, -28, 240, 102, 167, -27, -290, 261, -138, 166, -265, -110, 114, 7, 252, -175, -84, 137, -44, -19, 41, -277, 21, 82, 209, 21, -140, -231, 378, -54, -203, -112, 365, 29, 221, 160, -320, 52, 3, 364, 115, -10, -74, -104, 274, -264, -235, -243, 104, -48, 357, 191, -34, -95, 98, -56, -223, -225, -131, -64, 69, -95, -44, -1, -155, -94, 0, 318, -249, -150, -84, -4, 4, -182, 109, -28, 162, 27, 105, -15, -50, -9, 50, 83, -335, 142, -197, 150, 11, -19, -5, 65, -415, 220, 342, 294, -116, 23, -71, -63, 87, -228, -17, 80, -44, -340, 242, 32, 191, 211, 127, -160, -160, 37, -133, 135, 88, 79, -59, -25, -39, -188, -78, -119, 0, 16, -201, -128, -22, 51, 205, 203, -251, 55, -68, 139, -213, 57, -194, 89, 143, -474, -147, -11, 215, -80, 10, 483, -289, -150, -102, 402, -64, 199, 92, 89, 74, -32, -19, -82, -39, 30, 315, 160, -190, 46, -287, -29, -401, -124, -363, 145, 379, -251, -80, -198, 123, 64, 200, 139, -314, 131, -168, 274, -175, -17, -56, 74, -237, 399, -4, 77, -194, -69, -225, -175, 220, 88, -68, -72, 189, -183, 57, -90, 104, 45, 77, 23, -30, 34, 245, 32, -195, -78, 9, -6, 126, -20, -48, 129, -4, -185, -77, -126, 106, 235, 104, 426, 31, 20, -284, -41, 172, -66, -98, 84, 373, -314, -14, -207, 90, -31, 359, 299, -430, -48, -280, 430, -229, 122, -257, 16, 360, -122, -226, -7, 332, 2, -61, 393, -208, 48, -257, -4, 70, -135, -152, 30, -188, -33, 162, 90, 24, 89, -147, 123, 221, -219, 105, -231, 67, -141, 68, -151, -95, 78, 152, -117, 5, 78, -312, 72, -86, 77, 102, 46, -7, 93, 209, -19, 123, -276, 218, 63, 184, -116, 13, 302, -95, -30, -169, 141, 71, -137, -58, 291, 356, -220, -165, -56, 144, 298, 156, 262, -250, -88, 33, 444, -421, 74, -504, 153, 59, -3, -20, -179, 58, -266, -160, 256, -217, -209, 60, -26, 64, 190, 11, -116, -36, 5, 18, 100, -111, -164, -197, 136, -5, 32, 19, -13, 28, -95, 201, -166, -177, -132, 273, 45, 60, 41, -72, -60, 64, -261, 165, 44, 86, 152, 205, 64, 371, -359, 1, 235, 109, 66, 54, 102, -121, 97, 71, 202, 22, -268, -198, 94, 123, -164, -106, -264, 18, 307, -108, -5, -209, 149, 279, -20, -235, 312, -34, -47, -77, 0, -136, -78, -73, 262, 133, 90, -191, 18, 17, 210, 84, 227, 0, -135, 138, -106, -124, -26, -125, 0, 123, 135, 60, 185, -230, 295, -524, -214, -158, -99, -137, 201, 84, -204, -170, 151, -142, -41, 94, -43, 135, -121, 274, -3, -114, 36, -194, -89, 140, 161, 3, 147, 38, 239, -238, -30, 91, 114, -197, 126, -186, -83, -100, 128, 198, 10, -154, 57, 48, -232, 155, -210, 348, 37, -83, -130, -85, 3, 15, -13, -307, -138, -28, 48, -28, 58, -26, 26, 177, -27, 61, -100, 91, -81, 434, -211, -47, -101, 42, -92, -68, -6, -324, 270, -162, 296, -227, -208, -115, 26, -97, 159, -142, -114, 60, 108, 189, 158, 109, -63, -39, -165, -80, -222, -97, -22, -105, 108, 83, 76, -43, 116, -48, 177, 195, 237, -73, -95, -361, 154, -186, 185, 38, -54, -88, 10, -34, 191, 225, 53, 14, -63, 183, 41, -166, -26, -154, 45, -300, 267, 65, 196, -13, -244, -54, 60, 221, 162, 1, -144, 358, 5, 242, -241, -56, 207, -172, 68, 226, -44, 24, -149, -174, 293, -346, 218, -298, -73, 68, 197, -24, -127, -47, -77, 65, 35, -150, 139, -218, -55, -267, -30, -107, 182, 166, 103, 121, -172, 160, -121, 90, 19, -86, 153, 210, -88, -188, 51, -277, -198, -20, 107, 23, -304, -154, -166, -35, -32, 35, 266, -42, -243, -176, 223, -282, -49, -382, 12, -90, 60, 228, 25, -65, 61, 113, -115, 55, -10, 54, -67, -20, -88, 110, 46, -367, 416, 400, -84, -2, 160, -258, -325, 301, -10, -93, -286, 42, -435, 8, -1, -31, 6, 241, 89, -97, 122, 81, 21, -3, -101, -77, -297, -110, 68, -92, -46, 317, -59, -308, -152, 72, 253, 332, 231, -370, 15, 13, 413, -143, -71, -169, -17, 15, -217, 82, -70, -75, 277, -13, -59, 68, 165, -80, 260, -12, 172, -332, -350, 72, -90, -24, -114, 169, 108, 121, 190, 57, -26, -83, 4, 24, -317, -132, -5, -94, 456, 278, 57, -108, 35, -43, -176, 158, 372, -98, -339, -270, -190, -220, 220, 290, -266, -206, -64, -41, -141, -117, -18, -327, 96, -117, 106, -8, 17, 100, -139, 105, -455, -354, -210, 78, 110, 56, 276, -312, 151, -78, 387, -14, -96, -422, -140, 133, -50, 140, -109, -171, -22, 50, 131, 101, -48, 310, -29, 42, 45, -193, -239, -20, 274, -98, 229, 16, 142, -100, 43, 119, 165, 73, -83, 11, -413, 54, 63, 211, -158, 59, -197, 63, 243, 88, -8, -228, 401, -273, 69, -212, -14, -167, 128, 104, -152, -365, -98, 67, -117, 348, 124, -12, -7, -115, 193, -123, 6, -279, -49, 371, -328, -340, -126, -28, 241, 98, 101, -317, 155, -108, 176, -166, 36, -494, 69, 296, -345, -282, 43, 121, 113, 189, 402, -338, -142, -49, 193, -279, 156, -75, -254, -118, 218, 151, 28, -95, 72, -197, -206, 52, 172, 363, -26, -153, 25, -257, 82, 293, -72, 128, -227, -135, 87, 50, -101, -80, 328, -90, 131, 54, 92, -325, 197, 148, -329, -25, 24, -202, 37, 94, 128, -156, -284, 189, 109, -138, -28, -158, 195, 389, -373, -160, -15, 81, 223, 308, 210, -183, 184, 31, 121, -50, -15, -287, 40, 178, -461, -201, -28, 359, 280, 143, 228, -155, -85, 10, 138, -297, 140, -414, 76, 121, 100, 132, -226, 53, 187, 41, -145, -142, 149, 124, 178, -328, -72, -207, 254, 117, -233, -1, -44, -131, 0, 91, 139, -113, 82, -35, 239, -93, 22, -172, 317, 107, 120, 29, -158, -129, -363, 110, 238, 111, 86, -159, 13, -36, 112, 67, 137, 271, -191, -127, -218, -76, 131, -7, 28, -30, -10, 143, -40, -217, -167, -362, -212, -35, -280, -203, 9, 221, 117, -52, 348, -83, -29, -257, 110, -330, 154, -171, -99, 372, -146, -231, -457, 200, 320, 151, 235, -105, 369, 82, 301, -280, 91, -390, -142, 178, 65, -95, 5, 228, 101, 162, 45, 51, 64, -12, 202, 1, -138, -181, 271, -188, -175, 102, 25, 92, -81, 132, -26, -217, 108, -95, 96, -115, -100, -88, -336, 221, -319, -213, -399, 80, 195, 165, 154, 110, 179, 17, 312, -418, -147, -353, 73, 104, -59, -130, -276, 197, 170, -42, 151, 65, 319, 122, 107, -27, 244, -101, -101, 165, -72, -248, -237, -230, 185, 263, 225, -225, 107, 175, 122, 234, -21, -6, -112, -116, 186, 66, -152, -70, -73, 59, -40, 77, -26, -228, -141, 197, -200, 22, 41, -17, -158, 162, -35, 75, 268, 198, 96, 15, 10, 19, 77, -156, 0, -277, -40, 486, -302, -359, -201, 349, 285, 301, 149, -104, 132, -256, 260, -178, -151, -475, -6, 14, -81, 39, -108, -159, 175, -164, 180, 242, -90, -30, 51, -215, 146, 225, 136, 305, -45, -111, -49, 18, 297, 122, 156, -326, -197, -3, 9, 112, 153, -334, 221, -196, -97, 19, -54, -199, -92, 28, -179, -105, -139, 230, -6, 115, -143, -102, -91, 214, -42, 27, -321, -40, 145, 39, -141, 114, -57, -287, 173, 67, -16, -158, -106, 130, -286, -393, -191, 211, 196, 80, 368, -338, -79, -141, 334, 200, 79, -316, -64, 140, -64, 39, -114, 115, 17, -46, 186, -127, 37, 16, -3, -230, 5, 38, 384, 210, -360, -255, 155, 28, 149, 289, 69, -72, -25, -139, 53, -119, 69, -83, 180, 164, -118, -107, -100, -55, 27, 150, 260, 75, 29, -262, -100, -193, -31, 12, 25, 5, 179, 100, 23, -3, 35, 160, 25, 192, 102, -65, -182, -234, 50, -113, 131, -24, -270, -163, 4, 88, 155, 223, 160, -171, 95, -280, 391, -28, -301, -172, -64, 275, -202, -35, -20, 356, -15, -35, 167, -57, 112, -197, 280, -325, -75, -119, 196, 110, -320, -116, 93, 130, -43, 67, 171, -38, 84, 61, 99, 22, 56, -33, -264, 362, -250, -96, 32, 139, -72, 209, 81, -76, 176, -76, 43, -213, -136, -201, -173, 126, -21, -62, -246, -105, 381, 339, 94, -111, 243, 153, 13, -227, -181, 159, 253, 200, -48, 0, -202, -34, 181, 196, 92, -296, 161, -256, 269, -277, 171, -192, 23, 301, -61, -135, -137, 291, 358, 303, 67, -183, 118, -82, 50, -280, -6, -223, 40, 206, -160, -160, -159, 85, 233, -9, 155, -173, 96, 165, 57, -149, 117, -173, 107, -33, 202, 202, 223, 95, 338, 73, -246, 264, 113, -75, -230, -321, -208, 168, 94, 74, -58, 105, -49, 220, 209, -154, 124, 15, 184, 50, -29, 0, -85, -54, -192, -93, -369, -252, -199, 30, 15, 9, -55, -229, 88, 334, 188, -104, 101, 53, 39, 215, -312, -153, -124, 8, 216, 67, 72, -13, 113, -342, 285, -68, 150, -222, -1, 209, 0, -58, -194, 187, 81, -62, 269, -203, 161, -5, 150, 77, 127, -46, 268, 90, -54, -4, -31, -275, 253, 69, -284, 149, -111, 81, -262, -212, -277, -111, 57, 242, -188, 55, -217, -20, 432, 154, 21, 69, 207, 94, 166, 78, -71, -181, 45, 64, -198, -40, -179, 71, 71, 28, 56, -262, 158, 358, -158, -103, 87, -199, -118, 284, -308, -174, 178, 155, 165, 13, 157, -88, 150, -139, 121, -132, 50, -151, -59, 4, 151, -14, -199, -174, 185, 94, -71, 24, 29, 117, 56, 354, -244, -10, 229, -70, -94, -13, 351, 202, -13, -128, 57, -77, -121, 6, 21, -139, 142, -159, 111, 73, 24, -14, -54, 78, 95, -85, 4, -64, -97, 97, -202, 87, 123, 190, -37, -172, 18, 51, -176, -335, 147, 66, 130, -1, 227, 143, -11, -2, 101, -187, 146, -114, 87, 39, -118, -8, 209, -37, 90, 231, 82, 73, -115, -153, 63, -179, -111, 83, -130, -356, 146, 181, 22, 119, 142, -15, 169, -225, -42, 233, 59, -204, 183, 59, -15, 36, 162, -141, 55, -29, -260, 33, -13, 144, -190, -27, -21, 120, 287, -74, 152, -86, 78, -42, 76, 138, -22, 8, 153, 300, -6, -67, 126, -88, 98, 312, -59, -312, -30, 25, 233, -18, 79, -263, -144, -15, 154, 203, 75, -291, 202, -62, 48, 117, 19, -274, 174, -188, -268, 298, 277, 209, -63, -146, -319, -5, -188, 126, -221, -115, 158, -140, 43, 85, -32, -154, 3, 213, 105, 308, 256, -119, 171, -236, -139, -171, 117, -19, -34, -168, 2, -23, -100, -250, -166, 41, -158, -119, -101, 82, -64, -256, -25, -53, 151, 224, -231, -47, 26, 66, 188, 58, 129, 122, -23, 91, -25, -150, -230, 208, 141, -34, 28, -50, 8, 117, 139, -77, 205, -213, 199, -122, 142, 344, -213, -477, 44, -117, -107, 351, 311, 112, -84, 274, -355, 80, 112, -149, -61, -85, 1, -15, -141, 38, 292, -82, -4, 155, 88, 132, -10, -35, -31, -260, 206, 62, 186, -90, 25, 79, -196, 204, -62, 173, -12, 208, -158, -21, -172, 49, 3, -109, -85, 230, -51, 28, 245, -202, 70, -349, 122, -185, -26, -309, -254, -66, -133, 221, 29, -225, -109, -199, 101, 93, 145, 26, -64, -161, -135, 181, -16, -49, 286, 177, 106, -210, 40, -241, 8, 169, -32, 25, -150, -5, 46, -62, 271, -250, 130, 143, 204, 43, 81, -49, -102, -63, -26, 247, -58, 200, 0, -27, 46, 30, 202, 169, -111, -164, 57, -53, -227, -117, -74, -93, -78, 77, 50, 201, -191, 68, -183, -165, -48, 124, 98, 306, 16, -177, 89, -181, -102, -204, 290, -186, -46, -93, 176, 314, 167, -110, -32, -194, 89, 145, 314, -154, -78, 292, -96, 93, -127, -128, 133, -108, -139, -44, 238, 53, -127, 126, 329, 116, 112, -173, -233, -124, 133, -1, -199, -60, 204, -55, 170, 168, -62, -45, 149, 129, 229, -75, -126, -154, 233, -119, 41, 44, 183, -121, 195, 149, 30, 61, -137, -69, 6, -264, 129, -98, 207, 172, -14, -390, -341, 199, 155, -71, -174, -121, 149, -37, 189, -1, -42, -122, -18, -104, 89, 103, -142, -89, 173, 146, -169, 136, -102, -165, 30, -106, -49, -108, -216, -81, 109, 6, -142, 203, 285, -38, -31, -183, 133, -3, -155, -158, -21, -24, 143, -108, -291, -209, -15, 87, 261, 215, 86, -236, -149, -38, -169, 1, -142, -216, 184, -155, -94, -141, 49, 77, 136, 66, 84, 159, -90, 176, -48, 0, -5, -87, 5, 104, -71, -335, -131, -157, -118, -98, 228, -164, 207, -202, -3, -5, 72, -256, -40, 22, 99, -172, -9, -471, 278, -10, -7, 19, 138, -242, -47, -152, -217, -51, -124, 422, -351, -51, -336, 146, 16, -11, 21, -222, 19, -233, -8, -186, 57, -116, 224, 16, -151, -174, -6, 155, -101, 320, 73, -71, -186, 145, 213, -120, 186, -234, 31, -97, -10, 225, -79, -265, 166, -133, -207, -18, -20, 122, -18, -246, 138, 90, 38, -4, -256, 27, -292, -134, -31, 45, 209, -245, 132, -374, 254, -310, -108, -247, 48, -23, 143, 116, -200, -177, 352, 144, 1, 262, 166, 50, -192, -14, -309, 47, -68, 289, -185, -5, -199, 240, 175, 231, 73, -280, 101, -464, 322, -410, 190, -127, 28, -21, 9, -92, 8, 117, -134, -10, 72, -263, -322, 74, -177, -134, 80, -199, 59, -81, 112, 49, 34, -46, -68, -201, -39, 337, -11, -98, -237, -155, 69, 89, -333, 338, 88, -36, -408, -90, -64, 91, 263, -41, 193, -123, -31, -338, -70, -49, 33, -535, 211, 351, 102, -468, 46, -232, -58, 603, 355, 330, -287, 270, -402, 232, 174, 223, -348, 66, 52, 5, 361, 139, 85, -128, 197, -240, -9, -195, 0, -370, 352, 178, -91, 6, 290, 156, -213, 184, 445, -149, -508, -32, 142, -21, -9, -368, 46, 240, 89, -16, -96, 169, -51, 242, -148, -153, 149, 49, 97, -294, 101, 18, -200, 216, -23, 155, -278, -197, 75, 155, -115, -147, 199, 143, 138, -185, 154, -178, 64, -236, 351, 223, -163, -474, 286, 61, -160, 161, -24, 413, -508, -102, -111, 255, -81, -263, 122, 266, -42, -109, 147, -176, -156, 309, -23, 41, -10, 118, -188, -95, 160, -249, -205, -155, 148, -239, -47, 169, 143, 114, -217, 144, -132, 6, 101, 105, 104, 90, 51, -93, 30, -100, -111, -83, 223, -182, 112, 26, -18, -151, -174, -44, -168, 214, 59, 35, -195, -253, 186, 13, 13, 8, 452, 348, 23, -141, -89, -192, -102, -455, 283, -57, -122, -35, -16, -157, -178, 15, -39, 224, -405, 78, -185, 215, 258, -256, -224, -13, 28, 123, 41, 25, 81, 139, 139, -1, -148, -34, 141, 211, 276, -139, 20, 78, 126, 46, -196, -120, 39, -114, -157, 46, -228, 355, 35, 148, 162, -305, 13, 362, -86, -141, 23, 23, -188, 286, -84, 209, -302, 171, -331, 135, -128, 81, 99, 146, -104, -97, 35, 108, 91, -62, 118, 133, 108, -69, 107, -57, 144, -371, 115, 132, -3, 19, 211, -46, -164, -57, -56, 9, 73, 97, -138, -29, 61, 169, -32, -116, -29, 106, 96, -12, 111, -295, -52, 102, 106, 110, -3, -126, -163, -326, 365, 11, -57, -93, 141, -364, -193, 297, -18, 1, -147, 23, -113, 142, 58, -274, 343, 86, 115, -225, 6, -86, -73, 158, 129, 8, -191, 179, -54, 316, -83, -168, -165, -108, -90, -24, 2, 212, -131, -37, 183, -117, 140, 89, 241, 143, 98, -50, 34, 215, -61, -267, 317, -118, -151, -110, -68, 201, -60, -254, 94, -87, -113, 126, -12, 113, -126, -55, -44, 79, 175, 92, 205, 193, 215, 22, 92, -128, -326, -261, 297, 293, -21, 78, -36, -259, -81, 53, 205, 1, 41, -102, -152, 44, -119, 85, -68, 0, 56, 144, -16, -35, 154, -25, 207, -124, -20, -170, 40, -56, -114, 139, 221, -108, 123, -230, -131, 125, -33, 142, 55, 314, -130, -70, 192, 31, 254, -414, 223, -26, 169, -202, 98, 168, -21, 216, 96, 191, -22, -98, 98, 117, 182, 105, 197, -9, -38, -157, 97, 193, 85, -125, -227, 55, -21, 109, 6, -56, -223, -219, 291, 246, -140, -205, 43, -24, -255, 85, -136, 141, -36, -17, 14, 294, -236, 179, -27, 46, 48, 115, 170, 106, -17, -186, 259, -150, 18, -157, 64, 121, -190, -60, -182, 80, -66, -73, -67, -171, 196, -168, 119, 297, -150, 168, 323, -29, 127, -139, 114, 19, -65, -288, 233, 7, -25, 161, 126, 27, 101, -57, -101, 11, 257, -331, 220, 163, 101, -9, 157, -14, -317, 189, 48, 43, -189, -128, 145, -172, -141, -59, 278, 296, -82, 135, -62, -137, 104, 300, -95, 145, -32, 32, -271, 134, -59, 9, -23, -151, 186, 0, -11, -156, 103, 174, 81, 87, -188, -14, -304, 155, 135, 50, -32, 254, -160, -256, -228, -248, 128, 147, 117, 105, -16, 100, -105, 119, 57, -171, 158, 0, 30, -189, 110, 40, -201, 171, -39, -65, -9, 184, 245, 35, -114, -273, 398, 211, 29, -41, 37, -116, -156, 137, 31, 121, -376, -98, -137, 123, -87, -168, 41, -41, 7, -76, -25, 45, -136, -184, -139, -3, -18, 127, 179, 152, 116, -164, 76, -46, 150, -120, 123, -192, -195, 67, 97, -211, -8, -72, -251, 188, -24, -163, -98, 136, 153, 95, 54, -181, -162, 303, -117, 277, -89, -84, 129, 147, 25, -116, 262, -29, -118, -235, 177, -107, -59, 51, 296, 122, -5, 81, 81, 119, -15, -168, 267, 344, 30, -162, -61, -303, -192, 225, -135, 173, -13, 220, -257, 239, 53, -12, -110, -89, 82, 27, -382, -33, -183, 10, -72, -272, -146, -26, 55, 188, -172, -230, 12, -136, 65, -32, -61, -276, -140, 243, 102, -5, -94, 88, -92, 31, 102, -77, -81, 267, -31, -29, 40, -300, -150, 3, 136, 74, -181, 66, -192, -61, 110, -323, 293, 262, -129, -224, 226, -302, -135, 263, 103, -115, -44, 297, 166, -109, -54, 82, -80, 129, 6, 34, 23, -4, 32, -25, -180, 18, 43, 213, -139, -41, -18, 26, -208, -216, -66, 206, -457, 169, 131, -224, -110, -229, 268, 12, 14, -281, -3, 93, 13, -8, -136, -119, 245, 106, -42, 152, 293, -42, 100, 44, -127, 133, 256, -130, 22, 55, -56, -70, -225, -196, -108, 23, -37, 90, -191, 71, -51, -27, -99, -164, 311, 313, -217, 154, 109, -142, -82, 0, 142, 188, -134, -126, 167, 82, 192, -110, -25, 1, -134, 25, 0, -218, -273, -49, 49, 375, -155, -103, 144, 222, 109, 84, -100, -521, -101, 41, -353, 472, 73, -210, -83, -350, 379, -96, 40, -206, 165, -145, 163, -129, 7, -116, 47, -244, -5, 125, -155, 49, 69, 92, -129, 83, -60, 13, -43, 194, 138, -143, -3, 4, -58, -195, 3, -59, -104, 166, -1, -119, -207, 62, -146, 129, -85, 127, 5, 136, 228, -143, 102, -154, 151, -237, 213, -213, 6, -349, 112, 279, 183, -199, 87, -13, 65, -22, 88, -14, -188, 23, -356, 185, -154, 357, -301, -398, -191, 45, -155, 38, 5, -377, 3, -139, 119, 59, -26, -162, -40, -92, 157, 59, 9, -106, 50, -42, -24, 113, 388, 113, -179, 10, -89, 193, -42, -78, 20, 226, 220, 45, 199, 104, 105, -42, -89, 292, 20, 78, -98, 37, -227, 100, 49, 131, -95, 197, 85, -21, -108, -68, -127, 128, -67, 78, 41, -44, 72, -176, 22, 368, 15, -280, 57, -113, -61, 254, 76, 222, 41, 212, 10, 68, -194, 57, -214, -27, -135, -49, -200, -65, 46, 2, -172, 219, -65, 116, 167, 24, -94, 39, 210, 310, -162, 19, 56, -79, 51, 305, 113, -152, -46, 76, -327, 171, -15, -46, 82, -153, 17, 10, 80, -164, -159, -18, -126, -4, 80, 94, 12, 197, -179, -54, 135, -147, -187, -108, -63, 136, -173, 116, 102, 219, 94, 159, 49, 89, -115, -140, 208, 324, 230, 9, 146, 3, -244, 84, 131, 114, -328, 122, 84, 96, -206, -253, -60, 26, 104, 124, 98, -142, 74, 83, -63, 160, -123, 21, 93, -93, -41, -29, 132, 61, 153, -47, -147, 9, 58, 35, 165, 112, 69, -13, -231, 171, -47, 90, 158, -25, 47, -132, 36, 214, -164, -224, -17, 9, 83, -82, 134, -153, -116, -48, 76, -173, -219, -106, -15, -77, -198, 21, -202, 161, -132, 28, -68, 137, -54, -76, 74, 63, 240, 1, -232, -229, 46, 226, -103, -190, -117, -85, 130, -71, -143, -89, 196, 99, 18, -169, -147, -114, -145, -85, -50, 48, -43, 115, 130, 48, -224, -402, 535, 529, 2, -64, 181, -160, -73, 488, 17, -69, -461, 52, -249, 389, -365, -89, 46, -233, -242, -119, -119, 199, -88, 16, 85, 0, -130, -156, -154, -198, -172, -192, 100, 13, 98, 149, -306, -18, -6, 197, 80, 105, 64, -71, 58, -1, -141, 8, -73, 111, 130, -260, 21, -95, -257, 161, 118, 9, -278, -96, 149, 148, 37, 87, 102, -225, 181, 13, -120, -272, 147, -90, -223, 290, 213, 258, -42, -4, 180, -434, 122, 56, 199, -340, -58, -184, -117, 145, 129, 42, -313, 220, -62, 89, -362, 1, -235, 26, -152, -19, -27, -207, 202, 11, 90, 130, 295, -18, -263, -320, 28, 97, -4, -97, -154, 169, -342, -102, -168, -75, 78, -8, 32, 181, -210, 26, -95, -149, 149, 240, 83, 76, 33, -212, -67, -9, 26, 2, -124, 151, 39, 231, -144, 104, 136, -110, 71, 145, -64, 86, 83, -177, 2, 152, 119, 226, 153, 113, 358, -183, 111, 366, 330, -70, -143, -87, -283, 245, -266, -142, -89, 270, -201, 357, -286, 219, 114, -164, -76, 210, -91, -1, 240, 105, 382, -164, -102, -142, -92, -171, -18, 79, -131, 66, -240, 55, -118, 24, 22, 85, 13, 64, 134, -64, -27, -85, 41, -102, 164, 114, 130, 24, 120, -212, -153, 29, -131, 0, -147, 42, -42, 269, 32, -288, -40, 239, 234, -172, 256, 22, -191, -103, -272, 230, -210, 377, 125, 340, 32, -193, 383, 220, 383, -47, -200, -121, -132, 269, -59, -42, -282, -3, 140, 217, 101, 70, 28, -168, -28, 45, 104, 83, -190, 69, -68, -58, 18, -4, 109, -61, -174, -80, 144, 12, 36, 69, 22, 155, 4, -63, 275, -151, 209, -6, -63, -72, -142, 49, -85, -34, 117, -82, -184, -134, -93, 7, -6, 159, -255, 73, 94, 138, 104, -87, 240, 193, 259, -108, 117, 111, -240, 193, -37, 105, -15, 172, 116, -98, 63, -296, 33, 21, 286, -122, -292, -353, -195, 323, -38, 170, -138, 95, 68, -39, -74, 185, 129, 133, 11, 70, -13, 180, -64, -74, -108, 173, -53, -11, 281, 77, -145, -39, 230, 270, 99, -44, -225, -166, -155, 334, 215, 120, -202, -159, -320, 77, -340, -148, 170, -1, -161, -125, -8, -56, -105, -90, 144, 73, -59, -259, 215, -76, -250, -212, 17, -117, 73, -63, -80, -167, -98, 101, 145, -73, -107, 294, -173, 111, -11, -271, 106, 206, 173, -130, -192, -95, -1, 85, -111, 123, -25, 12, 37, 105, -149, -89, 103, -43, 26, -252, 171, 31, -24, 21, -21, -111, -40, -39, -136, -68, 140, -260, 452, 305, 218, -366, -42, -236, -70, 404, 140, -51, -349, 21, -287, 334, -301, -308, 336, 227, -222, -231, -62, -208, -135, 153, 62, 34, -271, 17, 52, 163, -284, -154, -44, -182, -24, 245, 120, 64, -8, -98, -49, 307, -77, 233, -102, -102, -33, -42, -96, -12, -127, -108, 13, -66, -23, -55, 36, -298, -155, -13, -103, 3, 151, 107, -72, -44, -68, 177, 312, 197, 227, -248, 108, 86, 244, -299, -21, -300, 47, -414, 427, 291, 123, -82, 148, -185, -44, 114, 27, 141, -307, 73, -324, 200, -144, -72, 348, 10, -47, -80, 222, 154, -297, 54, 119, 40, -6, 54, -90, -16, -72, 83, 177, -138, 81, 0, 123, -277, 137, -185, 72, 167, -36, 153, 30, 23, 248, 249, 67, 48, 253, 189, -88, -143, 193, 52, -154, -143, -12, 122, 90, -152, -109, 83, -86, -94, -180, -31, 124, 146, -48, -123, 27, 123, -147, -128, -78, -139, -60, -236, 201, 30, -122, -84, -61, 79, -128, 194, 0, -6, -196, 0, -211, 360, -179, -128, 70, 44, -158, -109, -128, -10, -144, 176, -87, 132, 0, -49, 117, -225, -240, 117, -44, -5, 145, -8, -38, -158, 99, 57, 73, 32, 112, 70, 19, -186, 16, -107, 124, -48, 2, -143, -70, 5, 105, -94, -124, 99, 129, -76, -179, -88, }; +int32_t to_patch_embedding_linear_bias[16] = {227, -68, -2, -126, -99, -174, -84, 74, -6, 99, -139, 80, -62, -140, 83, -7, }; +int32_t to_patch_embedding_layer_norm2_weight[16] = {3971, 4588, 4419, 4328, 3995, 4153, 4080, 3987, 4099, 4443, 4075, 3864, 4214, 4134, 4104, 4276, }; +int32_t to_patch_embedding_layer_norm2_bias[16] = {132, -148, 57, 34, 72, -70, -116, -26, -76, 79, -190, 10, -46, 57, -30, 204, }; +int32_t transformer_layers_0_0_norm_weight[16] = {4052, 4657, 4613, 4245, 4042, 4415, 4086, 4275, 4240, 4498, 4285, 4081, 4387, 4184, 4302, 4580, }; +int32_t transformer_layers_0_0_norm_bias[16] = {80, -54, 40, 214, -203, -129, -101, 57, -177, 57, -56, -281, -36, 219, -182, 92, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H0[64] = {-568, -962, 189, -868, -562, 692, 858, 407, -818, -814, 262, -471, 1273, 623, -384, 338, -321, -114, -723, 913, -697, 294, -35, -123, -264, -331, 509, 129, 184, 595, 16, -677, -348, 313, -401, 679, -798, 378, -145, 190, 618, -246, 776, 801, 974, 570, 842, -29, -685, 721, 640, 87, -612, -939, 890, -225, 522, 70, -514, 927, 990, 825, 114, -893, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H1[64] = {640, 166, -336, 542, 491, -1105, -458, -497, 20, -292, 989, -578, -438, 699, -855, 724, 901, 119, -824, 607, 1135, 1478, -883, -673, -923, -897, 445, 395, -782, 260, 591, 327, 970, -1386, 631, 281, -121, -721, 109, 203, 74, 106, 593, 1065, 857, -728, 761, -620, -558, 765, -514, 587, -489, -144, 839, -142, -270, 415, -757, 288, 305, 1302, -249, 247, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H2[64] = {-1419, 962, -640, 252, -124, -585, -573, 363, 218, 537, 461, 201, -502, 636, 804, -1101, 434, 91, -595, -67, -209, -257, 132, 782, -55, -268, -36, -205, -1225, 1346, 648, -933, 360, 693, -726, -675, 1319, 324, -601, -707, 234, 687, 630, 769, 323, -334, -855, 135, -410, 330, -330, 739, -812, -33, -356, -471, 689, -841, 242, -763, -1304, 937, 743, -440, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_Q_H3[64] = {-1060, 1048, 444, 53, 299, -1202, -112, -899, 1136, 226, 103, -466, 653, 104, 151, -131, -910, 333, 104, -1167, -337, -744, -291, 445, -339, -916, 64, -170, -569, 334, -1016, 803, -782, -18, 583, -961, 304, -358, 725, 244, -567, -128, -370, 950, 536, -757, 290, -506, -365, -1083, 685, -1292, 555, -640, -304, 840, 919, -707, 665, -777, 781, 909, 869, 882, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H0[64] = {339, 84, 743, 513, 937, -490, 499, -304, 1092, 299, 522, -95, -850, -672, -565, 107, -47, -401, 196, 1062, -158, -507, 736, -381, -249, 768, -185, -849, -107, 483, 520, -997, -234, -945, 1008, -44, 674, -34, -388, -817, 289, 988, -652, -446, -603, 226, 427, 582, -422, 37, 474, -103, 561, 198, 113, 520, 150, 37, -857, 1162, -361, -122, -909, 596, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H1[64] = {587, -190, 215, -264, -1101, -633, 784, 643, 562, 794, -31, 134, -75, 572, -551, 233, -162, -1081, 780, -472, -588, 170, 1040, -1217, 805, 505, -961, -23, 457, 730, -77, 117, 771, -422, -811, -611, 622, 678, 554, -690, 435, 403, -904, 91, -350, -398, -563, -750, 352, -406, -22, 667, 468, -1362, 395, -764, 132, -553, -612, 61, -284, -933, -340, -561, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H2[64] = {399, -840, -111, -768, -787, 925, 1041, 579, -842, 1107, -195, -454, -1018, -673, 330, -1015, 554, 339, 389, 461, 579, -387, -826, 465, -1171, 274, -94, 518, 899, -878, -986, 258, -406, 199, -487, -577, -1264, 1126, -283, -1205, -1311, -101, 970, 79, 183, -108, -499, 980, 122, 110, -163, -25, 767, -718, -836, -838, 839, 120, -734, 789, -324, 119, -159, -411, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_K_H3[64] = {585, 567, -262, -561, -166, 469, 155, -56, -512, 839, -519, 859, -225, 693, -983, -707, 395, -196, -574, 63, 3, -162, -1000, -962, 248, 335, 1235, -284, 994, 727, -475, -891, -428, -817, -598, -1159, 526, 715, -232, -742, -191, -21, 65, 1479, 84, 389, 658, 385, 674, 729, 169, 221, 7, -27, 811, 841, -1080, 645, 14, -1033, -1146, -472, -74, 265, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H0[64] = {356, -364, 862, -1113, -938, 408, 1437, 968, 987, 664, -411, -881, 756, 768, -795, 77, 326, 481, -714, 196, -110, -215, 106, 621, -812, 542, 213, 1043, -188, -725, -266, -114, 785, -690, 427, 627, 1001, 796, -752, -410, -760, -304, 129, 1112, 62, 805, -1030, 382, -1195, -1002, 855, 1261, 1026, -281, 57, -850, 763, 77, 738, -135, 1189, 65, -1168, 617, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H1[64] = {536, 374, 293, 992, -103, -576, -463, -1069, -605, 1261, 597, -599, 643, -622, 268, 603, 712, 373, -455, 8, 760, -1245, -460, 201, 1035, 731, 955, 626, -131, -759, 43, -722, -817, -398, 168, 999, 474, 150, 639, -148, -359, -493, -551, 339, -737, 825, -827, -86, -681, 474, 757, -1097, -858, -351, 372, -792, -44, -609, -879, 540, 286, 701, 875, 406, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H2[64] = {764, 345, -422, -624, 1231, 99, -640, -1501, -301, -900, 283, 1233, -1172, 202, 1417, -498, 544, 858, 106, 761, 381, -695, -1310, 63, 651, -635, 946, 848, 999, 198, 84, -923, 1050, 851, -766, -870, -854, -29, 999, 47, -538, -926, -208, 448, 898, 61, -418, 1075, 429, -731, -414, -264, -538, 892, 876, 667, 311, -928, -294, 449, -854, 53, 670, -212, }; +int32_t transformer_layers_0_0_fn_to_qkv_weight_V_H3[64] = {-944, 62, 621, 124, -535, -149, 709, 95, 1129, 832, -644, 656, 547, 233, -187, 737, -793, 821, 16, -558, 129, -235, -896, 491, 753, 42, 343, 894, -531, -820, 518, -426, -787, 3, -398, -1120, 1170, 1063, -813, -105, -78, -135, 248, -263, -351, -172, 224, -430, -1072, -956, 331, -6, -221, -602, -34, 0, 913, -859, -110, -512, 1154, 657, -630, 8, }; +int32_t transformer_layers_0_0_fn_projection_weight[256] = {-402, -1077, -244, -103, 318, -176, 766, -1187, -866, 337, 1127, 451, -280, -1007, -185, -704, 654, 854, 369, -532, 565, -666, 1063, 433, 312, 232, 211, 846, 273, 115, -969, 847, -514, 236, -588, 549, -298, 759, -253, 1035, 6, -854, -445, -1030, -204, -85, -398, -307, 785, 142, -1233, -991, 496, 512, -675, -12, 172, 11, -1111, -633, 573, 502, -201, 322, -391, 248, -499, -56, -559, -305, -527, 629, 315, 130, -98, -248, 172, 148, 36, -337, 494, 353, 696, 517, 187, -1141, 985, -1041, -1095, 86, -29, 626, -1129, 678, -357, 67, 557, 291, -223, 493, -797, -561, 1218, -793, -542, 266, 275, 229, -637, -993, 965, 673, -884, 707, -19, -635, -663, -730, 87, 528, -179, 1047, -677, 1117, -854, -716, -700, 234, -970, 807, -180, -116, 1006, -13, -1029, -40, 182, 390, -1164, -858, 584, -453, 202, -765, 821, 362, -337, -572, 40, 20, -963, 525, -390, -743, 990, -432, 156, -54, 629, 666, -252, 461, 486, -5, 762, -728, 3, -742, -741, 1112, 1431, 1199, -676, -393, 403, -522, -474, -760, 508, -904, -265, 203, 78, -1096, -852, 587, 113, -680, 171, -308, -231, -484, -210, -463, 635, -561, -1093, 140, 509, -767, -329, 120, 518, 396, 280, -194, -414, 772, -697, -104, 218, 260, -105, 210, 1339, -369, -991, 856, 977, -735, 664, 306, 405, -156, -290, -772, -732, 594, -101, 930, -1060, 1133, 977, -515, -736, -390, 1010, 118, -351, -652, 74, -553, 216, -609, 289, -209, 1004, 930, 462, 171, 755, -914, -686, -185, -616, -648, }; +int32_t transformer_layers_0_0_fn_projection_bias[16] = {-840, -92, -107, 118, 323, -361, 278, -5, 135, 300, -784, 540, -15, 380, 771, 648, }; +int32_t transformer_layers_0_1_norm_weight[16] = {3913, 4457, 4086, 4198, 3935, 4065, 4044, 3934, 3956, 3983, 4205, 3852, 4319, 4076, 4119, 3967, }; +int32_t transformer_layers_0_1_norm_bias[16] = {-176, -178, -255, 86, 151, -163, -161, -8, 155, -133, -118, 180, -206, 30, -113, -222, }; +int32_t transformer_layers_0_1_fn_ff1_weight[64] = {-269, 879, 417, 125, -1042, 562, 825, 151, -22, 941, 340, 837, -99, -941, -81, -34, 779, -802, -170, 98, -331, -642, 898, 694, -266, 574, -677, 748, -770, -37, 501, -738, 539, -756, 846, -539, 380, 724, -628, 795, 1144, 372, 525, 499, -257, -2, -298, -356, -821, -8, 829, 852, 205, 290, -229, 201, -910, -991, -340, 841, -610, 961, 227, 151, }; +int32_t transformer_layers_0_1_fn_ff1_bias[4] = {-143, -827, -308, 129, }; +int32_t transformer_layers_0_1_fn_ff2_weight[64] = {305, -252, 1555, 1351, -1680, 1389, 1229, -741, -1475, 285, -203, -1095, -1407, -1403, -1965, 1256, -273, -533, -1, -1734, -417, 176, -253, 1055, -326, -525, -1, 343, -413, 309, -1034, -1608, -1219, -547, -472, -663, -1628, -1026, -56, -1330, 673, 451, -900, -1720, 2030, 607, 1103, -1915, 1853, 911, -939, 398, 21, 15, 1670, -409, 378, -1568, 1405, 1371, 933, -759, 545, -2014, }; +int32_t transformer_layers_0_1_fn_ff2_bias[16] = {837, -1010, 736, 2060, 1857, -1132, 728, -1052, 947, 1603, 1612, 1908, 1519, 508, -1745, -1202, }; +int32_t transformer_layers_1_0_norm_weight[16] = {3943, 4401, 4285, 4286, 4112, 4059, 4094, 4023, 4156, 4435, 4079, 4136, 4219, 4111, 4081, 4076, }; +int32_t transformer_layers_1_0_norm_bias[16] = {-44, -53, 85, 19, -34, -44, 71, -39, 40, 66, -63, 14, 27, -106, -87, -76, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H0[64] = {495, 600, -127, -357, 489, 355, 41, 97, 758, -317, 99, -403, 730, 452, -27, 354, -495, 997, 387, -732, -742, 475, 67, -193, 464, 305, -691, 995, 902, 1007, -985, -300, -608, 939, -555, 527, 454, -789, 77, 203, 550, 130, 912, 756, 104, 733, -477, -462, -25, 816, -253, -828, -407, 607, -1024, 458, -159, -75, -422, -327, 772, -845, 661, 673, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H1[64] = {-780, -895, 1016, -316, 1036, -767, 839, -289, -582, -1437, 46, -283, -830, 69, 661, 720, 925, -302, -908, -185, -771, 486, 460, -953, 327, -491, -209, -21, 210, -935, -445, 117, 541, -967, 810, -458, -985, -328, -38, 647, 456, 982, -64, -586, -155, 738, -358, 85, -536, 5, -210, 168, -628, 278, -280, 13, -793, 687, 18, -27, -340, 178, 258, -977, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H2[64] = {-397, -371, 571, 275, -30, 516, 642, 475, 831, 781, -398, -383, -510, 210, -543, 47, -637, 293, 625, -645, 40, -892, -734, 402, -172, -431, 7, -150, -549, 512, -208, 249, -527, -433, 922, 769, -788, -851, 328, 370, -51, 214, -971, -639, -809, 119, 54, 694, 746, -331, -515, 64, -894, 340, -713, -372, 540, -418, 924, 572, 1071, 882, 877, -633, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_Q_H3[64] = {476, -152, -876, 172, -361, -748, -636, -123, 162, -616, -504, 793, 661, 27, 626, 102, -518, 900, 891, -508, -848, -553, 519, 101, 122, -683, -204, 986, 44, 263, 421, -1069, 811, -302, 909, 942, 864, 478, -225, -1105, -470, 4, 387, 537, 133, 434, -6, -780, 301, 739, 1092, -834, -1072, 173, 106, 480, 981, -1, -672, 1039, -32, -769, -809, -673, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H0[64] = {-536, -105, 457, -372, -36, -789, 776, -669, 705, -386, -480, -493, -216, 652, -161, -285, 385, 1026, -222, 268, -761, -564, 815, 991, -417, -308, 967, -141, 950, -843, -774, 222, -9, -387, 466, 539, -385, 108, 569, 873, 607, 184, -627, -371, 92, 143, 355, 885, 141, 339, 397, 598, -574, 500, 226, 716, 449, 328, 820, -210, 614, -841, -650, -881, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H1[64] = {487, 12, -424, -75, 464, 210, 601, -479, 874, -114, 421, 630, 621, 563, 671, -886, 856, -783, 351, 676, 1263, -231, 1, -862, 609, 307, -259, -737, 649, -552, 811, -851, 764, -42, -780, -1011, -595, 521, -447, -604, -581, 286, -718, 184, -32, 81, -644, 927, -789, -145, 864, 638, -400, 675, -935, -786, 1144, -920, -702, 755, -341, -782, -596, 566, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H2[64] = {339, 539, 363, -56, -218, 918, 616, -856, -651, 992, -167, 175, 652, -456, -927, 539, -234, -846, -502, 924, 457, -677, -48, 41, -224, 685, -994, -17, -373, 766, 1014, -845, 509, -554, -878, 187, 824, 437, 871, 410, 1037, 18, 459, -666, 496, 360, -294, 407, 245, 266, -455, -167, -1086, -133, -739, 1113, 462, -910, 764, 1087, 238, -358, -725, -713, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_K_H3[64] = {-909, -289, 660, -80, -802, 331, 600, 430, -889, 182, 205, -1121, 799, 211, 337, -537, 1094, -867, 396, 415, 806, 787, 683, 530, 240, -442, 73, -203, 433, 326, 802, 184, 1048, 362, 49, -755, 903, 970, 491, -289, -807, -123, -625, -826, -348, -711, 943, -872, 369, 459, -610, -780, -902, 865, -479, 952, 251, 723, 10, 137, 110, 432, 545, 827, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H0[64] = {-904, -972, 395, -281, 1346, 1215, 17, -994, -340, 936, -382, -125, -644, -779, -546, 815, 142, 820, 98, 552, -377, 959, 1113, 123, -221, -107, -964, -219, 206, 648, 834, -596, -35, 431, 658, 398, -1069, -140, -465, -39, 455, 824, -75, 420, -270, -55, 619, -394, -685, 548, 194, -23, 38, 815, -786, 474, 684, 318, -763, 593, -655, -618, -263, 251, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H1[64] = {550, 404, -867, -355, 1129, -344, -759, 403, 203, 811, 891, 674, 433, 812, 428, 68, -321, 344, -725, 560, 425, 801, 653, -328, 60, 269, 427, -15, -159, 367, 235, -599, 8, -1167, -239, -594, -544, 871, 675, 78, 607, 621, -244, -492, 415, 668, 1004, -170, 961, -1137, -717, 1007, 228, -242, 508, 511, -703, 429, 800, 807, 826, -723, 855, 790, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H2[64] = {137, -567, -524, -1077, -226, -320, -619, -639, -215, 351, 297, -193, 280, -282, 92, 700, 987, -271, 103, -408, 138, -763, -252, -592, 890, 463, 961, -740, -487, 323, 233, -639, -752, -186, 124, -984, -70, 996, 194, 663, 72, 109, 382, -590, 948, 98, -885, -1018, -411, -896, 847, 478, 16, 0, -861, 876, -875, -176, -784, 30, -797, -803, -906, 896, }; +int32_t transformer_layers_1_0_fn_to_qkv_weight_V_H3[64] = {523, -54, 650, 319, 905, -162, 443, -845, -509, 320, -1008, -984, -99, 709, -64, -938, 175, -357, -351, 40, 777, 340, 1157, -867, -689, 733, 553, -237, 721, -1006, -476, -684, -446, -31, -974, 214, 469, -240, -1137, -233, 285, 528, 266, -798, 538, 786, 438, -717, 586, -872, -901, 1040, 137, -19, 215, -995, -446, -870, 675, 139, 103, -691, -115, -573, }; +int32_t transformer_layers_1_0_fn_projection_weight[256] = {-961, -497, -218, -462, -752, 764, 182, -416, 43, -295, -1317, -752, 990, 758, 595, 383, -297, 299, -272, -565, -953, -338, -303, 1186, 1256, 504, -455, 329, 353, -416, 202, 446, -869, 19, -776, -409, 959, 382, -5, 278, 503, 440, 209, 407, 410, 406, -331, 877, 463, 721, 65, -135, 293, -336, 674, -687, -1054, -331, -225, -675, -963, 710, 728, 790, -392, 108, -834, 300, -154, 767, 401, 421, -820, 246, -236, -957, 669, 358, 483, 60, 249, 66, 1149, -828, -539, 332, 57, -1235, 282, 268, 978, 216, -830, -553, -541, 279, -214, -340, 977, -249, 205, 70, -401, -502, 17, 1231, 634, 390, -937, 15, -798, -473, 50, -277, -825, 504, 79, 163, -647, -875, -860, 161, -256, -936, 594, -491, -403, -47, 643, 316, -778, 1075, -1066, -1276, -590, -713, 888, 114, 749, -78, -257, 103, -363, 247, -128, 40, 1004, 152, 639, 171, -485, -1083, 70, 342, 903, 569, -606, 472, -894, -585, -682, 488, -726, 169, 16, -905, -906, -734, 796, 697, -527, 807, -1091, -911, -320, -791, 718, 622, 475, -343, 853, 769, 884, 564, -1171, -59, 180, 14, 288, -1012, 1087, -518, -549, 777, 576, 765, -356, 945, 640, -174, 238, 281, -341, -889, 1007, 311, 40, -45, 633, -584, 1091, -101, -801, -483, -527, 411, 164, 457, 365, 19, 209, -542, 114, 352, -625, 590, 666, -706, 1037, -388, -993, -373, 240, -343, -914, 856, 956, 617, 982, -140, 371, -455, 208, 973, 133, 652, -646, 344, 297, -880, -97, 271, -380, -219, 827, 596, }; +int32_t transformer_layers_1_0_fn_projection_bias[16] = {-736, 309, -43, -180, -220, -446, 37, 54, 389, -788, 1114, -969, -17, 10, 286, 852, }; +int32_t transformer_layers_1_1_norm_weight[16] = {4083, 4051, 4008, 4127, 3974, 3860, 4095, 4052, 3996, 4005, 4114, 4195, 3983, 4097, 4071, 4004, }; +int32_t transformer_layers_1_1_norm_bias[16] = {137, -2, 135, 87, 127, -139, -134, -96, 67, 14, -108, -63, -78, 31, 15, 53, }; +int32_t transformer_layers_1_1_fn_ff1_weight[64] = {-127, -843, -176, -862, -255, -382, -561, 758, -943, -676, -585, -721, -737, -526, -519, -110, 481, 81, -122, -888, 358, 455, 170, 527, 336, 86, 266, 133, 896, 362, 806, -114, -894, -490, -7, 55, -544, 938, 456, -382, 987, -919, 127, 210, 427, -677, 788, -316, 776, -675, 152, 89, -813, -174, -14, 274, 317, -26, 399, -560, -367, -255, 649, -1004, }; +int32_t transformer_layers_1_1_fn_ff1_bias[4] = {90, -953, 421, -933, }; +int32_t transformer_layers_1_1_fn_ff2_weight[64] = {-1042, -1584, 1737, 504, -1780, 1348, 536, -1647, -1350, 839, -1377, 663, 455, -1985, -1640, 1642, 1730, -960, -1286, -54, -1541, 714, 971, 579, -69, 1795, -831, -1040, 1600, -382, -1386, 245, 1170, 1367, -210, 904, 1794, -1331, -524, -1304, 84, 743, 593, -621, -1397, -1482, 1047, -849, -1283, -1557, 911, 218, -1263, -1694, 1757, 1760, 812, 762, 1568, 1882, -1391, 1405, -244, 478, }; +int32_t transformer_layers_1_1_fn_ff2_bias[16] = {-1109, -350, -895, 2006, 686, -472, 1124, 1903, 1174, -405, -1500, -440, -422, -142, 1269, -836, }; +int32_t transformer_layers_2_0_norm_weight[16] = {4135, 4645, 4316, 4215, 4243, 4415, 4186, 4002, 4224, 4214, 4305, 4162, 4319, 4117, 4437, 4432, }; +int32_t transformer_layers_2_0_norm_bias[16] = {-10, -219, 118, -51, 66, -61, 16, 57, 4, 67, 27, 112, 24, -177, -70, 114, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H0[64] = {750, 642, 712, 102, -275, -314, 514, -1305, 48, 907, 72, -639, -859, -1227, -96, 131, -174, 771, 585, -694, 1109, -192, -60, -1356, 95, -133, -539, -295, -1002, 421, -649, 590, 403, 1025, -703, 311, 867, 275, -77, -759, 624, -841, -753, -297, -807, 129, 827, -804, -772, 63, 894, -59, -512, -206, 425, 657, 431, -1100, -646, 1259, -1036, -1045, 252, 1058, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H1[64] = {-101, 525, -497, -703, 267, -890, -574, 202, 304, -567, 1090, -181, -37, -245, -262, 545, -260, 686, -634, -882, 1059, -247, -562, -1061, -944, -143, 1018, -218, -608, -752, -127, 623, 467, -1114, -92, -355, -635, 947, 626, 710, -41, -864, -216, 275, -567, 834, -282, -558, -925, 848, 565, -826, 129, -724, 323, -1025, 681, 725, -81, -38, -463, -653, 1066, -210, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H2[64] = {-1000, -805, 417, -430, -467, 482, -643, 174, 646, -165, -599, 93, 65, -1101, 230, 546, -172, -758, -61, -837, 974, 408, -104, -727, -296, -456, -186, -148, -786, 216, -490, -825, 362, 932, -340, 816, 142, 20, -125, -1072, 390, -69, -839, 806, 830, -740, -407, -804, 1087, 182, 602, -206, -283, -331, -868, 454, 758, -753, -277, 266, -147, 297, -885, -669, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_Q_H3[64] = {890, -862, -125, -582, -1112, -1234, 52, -854, -742, -485, 26, -1324, 767, -304, 274, 490, 285, -878, -741, -904, -46, 536, -1020, -689, 33, 434, 481, -13, 67, -67, -28, 798, 162, 915, -629, 766, -1016, -907, 705, -1195, 1089, 399, -878, -55, -212, -838, -19, -777, 207, -357, -446, 28, 210, -1012, 500, 196, -409, 121, 470, 957, 885, -742, -227, 284, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H0[64] = {196, -857, -988, -250, 851, 1125, 256, 246, -13, -115, 43, 444, -62, 5, 196, 922, 603, 803, 7, -895, 225, 886, -688, 262, -355, -427, 167, 47, -220, -688, 373, -63, 36, 672, 524, -170, 675, 562, -1017, 662, -648, -36, -1136, 523, -305, 50, 303, 147, 246, -676, -142, 524, 327, 584, -688, -1043, 1089, -277, 414, -934, 798, 883, 1051, -572, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H1[64] = {893, 528, -509, -849, 255, -684, -717, 423, 113, -646, -210, -702, -66, 1028, -1014, -219, -40, -803, -291, 773, -187, 46, 954, 809, -872, 516, 833, -855, -848, 835, -481, 54, -295, 326, 904, 732, 338, 604, 78, -733, 129, 699, 498, 835, -949, 376, -955, -820, -618, 1033, 981, -643, 906, -534, -1152, 65, -322, 66, -274, 926, -558, -402, -926, -78, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H2[64] = {1036, 778, -513, 648, 42, 482, -147, 968, 12, -521, -380, 241, 982, 639, -959, -558, -511, 941, 56, -425, -745, 546, -937, 670, 819, -652, 739, -106, -552, -691, 445, -287, 30, -36, -715, -196, 884, -637, 0, 586, -230, 692, -169, -1036, 9, 548, 426, 797, 300, -356, -648, -432, 1287, -533, -110, -604, 835, 396, 466, -484, -443, 443, 421, -29, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_K_H3[64] = {-1028, -82, 553, 856, -861, -129, 600, -637, 300, -239, 141, -296, 443, 358, 949, 498, -736, 977, 339, 225, -1016, -994, 330, -1120, 1007, 178, -78, 1380, -459, -932, 620, -454, -671, -885, -617, -1051, 1021, -378, 542, 1186, 512, 608, -809, 418, 153, -173, -46, -342, -1247, -413, 461, -858, 482, -234, 593, 168, -638, -919, -2, -734, -703, -717, 275, 1043, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H0[64] = {-569, -735, 276, 102, -180, 537, -520, 1212, 789, -363, 25, -565, 952, 177, 147, -941, -448, -1023, 433, -198, 197, 686, 450, 217, 498, 850, 455, -791, 992, 707, 544, -393, 914, 631, -407, -221, 131, 614, 619, 430, 710, -753, -270, 347, 115, 834, 648, -138, -386, -1090, -122, 758, 753, 488, -639, 843, 35, 193, -708, 1173, -499, -677, -894, -551, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H1[64] = {189, 384, -576, 584, 707, -516, -1085, 81, -652, 809, 849, 929, -834, 725, 256, -568, -77, 932, 4, 445, -174, -238, -718, -991, 539, -472, -577, -951, -1016, 229, 73, 838, 980, -710, -18, 111, -583, 916, 1046, -814, 551, 95, 777, -46, 975, 27, 252, 362, -772, -863, -803, 496, 855, 100, -481, 357, 577, 945, 630, 44, 712, -157, -147, 1142, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H2[64] = {668, -279, 884, 126, -1152, -408, 994, -84, 549, -356, -363, -365, 596, -513, 305, -212, 175, 181, -1146, -1, 588, 511, 147, 231, -751, -28, 129, 877, 385, 904, -362, -628, -290, -366, -1028, -102, 909, -942, 1006, 653, 454, -908, 1069, -462, 1201, -227, -847, -775, -1091, 75, -924, 178, 87, 519, 431, 287, -411, 100, 605, -926, 593, -438, -588, 618, }; +int32_t transformer_layers_2_0_fn_to_qkv_weight_V_H3[64] = {496, 644, 748, 90, 519, 492, 816, -402, -44, -1013, -886, -581, 880, 744, -302, 821, -992, 729, -44, -493, -1191, -137, 352, 950, 342, -211, 347, -1036, 125, -31, 912, 313, -1230, 354, 356, -195, 220, -693, -1152, 538, 1248, -1006, 152, -822, -541, -813, 12, -269, -863, -739, -438, -650, -250, 770, 240, 195, -813, 411, 597, 1034, -114, -202, 777, -162, }; +int32_t transformer_layers_2_0_fn_projection_weight[256] = {-250, -616, -353, -787, 606, 329, 1043, 644, 827, -65, 841, 68, -804, -131, 515, 298, 594, 611, 284, -40, -72, -695, 564, -25, -141, -9, -936, 100, 318, 1101, -899, -442, 755, -919, -439, 111, -58, -1232, 34, 191, -666, 651, -416, -578, -160, -1101, 927, 786, -1151, 834, -830, 143, -180, 381, -887, 812, 755, -287, -1322, 98, 629, 499, 917, 957, 261, 509, -1001, -522, -102, -106, -48, -816, -161, -516, 345, 373, -881, 1022, -493, 648, 1124, -152, -542, -293, -708, -46, 779, -106, -1112, 1022, -634, 145, 401, -1117, -374, 775, -378, -672, 956, -497, 798, -1060, 359, -1384, -853, 802, 1090, -431, -391, -659, -931, 348, 565, 363, 395, -576, -696, 206, 157, 741, 253, -57, 848, -844, -828, -758, 621, -122, -565, 1162, 834, -754, -840, -883, 464, -1167, -816, 670, 613, 272, -459, -529, -585, -854, -559, 925, 240, 1169, -413, -69, -1001, 513, 571, -426, 359, 319, 612, -510, -580, -707, 391, 896, 354, -1138, 922, 943, 115, -252, 36, 225, -326, 598, -232, 828, -678, 621, 582, 930, -1020, 375, -504, -157, -669, -629, 577, -491, 312, 701, -909, -779, -159, 95, -738, 806, 1109, 64, -398, -15, 1345, -1061, -833, 827, 756, -223, 460, -359, -417, -114, 719, -1035, -180, -515, 124, 428, -975, 993, 533, -1178, 966, -308, 575, -908, -113, -656, -439, -547, -542, -343, 1116, -219, -704, 32, -184, -1065, -794, 784, 247, -762, -59, 35, -98, 387, 100, 593, 748, 564, 413, 453, -306, -254, 7, -255, -889, 814, -766, -481, }; +int32_t transformer_layers_2_0_fn_projection_bias[16] = {194, 93, 543, 448, -911, -445, 195, -40, 634, 876, 754, -1012, 50, 857, -446, -108, }; +int32_t transformer_layers_2_1_norm_weight[16] = {4070, 4054, 4113, 4250, 4054, 4081, 4083, 4181, 3917, 4167, 4225, 4116, 4074, 4125, 4118, 4086, }; +int32_t transformer_layers_2_1_norm_bias[16] = {42, 64, -32, 110, 137, -170, 140, 80, -43, -16, 168, -178, 100, 6, 44, -66, }; +int32_t transformer_layers_2_1_fn_ff1_weight[64] = {-874, -1079, -163, 736, -294, -562, -500, 987, 108, 568, -363, -934, -409, -573, -1048, -366, 277, -902, 259, 602, -45, 983, 366, 811, -394, -751, -662, -964, -400, -240, -967, -749, 166, 599, -648, -608, 618, 609, -928, -602, 56, -852, -818, -343, -398, 671, 187, 523, 906, -568, 602, 1123, 788, 123, 297, 817, -692, -732, -585, 704, 1029, 787, -902, 971, }; +int32_t transformer_layers_2_1_fn_ff1_bias[4] = {267, 470, -574, -399, }; +int32_t transformer_layers_2_1_fn_ff2_weight[64] = {1877, 1625, -992, -1629, -1178, -1784, 4, -1248, 905, 507, 1721, -4, 1659, 420, -527, 1624, -482, 1213, -223, 1858, -200, -1466, -160, 330, 1406, 396, -1566, 1945, -1635, 733, -1490, -1626, 404, -1409, -268, 1645, 1503, 1635, -1849, 1682, -1379, 1453, -465, 666, 593, -578, 1630, -747, -1665, -1625, 436, -1834, -1397, 1706, -1779, 42, -96, -1266, -1052, 1321, -1843, 128, -1722, 1636, }; +int32_t transformer_layers_2_1_fn_ff2_bias[16] = {-473, -1167, 1703, 46, 113, 609, -1347, 396, -303, -1647, -449, -372, 176, -1396, 1388, -966, }; +int32_t transformer_layers_3_0_norm_weight[16] = {4331, 4371, 4459, 4169, 4329, 4301, 4145, 4299, 4294, 4423, 4268, 4098, 4104, 4173, 4155, 3944, }; +int32_t transformer_layers_3_0_norm_bias[16] = {-9, -50, -35, -36, 149, -24, -70, 75, 0, 43, 35, -47, -72, 36, 13, 91, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H0[64] = {812, -991, -1033, 164, -795, 579, -348, 766, 1070, 162, 149, -447, 298, -560, 489, -455, -458, 1003, 28, 1178, -74, 572, 1063, -531, 288, -656, 52, -852, 268, -340, 554, 363, -261, 534, -24, -513, -736, 186, -265, -656, -131, -1131, 917, -628, -624, -829, 190, 508, -405, 31, 991, -533, 728, 1148, 761, -174, -792, -169, 356, 52, 950, 90, -723, 659, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H1[64] = {417, 44, -833, 344, 124, 505, 217, 114, -753, -223, 59, 506, 404, 796, 326, -824, 45, -937, -647, -1044, 367, 197, -42, 101, 914, -45, 768, 244, 988, 114, 388, 165, 502, -169, 880, 852, -46, -1099, -445, 420, 903, 508, 945, -334, 729, -605, 8, -69, 950, 0, 277, 227, -321, -251, 636, 393, 441, 75, 269, -270, -713, 662, -916, -227, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H2[64] = {-625, -372, 134, 911, -887, 1167, -760, 713, -72, 576, 108, -1107, -353, -550, 605, -319, -229, 136, 335, 688, 221, -610, 366, 98, -380, -125, -61, -205, -432, 389, 110, 286, 1046, 550, -314, -243, 626, -699, -397, -950, 806, 553, -298, -1018, 713, 74, 860, 746, 348, -952, -293, 440, 797, -396, -340, -810, 182, 1001, 47, 626, 734, 45, -284, -563, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_Q_H3[64] = {1082, 533, -719, 574, 747, -378, 72, -655, 244, -372, -790, -465, -449, -305, 970, 536, 218, -626, 396, -1083, -413, -840, 679, -186, -650, 865, 721, -883, 882, -1084, 614, -783, -846, 623, 94, 490, 1052, -340, -1226, -483, -16, -382, 717, 491, -780, -723, -848, -613, 345, 648, -319, -34, -72, -347, 989, -457, 377, -805, -29, 734, 973, 791, 861, -764, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H0[64] = {-521, 858, 454, -495, 916, 442, -168, 604, 411, -89, 999, 1, -96, 421, 95, 197, -129, -822, 103, 866, -480, 714, -342, 656, -813, -974, 231, -1000, 783, -582, -154, -1051, -942, -760, 788, -81, -396, -102, 270, 72, 1116, -755, -832, 101, 1, -476, 195, 308, -144, -1003, -811, 813, -853, 1089, -738, -198, -100, 252, 935, 526, 115, 513, 18, 735, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H1[64] = {-918, -29, 832, 896, -778, 564, -148, 730, -237, 85, 834, 823, -836, 820, 575, 638, 661, 140, -132, 629, -1014, 82, -486, -571, 994, -457, 1027, 346, 445, -634, -202, 487, 587, 25, 580, 854, -154, -265, -46, 733, 728, 507, -780, -448, -367, -229, 937, 305, 293, -1028, 445, -37, -608, -867, 512, 240, 230, -243, -412, -676, 930, 645, -19, -602, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H2[64] = {-77, -1040, 122, 316, -714, 687, -1048, -1038, 982, -600, -161, 541, -937, -978, 541, 656, 134, -443, -314, -18, 239, 44, 138, -596, -403, 588, 715, 958, 812, -651, -300, 441, -765, 319, -127, -1081, 385, -228, -45, -405, 134, -655, 949, -141, -850, 513, -829, 466, -601, -76, 280, 217, 155, -150, 1085, 409, -572, 165, 818, 548, -504, -663, -25, -151, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_K_H3[64] = {-822, -987, 500, 498, -380, 118, 296, -875, -428, 525, 721, -948, -96, -220, 952, -534, -1220, -182, -802, -290, 53, 825, -687, -910, 930, -42, -265, -297, 1184, -688, -121, -414, 524, -856, -476, 496, 631, 134, 1193, -132, 486, -166, 691, 1058, 274, -1097, -921, 388, 993, -9, -933, 525, -20, -405, -604, -828, 207, -280, -1049, 406, 872, -153, 134, -7, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H0[64] = {883, 284, 1094, -584, -1043, 1291, -1017, 538, 1181, -826, 537, -743, 1056, -1051, 1065, -347, 947, -152, -36, -529, -394, -532, 143, -447, 819, 768, 375, -626, 107, 1032, -154, 691, 845, 1047, -224, 931, 1173, -396, -983, -455, 16, -1076, -83, 121, -988, 816, -291, 72, -1167, -783, 823, -605, 196, -86, -857, 738, -495, 625, -374, -571, 128, -985, 844, 796, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H1[64] = {-121, -695, 45, -12, 29, 145, 226, 781, -515, 970, 780, 1133, -311, -960, 447, 445, 896, -274, 519, -1066, -274, -909, 923, 193, 246, 733, -661, 1113, -95, -1037, -874, -375, 807, -375, 333, -1144, 290, -112, -464, 1003, -578, -207, 751, 1000, 582, -342, 641, 775, -672, 604, -283, 834, 8, -312, -856, -454, 326, -226, -11, -959, 70, 1098, -225, -777, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H2[64] = {800, -780, 659, 436, 608, 983, -692, -810, 1055, 209, -284, 989, 203, -579, -376, 84, -312, -39, 309, 272, -631, -387, 500, -413, 866, 99, 322, -723, -751, 811, 635, 257, -571, 521, 454, -915, 239, -332, 381, -897, 1141, 265, 813, 83, 105, 243, -431, -597, -886, -987, -1014, -252, -271, -94, -218, -324, -948, 846, 376, -282, -851, 724, -920, 601, }; +int32_t transformer_layers_3_0_fn_to_qkv_weight_V_H3[64] = {-539, 136, 319, -1137, 523, -281, -164, 890, -243, -237, -195, 331, 203, 862, -165, 188, 480, -509, 632, -963, 98, -30, -1019, 1024, -732, -486, -843, -480, -458, -729, 528, 728, -402, -495, -697, 1208, 689, -417, 308, -1250, 809, -878, 772, -534, 648, -420, -677, -614, 230, 167, -953, 828, -357, 801, 752, 1045, -868, 305, 622, 1084, -482, 809, 990, 825, }; +int32_t transformer_layers_3_0_fn_projection_weight[256] = {342, 5, -248, -706, 551, -1138, -335, -803, -1059, -259, 550, -227, -212, -948, 336, -347, 724, 0, -258, -610, 104, 853, -1145, 801, 45, -122, -296, -960, 979, -164, 227, -633, 291, -29, 331, -570, -899, 539, 166, -885, 666, -86, 227, -209, 44, -1134, 439, 556, 428, -932, 165, 517, 13, 135, -735, 917, 412, 6, -317, -426, 450, 310, 11, 70, -476, -749, -107, 792, -254, 818, -650, 707, -400, 687, 222, 431, -284, -826, 120, 150, -819, -614, -974, -859, 345, 367, -32, -770, -762, 372, 1068, 352, -201, 500, 166, -592, 665, -217, 231, 366, 564, 47, -268, -925, 1011, -851, 371, 688, -1137, 740, 918, -1041, 971, 42, 914, -1073, -248, 73, 271, -1088, 335, 392, -633, 626, 233, 825, 398, -790, 157, 1155, 441, -655, 356, -920, 699, -145, -525, 955, 180, -23, 97, 817, -420, -964, 1096, -19, -195, -12, 843, 359, -504, 273, 655, -269, 438, 373, -546, -25, 663, -717, -136, -276, 938, 78, -921, -687, 740, -459, -1038, -826, 965, -535, 352, 804, 894, 293, -451, 707, 613, 768, -1007, -1111, 410, -671, -224, 418, 773, 388, -242, -517, 908, 3, -794, 179, -520, 518, -565, -638, -300, 55, 888, 790, 754, -689, -561, 358, 723, -21, -528, 557, 1065, -476, -312, -544, -658, 803, -328, -464, -309, -778, -558, 298, 299, 445, -143, 526, 1111, -49, -762, -721, -224, -158, 529, 1242, -545, -287, -974, -391, 603, 743, -589, -1132, 55, 661, 757, 273, -1212, 1374, 396, -276, -975, -866, -192, -78, 168, -164, }; +int32_t transformer_layers_3_0_fn_projection_bias[16] = {-513, 807, 27, 109, 381, 633, 651, -345, -188, -948, -40, -1119, 69, -344, 610, -562, }; +int32_t transformer_layers_3_1_norm_weight[16] = {4014, 4033, 3946, 3968, 4029, 3985, 4117, 4068, 4052, 4005, 4190, 4268, 4082, 4047, 4155, 3996, }; +int32_t transformer_layers_3_1_norm_bias[16] = {114, -8, 39, -134, -76, -28, -5, -45, -16, 95, 69, -148, 162, 32, 143, -74, }; +int32_t transformer_layers_3_1_fn_ff1_weight[64] = {45, -294, -338, -514, 405, -861, -371, 974, 831, 195, -815, 159, -8, -783, 753, 635, -125, 722, 314, 472, -678, 633, 911, -906, 948, -593, -502, 602, 482, 1182, 18, -479, -804, 954, 458, 242, -300, 779, -731, 989, 108, -1102, -456, -82, 914, -716, 923, 673, -451, 517, -480, -898, -279, 521, -213, 1045, -1039, 728, -1044, -504, 824, -374, -136, 480, }; +int32_t transformer_layers_3_1_fn_ff1_bias[4] = {420, -528, 708, 556, }; +int32_t transformer_layers_3_1_fn_ff2_weight[64] = {-1264, -245, -243, -1258, -1099, -1898, -832, -1786, -91, -535, 338, 531, 99, 47, 1132, -293, 1776, -1641, 1705, -1170, 1156, 1020, -187, -1538, -652, 147, -962, -721, 748, -398, -1670, -84, 1373, 389, -1031, -329, 520, -615, -769, 1458, 1650, 1183, 1178, -137, -775, -271, -1281, -1755, 1191, -1755, -561, -1893, -104, 833, 1300, 1269, 1925, 1248, -225, 316, 1618, -1789, 479, -958, }; +int32_t transformer_layers_3_1_fn_ff2_bias[16] = {170, -517, 322, 1989, -502, 37, -357, 766, 1958, -45, 1673, -1260, 1175, -1481, -1355, 818, }; +int32_t mlp_head_layer_norm_weight[16] = {4039, 4009, 3972, 4135, 3957, 4168, 4133, 4187, 4009, 4196, 4210, 4267, 4051, 4053, 4018, 3976, }; +int32_t mlp_head_layer_norm_bias[16] = {-17, 24, 34, 16, -13, -23, -17, 16, 1, -62, 29, -4, 6, 46, 47, -28, }; +int32_t mlp_head_linear_weight[256] = {-400, 764, -464, -564, 75, -317, 351, -609, -341, -736, 55, 467, -747, 464, -536, 11, -341, 380, 479, -292, 53, 351, -332, 245, 155, -579, 630, 827, 727, 483, -86, 108, 213, 752, -431, 437, 649, -37, 685, 776, 793, -899, 934, 175, 432, -808, -868, 652, 337, 186, -967, -417, 839, -193, -764, 361, -577, 497, 103, 29, 709, 472, 390, -606, -656, -616, -69, -770, 191, -494, 187, 355, 687, -821, -806, 283, 407, -555, -704, -244, 293, -970, -991, 380, 67, 390, 291, 35, 677, 337, -688, -817, 332, 688, 115, -779, 759, 534, 1055, 544, -116, -636, -247, -774, -784, -208, -659, 704, 557, 19, -829, 373, -758, -1026, -1167, 763, 885, -721, -593, -330, 864, 108, -561, 49, 217, -543, 154, -191, 121, -393, 365, 39, 803, 558, -218, 55, 207, 304, -657, -35, -421, 416, 483, 446, 703, 943, 692, -200, -8, 13, 895, -533, 740, -906, -911, -388, 582, -75, -1053, 767, 540, -323, 452, -414, -781, 723, 942, 1029, -920, 937, 884, 1034, 698, 554, -1068, 265, 816, 549, -8, -511, -490, -485, 385, 399, 523, -225, -770, 248, -263, 463, -796, 920, 392, -447, 302, -81, 528, -831, 62, 885, 86, -591, -37, -233, -211, -441, 837, 72, -598, 370, 45, -481, 671, 651, 781, -823, -731, 754, -199, -540, -639, -364, -318, 723, 485, 423, -650, -648, -909, 197, -795, 824, 336, 546, 837, 201, -398, -653, 219, -537, 809, -402, -652, -289, -437, 160, 122, -485, -203, -50, 731, -353, 805, -87, 878, -517, }; +int32_t mlp_head_linear_bias[16] = {-54, 918, 756, -770, 1018, -2, -846, 44, 784, -104, -384, -203, 212, -628, -94, -97, }; + +// Total 14512 parameters \ No newline at end of file diff --git a/sw/applications/trans_versasense/data_cpp/signal.cpp b/sw/applications/trans_versasense/data_cpp/signal.cpp new file mode 100644 index 00000000..0f18a419 --- /dev/null +++ b/sw/applications/trans_versasense/data_cpp/signal.cpp @@ -0,0 +1,5 @@ +#include "stdint-gcc.h" +//int32_t STFT_out[48000] ={15022, 16390, 15545, 7388, 9791, 14435, 15910, 14934, 8889, 9029, 12589, 14368, 13003, 9548, 6344, 9857, 11479, 9461, 8476, -1914, 9560, 7842, 5972, 6077, 3300, 9683, 6443, 5918, 4306, 3938, 8512, 3724, 5741, 5023, 2931, 7275, 3649, 5604, 5232, 3039, 7640, 5448, 5155, 3191, 4248, 7282, 5707, 3886, -1395, 4874, 5392, 5566, 307, 3140, 5102, 5513, 5713, 2597, 3891, 5867, 6802, 5914, 4893, 3388, 6861, 6592, 6289, 5121, 3314, 7333, 4961, 6907, 3998, 3581, 7119, 1288, 7340, 1455, 3347, 6134, -4195, 7221, -649, 2575, 4133, 1906, 6413, 1158, 1360, 639, 3608, 4810, 1664, -862, -2161, 4537, 2477, 1308, -3721, -2389, 5307, 903, -4, -555, -6878, 5826, 1113, -906, 1167, -1543, 5776, 1199, 1884, 1762, 149, 4966, 11, 3047, 1390, -386, 3716, -5616, 2671, -203, 74, 2832, -1861, 1678, -2604, 1596, 1292, 161, 1333, -2384, 1575, -3881, 818, 667, -1833, -390, -1812, 1707, -740, -1805, -3086, -694, 1426, -453, -1980, -790, -124, -648, 361, -3457, 42, 1155, -1014, 791, -13091, -656, 812, 379, 1297, -3332, -2853, -1853, -235, 1618, -420, -3919, -2006, -4401, 1689, 1044, -2273, 275, -565, 1635, 1800, -2376, 792, 2138, 1102, 1969, -2561, 237, 2818, -543, 1624, -310, -1249, 2136, -4400, 904, 920, -3606, 71, -6615, -81, 501, -2837, -1532, -4246, -1490, -2411, -879, -159, -3977, -4394, -7388, -319, -37, -4141, -10580, -1874, -1163, -1711, -3155, -3770, -1572, -3881, -5011, -826, -3183, -2875, -10316, -4701, 956, -4547, -3369, -6280, -4795, 1932, -4555, -2151, -4832, -7088, 2278, -4062, -1050, -4362, -9139, 2188, -5250, -628, -4430, -6307, 1816, -7122, -665, -4281, -3722, 1238, -4499, -856, -3217, -2790, 465, -2960, -1433, -2147, -3077, -434, -3195, -2783, -1981, -2941, -1212, -5049, -5353, -3217, -1690, -1498, -5065, -11050, -3855, -942, -1402, -2999, -6061, -1383, -1013, -1582, -2083, -3332, -275, -1903, -2508, -2036, -2211, -841, -4324, -4298, -2542, -2304, -3922, -6944, -6426, -3393, -3771, -7282, -2375, -9088, -4619, -7090, -2152, -895, -13285, -6205, -9679, -953, -1090, -7111, -6943, -7333, -1160, -2657, -5178, -6399, -4361, -2748, -5439, -4401, -5331, -2684, -7849, -7725, -4121, -4253, -2323, -6348, -6897, -3765, -3744, -2985, -4222, -5344, -3340, -3952, -4292, -6316, -3943, -3635, -5099, -5501, -6581, -3258, -5395, -8104, -6121, -2890, -3694, -8349, -8938, -7267, -2405, -5253, -6570, -6183, -8317, -3901, -6728, -6160, -6023, -6129, -6730, -5623, -7081, -8065, -5117, -7618, -3654, -5993, -12612, -5517, -6372, -2633, -5248, -9541, -6669, -4810, -2844, -6076, -6778, -7488, -5029, -4130, -6289, -5302, -5846, -9132, -5152, -5290, -5980, -4321, -6877, -5027, -5471, -8488, -3290, 10948, 5340, 9881, -583, -1529, 10281, 3184, 9400, 6255, -1363, 7983, 1790, 7839, 8319, -1213, 2985, 5766, 4578, 8716, -1201, 5806, 5972, -7468, 8093, 239, 7278, 3992, 2631, 6914, 2658, 7007, 3013, 4259, 6183, 4335, 5657, 4920, 4879, 6103, 5026, 5172, 5662, 5285, 5893, 4883, 5509, 5524, 5613, 5378, 4402, 4184, 4538, 5872, 4553, 4309, 3084, 2519, 6053, 4412, 4533, 5541, 2182, 5884, 5410, 4304, 6269, 3345, 4957, 5653, 3045, 5565, 3276, 3046, 4418, 1028, 4272, 2407, 595, 1213, 734, 3636, 1612, -1021, -9, 1479, 3416, 1031, -324, 1364, 1998, 3255, 94, 588, 973, 1467, 3470, -317, 408, -256, -1566, 3966, 176, -148, -1555, -5910, 4403, -381, 149, -3399, -1218, 4406, -3162, 1043, -3706, -2034, 3699, -6969, 1255, 13, -2967, 2095, -928, 675, 2541, -309, -742, 1059, -55, 3772, 276, -5152, 1483, -1167, 3918, -918, -2310, 600, -2456, 3234, -4253, -629, -1699, -803, 2143, -8360, -748, -4480, 187, 920, -4510, -2796, -5722, -657, -732, -2852, -6555, -8562, -5101, -1617, -1578, -3238, -2751, -2692, -76, -473, -1770, -1006, 672, 1164, 146, -1307, -1054, 1972, 1728, -76, -1108, -747, 2401, 1777, -1105, -617, 737, 2292, 1237, -496, 491, 1494, 1811, -216, 1202, 1623, 1157, 1162, -1153, 1656, 2217, -332, 552, 898, 776, 2074, -3098, -150, 2083, -258, 1096, -4664, -1276, 2076, 269, -817, -3732, -2660, 1252, 403, -3595, -2332, -3627, 139, -804, -5568, -652, -4610, -491, -4906, -5112, 12, -5653, -40, -5243, -4091, -766, -6220, 444, -1562, -3606, -3645, -7870, -40, -1055, -4503, -10695, -8347, -1875, -1973, -6634, -7025, -5321, -3534, -3721, -6422, -10405, -3470, -2072, -5833, -8296, -6307, -2409, -1348, -8634, -8763, -3250, -1734, -1712, -13134, -3935, -2113, -1132, -2943, -10088, -2782, -1927, -552, -3587, -7851, -3207, -2420, -210, -2134, -5907, -4824, -3031, -288, -1175, -4432, -6584, -2800, -678, -1292, -3739, -5705, -2132, -1039, -2508, -3901, -3854, -1624, -1437, -5728, -4955, -2528, -1266, -2274, -7524, -5831, -2232, -1272, -3370, -2624, -5012, -3195, -2200, -3783, -947, -4277, -4836, -4802, -3420, -488, -3943, -4317, -5543, -2886, -691, -4040, -4122, -3597, -2892, -1142, -4925, -6452, -3758, -4002, -1519, -5252, -10060, -5054, -4808, -1904, -3326, -4930, -4535, -2874, -2275, -1642, -3491, -3392, -1585, -2128, -765, -3125, -2599, -1366, -1867, -687, -3101, -1848, -2227, -2471, -1521, -3092, -1584, -4873, -5110, -4002, -3221, -2450, -8948, -5746, -11796, -3989, -5450, -4673, -2300, -3014, -6275, -6993, -3629, -1265, -1233, -13060, -3994, -3325, -1129, -1401, -6473, -2795, -2634, -856, -3122, -4984, -1852, -2143, -668, -4531, -4954, -1543, -2277, -1158, -4444, 8135, 6088, 8626, -4024, 9938, 7329, 6317, 8147, 3034, 9253, 4904, 6099, 7090, 5534, 7062, 4788, 5168, 5821, 5756, 2868, 6323, 4576, 3219, 3312, 1833, 6494, 3735, 3133, -3194, 4473, 5760, 1781, 5247, 3503, 5033, 4322, 154, 5491, 4139, 2895, 2112, -1883, 5106, 3344, 1160, 567, -8604, 5398, 2834, 5248, 2441, -1097, 6168, 3530, 5936, 4900, 904, 6690, 4608, 5104, 6129, 2446, 6590, 5040, 5192, 6005, 3385, 5551, 4266, 6075, 4500, 3096, 3111, 1873, 6379, 1400, 1015, -337, -2432, 6535, -3148, -6312, 1153, -3379, 6387, -4178, -2431, 1960, -3097, 5323, -2846, -282, 1735, -1790, 2714, -1477, 1123, 1114, 483, -5178, -288, 2408, 349, 2279, -962, 828, 2867, -310, 3205, 602, 1651, 2089, 248, 3324, 1195, 1919, -836, 1723, 2724, 2721, 1435, -8160, 2498, 1506, 3795, -83, -1480, 2126, 141, 3702, -2304, -1676, 632, -186, 2139, -1688, -2840, -452, 758, 749, -1085, -1050, 84, 1955, 2587, -1448, -667, 47, 2776, 3314, -1334, -1973, -584, 3074, 2871, -1128, -4037, -927, 2914, 2029, -1831, -4223, -893, 2430, 1750, -3735, -1903, -725, 1721, 2124, -4438, 91, -814, 695, 2326, -1846, 1159, -718, -1112, 1779, -605, 1229, 953, -4285, 161, -1077, 226, 2278, -2549, -3196, -1597, -1233, 2448, -61, -10037, 1326, -207, 1631, 1238, -5459, 2800, 1173, 597, 1719, -2662, 2475, 1064, 234, 1395, -1008, 22, -931, 85, 225, -520, -10125, -1692, -101, -2013, -1056, -3239, -169, -365, -5623, -1918, -2721, -886, -713, -4148, -1070, -4144, -4883, -992, -3366, -504, -5371, -7334, -1451, -4299, -1722, -5860, -5572, -2058, -2407, -3307, -5420, -9669, -1902, -626, -800, -3278, -4000, -1470, -465, 514, -2492, -1965, -1758, -2323, 435, -3628, -1768, -2921, -5922, -956, -9229, -2309, -4942, -927, -4084, -4407, -2502, -9038, 836, -8231, -2095, -2284, -5389, 1066, -5365, -1906, -1985, -2756, 264, -3891, -3017, -2226, -2262, -1447, -4557, -4960, -3502, -3466, -3976, -11280, -5981, -3511, -5119, -4299, -3848, -5230, -2657, -3228, -2919, -1482, -4701, -3847, -1903, -2750, -1004, -4962, -9136, -1535, -4156, -1487, -5918, -5496, -1578, -9790, -2332, -7666, -4300, -1746, -6635, -2932, -11718, -5430, -1928, -3956, -3045, -13570, -7603, -2016, -3785, -2822, -9656, -7021, -2159, -4384, -2470, -5004, -4553, -2859, -3625, -2045, -2525, -3046, -5049, -2807, -1748, -1425, -2589, -10651, -3267, -2273, -1223, -2394, -5327, -4768, -4832, -1712, -1883, -4089, -3759, -6611, -2592, -1631, -4451, -2098, -3778, -2317, -1688, -4707, -1511, -4370, -1104, -1674, -5347, -1880, -7616, -511, -1990, -8962, -3392, -5659, -637, -3117, -7329, -6851, -5500, -1134, -4374, -4297, -12628, -9453, -1507, -3914, -3602, -7923, -7498, -4224, -5554, -4353, -4133, -2129, -3878, -7270, -2473, -2452, -1737, -3507, -7586, -2008, -2512, -2831, -2846, -5254, -3025, -3418, -5986, -2821, -3714, -5611, -3744, -7985, -2808, -3010, -13840, -2935, -6763, -2277, -2991, -6283, -2459, -7017, -2183, -3789, -3468, -3366, -5831, -3055, -6182, -2980, -5755, -4109, -5251, -13347, -4226, -3284, -3689, -9905, -6728, -7062, -1040, -4341, -6515, -5290, -10547, -88, -4173, -4287, -5037, -9538, 15, -3219, -3665, -4580, -5533, -670, -3366, -3725, -4293, -3755, -2433, -5426, -3616, -4979, -3342, -5897, -10483, -3418, -6809, -4226, -5644, -6907, -3888, -7436, -6950, -4348, -6768, -4698, -5425, -7290, -5661, -11547, -4637, -4024, -4705, -7820, -7789, -5294, -3717, -3606, -4001, -4241, -7811, -4602, -2791, -2423, -2364, -6255, -6510, -1775, -2276, -1164, -5607, -6340, -1017, -3077, -580, -7866, -4238, -901, -4310, -652, -11726, -3115, -1541, -5083, -1309, -10766, -3063, -2977, -5072, -2160, -5334, -3219, -5153, -4673, -2549, -2761, -2681, -5813, -4537, -2539, -1887, -2418, -4519, -5214, -2776, -1955, -2947, -4445, -6446, -3623, -2344, -4213, -5961, -6591, -5118, -2949, -6336, -7215, -6457, -7136, -4560, -9194, -6317, -7439, -9810, -7339, -9647, -7399, -9089, -8084, -5084, -8196, -10603, -8142, -4773, -4006, -6529, -5264, -6082, -3144, -4962, -5245, -3482, -4467, -2991, -7160, -4667, -3534, -3485, -4536, -5624, -4729, -5032, -3222, -8808, -4191, -5173, -6219, -3555, -16024, -4330, -5943, -5030, -4186, -8660, -6684, -6669, -4314, -4229, -3671, -7971, -6376, -4176, -3187, -1670, -3458, -5898, -4030, -2731, -1236, -1895, -5622, -3478, -3836, -1952, -1883, -5111, -2565, -7553, -3555, -3115, -4399, -1740, -7056, -5274, -5062, -4108, -1482, -5186, -5586, -5718, -5093, -2065, -5623, -4664, -4970, -9301, -3493, -7925, -3350, -3927, -8207, -4928, -13647, -2286, -3205, -5647, -5288, -11389, -1695, -3351, -5048, -5436, -10277, -1476, -4273, -3759, -5299, -11084, -1462, -3966, -2469, -4478, -12156, -1510, -2701, -2149, -3377, -9283, -1412, -2234, -3086, -2832, -6406, -1068, -2636, -6186, -3387, -5200, -747, -3812, -10087, -5553, -4196, -911, -5894, -5260, -12137, -2698, -2137, -8129, -4371, -9214, -1973, -5654, -7221, -4905, -7118, -2635, -11761, -6359, -5793, -7149, -5285, -7383, -5904, -6008, -8398, -8178, -8107, -5657, -6536, -9448, -5544, -5874, -6363, -8914, -8639, -5672, -4566, -8413, -10223, -8665, -9040, -4611, -8140, -6790, -7995, -9845, -5443, -6600, -5701, -5196, -5562, -6064, -6901, -5391, -3432, -4047, -5589, -10634, -4751, -2899, -3579, -5435, -9912, -4255, -3442, -3902, -5816, -6228, -4453, -4620, -5031, -6518, -5566, -5374, -5341, -6901, -8805, -6416, -7360, -5643, -8714, -17696, -8138, -11290, -6006, -9255, -12064, -8799, -7964, -6673, -10575, -9542, -7865, -5755, -8615, -10922, -5114, -7102, -4998, -11781, -6158, -3484, -4628, -2421, -3126, -2497, -6789, -5250, -4794, -4449, -4410, -7477, -9881, -6436, -5064, -3607, -3449, -4608, -4046, -5613, -2139, -2217, -2871, -2510, -6822, -1828, -2235, -3843, -2185, -5537, -2152, -3064, -6329, -3289, -4432, -2550, -4718, -4122, -6236, -4556, -2730, -8599, -3320, -6537, -4686, -2432, -7789, -4202, -4618, -4608, -2175, -3777, -6026, -3566, -6205, -2668, -2263, -7801, -2576, -13093, -4308, -2029, -9251, -1785, -4928, -7375, -3049, -8052, -1709, -2944, -9674, -6259, -5386, -2760, -2434, -9137, -6066, -4239, -5655, -2581, -6472, -3521, -4001, -10908, -3366, -5255, -3280, -3305, -4920, -6014, -6907, -4092, -2406, -3021, -9081, -10022, -4709, -2289, -2635, -3189, -5011, -4448, -3296, -3604, -1475, -4570, -4321, -5646, -6025, -1196, -5631, -5608, -5570, -5345, -1726, -3948, -8925, -3247, -3919, -2528, -2846, -4629, -2085, -3725, -3203, -2884, -1340, -1892, -3501, -3959, -2956, 213, -2570, -3436, -5344, -3247, 385, -3672, -4179, -7922, -4596, -782, -4517, -4623, -10663, -5247, -3613, -5710, -4269, -7357, -3805, -8204, -7537, -4200, -4774, -3261, -3386, -9210, -3521, -3260, -4029, -1266, -10245, -2801, -2777, -6779, -618, -8283, -3242, -3408, -5810, -806, -5770, -5696, -4816, -2843, -1404, -3474, -12002, -4835, -2324, -2230, -1947, -5336, -3635, -4445, -3446, -1253, -3757, -2754, -9328, -5841, -1357, -3536, -2539, -2725, -13317, -2351, -3881, -3123, -1220, -7147, -4485, -4898, -4220, -1221, -5824, -7862, -8392, -5317, -2285, -6768, -11502, -7970, -6846, -4558, -7862, -6879, -3544, -8386, -8920, -5639, -3193, -1802, -5582, -16426, -4403, -1478, -1162, -3322, -11213, -4289, -1030, -1320, -2236, -7203, -4753, -1637, -2259, -2066, -5910, -5082, -3287, -4154, -2592, -7050, -4526, -5607, -7379, -3425, -5504, -4246, -5552, -9774, -4065, -2373, -5163, -4380, -8617, -4242, -1009, -7160, -3989, -7901, -3963, -876, -8081, -4222, -6692, -3726, -1778, -6391, -4630, -5593, -4172, -3764, -4734, -4670, -5500, -5797, -7407, -4288, -4354, -7442, -8769, -8786, -5317, -4301, -11498, -6984, -5990, -8221, -4744, -5009, -4564, -5757, -9903, -4512, -3263, -3106, -7633, -8076, -3552, -3447, -2234, -11771, -6541, -3325, -5117, -1930, -12667, -4415, -4296, -5804, -2117, -11981, -2877, -7575, -5708, -2684, -12463, -2311, -10012, -7172, -3786, -17520, -2856, -5074, -5329, -5509, -11698, -4665, -4276, -3556, -6559, -7320, -4445, -5423, -3139, -6032, -4982, -2432, -6815, -3515, -5233, -3675, -1834, -5983, -4451, -4885, -3100, -2452, -6053, -5609, -4813, -3412, -3794, -7398, -6187, -4484, -5126, -5070, -8555, -5637, -4332, -8942, -6059, -7890, -4903, -4780, -8156, -5664, -6966, -5044, -5826, -7445, -4759, -6094, -6121, -7366, -8944, -5258, -4845, -7107, -8586, -12286, -7313, -4354, -6859, -8099, -16158, -6273, -5653, -6242, -7236, -8803, -5182, -11020, -6046, -6956, -5479, -6656, -1536, -2950, -4414, -6079, -3604, -1428, -2411, -7541, -5139, -1848, -1324, -2361, -9913, -4836, -1486, -1298, -2802, -4591, -3959, -2406, -1573, -3744, -2758, -1712, -4194, -2495, -5418, -2422, -42, -5054, -4591, -9189, -3442, 459, -3980, -9195, -8925, -4492, -230, -2899, -11097, -5822, -3678, -2121, -2792, -12465, -5374, -3936, -5487, -3382, -10965, -6491, -4860, -13201, -3897, -6980, -8176, -4223, -4575, -4537, -5943, -7331, -4482, -2722, -5484, -5427, -5826, -5564, -2821, -5674, -5105, -4386, -3766, -4394, -4608, -5164, -2664, -1603, -5443, -3593, -4710, -1555, -639, -4933, -2796, -3042, -1221, -1098, -6719, -1430, -1246, -1225, -3395, -11421, -447, -162, -1211, -8133, -7246, -627, 167, -1171, -4891, -10083, -2175, -139, -1219, -3020, -7058, -4571, -1084, -1635, -2768, -4466, -3412, -2470, -2518, -4109, -4079, -1188, -3285, -3544, -6015, -4011, 137, -3802, -3376, -4381, -3608, 518, -4965, -1353, -3572, -3037, -126, -7139, 168, -4533, -3447, -1934, -13471, 690, -7204, -6408, -3553, -5680, 417, -9220, -8269, -2607, -3936, -222, -8050, -5319, -2079, -4119, -761, -4771, -4550, -1746, -4482, -1413, -3437, -3790, -1023, -3611, -2864, -3832, -3177, -620, -2645, -4979, -5815, -2643, -652, -2136, -4731, -10493, -2648, -695, -2344, -4163, -10081, -3430, -880, -3418, -4701, -6001, -2792, -1648, -5340, -4910, -4263, -1434, -2959, -6768, -3486, -3360, -1291, -4215, -5259, -2557, -2870, -2715, -5327, -4127, -2717, -2591, -6908, -7188, -3928, -3565, -2566, -9345, -9250, -4424, -3837, -3153, -6026, -6089, -5596, -3329, -4823, -4115, -4029, -5332, -3093, -7403, -2244, -3228, -3730, -3423, -6394, -1321, -3169, -3120, -4030, -4822, -1391, -3856, -3352, -4019, -4452, -2389, -6223, -4162, -3507, -5531, -3885, -11595, -5537, -3763, -9584, -4454, -7117, -6049, -5539, -11492, -4732, -8537, -4404, -6531, -8904, -4400, -6582, -2673, -5208, -8826, -2727, -2659, -1747, -5819, -5655, -2061, -1277, -1705, -9453, -4239, -3059, -1187, -2241, -10353, -4868, -6682, -1802, -3158, -5447, -8286, -8509, -2649, -4713, -3619, -12757, -5460, -3539, -4764, -3014, -12636, -4901, -4068, -3348, -2840, -8742, -5394, -4270, -3392, -2768, -4667, -6856, -5074, -5305, -2984, -3324, -7579, -6296, -6783, -3459, -3532, -4949, -5979, -5328, -4029, -5532, -2721, -5319, -5970, -4667, -14849, -1369, -6133, -10401, -5585, -6837, -790, -12638, -8761, -7334, -5777, -937, -6287, -6741, -9955, -8368, -1808, -3420, -7326, -12278, -8497, -3363, -2912, -8770, -16695, -5559, -4951, -4095, -8610, -13416, -4846, -5025, -7435, -7926, -11937, -3580, -4428, -9001, -6381, -11803, -2464, -4303, -6744, -4580, -13182, -2617, -4979, -6343, -3508, -14602, -4359, -6610, -6657, -3260, -15423, -8127, -8838, -6860, -3720, -14890, -7968, -8299, -6477, -4389, -9173, -6467, -6679, -6249, -4327, -7138, -6132, -6455, -6392, 992, 7886, 7836, 5707, 2952, 5763, 7674, 7512, 5744, 3131, 7257, 7047, 6697, 5594, 2840, 6944, 6137, 5861, 5029, 1656, 6387, 5254, 5171, 4191, 1669, 6716, 4499, 4157, 3252, 2364, 6445, 3756, 2809, 2540, 1949, 4670, 3162, 2233, 3092, 910, 3710, 3344, 2679, 4147, 410, 5517, 4146, 3327, 4671, 452, 6178, 4380, 3727, 4620, 2149, 6053, 3711, 3627, 3805, 4693, 5401, 2486, 3007, 1193, 6237, 3584, 1501, 2138, -2809, 6624, -1377, 1312, 1430, 1631, 5874, -740, 1336, 1335, 2278, 3788, 1232, 544, 1760, 1376, -797, 984, -1787, 1610, 858, -4456, -16, -4421, 402, 1445, -841, -510, -1344, -1367, 1905, -616, -34, -459, -2302, 2253, -1120, 504, -1942, -2912, 2376, -1730, 720, -3838, -5891, 1875, -2627, 388, -695, -5800, 806, -4711, -673, 741, -1852, 50, -11015, -2310, 1308, -789, -233, -8245, -3429, 1893, -426, -743, -6045, -3855, 2501, -212, -1327, -3983, -5484, 2535, -521, -2006, -2393, -6745, 1562, -1584, -3385, -1364, -4140, -858, -3071, -6674, -598, -3454, -2410, -4007, -10510, -171, -4255, -203, -4907, -4974, -243, -6219, 582, -5832, -3180, -1018, -8783, -28, -4707, -1608, -2965, -5414, -2510, -3392, -581, -7330, -3019, -3582, -2700, -677, -6955, -1847, 35, -2277, -1773, -3219, -1611, 1252, -2376, -2733, -1083, -2530, 694, -4002, -2387, -716, -5145, -2053, -9433, -1461, -2429, -5676, -2719, -10283, -1021, -1831, -3878, -761, -5449, -1362, 475, -3664, -1287, -2617, -1862, 915, -3556, -2383, -2085, -1446, 149, -2817, -670, -4159, -375, -472, -2112, 394, -5643, 323, -35, -1757, 248, -2140, 192, 320, -1983, -1029, -1086, -983, -22, -2932, -3865, -1238, -3894, -1474, -4558, -9183, -1959, -7920, -3368, -5977, -7833, -2767, -2841, -1495, -4291, -6174, -3929, -1107, -176, -2147, -2464, -4110, -851, -181, -1039, -299, -2417, -2003, -1071, -1016, 578, -2123, -5311, -1919, -1861, 617, -3951, -4696, -2089, -1896, 235, -9294, -2333, -2652, -733, -288, -6439, -1996, -4479, -339, -1155, -4501, -2973, -7503, -1126, -2682, -2749, -3114, -5895, -3277, -4758, -822, -1788, -4046, -8511, -7487, 437, -1922, -3277, -7813, -5958, 551, -5066, -3319, -4848, -2147, -756, -6046, -3552, -4780, 106, -3455, -2730, -2710, -5057, 1332, -4293, -3013, -1523, -5034, 1646, -4528, -6230, -887, -6935, 891, -6414, -9181, -812, -4640, -1659, -7119, -6210, -1117, -2365, -14029, -5370, -6259, -1621, -1609, -3314, -5115, -7142, -1958, -1108, -2256, -7398, -7089, -1758, -994, -2106, -4836, -5489, -1371, -1982, -2098, -2545, -3927, -1402, -4561, -3066, -2233, -3486, -2416, -7078, -4875, -3155, -4911, -5524, -4643, -4758, -5020, -7861, -12217, -3992, -3582, -9911, -4628, -6038, -4259, -2813, -6597, -3333, -5671, 4431, 6956, 4647, 3404, 3214, 3330, 6394, 4445, 4636, 4919, -2018, 4626, 3869, 5670, 6749, 174, 1203, 3186, 5540, 7498, 1979, -3313, 3158, 4216, 7309, 89, 504, 3878, 1072, 6525, -7332, 2160, 4371, 83, 5384, -1885, 2720, 4121, 2851, 3793, -2387, 2886, 3245, 3140, 2596, -131, 3575, 2615, 2064, 2369, 2750, 4385, 2649, 2541, 1643, 4474, 4335, 2717, 3876, 2216, 5069, 3125, 2641, 4261, 3761, 4424, 1483, 2251, 3750, 4483, 2485, 1454, 1283, 2464, 4432, 1067, 1443, 85, 569, 3826, 2180, 401, 47, -1340, 3066, 2822, -1339, 182, -2231, 2563, 2587, -1558, -920, -2301, 1920, 1218, 336, -3313, -1700, 683, -1842, 1950, -4908, -599, -386, -1289, 2887, -5087, -836, 463, 149, 3227, -887, -4338, 1261, -594, 3167, 1502, -1816, 1038, -2955, 2939, 2548, 680, 327, -2472, 2629, 2745, 1043, 51, -1627, 2053, 2212, 948, -302, -2321, 933, 785, 1074, -1594, -3706, -838, -1956, 601, -3409, -3084, -3032, -6554, -656, -3464, -1611, -4914, -7763, -1656, -4244, -1174, -4880, -6737, -1234, -2011, -1233, -4355, -3618, -340, 526, 47, -5364, -1510, -318, 1544, 1463, -7198, -750, -1860, 1727, 1828, -5679, -1416, -7268, 1307, 931, -6528, -3862, -4626, 11, -1518, -4014, -6626, -1510, -2411, -4306, -437, -6696, -397, -3961, -3760, 1004, -6606, -513, -3297, -2746, 1013, -5990, -1930, -2778, -663, -172, -11236, -2111, -3063, 473, -2169, -4851, -144, -4907, 464, -3009, -1982, 781, -8275, -439, -1982, -1424, 776, -9936, -1390, -912, -1763, 71, -6078, -531, -87, -1362, -1265, -4817, 709, 402, -298, -2933, -7191, 1147, 411, 464, -3762, -5416, 641, -36, 858, -3242, -3244, -878, -725, 974, -2772, -4068, -3062, -1369, 786, -3532, -4200, -3880, -2030, 165, -5898, -1956, -3455, -3426, -1106, -5290, -1439, -3346, -6797, -3430, -3721, -2194, -3895, -5475, -7296, -2447, -2540, -5088, -2472, -7216, -1279, -1260, -6922, -1288, -5455, -683, -66, -6827, -1382, -4648, -376, 376, -4007, -2543, -4856, -190, 93, -2386, -3378, -5880, -477, -515, -2070, -2682, -4918, -1273, -1178, -3491, -2129, -3087, -1615, -2334, -12014, -1948, -2105, -1411, -4243, -2991, -1997, -1792, -1734, -8766, -470, -2496, -1876, -2784, -5016, 104, -3838, -1877, -4591, -1105, -731, -6301, -1746, -9082, 199, -3223, -8534, -2817, -6844, -58, -8548, -7309, -10561, -3983, -1936, -10120, -5995, -3376, -3673, -4603, -20985, -4612, -1454, -2665, -1776, -7189, -3343, -2512, -930, -299, -4932, -3211, -7404, -583, -305, -4692, -4774, -3010, -1973, -1335, -5472, -5595, -369, -4883, -2031, -6404, -3584, 783, -3635, -1048, -6310, -2819, 852, -2206, -154, -5323, -1834, -93, -1718, 30, -4480, -626, -1947, -1728, -541, 4174, 4649, 8112, 4717, 10466, 5280, 6423, 7948, 6862, 10222, 6501, 8002, 7664, 8295, 9563, 6769, 8408, 7456, 8429, 8561, 6127, 7730, 6905, 7644, 7034, 5048, 5903, 5514, 5941, 4594, 4185, 2543, 3305, 2660, 982, 3149, -888, 1426, -2564, -1865, 1011, 1471, 735, 1166, -1159, -5527, 2616, -306, 1632, 314, -106, 3024, -43, -844, 734, 2930, 3341, 2467, -2478, 2614, 3788, 3719, 3345, 2597, 4789, 2812, 3667, 2827, 4269, 5884, -511, 3317, 2219, 4869, 6290, 1704, 3473, 2860, 4963, 6365, 3274, 3591, 3308, 4690, 6044, 2644, 2936, 2953, 4056, 5092, -557, 1584, 1968, 2995, 3317, -4360, 179, 891, 1167, 815, 452, -215, 513, -2135, 86, 1319, 299, 907, -1288, 765, 870, 155, 1373, 1199, 403, 686, -2036, 1276, 2295, -1164, 1208, -6659, 115, 2607, -2310, 701, -1110, -2708, 2307, -1258, -1150, -328, -2530, 1467, -1410, -736, -1907, -296, 883, -2029, -52, -5263, 495, 1564, 553, -1306, -5543, 797, 2156, 1991, -3684, -3848, 1128, 1951, 1912, -3782, -1034, 1249, 1359, 895, -5389, 388, 952, 1349, 218, -6377, 657, 576, 1456, 759, -2880, 335, 729, 494, 1309, -1657, 478, 1458, -2099, 866, -473, 1422, 2292, -1460, -620, -50, 1993, 2768, -94, -1113, -2239, 1399, 2583, -751, -410, -4992, -1336, 1481, -2172, -510, -476, -3462, -839, -1211, -841, -618, -17, -2638, -555, 273, -3499, 496, -876, -1009, 1572, -1315, -297, 196, -2170, 2027, -228, -1264, 454, -3745, 1439, -1464, -2322, 81, -4717, -381, -5409, -4077, -907, -4231, -3575, -11310, -5445, -2337, -2910, -8052, -6921, -5310, -4192, -1845, -13976, -4606, -4917, -4348, -2024, -8954, -3415, -5146, -1546, -3490, -8070, -3267, -5532, -149, -4645, -5821, -3369, -4589, 86, -4673, -3846, -4033, -4557, -413, -2522, -2014, -7275, -7793, -1331, -262, -1161, -6355, -4242, -2505, 707, -1661, -2821, -1515, -4093, 563, -3620, -1675, -1146, -6469, -473, -6858, -1510, -2831, -7219, -1769, -5947, -1635, -7801, -5863, -2385, -4331, -2407, -5390, -5883, -3613, -4909, -5852, -2773, -7221, -9159, -8695, -6468, -1251, -7432, -3003, -8598, -3055, -955, -3342, -265, -7250, -2386, -2007, -710, 612, -7422, -1428, -3766, 347, 364, -4521, -496, -3947, -144, -697, -1507, -547, -3434, -2881, -2096, 292, -1598, -3256, -5414, -2594, 965, -3239, -3247, -2169, -2317, 652, -4359, -2603, -1742, -3337, -557, -4459, -1171, -2509, -10715, -2786, -4692, -227, -3927, -3425, -7108, -6957, -226, -4770, -818, -4731, -6172, -1041, -2897, -248, -2449, -1775, -2384, -1771, -697, -2684, -90, -5076, -1110, -1802, -6855, 99, -9796, -337, -4902, -5453, -1061, -2976, -36, -5415, -2246, -3853, -1317, -549, -918, -1705, -3747, -2112, -4001, -3034, -4635, -4213, -1260, -3727, -2473, -2438, -6982, -367, -3185, -1593, -982, -4534, 264, -2079, -1182, -222, -2747, 483, -2456, -1750, 35, -2512, 388, -5304, -3164, -88, -2206, 140, -4527, -3982, -532, -1428, -144, -2873, -3008, -1346, -1345, -365, -3984, -1784, -2639, -2397, -697, -6265, -1517, -3277, -2307, -1651, -4134, -2354, -1553, -288, -3640, -3791, -3550, 65, 652, -3861, -4141, -3568, 950, 228, -2067, -2900, -2781, 1302, -1954, -1289, -2053, -2108, 1342, -6273, -1345, -1988, -2096, 1204, -4779, -1906, -1653, -3694, 637, -5027, -1988, 82, -10105, -1492, -629, -486, 2110, -1648, -3002, 1882, 1459, 3378, 657, 1358, 2660, 2603, 3623, 1185, 2820, 2130, 2627, 2740, 637, 2565, 365, 1434, 560, -235, 841, -2650, -1067, -3141, -370, -1308, -5821, -3575, -5607, 47, -1692, -6442, -2726, -5532, -168, -2738, -4904, -1480, -7712, -1903, -4340, -3564, -672, -11754, -6389, -3800, -3243, -417, -5924, -5494, -2953, -3758, -816, -4087, -4188, -2255, -4726, -1998, -3790, -4542, -1674, -5694, -3952, -5810, -5381, -1442, -6169, -5589, -7299, -5101, -1910, -5950, -4971, -2468, -4109, -3935, -6223, -3510, -1109, -4084, -12610, -7526, -2798, -1748, -4875, -2691, -6655, -3009, -5180, -3571, -299, -4560, -3222, -5909, -1531, 345, -3402, -2278, -3277, -663, -382, -2929, -1166, -3916, -1028, -2305, -2012, -494, -7351, -2594, -3089, -610, -250, -8475, -5069, -3070, -48, -487, -5563, -7464, -4932, -943, -1479, -3054, -7030, -5903, -3367, -3876, -1946, -5475, -4377, -2021, -7366, -2306, -4082, -4492, -563, -4662, -4219, -2805, -3707, -1053, -3735, -9693, -2621, -1912, -4055, -3845, -8011, -3894, -912, -8948, -3433, -5298, -6418, -661, -3656, -2446, -5489, -10928, -1071, -2590, -1764, -7680, -8049, -2208, -2121, -1662, -6862, -3920, -4199, -1926, -2121, -4885, -2611, -7311, -2486, -3145, -4183, -2502, -6901, -3554, -5151, -3631, -2937, -4649, -4186, -7162, -2699, -4051, -3461, -4742, -5468, -2078, -6172, -2738, -5050, -5448, -2188, -5573, -2471, -5332, -7820, -3023, -4144, -2849, -8141, -9531, -4575, -4189, -3847, -6521, -7025, -4941, -5784, -4681, -3328, -4626, -2908, -10587, -4944, -2513, -3434, -1903, -8857, -6083, -3079, -3631, -2184, -6619, -7385, -4605, -4939, -3503, -7520, -4832, -5781, -5437, -4992, -16740, -3000, -5635, -4065, -5684, -7742, -2005, -6065, -2885, -6214, -5278, -1464, -7700, -2155, -7036, -4340, -1287, -9068, -1918, -8916, -4106, -1409, -10187, -2433, -8882, -4859, -1646, -9359, -4090, -7672, -7479, -1849, -6429, -6578, -10293, -11893, -2146, -5860, -5821, -9577, -9527, -2889, -7698, -5002, -5400, -10978, -4290, -10471, -5225, -4621, -9688, -5863, -8450, -5468, -6029, -7785, -7006, -10558, -5211, -9458, -7926, -8354, -10826, -5036, -5769, -9321, -8951, -3863, -401, -4910, -2323, -2099, -3046, -1484, -5082, -3636, -4300, -1990, -3768, -3293, -6039, -2892, -1020, -3385, -4360, -10286, -1381, -255, -1195, -8361, -4200, -844, 278, 114, -2769, -1775, -811, 435, 634, -894, -1206, -1477, -8, 381, -142, -2189, -3598, -1427, -717, 335, -4704, -8123, -5223, -2835, 417, -4946, -7597, -6079, -6358, -351, -3272, -5801, -2029, -7051, -2202, -2890, -3212, -1142, -3754, -3082, -3662, -1664, -2077, -2099, -2011, -3470, -1050, -5634, -1766, -1891, -1794, -940, -8934, -2247, -2760, -858, -1262, -3438, -2825, -4027, -444, -2366, -964, -2952, -3780, -62, -4754, 1092, -744, -1225, 785, -3777, 2671, 1289, 547, 1815, -1385, 3401, 2002, 1037, 2102, -919, 3093, 1419, 302, 1159, -2604, 1611, -615, -1667, -1151, -6590, -1305, -4651, -4417, -2579, -2497, -5931, -3787, -3795, -2262, -1112, -6328, -1578, -2133, -2192, -1282, -5249, -492, -1608, -1433, -1872, -5463, 56, -2829, -1033, -1877, -6735, 108, -8921, -1287, -2722, -7527, -461, -2687, -1650, -8005, -5833, -1891, -802, -2093, -3565, -4344, -4628, -1311, -2714, -996, -3912, -7108, -4596, -2647, -767, -3612, -5606, -7922, -2412, -2013, -1807, -5153, -3394, -3264, -3955, -187, -5528, -2571, -5326, -4593, 284, -4498, -2853, -4618, -4179, -632, -2208, -3530, -2875, -3441, -3109, -724, -4099, -2419, -2947, -2721, -181, -4229, -3471, -2999, -1022, -361, -3709, -7384, -3834, -599, -967, -3015, -8685, -5134, -711, -1899, -2887, -5903, -3554, -765, -3358, -3166, -5754, -1923, -714, -3785, -2993, -5364, -1627, -914, -2953, -2677, -4464, -2332, -1681, -3383, -2699, -3035, -3388, -3309, -3892, -3248, -1738, -3700, -6108, -2633, -5378, -1179, -2604, -4500, -2448, -6191, -1404, -1393, -2437, -4005, -3079, -2358, -977, -2288, -5299, -2310, -4056, -1572, -3908, -3726, -3124, -5777, -3196, -5321, -2909, -5437, -4515, -4846, -3710, -2791, -11497, -2689, -5536, -3021, -3005, -9364, -1774, -7165, -3170, -3541, -5741, -2088, -5895, -4048, -4716, -2782, -4370, -4907, -6604, -7144, -759, -6454, -7052, -7518, -8122, 162, -3555, -4903, -4158, -5895, 171, -3090, -2152, -3245, -5270, -458, -3873, -1626, -3560, -5052, -1399, -4831, -2721, -3192, -3680, -2242, -6011, -5172, -1962, -2520, -2037, -8181, -5573, -1320, -2241, -1316, -8217, -4278, -1378, -2414, -1338, -6014, -3858, -2009, -2515, -2295, -5196, -4232, -3320, -2881, -3690, -5759, -4847, -5692, -3846, -4289, -8306, -4073, -8223, -5282, -3679, -16164, -3100, -6849, -6858, -3166, -9936, -3173, -6371, -6714, -3424, -8925, -4364, -5933, -6648, -3920, -7339, -6037, -4464, -9019, -3779, -6133, -6647, -3996, -10396, -3640, -6068, -6735, -5136, -8205, -3995, -6796, -7047, -8061, -8816, -4599, -6902, -7482, -10407, -11258, -4973, -5821, -7887, -7805, -11952, -5019, -5191, -8094, -3997, -1225, -1726, 455, -2235, -1923, -1850, -2943, 550, -3777, -1445, -2087, -3342, -100, -5814, -1953, -2336, -3153, -1103, -4142, -2632, -4684, -3320, -1695, -2613, -2901, -8141, -4337, -1264, -1490, -2999, -2810, -6058, -562, -465, -3671, -2464, -7398, -133, 2, -5802, -5233, -7651, 29, -553, -6365, -4151, -6733, -20, -2718, -6204, -1790, -5319, -477, -5304, -14004, -1346, -5160, -1726, -2391, -5560, -1932, -7949, -4745, -808, -3556, -3041, -3434, -9599, -338, -2007, -3100, -831, -3094, -916, -500, -1744, -360, -1619, -2268, -816, -956, -1394, -1788, -2899, -8095, -2464, -3479, -2063, -2920, -96, -6021, -2134, -158, -528, 2698, 497, 628, 1616, 1838, 3059, 2030, 1896, 2141, 2847, 1232, 1605, 1912, 1225, 2745, -8986, -425, 926, -1296, 1901, -483, -2512, -753, -2453, 956, 843, -1462, -2673, -1688, 9, 95, -537, -4408, -2272, -2437, -1608, -347, -5766, -2994, -5430, -3559, -711, -6027, -2730, -1048, -6876, -1160, -5132, -2448, -191, -9054, -1174, -3723, -2641, -1234, -7680, -999, -2339, -3458, -3787, -4533, -1345, -1551, -4958, -4962, -1365, -2678, -1656, -4757, -4839, -255, -4576, -3032, -2895, -6716, -603, -5046, -6251, -2278, -6261, -1986, -4877, -5405, -3344, -5445, -3752, -4363, -3169, -7274, -8626, -5077, -4816, -2093, -8234, -4423, -6048, -8315, -1521, -5655, -2150, -7367, -4908, -1421, -4987, -2215, -8890, -2915, -1900, -3782, -4512, -8844, -3645, -2610, -2110, -11768, -7070, -6387, -2648, -642, -5088, -5925, -2978, -2638, 160, -3597, -6593, -1333, -4099, 112, -3402, -10426, -1467, -8395, -890, -3571, -6303, -2852, -3149, -3120, -4245, -3113, -4508, -964, -7471, -4544, -1674, -5138, -434, -8217, -3670, -1793, -6248, -1070, -7179, -3860, -3207, -11460, -2975, -7530, -5558, -2942, -8060, -6450, -4451, -7461, -2403, -5962, -4914, -1935, -10274, -3799, -6274, -3149, -605, -5873, -6762, -4510, -3147, -166, -3850, -6233, -2935, -4624, -373, -4159, -5653, -2806, -7555, -1092, -5467, -7347, -3662, -11322, -2169, -5232, -6273, -4987, -12250, -1931, -6186, -3310, -6732, -12012, -704, -11559, -2685, -8575, -6899, -460, -3157, -3793, -10286, -3554, -1608, -737, -6339, -9748, -1825, -4462, -94, -7832, -6802, -1348, -6603, -749, -7260, -7043, -2270, -5405, -2259, -6798, -13103, -5551, -4543, -3056, -6387, -5503, -8667, -4196, -3570, -6220, -3738, -5031, -5614, -4747, -6335, -4764, -4838, -14754, -2743, -6782, -10976, -6079, -6492, -839, -8010, -3814, -6350, -4274, -270, -10839, -1667, -4784, -3521, -885, -8579, -1418, -3388, -3149, -2850, -6281, -2455, -2546, -3133, -7300, -6330, -4263, -2585, -3700, -11042, -7839, -5477, -3646, -4679, -6705, -5640, -5430, -5216, -5187, -4908, -3996, -4950, -5622, -5062, -3597, -3962, -5171, -5520, -5080, -3056, -5109, -6746, -6170, -4909, -3343, 12256, 8004, 12464, 10904, 8416, 11661, 8838, 11745, 10292, 7837, 9829, 9223, 9416, 8226, 5859, 6696, 8767, 5290, 3434, 1111, 2977, 8757, 4969, 1397, -464, 2108, 8772, 5794, 2522, 410, 3623, 7901, 5356, 2679, -1019, 5245, 5907, 2704, 4437, 2837, 6340, 1941, -1646, 4585, 4770, 6369, -1679, 2483, 2553, 5902, 5187, 2214, 1437, -1825, 6887, 4304, 3741, 84, 2872, 7698, 4748, 5084, 4322, 4584, 8097, 3880, 6081, 5659, 4890, 7818, 404, 6185, 5249, 4249, 6527, -7291, 5006, 2951, 2881, 3497, -5240, 2206, -4488, 1561, -9294, -62, 927, -185, 1006, 283, 2058, 2088, 1229, 656, 1421, 2252, 1775, 1014, 258, 2453, 1699, 199, 430, -287, 3213, 2191, -2181, -57, -1054, 2911, 3325, -3151, -687, -1903, 1542, 3738, -1571, -2331, -1605, -940, 3089, 510, -6440, -368, -8987, 1177, 1854, -1607, -59, -1887, -1725, 2033, 1828, -1407, 592, -2381, 864, 3501, -5873, 1064, -2537, -1580, 3845, -3362, 542, -1505, -2445, 2886, -229, -405, 220, -2483, 444, 1400, -1286, 1392, -3217, -2656, 2135, -1229, 2661, -1199, -1080, 1981, -101, 3840, 256, 738, 747, 983, 4422, 182, 1386, -1648, 1393, 4214, -1355, 859, -838, 572, 3078, -2979, -575, 1179, -2779, 1287, -2136, -2727, 2186, -603, 978, -480, -6706, 2734, 2007, 1252, 808, -2298, 2885, 2142, 482, 891, -647, 2223, -222, -882, 48, -1264, 701, -928, -1442, -453, -2690, 1267, 2068, -781, -1361, -3028, 2620, 2817, -385, -2744, -5865, 2610, 2421, -936, -733, -3840, 1366, 1544, -2087, 10, -1101, -272, 683, -2789, -693, -877, -801, 163, -3096, -1309, -2391, -582, 299, -3274, -1850, -6029, 58, 616, -2384, -4761, -7028, 879, 179, -883, -6516, -4411, 1277, -1468, 34, -2535, -2780, 952, -4018, -129, -857, -2165, 261, -4386, -1751, 839, -3254, 107, -2568, -3835, 2081, -8946, 80, -1732, -2107, 2452, -4218, -605, -3095, -1867, 1838, -2078, -1614, -6924, -5828, -12, -2580, -2200, -2167, -3131, -2820, -2926, -3767, -1126, 719, -1176, 479, -6279, -2542, 2094, 49, 2495, -2044, -5879, 2347, -592, 3243, -1135, -5126, 1748, -3047, 3057, -3205, -4156, 138, -1356, 2208, -7246, -1605, -2387, 720, 1134, -3015, 104, -1286, 1267, 413, -3284, 616, 176, 843, 110, -6889, 398, 697, -193, -436, -11669, -33, 829, -1605, -2037, -10863, -448, 101, -2500, -5866, -5674, -1045, -2758, -2960, -12132, -2950, -1885, -5134, -5512, -10490, -2075, -2092, -2006, -4752, -10492, -2218, -1038, -1937, -3669, -4559, -1907, 129, -3237, -4189, -2470, -812, 589, -2988, -1045, -2067, -276, -42, -1464, 325, -2838, 109, -2212, -1060, 380, -3663, 1003, -7791, -1896, 621, -2976, 1814, -2913, -403, -258, 8045, 9550, 7186, 501, 120, 7325, 8675, 6888, 1718, -160, 4903, 5702, 5722, 2833, -1728, 3467, 5928, 3912, 3925, -1514, 5284, 7940, 4257, 4699, 1072, 4933, 8041, 4843, 5014, 3906, 1122, 6909, 4358, 5019, 5623, 1005, 5540, 3590, 4792, 6091, 4076, 4906, 3947, 3907, 5549, 3769, 3762, 4786, 890, 4882, 741, 1371, 5631, -291, 4994, 728, 1159, 6304, 4450, 4886, 3321, 2554, 6345, 5797, 3780, 3904, 2829, 5709, 5579, 1185, 3568, 1699, 4629, 4263, -2447, 2989, -2181, 3142, 3186, 129, 2449, -5138, 1168, 3525, 1168, 1787, -1819, 195, 3274, 742, 1218, -663, 1042, 1324, -866, 1954, 1364, 1572, 1662, -4443, 3379, 2084, 1684, 4019, -8671, 4064, 1194, 1955, 4407, -4026, 3688, 230, 2287, 3023, -2688, 2463, 1878, 2236, 1119, -1896, 1342, 2899, 2547, 2351, -1459, 192, 2690, 3911, 2889, -558, -3703, 1611, 4897, 2077, 1155, -4453, 1426, 4812, 253, 2535, -1286, 2192, 3359, -1729, 3156, -1705, 2219, -457, -1692, 2994, -4273, 1368, -6251, -398, 2085, -4517, -325, -1626, 744, 1019, -1348, -3731, -2295, 1545, 1093, 732, -3623, -5882, 1875, 1617, 2194, -270, -4617, 1827, 2031, 3166, 506, -916, 1703, 1981, 3615, -387, 1276, 1579, 173, 3603, -2179, 2473, 1186, -3435, 3314, -2054, 2724, 140, 1652, 3011, 491, 2149, 1076, 2844, 2872, 2244, 1128, 3283, 1936, 2805, 2588, 349, 3957, -821, 2510, 1202, -190, 2950, -1257, 1734, -4619, -1319, 204, -250, 544, -1348, -2007, 294, -875, -352, 1091, -997, 1688, -2024, -425, 1248, -1371, 1668, -855, -262, 382, -5691, 956, 510, -302, -817, -2914, 1049, 907, -595, -1920, 502, 1943, 448, -821, -2724, 1601, 2352, -661, -746, -3330, 1475, 2140, -2026, -671, -4629, 392, 1396, -2031, -648, -7270, -1545, -146, -264, -553, -5524, -5040, -3276, 1055, -589, -3499, -9133, -5950, 1530, -979, -2698, -4207, -2716, 1158, -1913, -2031, -4130, -1612, -210, -3641, -1409, -6419, -2059, -2883, -5326, -565, -1954, -4178, -5976, -4314, 748, 198, -8769, -5558, -2953, 1516, 195, -7740, -4682, -1797, 1192, -2740, -4010, -3483, -331, -413, -5649, -2104, -2098, 1117, -2120, -1314, -1318, -954, 2108, -357, -1250, -1381, -306, 2503, 958, -537, -1893, -644, 2144, 961, 741, -1843, -2192, 590, -137, 519, -1748, -1145, -2490, -1252, -1332, -2488, 606, -797, -2951, -2477, -3125, 1038, 190, -3824, -112, -2300, 779, -1038, 313, 1460, -1318, 19, -3384, 1074, 2146, -964, -1678, -3315, -616, 2249, -1141, -4332, 867, -1709, 1865, -1088, -9021, 3321, 629, 1195, -654, -782, 4100, 1998, 1048, -939, 2199, 3533, 2857, 1285, -2908, 3349, 1691, 3051, 932, 8460, 8764, 11352, 9229, 2753, 7994, 8949, 10816, 8749, 4209, 6432, 8797, 9288, 7514, 4087, 3028, 7763, 7221, 6280, 2883, 4307, 6429, 6286, 6063, 5151, 7170, 5960, 7057, 6742, 5915, 7885, 5807, 7424, 7641, 5033, 6634, 4701, 7023, 8459, 3040, 2317, 292, 6300, 8670, 1377, 4805, 1482, 5279, 7906, 2178, 6627, 4124, 3261, 6187, 1619, 6761, 5003, 2385, 4000, -1840, 6090, 5749, 4444, 149, 435, 4690, 5625, 4623, 68, 1056, 2124, 4213, 2140, 3875, -22, -3026, 2354, -1857, 4641, 1532, -8310, 1683, 2757, 4313, 3311, -7519, 872, 3382, 3707, 4183, -6729, -44, 2501, 2651, 4306, -3805, -1024, 1050, 4, 4095, -3055, -2232, 319, -2462, 4125, -2696, -1606, 834, 1370, 4268, -2410, -1369, 1480, 2791, 4182, -2101, -3471, 1399, 2977, 3828, -1520, -10223, 1, 2121, 3192, -775, -2869, -4311, -529, 2125, -186, -1618, -5470, -6680, 279, -352, -75, -2436, 917, -2823, -2656, 1519, -1145, 3016, -804, -4637, 1827, 182, 3785, 2504, 898, 1495, 964, 3725, 4232, 2812, 2149, 1390, 2948, 4710, 3434, 2418, 1520, 1436, 4089, 3316, 1374, 1283, -1088, 2899, 2824, 1657, 994, -7632, 2226, 2433, 2951, -5, -3054, 1144, 2270, 2699, -55, 100, -2935, 1379, 725, 3089, 1043, -1725, -2073, -2755, 4658, 399, 1008, -1394, -4091, 4839, -2461, 1439, 629, -1411, 3963, -2723, 695, -1442, -2145, 2462, 299, -1740, -1715, -2818, 1113, 1355, -2852, 2143, 2129, 732, 1797, 736, 2904, 3268, 1169, 2289, 1744, 1974, 1867, 1005, 2571, 1211, -754, -5190, -349, 2287, -231, -8360, 810, -1871, 1834, -1632, -3091, 2122, -1322, 2495, -2923, -1269, 1075, -755, 3536, -2198, -695, -2012, -865, 3776, -238, -991, -3860, -1450, 2933, 160, -2163, -644, -2220, 1230, -1354, -3734, 1575, -2364, 379, -5293, -4967, 2724, -1855, 144, -3369, -5844, 2915, -1599, -1240, -2022, -5521, 2148, -1625, -2487, -1109, -3257, 70, -1427, -1644, 471, -1981, -5198, -595, -705, 1684, -2131, -6811, 346, -443, 2197, -3951, -6458, 798, -2139, 1940, -8099, -3504, 634, -5089, 805, -6176, 47, 469, 671, -1372, -7883, 1266, 1254, 2689, -5451, -5118, 975, 2109, 3192, -9195, -643, -664, 2208, 2548, -3472, 822, -3077, 1423, 640, -719, 902, -5188, 621, -3357, 1233, 509, -7465, 1372, -8998, 2263, 412, -1372, 1921, -3528, 2170, 457, 1163, 1371, -1897, 689, 419, 2608, 199, -990, -2223, 406, 3461, -518, -285, -1417, 524, 3722, -721, -471, -59, 846, 3468, -3, -2518, -219, 1216, 2950, 769, -6634, -1664, 1267, 2254, 1212, -4126, -3522, 954, 1146, 1796, -4887, -2688, 562, -252, 2150, -5063, -1078, 15, -607, 1798, -1354, 64, -2422, 1217, -1222, 2356, -549, -826, 1359, 46, 2528, 77, 703, 1093, 540, 2047, 385, 1584, 810, 575, 906, 905, 1793, 607, -30, -280, 928, 1335, 127, -2231, -579, 524, 372, -1104, -3372, -1242, 594, -759, -2885, -1276, -2669, 1271, -2051, -1787, -2151, 731, 1607, -3941, -142, -2902, 2755, 1031, -2410, 257, 526, 3356, 338, 368, -416, 1648, 3127, 1169, 1554, -883, 1187, 2447, 1919, 1349, 35, -355, 1505, 2010, -49, 491, -1493, 290, 1885, -1012, -189, -706, -1402, 1835, -653, -1342, 414, -4049, 1445, -1380, -835, 1399, -2753, -656, -1061, 407, 2389, 328, -5594, 1578, 1699, 3256, 1557, 1803, 3104, 2721, 3595, 1262, 3600, 3538, 2988, 3157, -425, 3530, 3049, 2241, 2007, -2748, 1807, 1702, 292, 913, -2749, -1753, -271, -1737, 416, -410, -2780, -2211, -796, -825, 738, -3053, -3166, 224, -4159, 388, -6781, -1350, 778, -7538, -684, -6021, 40, 794, -8075, -1196, -2613, 194, 186, -5381, -1710, -796, -846, -876, -3076, -2264, 450, -3535, -2173, -2795, -2610, 1111, -3248, -2985, -3229, -2763, 942, -1127, -3091, -2968, -2029, -564, -957, -3445, -2602, -2077, -4367, -1931, -2600, -3586, -4953, -599, -2966, -1270, -6257, -3913, 1906, -3599, -1194, -3077, -125, 2630, -4263, -2647, -1461, 1024, 1879, -4804, -1485, -2161, 636, -401, -5464, 880, -7517, -1091, -1523, -7686, 1802, -3875, -3391, -522, -10960, 1715, -893, -3458, 65, -4600, 963, 83, -1659, 494, -638, -385, 426, -37, 215, 1234, -2347, 531, 777, -961, 1538, -3032, 550, 806, -2996, 382, -1489, 670, 104, -6353, -2430, -72, 764, -1070, -7499, -7218, 711, 512, -2166, -6543, -16015, 894, -116, -4145, -8256, -4972, 799, -1035, -9862, -3472, -1895, 662, -2096, -2376, -442, -683, 312, -2580, -257, 980, -586, -284, -2829, 219, 1468, -997, -665, -3893, -358, 1381, -1313, -924, -5072, -1739, 1043, -1979, -2041, -4316, -4271, 900, -3999, -5376, -3714, -10667, 1246, -9268, -12061, -4294, -2703, 1723, -5847, -6724, -5843, -451, 1670, -3115, -8155, -5466, -5, 553, -2213, -8196, -3675, -928, -2179, -2481, -5031, -2801, -2871, -5236, -2656, -4252, -2905, -3313, -4565, -1879, -5726, -3708, -2167, -4952, -1631, -9692, -4346, -1480, -4648, -2599, -3388, -4863, -1423, -3280, -5618, -1103, -6256, -2118, -2033, -7619, -369, -4822, -3878, -1391, -3919, -476, -2701, -7312, -1380, -2864, -804, -2024, -5814, -1760, -2468, -1219, -2327, -3750, -2191, -2058, -2263, -2831, -3560, -2300, -2160, -4133, -2731, -4973, -1943, -3298, -4746, -2163, -8332, -1633, -5245, -3793, -1897, -9267, -2145, -4547, -3877, -2678, -7678, -4342, -3610, -5656, -5583, -6145, -6009, -4297, -9752, -11844, -3874, -3231, -9564, 3317, -1712, 2495, -249, -4231, 2333, -4860, 1441, -2319, 472, 214, -2134, 332, -6326, 2920, -5387, -2290, -772, -1964, 3892, -958, -9231, -1652, 802, 3680, 1596, -2025, -1339, 1828, 2542, 1900, 188, -1396, 1656, 1022, 311, 218, -2450, 361, -494, -5238, -143, -2696, -2148, -2685, -3968, 428, -2002, -5779, -3974, -1723, 596, -1375, -7355, -2275, -1966, -382, -1209, -4313, -1981, -1460, -2295, -2147, -1661, -4310, -181, -3322, -3900, 111, -7570, -182, -3673, -3565, 1099, -2872, -1643, -4352, -1997, 1367, -1554, -2401, -4965, -514, 875, -433, -1869, -6022, 566, -330, 1229, -3502, -2602, 1703, -1157, 2667, -3167, -378, 2998, -711, 3240, 137, 101, 3765, -609, 2728, 1359, -902, 3624, -1976, 1083, 1316, -2345, 2389, -8600, -1322, 389, -1026, -309, -758, -3238, -266, 437, -6312, 2126, -4703, 816, 1101, -3475, 3235, -5948, 1770, 967, -999, 3122, -5564, 1828, -395, -227, 1573, -3359, 1194, -5735, 255, -3600, -2273, 303, -2483, 1032, -1824, -2752, -632, 326, 1326, 840, -5005, -1329, 466, 820, 941, -4284, -1794, -1498, -222, -125, -1421, -2664, -5865, -1489, -924, 146, -2813, -1618, -2149, -70, 669, -2351, 367, -1519, 961, -46, -1477, 1177, -1038, 1226, -1699, 628, 1361, -486, 532, -76, 2150, 963, 527, -1000, 1627, 2592, 101, 1346, -1927, 2020, 1908, -700, 1647, -1514, 1653, -332, -1236, 1406, -1411, 1325, -10068, -989, 667, -924, 1690, -1303, 515, -409, -10, 2410, 1293, 1728, -1478, -109, 2706, 2163, 2160, -2210, -2149, 2184, 1921, 1908, -2428, -9430, 658, 573, 1130, -1598, -8966, -2020, -2038, -112, -240, -6766, -3364, -3674, -1602, 690, -1499, -2217, -1771, -1832, 920, 140, -2417, -677, -1264, 421, -87, -4587, -576, -1291, -567, -1831, -8048, -1305, -1898, -875, -4965, -3671, -2780, -2956, 215, -9928, -2334, -4840, -3151, 960, -8429, -2557, -4926, -2364, 391, -4029, -3040, -2353, -2119, -1905, -2826, -2297, -703, -1551, -2284, -3370, -806, -431, -283, -701, -2411, 257, -1976, 712, -781, -110, 523, -5822, 1049, -1996, 1024, 18, -2396, 621, -3525, 1091, -1011, -1452, -564, -4353, 241, -1537, -3027, -1276, -3894, -1498, -1273, -1980, -230, -3036, -4200, -1669, 593, 335, -2142, -8792, -3426, 1475, -195, -1508, -9505, -5679, 1171, -1675, -1465, -6397, -4053, 5, -4040, -2016, -6187, -2771, -1603, -8102, -3353, -6786, -2667, -2941, -7881, -5242, -6067, -3708, -3427, -6175, -3917, -4149, -5051, -3540, -5787, -2668, -2366, -3368, -4009, -4915, -2502, -1633, -1766, -4810, -3513, -2509, -2258, -1212, -5520, -2392, -2325, -4518, -1430, -6411, -2023, -2446, -5615, -2144, -7517, -2545, -2686, -4291, -2848, -6527, -3844, -1880, -4841, -1145, -145, 628, 475, 457, -2957, -10, -1570, 1391, -133, -4206, 52, -6385, 1664, -1805, -3079, 145, -4327, 1253, -3114, -1486, -819, -975, 374, -2454, -1235, -5610, 467, -293, -1797, -3162, -3606, 815, -758, -304, -3796, -1578, 354, -1073, 797, -583, -2625, -499, -771, 551, 92, -2287, -1511, -778, -390, -1734, -786, -2860, -1886, 191, -5805, -598, -3619, -3831, 690, -130, -1444, -1214, -2643, 209, 1606, -3083, 1408, -614, -1114, 2381, -4094, 2906, 633, -6743, 2871, -2164, 3295, 1471, -1532, 2341, -551, 2600, 1803, 1710, -254, -1350, 670, 852, 2520, 1150, -2959, -1344, -3412, 1716, 3180, 1734, 1280, -675, -265, 2878, 3379, 3075, 1577, 593, 564, 3251, 3563, 1385, 2170, 651, 1874, 3033, -583, 2850, 2123, 884, 1686, -4414, 3101, 1837, 1719, -398, -9515, 2822, 99, 2401, -3167, -4597, 1589, -2826, 2676, -4771, -1401, -138, -5814, 2910, -6350, -610, -104, -6063, 3013, -8985, -1488, -619, -3875, 2957, -8283, -2294, -2217, -1501, 3230, -2237, -1782, -1127, 361, 3596, 688, -1570, -753, 1476, 3297, 1530, -1263, -1992, 1754, 1762, 584, -332, -3281, 1156, -2419, -2802, 614, -2246, -349, -3108, -5652, 727, -1032, -2545, -441, -2741, -363, -1151, -3433, -692, -2244, -2517, -3094, -2801, -2605, -2152, -2148, -5145, -2558, -3874, -1905, -258, -4390, -2293, -3149, -1464, 888, -6111, -1497, -3126, -774, 1634, -5495, -650, -2098, -295, 1935, -2774, -379, 67, -790, 1403, -1358, -1010, 1457, -3443, -11, -51, -2306, 1889, -3109, -284, 1057, -4607, 1583, 263, 789, 1584, -6906, 976, 1375, 1056, 1371, -1678, 582, 1247, 544, 460, -635, 136, 304, -188, -774, -1331, -1029, -952, -1160, -2151, -918, -1051, -1310, -2378, -3368, 140, 174, -419, -310, -2190, 673, -106, 227, 1558, -1586, 1039, -2416, -134, 2027, -2991, 893, -6580, -1703, 1269, -6484, -115, -5723, -4105, -856, -2971, -2238, -3554, -6704, -5229, -939, -6743, -2910, -7597, -3618, -429, -10337, -4056, -6796, -1566, -1561, -6673, -4428, -12669, -1216, -7896, -6061, -3668, -2993, -1485, -2882, -5866, -4362, -584, -1137, -280, -6184, -5742, -232, -590, 311, -7151, -6190, -1667, -693, 372, -10047, -5120, -7048, -1029, 73, -10798, -3369, -4997, -1002, -1285, -5770, -2927, -2547, -1148, -2374, -4233, -4789, -2791, -1988, -447, -4173, -8613, -4557, -3999, 457, -4995, -3105, -6255, -7731, -100, -6188, -1730, -7142, -5266, -2370, -6593, -2111, -11767, -3767, -5091, -5145, -3803, -7493, -3824, -2533, -4008, -6733, -4307, -4295, -1719, -4287, -10252, -3294, -4072, -2339, -5571, -8014, -3507, -3417, -3899, -3474, -6660, -4456, -2442, -6205, -1628, -7007, -4803, -1214, -10809, -1319, -8609, -4288, -465, -10738, 11098, 5212, 12300, 10731, -13274, 10442, 6685, 11667, 10185, -5310, 8302, 7186, 9625, 8459, -3020, 3785, 5776, 5462, 5253, -2244, 1023, 3996, -1424, 287, -1736, 2976, 4149, 407, -1784, -605, 3079, 3114, -722, 661, 89, 2958, 784, -5, 1303, 325, 3135, 1756, -86, -672, 1340, 3989, 2726, 137, -26, 2416, 4821, 2709, 1082, 3029, 3017, 4752, 3030, 538, 4385, 3491, 3277, 4047, -3489, 4673, 3810, -348, 4441, -1135, 3980, 3758, 216, 3628, 293, 2357, 3336, 1802, 1749, -2091, 829, 2509, 1505, 768, -891, 395, 811, 631, 636, 1899, 109, -4455, 226, -296, 2648, 168, -1596, -540, -1523, 2391, 272, 1368, -1774, -3220, 1437, 265, 1752, -1880, -5949, -332, 528, 741, -1641, -3799, -3154, 1030, -656, -1690, -2449, -3611, 1340, -1832, -1245, -2534, -2997, 1490, -4817, -374, -2040, -4587, 1682, -2789, -169, -908, -9040, 1674, -187, -1274, -1075, -8328, 1255, 257, -3880, -3698, -4611, 584, -873, -5979, -5615, -2235, 163, -3707, -9433, -1926, -1347, 160, -9210, -7969, -1200, -1870, 103, -12453, -4893, -2052, -4712, -220, -7170, -5432, -4455, -7397, -715, -3549, -7741, -7953, -2554, -1232, -1773, -5242, -5832, -1528, -1503, -1547, -2831, -3492, -2060, -1501, -3042, -1437, -1902, -3381, -1917, -4839, -896, -1487, -4409, -3751, -2231, -1335, -2925, -5361, -9173, -752, -2493, -11578, -7925, -5094, -347, -2519, -3585, -18176, -3398, -604, -1625, -1877, -10374, -3873, -1355, -1285, -2854, -12016, -6563, -2503, -1518, -6327, -12043, -7376, -3559, -2105, -3820, -7938, -4767, -3599, -2760, -2402, -6678, -4353, -3201, -3089, -2845, -6013, -5385, -3098, -2942, -4488, -4418, -8138, -3288, -2847, -6622, -2408, -14394, -3652, -3416, -8079, -1161, -5638, -4190, -4624, -8116, -831, -2668, -4954, -5222, -6976, -1189, -1206, -5770, -5339, -5479, -1860, -828, -5995, -6444, -4132, -2620, -1298, -5463, -7908, -3071, -3510, -2244, -4449, -6470, -2511, -4811, -3266, -3517, -4756, -2817, -6980, -3990, -3400, -4214, -4423, -6924, -3501, -4595, -5061, -7353, -5594, -2586, -6687, -5601, -7305, -5826, -2433, -5014, -4189, -6156, -7004, -3291, -3297, -3931, -4989, -7679, -4740, -2520, -5206, -4326, -7732, -5585, -2025, -5975, -4052, -6323, -7057, -1360, -4578, -2613, -4732, -12016, -683, -3435, -1212, -4410, -7504, -294, -2585, -828, -5621, -6556, -375, -2187, -1415, -5592, -8070, -1032, -2424, -2718, -3489, -9643, -1973, -3028, -4759, -3094, -7536, -2619, -3475, -9114, -5000, -4308, -3469, -3501, -6100, -6687, -2197, -4270, -3029, -3362, -3660, -1111, -3131, -3031, -2650, -3297, -786, -2407, -4677, -3325, -5145, -1064, -3122, -10750, -5078, -6277, -1863, -5590, -9095, -6716, -4257, -3437, -10057, -8470, -7109, -3506, -7310, -10609, -11511, -6290, -2969, -8178, -5305, 1585, 3305, 8481, 3947, -7373, 857, 2438, 7871, 4483, -5163, -1996, -93, 5893, 4989, -1325, -1659, 841, 2403, 4908, 1273, 2099, 2461, 2031, 4779, 2616, 3751, 2638, 2640, 5051, 3061, 4361, 2355, 1685, 5346, 2837, 4441, 2016, 406, 5189, 2082, 4328, 247, 1849, 4410, 1080, 4039, -3195, 3468, 3163, -336, 4027, 2040, 4662, 1497, -3365, 4988, 3859, 5658, -982, 38, 5693, 4172, 5994, -1242, 3006, 5278, 3567, 5174, -822, 4260, 3458, 2747, 2548, -2184, 4354, 706, 2516, 58, -2813, 3520, 445, 2291, 2562, -2896, 2005, 192, 1550, 2941, -4081, 194, -869, 734, 1859, -4434, -1360, -785, 930, 155, -3206, -2027, 300, 1899, -530, -2885, -1699, 1254, 2444, 93, -5182, -1408, 1767, 2207, 423, -10119, -1961, 1778, 1408, -459, -6219, -2644, 1226, 771, -1880, -1894, -2940, 111, 722, -634, 805, -3221, -589, 873, 577, 1830, -1550, 239, 766, 783, 1632, -334, 995, 95, 209, 354, -388, 892, -717, -877, -2339, -1423, -500, -449, -1883, -4972, -3426, -5195, -1, -1938, -2367, -8461, -3421, -187, -1485, -1279, -4852, -866, -240, -1510, -1196, -1826, -1293, 206, -2200, -1447, -684, -4666, -29, -3118, -1524, -475, -6737, -1703, -3556, -973, -677, -4775, -4770, -3481, -59, -841, -4117, -4457, -3387, 502, -1063, -2478, -3343, -3405, 513, -1847, -1872, -2763, -3513, 216, -3158, -1954, -3293, -3491, 6, -1841, -2078, -6307, -3108, -39, -34, -2676, -4200, -3202, -70, 295, -4143, -1613, -4699, 133, -1057, -5056, -933, -8726, 735, -5222, -4775, -1032, -7064, 1143, -6540, -5723, -1051, -4089, 856, -4798, -7549, -1215, -2400, -195, -7213, -5635, -2425, -1542, -1435, -6176, -4819, -4529, -1232, -2289, -3326, -6213, -3064, -863, -4036, -3085, -8323, -2295, -451, -4993, -4715, -5061, -4020, -749, -2752, -3877, -3576, -6565, -1875, -2479, -2051, -3764, -3560, -2217, -3992, -1880, -5381, -3341, -1708, -5812, -3022, -4445, -4321, -1992, -6653, -5129, -2650, -3498, -3241, -5129, -7028, -2528, -2897, -4728, -3051, -5802, -4167, -3519, -5969, -2871, -4319, -7325, -4670, -9996, -4331, -3595, -4791, -4604, -7482, -4786, -3318, -3351, -3509, -5488, -4479, -3763, -3662, -3008, -6282, -6129, -6270, -5514, -3122, -7904, -5156, -9061, -7791, -2629, -5439, -3320, -3932, -5454, -1852, -3039, -2650, -2778, -3742, -1820, -1611, -1754, -3548, -3505, -2607, -1143, -1164, -7063, -4740, -3944, -1745, -1874, -6602, -7379, -5275, -3118, -4641, -2947, -5731, -4220, -3162, -4582, -1783, -3739, -2276, -2644, -2088, -1782, -3252, -1601, -3260, -1424, -2322, -3649, -2494, -4660, -1975, -3063, -4196, -5663, -5993, -3845, -3228, -4619, -8550, -9567, -6095, -2124, -4831, -5158, -8780, -3685, -1638, -4736, -3700, -5019, -2600, -2706, 3707, 2638, 6935, 2367, -409, 2736, 2365, 6486, 3751, 2168, 1377, 1343, 5470, 4876, 3115, 3163, -681, 4488, 4624, 1773, 4089, -697, 2993, 2655, -2576, 3762, 1709, 329, -2962, -906, 2292, 2976, 233, -1112, 746, -870, 3029, 587, -145, 458, -5764, 1947, 2, -1787, -2017, -2262, -4, 430, -2562, -3108, -14, -1930, 1231, -1716, 1821, 1788, -2410, 1649, -1517, 3826, 2804, -1236, 1710, -143, 4544, 3057, -441, 1395, 1775, 4359, 2635, 418, 578, 2847, 3582, 1434, 1425, -1172, 2693, 2857, -1028, 1644, -3601, 1070, 2653, -6563, 865, -687, -76, 2631, -10669, -513, 830, 1328, 2475, -6428, -1739, 525, 1282, 2073, -2958, -2828, -1301, -1020, 1441, -2750, -4133, -3430, -16441, 646, -4168, -2603, -3920, -2047, 242, -486, -225, -4235, -270, 624, 1024, 1000, -3784, 359, 546, 493, 1237, -3623, 640, -679, -2010, 381, -3130, 969, -2732, -3305, -2278, -1646, 1447, -3567, -2123, -7752, -834, 1559, -1510, -2701, -3584, -997, 908, 148, -4190, -2956, -1853, -521, 587, -4177, -3973, -2802, -2053, 103, -3373, -5826, -3259, -2014, -1133, -3022, -7751, -3502, -801, -3851, -2864, -7128, -4058, 12, -6858, -2197, -5368, -4733, -156, -2515, -1500, -4914, -3531, -1289, -1601, -2129, -5401, -1761, -934, -3359, -5833, -5855, -929, 961, -7624, -2855, -4490, -885, 1960, -1611, -733, -2348, -960, 2037, 345, -1164, -1348, -729, 1452, 1044, -3845, -1594, -613, 382, 974, -4552, -3003, -778, -1558, 95, -3389, -5396, -859, -5068, -1692, -3932, -3957, -712, -2859, -2906, -4352, -1844, -920, -1314, -2445, -3971, -1383, -2114, -710, -2151, -3884, -2316, -5126, 123, -1625, -4171, -3896, -7733, 660, -1102, -4685, -3933, -2734, 588, -702, -5475, -3649, -655, 67, -528, -6936, -4077, -101, -1149, -1218, -10007, -4253, -984, -4323, -3259, -7527, -2958, -3909, -5933, -3525, -3866, -1383, -6203, -2006, -1102, -2139, -615, -2993, -907, 107, -2018, -870, -1857, -1267, 143, -3948, -1987, -1685, -2792, -1038, -8334, -3092, -2154, -4408, -3392, -4299, -3602, -3363, -4114, -3630, -3513, -4155, -6059, -3263, -2461, -5321, -4200, -9254, -2273, -2403, -14087, -3900, -5744, -1227, -3193, -4042, -4117, -5267, -476, -3996, -1661, -4803, -7994, -240, -3732, -892, -5842, -10145, -634, -3205, -1265, -7545, -5716, -1846, -2950, -2523, -9839, -4877, -4653, -3034, -3705, -7522, -4084, -5418, -3877, -4613, -4659, -3178, -2218, -5807, -7387, -3785, -3515, -1403, -8260, -11497, -4984, -6182, -2172, -9360, -6346, -6504, -6892, -4239, -7743, -4428, -4122, -4123, -6879, -7008, -3190, -3511, -4579, -10967, -6432, -2575, -3400, -5683, -7842, -4646, -2471, -1945, -3157, -3757, -4293, -2553, -1025, -2473, -2903, -5273, -2585, -1288, -3610, -4283, -4097, -9523, -5943, -2164, -5581, -2444, -7776, -7923, -2002, -6584, -1324, -6893, -10160, -3126, -8249, -1242, -5853, -5730, -6185, -7069, -1318, -4999, -4494, -11606, -4761, -1033, -4625, -4512, -9209, -2764, -895, -4675, -5093, -5432, -2392, -906, -5316, -6753, -2629, -4217, -506, -7343, -12258, -1117, -18640, -111, -9723, -7977, -691, -4660, -501, -6642, -6882, -1346, -3457, -2156, -5205, -9530, -3231, -4659, -6435, -3930, -12152, -6519, -8626, -5634, -3154, -7490, -9589, -6737, -2102, -3723, -7020, -9157, -4072, -731, -5013, -8657, -9415, -2941, -398, -4607, -10880, -9679, -2876, -754, -5311, -14843, -9054, -4567, -1638, -14356, -6364, -8733, -13294, -3056, -4994, -2996, -4463, -5328, -4725, -2286, -1904, -2246, -4056, -4127, -1121, -2429, -1557, -5177, -2582, -734, -4504, -1938, -7300, -2004, -1035, -7966, -3344, -7584, -2366, -1927, -7388, -7014, -5819, -3508, -3280, -5943, -7778, -3259, -5056, -4883, -5403, -3711, -1761, -6577, -5724, -3812, -2815, -1334, -10214, -6432, -2134, -3513, -1800, -7198, -8335, -1299, -5112, -3064, -4323, -6722, -1216, -6206, -5131, -3659, -5068, -1666, -8050, -8021, -4004, -4996, -2605, -8072, -11208, -4015, -6186, -4652, -4438, -10588, -3273, -8792, -9297, -3155, -7707, -2889, -9015, -5467, -3343, -5270, -3625, -6067, -3545, -4613, -3311, -6748, -5065, -2944, -6260, -2057, -9865, -6187, -2925, -7114, -1475, -5008, -6917, -3686, -7323, -1268, -4218, -3167, -5852, -7615, -1271, -4439, -1312, -6944, -8678, -1771, -3908, -680, -4782, -8846, -3161, -3446, -825, -4036, -8856, -5418, -4445, -1466, -4437, -10779, -6813, -5622, -2382, -5802, -4930, -7126, -3128, -3724, -7505, -1874, -8631, -1671, -6449, -8103, -453, -13228, -1267, -9744, -7564, -269, -10195, -1356, -6865, -6983, -1270, -7884, -1598, -7550, -8264, -3377, -6582, -1809, -13209, -10664, -5900, -4933, -2029, -6603, -7333, -6637, -3141, -2649, -4805, -5579, -4607, -2065, -3786, -4159, -4530, -3556, -1958, -4434, -4021, -3946, -3579, -2653, -4115, -5443, -4218, -3204, -3892, -4038, -9143, -6128, -2134, -4915, -5295, -4613, -13797, -1494, -3796, -8152, -2934, -8834, -1618, -2501, -3860, -2776, -7296, -2660, -1837, -2081, -3349, -6771, -4973, -1725, -2184, -4176, -7035, -10012, -2470, -3850, -4867, -10270, -8530, -4484, -7644, -4945, -11567, -5452, -7947, -13246, -4593, -7648, -4465, -13331, -8972, -4690, -7031, -4486, -11865, -9795, -5755, -7391, -4672, -9503, -9418, -6950, -7780, -4682, -16058, -7030, -6089, -6621, -4720, -7791, -5977, -5453, -5265, -4802, -5117, -5921, -6064, -4721, -5110, -5085, -8222, -8408, -4431, -5728, -7469, -7815, -12098, -3763, -6161, -10741, -3895, -8584, -3051, -5790, -8524, -2729, -7566, -2674, -5077, -9058, -3014, -8564, -2654, -4944, -7027, -4310, -8408, -2854, -6054, -5405, -6337, -6067, -3169, -7725, -5604, -8646, -5427, -3730, -6045, -7173, -9349, -5644, -2745, -4435, -3255, -5100, -10319, -2409, -5707, -5709, -3217, -4289, -2904, -8567, -10219, -1759, -1428, -4532, -10403, -10345, -2067, -360, -8814, -11601, -8343, -3550, -360, -6021, -10113, -5433, -2952, -1047, -2621, -6476, -3020, -2146, -2014, -1286, -3590, -1799, -3138, -3347, -1293, -2157, -2028, -4382, -6207, -2485, -2222, -3986, -3157, -6363, -4376, -3953, -6302, -2993, -3178, -4933, -8381, -5066, -4482, -2127, -4846, -12400, -4240, -7919, -2555, -6214, -8454, -3503, -7013, -4322, -5684, -6272, -2668, -4389, -4535, -3199, -3959, -1933, -3414, -2477, -2617, -2243, -1718, -3123, -1327, -3827, -1305, -2294, -2093, -1066, -7001, -1076, -3850, -801, -1632, -8388, -1685, -6329, -498, -2998, -7507, -3648, -5368, -1515, -4982, -7466, -7383, -3325, -2655, -7653, -7390, -5273, -2413, -1555, -14324, -6261, -3707, -2532, -1035, -9651, -4787, -3281, -3732, -1629, -5854, -4420, -3728, -5714, -2317, -4014, -5483, -5742, -5663, -2378, -3529, -7319, -8604, -4638, -3085, -4334, -6198, -5104, -4462, -5674, -6502, -5078, -3689, -4555, -14132, -11050, -5171, -3450, -4259, -13545, -9341, -5933, -3294, -3862, -8457, -5184, -6151, -2572, -4167, -4497, -3611, -5143, -1653, -5473, -3356, -3468, -3974, -1278, -6098, -3895, -4212, -3747, -2331, -4030, -5500, -5145, -5045, -7589, -2336, -6391, -5749, -7203, -4400, -1870, -5463, -6348, -6143, -2208, -2193, -4082, -7322, -4906, -2997, -1735, -2751, -4971, -3830, -7372, -806, -1731, -2704, -3698, -7334, -695, -1307, -1781, -5715, -4778, -1785, -1633, -1760, -9078, -4864, -4826, -2603, -2323, -4936, -5444, -10881, -3398, -3460, -4051, -6080, -4726, -3330, -5913, -4514, -9708, -2940, -3278, -9419, -5049, -7931, -2193, -3486, -4353, -4575, -4653, -2333, -3719, -1933, -3317, -4288, -3790, -4057, -585, -2619, -6018, -6452, -4951, -5, -3009, -13340, -4646, -7322, -224, -4531, -8298, -3373, -11910, -1415, -6536, -5687, -3711, -8413, -4246, -7867, -4259, -5131, -4938, -8504, -10451, -3386, -6804, -2993, -4161, -10671, -3469, -9349, -2556, -2815, -8378, -5085, -9094, -3620, -2359, -9030, -9748, -5670, -6663, -1707, -10671, -5964, -4925, -6982, -1238, -6904, -4084, -6098, -4870, -1593, -4780, -4367, -8449, -4262, -3044, -3837, -7028, -7802, -3321, -5930, -3460, -13684, -7987, -2254, -10288, -3088, -6700, -13398, -1980, -7907, -2537, -5443, -5852, -2529, -5309, -2281, -5477, -3144, -3454, -3354, -2779, -6270, -2284, -3982, -2010, -4131, -8456, -2577, -3993, -1443, -5248, -14405, -3869, -3884, -1780, -5301, -7072, -6484, -3667, -3182, -6687, -4773, -11855, -3411, -6299, -13380, -4030, -9727, -3625, -13249, -6993, -4150, -8273, -5127, -5833, -5646, -4561, -7768, -9798, -3523, -7344, -4823, -7563, -9133, -2409, -13634, -5072, -8797, -8460, -2152, -6157, -5646, -14285, -14051, -2812, -4474, -6838, -10685, -8765, -4529, -4371, -9026, -8921, -7190, -2538, -2793, -5336, -3947, -3232, -2447, -6203, -5527, -1346, -4646, -2657, -11648, -5577, -289, -7774, -3120, -5916, -4942, -409, -4535, -2327, -3789, -3437, -1664, -3652, -1306, -2676, -2158, -4312, -5043, -1433, -2688, -1550, -4704, -12021, -2924, -4046, -1718, -2938, -6369, -5811, -5486, -2140, -2456, -4418, -9238, -4771, -1672, -2623, -5173, -7536, -5012, -1027, -2916, -7563, -5388, -6455, -1047, -3534, -5747, -3857, -6470, -1762, -6188, -4386, -2362, -5764, -3270, -7302, -3486, -1317, -5339, -5938, -2043, -2596, -977, -5002, -5752, -567, -2031, -1364, -5686, -4356, -871, -1595, -2485, -9444, -4559, -3048, -1263, -4310, -9670, -4284, -9537, -1203, -5912, -6224, -3258, -4981, -1598, -5220, -6752, -3456, -3016, -2725, -4270, -13093, -3992, -2290, -3813, -4408, -7856, -1929, -1810, -2808, -6610, -6766, -300, -1490, -1837, -12281, -9620, 182, -1437, -1396, -4540, -5758, -268, -1434, -1067, -2260, -3563, -1245, -1335, -1237, -1190, -3551, -1476, -1500, -2333, -991, -4916, -812, -2049, -2009, -1888, -4600, -483, -2455, -390, -4537, -3079, -788, -2471, -38, -8360, -2618, -1859, -2379, -449, -5758, -2959, -4411, -2219, -90, -6016, -3160, -7765, -2225, 307, -9508, -2980, -4024, -2636, -255, -5505, -3532, -2875, -3524, -1276, -2591, -5988, -3067, -5231, -1555, -1350, -8221, -4186, -8034, -1763, -1154, -3675, -7696, -8156, -2892, -1762, -1783, -8195, -7268, -4659, -2969, -1119, -3649, -6626, -3255, -4262, -1365, -2163, -6289, -1846, -4546, -1670, -1498, -6156, -1979, -4453, -425, -943, -4181, -3783, -5071, 723, -488, -2102, -7526, -5890, 759, -454, -991, -7736, -5490, -412, -1108, -886, -9249, -5507, -2500, -2611, -1753, -11330, -8110, -3541, -4951, -3085, -6498, -11560, -2818, -6163, -3838, -5476, -7744, -1613, -4473, -4503, -4895, -10538, -787, -3815, -4152, -4471, -9289, -772, -5325, -2438, -4617, -7042, -1681, -12156, -1011, -4078, -11124, -3652, -4463, -221, -3429, -6484, -6516, -2117, -224, -4362, -3413, -8298, -1303, -1142, -8465, -2652, -10619, -1620, -3147, -4694, -2958, -9320, -3078, -5244, -2625, -3493, -7538, -4728, -4215, -2782, -3538, -7417, -5557, -4010, -5181, -3169, -3829, -6440, -6266, -8421, -2777, -1878, -4202, -11497, -4542, -2452, -1751, -2812, -4234, -3385, -2148, -2715, -2843, -2160, -3604, -1954, -2837, -3958, -1415, -4855, -2031, -2412, -5695, -1431, -6987, -2535, -2219, -6285, -1866, -8006, -3450, -1908, -5988, -2553, -5303, -4148, -2209, -7158, -3775, -2744, -4606, -3348, -12623, -6204, -1360, -6610, -3959, -7071, -11644, -1069, -13710, -4590, -5496, -9894, -1583, -5968, -8329, -6387, -6163, -2172, -4522, -6894, -9424, -4457, -2212, -4798, -3904, -7938, -4179, -2202, -6264, -3431, -5745, -5168, -2666, -9482, -4409, -5407, -7155, -4061, -10419, -6791, -6801, -8847, -7855, -5501, -8849, -10972, -7787, -7849, 11195, 15123, 10025, 6099, 8571, 11019, 14694, 9644, 5733, 7741, 10391, 13372, 8577, 4369, 4786, 9563, 11038, 6931, 1192, -2344, 9374, 7356, 4436, -3542, 1962, 9099, 3349, 1630, -2046, 1944, 7586, 6115, 2811, -531, 935, 5291, 7372, 2914, 1121, 1036, 6408, 7321, 1143, 1454, 2072, 7296, 6291, 1497, 1177, 3087, 6928, 5468, 3598, 1443, 4050, 5664, 5714, 4290, 2105, 4939, 3856, 6142, 3746, 2319, 5591, 727, 6849, 1885, 1557, 5915, -7395, 7137, -2519, -389, 5801, -1126, 6483, -4415, -2680, 5201, -1921, 4721, -769, -2403, 4188, -739, 1647, -162, -594, 2599, 794, 821, -656, 91, -466, 1178, 2644, -1822, -1098, -11217, 1390, 3262, -1618, -5779, -4820, 1147, 2935, 896, -7053, -5800, -464, 1555, 2522, -6062, -6045, -5268, -1479, 3020, -9656, -3864, -1743, 964, 2638, -5107, -3853, -203, 3374, 1760, -4036, -6396, -1279, 3921, 776, -4029, -16551, -3809, 2968, -236, -3220, -8143, -3589, 368, -1465, -2442, -7889, -10233, -2711, -3780, -2795, -5569, -709, -936, -8300, -5686, -3273, 2446, 737, -3423, -7181, -2279, 3543, 1442, -1155, -2180, -1762, 3392, 861, 137, -815, -746, 2232, -1795, 961, -896, 52, 239, -5979, 1433, -1863, -189, -2099, -897, 1622, -3121, -1718, -3985, 551, 1557, -3537, -2905, -5520, 686, 1261, -2232, -1677, -7394, 27, 715, -885, -1237, -8488, -1059, -213, -377, -2039, -4980, -2121, -1747, -830, -4073, -2595, -3249, -4097, -2325, -6630, -1691, -4229, -7405, -4772, -5486, -2005, -3586, -7187, -7279, -4017, -3260, -3248, -4533, -7752, -3357, -5022, -4191, -3047, -4702, -3228, -5988, -5489, -2174, -3104, -3376, -4316, -6122, -1603, -2904, -3414, -2785, -8958, -1317, -3641, -3062, -2009, -8828, -1351, -4858, -2576, -1824, -4507, -1595, -6319, -2447, -2153, -3322, -1869, -7238, -2943, -2892, -4009, -2192, -6063, -3927, -4048, -7471, -2810, -5060, -5006, -6336, -7996, -4013, -5153, -6513, -12027, -5008, -6226, -6290, -9703, -6730, -4456, -10684, -7420, -12876, -5063, -4618, -8828, -6957, -13355, -4465, -4695, -6007, -6580, -10569, -3031, -4757, -4748, -6951, -6650, -1852, -5345, -4392, -8115, -5484, -1897, -6110, -5073, -11001, -5880, -3632, -5574, -7318, -9674, -5604, -9235, -5218, -9011, -7118, -4163, -8010, -6298, -7697, -7118, -3950, -7467, -7900, -8856, -9572, -5670, -9525, -7093, -9777, -8870, -11966, -4224, -6722, -7543, -6720, -9695, -2019, -7078, -7268, -6368, -8813, -1415, -6884, -7908, -6644, -10736, -2124, -5611, -8390, -6536, -9810, -4488, -4537, -9472, -6533, -7881, -9121, -4070, -12403, -7430, -6232, -5549, -3898, -14521, -8280, -5120, -4089, -3925, -8328, -6393, -5058, -4425, -4379, -6126, -4521, -6278, -5827, -5537, -5533, -3452, -9027, -5927, -8372, -6073, -3144, -11883, -5083, -12795, -7374, -3693, -10706, 7471, 1317, 4615, -14033, 6451, 6761, -946, 3861, 2250, 6218, 4361, 2064, 1361, 3975, 5565, 1245, 4653, -2752, 3802, 4901, 3821, 4949, -1612, 2915, 4689, 5122, 3530, -928, 2833, 4410, 5379, 619, -784, 3273, 3654, 5126, 1850, -228, 3372, 2809, 4595, 4245, 1260, 3195, 2679, 3317, 5555, 3236, 3066, 3585, 2570, 6007, 4835, 3199, 5060, 5802, 5615, 5821, 3574, 6185, 7650, 4281, 6151, 3833, 6600, 8050, 1836, 5719, 3310, 6301, 7191, -1342, 4359, 947, 5430, 4988, -2155, 1953, -4581, 4275, 1230, -1996, -855, 1888, 3139, -1090, -3080, -2669, 3627, 1920, -848, -2718, -4740, 3998, -120, -600, -370, -6840, 3703, -4798, 942, 482, -5468, 3139, -1418, 2099, 270, -1744, 2580, 254, 2134, 83, 206, 1939, -599, 1174, 971, 901, 592, -4386, -109, 2158, 709, -1687, -3201, -668, 2771, -56, -1057, -2015, -653, 2568, -1020, 370, -4131, -1203, 1562, -1873, 813, -8413, -3746, 260, -2548, 481, -4924, -3734, 66, -3146, -998, -6771, -975, 696, -3602, -5177, -5184, -1115, 1081, -3284, -2797, -2198, -5771, 1062, -1997, 6, -1363, -1954, 769, -720, 941, -1541, 928, 396, -202, 718, -2197, 1581, 51, -822, -701, -3020, 1164, -226, -3019, -3831, -3029, 261, -275, -7997, -4819, -2221, -863, -369, -19659, -2074, -2177, -2305, -1211, -8690, -561, -3244, -3692, -3153, -4836, 423, -3537, -3659, -4844, -3733, 1030, -1982, -2668, -3175, -3808, 1179, -958, -1967, -1121, -3089, 819, -892, -1758, -304, -2016, 0, -1850, -1648, -1034, -1839, -1084, -3559, -1352, -3952, -2599, -2187, -4248, -1182, -6726, -3883, -3331, -3728, -1352, -4597, -5022, -4866, -3655, -1972, -5668, -6061, -5979, -4598, -3524, -7075, -7941, -4363, -6821, -7352, -4790, -10153, -3141, -8647, -7694, -4560, -8181, -3059, -8163, -5139, -5967, -6999, -3522, -7499, -4662, -4430, -7789, -3323, -7236, -5095, -2678, -13015, -2370, -8770, -6402, -2326, -8020, -1428, -15172, -5738, -2779, -5912, -718, -6714, -3872, -3293, -6246, -269, -4852, -3756, -3844, -8584, -248, -5726, -6181, -5197, -8974, -895, -9090, -9187, -7961, -7599, -2222, -3604, -4499, -7550, -8094, -3415, -1637, -3358, -5196, -9103, -3766, -1415, -3280, -4638, -8634, -4531, -2375, -3022, -6155, -8514, -6723, -3882, -2388, -12957, -8294, -10702, -4611, -2183, -6208, -6294, -8596, -4624, -3030, -4294, -4482, -6502, -4505, -5533, -4369, -3588, -5140, -4437, -9778, -5678, -3492, -4094, -5129, -8125, -5901, -3924, -3454, -7825, -6824, -5268, -4546, -3504, -13669, -6096, -6415, -5086, -4449, -6758, -6129, -8657, -5754, -5507, -5122, -6649, -5868, -7418, -4495, -4525, -6668, -4849, -10128, -3423, -4501, -6654, -5680, -9210, -3299, -5553, -7664, -8110, -9114, -4008, -9971, -8777, -8515, -9887, -5323, -8213, 2153, 1795, 3912, 3587, 5834, -1016, 1537, 4466, 5109, 5613, 2066, 1108, 5719, 6749, 5662, 4755, 1217, 6345, 7241, 5840, 4602, 781, 5804, 6512, 5032, 2445, -1165, 4060, 4580, 2896, 1283, -330, 1412, 1818, 314, 2223, 989, -1502, -594, 801, 1915, 805, -2466, -1993, 3264, 2110, 52, 1217, -2491, 4804, 3837, -370, 3461, 1191, 5229, 5129, 1590, 4442, 3359, 5230, 5439, 3535, 4021, 3458, 5420, 4640, 4053, 1234, 1504, 5143, 2771, 2996, -656, -252, 3689, 1434, 58, 2848, 505, 725, 1598, -723, 3135, -993, -1702, 1350, 456, 1419, -4105, -508, 626, 15, -3113, -8520, -826, -156, -918, -6508, -1488, -4348, -47, -1237, -2357, 1393, -258, 649, -1318, -869, 2277, 2002, 1054, -1786, 235, 2361, 2321, 970, -2298, 985, 2258, 1436, 338, -2189, 1162, 1883, 110, -861, -1995, 521, 926, -600, -2784, -1977, -1188, -663, -1187, -5786, -2009, -2750, -2117, -1153, -5734, -2331, -1468, -1559, -424, -3789, -3391, -846, -124, -271, -2616, -5094, -1425, 568, -635, -1514, -7855, -2307, 193, -1079, -957, -6199, -1955, -1183, -242, -1688, -1225, -674, -3158, 874, -4361, 557, 144, -2714, 775, -2997, 622, 45, -932, -462, -885, -746, -456, -966, -1615, -916, -3384, 16, -3805, -3124, -3523, -8639, 1030, -4263, -9598, -4733, -6012, 1482, -1416, -4817, -1442, -2525, 1284, -727, -3537, -1493, -2039, 938, -420, -4252, -4997, -2887, 726, -354, -6085, -5058, -2260, 126, -945, -11731, -2710, -1154, -1202, -1769, -7325, -3777, -1094, -2891, -2222, -4635, -9826, -1999, -3706, -3273, -3883, -7014, -3719, -3379, -6908, -5244, -4869, -5933, -2992, -7082, -10324, -5168, -7420, -3277, -4263, -5530, -7436, -7158, -4667, -4579, -4126, -15350, -6271, -7759, -7094, -4505, -11147, -6313, -8923, -7329, -4495, -10853, -8293, -6150, -3947, -3008, -9408, -7699, -4367, -1877, -2408, -9026, -4849, -2898, -1183, -3101, -12385, -3941, -1949, -1875, -4788, -11231, -4544, -1903, -3954, -6879, -9517, -6720, -3039, -5178, -8548, -9850, -8467, -5021, -4193, -7323, -13018, -5354, -5141, -3844, -6560, -9112, -2811, -4752, -4008, -7486, -4419, -1606, -4762, -4680, -7503, -2441, -1777, -4502, -5971, -6081, -1754, -3403, -4646, -6904, -7030, -1869, -5849, -5379, -6375, -17535, -2471, -5899, -5749, -5793, -5734, -3495, -5789, -5025, -5445, -3960, -5428, -6367, -4398, -4889, -4138, -9359, -7064, -5009, -4619, -5597, -7328, -7851, -7654, -5160, -7970, -5438, -9383, -9530, -6483, -9446, -5387, -12105, -8456, -7893, -9236, -6564, -11607, -10606, -7852, -10832, -7544, -11498, -9134, -6662, -15210, -6070, -8433, -6344, -5589, -10395, -4950, -6170, -5338, -4885, -8898, -5055, -5460, -5829, -4232, -8021, -6466, -5481, -9062, -3557, -8159, -9262, -5154, -10191, -3290, -10077, -5350, -5843, -8811, -5320, -9128, -7464, -3738, -10143, -7960, -8100, -9496, -3235, -12739, -9271, -7889, -5974, -4061, -12627, -9218, -7999, -4389, -6014, -9309, -7709, -7663, -4306, -6351, -8323, -6228, -6876, -6256, -4848, -8023, -5981, -6369, -22941, -3874, -7185, -6829, -7207, -7048, -3467, -7086, -8196, -10378, -6642, -3479, -9258, -9857, -7156, -11084, -3651, -9220, -14935, -5104, -7677, -3819, -5829, -12594, -4775, -5058, -4090, -4704, -10755, -5069, -4478, -4545, -4855, -12465, -4925, -4561, -5231, -5501, -8389, -4510, -4559, -6212, -5288, -5943, -4715, -4564, -6756, -4783, -5362, -6670, -5045, -5267, -4956, -6155, -12391, -5872, -3268, -5009, -7774, -4679, -6195, -2051, -4210, -7952, -2658, -5427, -1662, -3561, -6643, -2372, -4257, -1872, -3409, -5854, -3374, -3473, -2318, -3894, -6110, -5644, -3255, -2620, -5374, -7144, -8270, -3633, -2712, -6792, -7214, -7604, -4796, -2792, -5905, -6319, -6949, -7097, -2972, -6274, -5927, -6965, -8726, -3185, -10383, -6426, -6650, -7111, -3338, -7288, -8155, -5905, -6216, -3604, -4812, -10773, -5450, -6311, -4407, -4748, -8935, -5538, -7599, -6173, -6452, -7096, -5857, -10204, -9091, -10233, -5895, -5855, -9265, -11213, -18393, -4744, -5604, -7013, -10177, -15188, -3829, -5427, -5872, -8567, -13044, -3467, -5386, -5846, -7906, -14226, -3806, -5568, -7225, -8231, -15640, -4867, -6064, -7962, -8570, -15315, -6491, -6603, -5666, -8093, -12325, -8361, -6551, -4535, -7626, -8564, -10203, -5893, -4544, -7566, -6681, -10950, -5123, -5408, -7591, -5847, -10538, -4421, -7186, -7343, -5592, -11590, -3902, -11545, -6836, -5673, -13925, -3799, -10239, -6406, -6118, -7636, -4267, -5771, -6545, -7258, -5346, -5225, -3950, -7375, -9963, -4827, -6336, -3422, -8649, -19154, -5777, -7520, -3945, -11323, -9199, -8682, -8992, -5413, -13915, -6826, -13591, -9162, -7564, -8499, -5978, -9332, -7473, -9923, -7084, -6291, -8315, -6112, -12872, -7505, -7801, -8927, -5640, -20680, -9918, -9336, -11811, -6077, -12715, -18131, -8541, -12484, -7082, -9311, -15387, -8505, -8095, -7985, -7318, -16632, -10172, -6551, -8789, -6129, -15036, -11625, -6071, -10040, -5623, -14149, -10038, -5712, -12652, -5786, -8795, -8596, -5150, -17093, -6398, -6442, -7428, -4844, -10921, -6799, -6098, -6908, -5106, -9167, -6896, -7377, -7247, -5934, -9277, -6995, -10019, -8436, -7206, -11837, -6677, -11714, -9005, -8900, -14474, -6423, -10326, -7606, -10715, -8786, -7193, -9644, -7153, -10266, -6949, -9861, -9951, -8611, -9436, -6413, -15358, -10963, -12247, -10379, -6633, -11458, -15410, -11217, -13295, -7154, -11108, -12643, -12588, -9742, -7396, -11499, -9731, -11903, -7479, -7161, -11064, -10301, -8998, -6598, -6914, -11898, -16542, -9630, -6623, -7180, -13601, -11254, -10157, -7547, -8109, -9983, -8363, -6865, -9548, -8945, -8289, -6601, -5682, -12160, -8646, -8391, -5706, -5913, -11865, -8276, -10447, -5925, -6935, -9121, -8354, -7604, -6798, -9462, -6838, -4716, -6822, -6549, -8462, -7693, -4000, -6594, -7895, -6769, -7586, -4973, -6013, -8419, -5617, -7780, -7360, -5270, -5937, -5635, -9492, -7264, -4908, -4523, -7270, -15655, -6850, -5062, -4234, -9884, -13528, -8888, -5614, -4852, -7523, -10928, -7270, -6215, -5311, -6747, -7114, -4923, -6566, -4600, -7739, -4724, -4564, -7040, -4242, -8549, -3727, -5943, -8435, -4850, -7798, -3812, -9394, -9503, -6331, -8229, -4845, -8458, -8618, -8332, -10959, -6702, -8161, -9438, -10704, -9777, -8455, -12745, -8288, -18293, -7542, -8917, -6757, -5409, -10329, -7475, -8013, -4059, -4109, -6316, -7180, -5499, -2730, -3871, -4034, -4328, -3872, -1852, -4352, -2859, -2390, -3590, -1313, -5337, -2758, -1733, -4776, -1285, -6561, -3900, -2343, -8214, -2047, -8071, -6182, -4479, -13300, -4172, -9847, -5768, -6314, -8925, -10777, -7609, -4552, -4439, -8330, -7203, -5519, -4559, -3779, -8590, -5127, -4699, -4959, -4239, -9071, -5260, -4944, -4503, -5149, -10096, -6423, -6439, -3922, -5556, -12913, -7777, -9690, -4341, -5107, -11462, -9815, -12056, -6622, -4521, -7703, -10977, -13298, -11830, -4439, -5979, -7696, -10712, -5605, -5086, -5555, -6830, -6915, -3485, -6244, -6340, -8277, -5108, -2779, -6934, -8530, -14756, -4508, -3014, -6373, -12795, -8122, -4962, -3946, -5447, -20497, -5840, -6385, -5337, -5108, -16593, -5327, -8387, -7255, -5739, -11819, -6191, -10161, -7649, -7019, -10547, -9152, -10066, -5847, -6470, -14486, -10060, -8501, -5217, -5286, -9341, -5770, -7874, -5880, -5256, -5970, -3900, -8430, -7759, -6395, -5144, -3241, -9640, -11092, -7933, -6040, -3405, -10804, -14053, -8638, -9004, -4054, -13237, -11551, -9299, -12484, -5009, -14033, -10711, -9999, -8460, -6175, -9999, -11959, -10288, -7217, -6379, -8146, -14966, -9243, -7447, -6123, -7424, -10787, -8123, -8228, -7030, -7654, -9525, -8109, -7544, -8848, -8383, -10883, -8998, -5887, -8280, -8208, -19806, -10114, -4968, -7492, -8023, -12012, -11740, -5422, -7524, -9341, -8940, -12506, -8279, -6865, -13448, -6894, -7999, -13915, -5800, -15544, -6065, -5780, -8611, -5322, -10285, -6815, -5080, -9507, -5177, -8316, -10562, -5325, -9006, -5229, -8222, -10018, -6044, -6886, -5836, -10249, -6882, -7736, -7052, -6820, -14958, -6880, -13252, -7863, -7128, -11928, -9877, -7676, -7032, -6802, -11699, -13657, -5602, -7377, -6714, -12093, -8943, -5430, -10822, -6575, -10612, -8469, -6471, -9368, -5754, -10230, -9748, -8396, -7060, -5243, -10757, -16112, -9310, -7211, -5730, -10197, -11386, -7731, -8958, -7499, -9370, -9610, -6667, -10252, -10601, -8998, -11204, -6622, -9982, -9833, -8612, -10396, -7354, -10764, -8613, -8016, -8505, -7972, -13083, -8838, -7443, -9133, -7421, -22329, -9933, -7356, -13400, -6717, -12747, -10748, -8053, -11388, -6577, -9403, -10115, -9711, -8863, -6951, -8050, -9368, -13137, -8426, -7709, -8026, -9329, -16157, -9241, -8961, -9285, -10204, -10665, -4364, -6294, -3836, -7219, -9365, -3929, -6002, -5580, -4914, -8936, -4243, -7687, -8215, -4495, -10010, -5284, -8697, -7519, -5838, -12775, -6430, -8266, -7565, -10654, -11040, -7006, -10283, -10751, -9930, -10448, -7897, -13324, -7606, -7022, -9663, -9744, -8958, -4818, -6295, -6927, -10911, -7584, -3691, -5889, -5940, -10517, -7192, -3582, -5363, -7219, -9895, -7168, -4360, -5180, -9619, -8691, -7961, -5198, -5803, -5978, -7237, -10391, -4804, -7380, -4833, -6109, -10396, -4192, -9450, -5547, -5263, -9089, -3209, -10289, -6763, -4585, -6318, -1948, -8639, -6093, -4576, -4159, -1231, -6172, -5231, -5832, -3620, -1236, -4528, -3804, -6468, -4263, -1849, -3621, -2225, -4256, -4723, -2965, -2791, -1475, -3322, -4411, -4578, -1826, -1700, -3905, -4468, -6272, -1273, -2831, -6034, -4816, -5906, -1430, -4717, -8818, -4714, -4902, -2262, -6920, -8330, -4036, -4736, -3635, -8333, -7975, -3348, -5249, -4955, -8431, -7728, -2994, -6889, -5195, -8476, -6570, -3102, -13434, -5928, -9587, -5214, -3852, -6093, -7567, -11295, -4506, -5399, -3752, -5774, -9771, -4808, -6523, -3233, -4852, -8863, -5962, -6095, -3654, -5989, -8809, -6196, -6473, -4103, -7589, -9073, -5738, -7981, -4108, -5257, -8939, -6148, -8299, -4780, -3803, -6527, -6477, -6990, -7861, -3288, -4499, -6232, -6105, -10866, -3259, -3479, -6646, -5314, -6065, -3503, -3374, -7567, -4174, -5087, -3853, -4226, -8037, -3362, -5254, -4256, -6220, -8814, -3278, -6154, -5008, -9116, -10928, -3834, -7891, -6764, -9195, -9869, -4800, -10372, -11778, -8982, -7745, -6119, -11778, -10249, -10527, -7539, -7762, -9666, -7519, -11275, -9557, -9285, -7147, -7933, -10382, -14017, -13071, -6178, -12286, -10424, -9186, -10255, -7514, -11687, -8993, -7492, -6503, -9128, -10698, -7872, -7326, -5508, -4999, -16246, -7830, -8372, -6157, -3467, -8183, -8341, -9524, -8154, -3266, -6474, -8933, -10035, -9500, -3579, -6851, -9384, -10592, -9732, -3931, -8966, -10573, -9352, -10725, -4621, -8411, -12677, -8166, -8141, -5573, -6177, -10671, -6396, -7005, -5019, -5664, -8539, -4903, -7998, -4353, -6129, -7154, -4439, -8108, -5015, -6479, -6239, -4922, -6675, -6239, -7302, -5595, -5903, -7161, -5943, -9650, -5466, -6010, -10543, -6084, -7520, -6087, -5225, -15220, -7054, -5292, -6691, -4902, -11189, -6657, -4647, -6504, -5288, -11743, -5961, -5358, -6616, -6282, -13219, -6286, -7658, -6664, -7806, -14203, -7961, -9002, -6051, -8918, -12693, -12553, -6606, -6071, -8136, -9552, -11452, -5097, -7414, -7769, -7945, -8942, -4260, -9978, -9190, -7114, -9340, -4201, -10764, -13846, -5954, -15349, -5477, -9096, -10039, -4706, -9028, -10172, -7495, -8385, -4112, -5674, -7674, -6897, -8848, -4367, -4294, -4688, -7419, -10627, -5427, -3950, -3679, -8725, -9351, -7109, -4392, -3577, -9706, -6925, -9179, -5632, -4123, -9339, -5498, -11658, -7746, -5061, -8542, -4782, -13051, -8615, -5995, 10207, 11289, 9083, 11137, 8447, 9430, 10944, 8381, 10592, 8026, 7216, 9886, 6198, 8985, 6673, 6633, 8129, 4138, 6584, 4431, 7475, 6153, 5042, 4490, 3804, 6993, 5102, 5109, 3740, 4357, 5154, 4561, 3913, 3153, 3361, 3044, 3469, 1068, 2251, 46, 5734, 1797, -3758, 2245, -1866, 7030, 564, 1773, 1725, 1478, 6789, 625, 3127, -1614, 3713, 6222, 488, 3036, -562, 5623, 5979, 1255, 3515, 3295, 6951, 4547, 3822, 4257, 4597, 7390, -822, 4900, 3891, 4550, 6732, 826, 4401, 2104, 3719, 4627, 2534, 2473, -938, 2962, -219, 1731, -34, -1834, 2546, -1652, 296, -325, -1352, 2012, -161, 110, -52, -1516, 1491, -1138, 1025, -483, -1726, 1399, -1913, 1741, -1410, -987, 1403, -1115, 1689, -1125, -40, 831, -211, 353, 543, -80, -702, -268, -1854, 1470, -1423, -4196, -1443, 1014, 1393, -2236, -3751, -2075, 2777, 588, -92, 156, -1659, 3229, -489, 1328, 1353, -2081, 2877, -1334, 1669, 744, -1109, 1810, -1551, 1024, -2013, 743, 890, -1334, -573, -3908, 1664, 2001, -1130, -2663, -2071, 1890, 2865, -872, -2943, -3700, 1837, 2831, -270, -1210, -6507, 1574, 2720, -90, 239, -577, 784, 2899, -1803, 1098, 983, -818, 2646, -5786, 1519, 789, -3360, 1812, -615, 1551, -667, -9003, 940, 404, 1184, -1470, -3667, 193, -742, 497, -1471, -710, -601, -2693, -262, -4084, 478, -929, -1549, -687, -2203, 1135, -674, -381, -561, 895, 1537, -720, -271, -731, 1593, 1380, -1903, -1418, -2215, 596, 488, -5180, -3958, -6036, -2502, -1253, -8537, -4943, -11206, -5160, -4763, -5640, -3247, -5166, -1946, -7933, -5692, -1330, -1766, -398, -2854, -7819, -79, -219, 665, -1759, -10432, 51, -41, 1234, -2617, -5774, -1231, -1204, 1088, -5262, -3406, -5013, -4180, 88, -4682, -2510, -7221, -6368, -1986, -2630, -2390, -4973, -4483, -5984, -1756, -2469, -4899, -4610, -6454, -1856, -2687, -3228, -6005, -3629, -3222, -3783, -2565, -6734, -2752, -7600, -6444, -3639, -5262, -2601, -7169, -2645, -4663, -2591, -2349, -4601, -60, -3248, -847, -1804, -5712, 1000, -2539, -362, -1421, -7959, 1097, -3055, -943, -1731, -5327, 408, -4410, -1942, -2930, -5813, -1139, -4321, -2170, -3867, -7668, -4112, -3678, -1571, -3272, -4025, -6533, -4260, -973, -2701, -2626, -3591, -6282, -1033, -2514, -2780, -2551, -9603, -1826, -2444, -3987, -2360, -8058, -2500, -2464, -5667, -2311, -6635, -2500, -3015, -6611, -2884, -7232, -2174, -4393, -6850, -3689, -11287, -1442, -5914, -7380, -1876, -8607, -1157, -5547, -5864, -537, -7727, -2009, -4643, -3494, -603, -8298, -4132, -4745, -2530, -1954, -3908, -5005, -6482, -3294, -4320, -2201, -3564, -8216, -7161, -5690, -2257, -2733, -6127, -9394, -4781, -2998, -2583, -3481, -7349, 5426, 7847, 9313, 7297, 4636, 5085, 7058, 8906, 6891, 6119, 4043, 4658, 7771, 5909, 7459, 2156, 2417, 6234, 5217, 7788, -1435, 1624, 5049, 5095, 7408, -7233, -3838, 4569, 4327, 6644, -901, -94, 3901, 1247, 5628, 546, 2292, 3526, -2961, 4485, 1089, 2669, 4078, 1769, 4119, 257, 2406, 3876, 672, 4579, -46, 2191, 2664, 96, 5252, 4383, 2794, 2833, 4355, 5809, 6437, 3970, 3823, 5731, 5659, 6971, 4748, 3719, 5315, 4453, 6348, 4851, 2532, 2791, 2260, 4618, 4379, 1086, -8967, 813, 1747, 3504, 474, 1170, 1665, 656, 2502, -629, 2487, 2435, 1586, 1424, -1338, 2665, 2198, 903, -639, 1323, 2723, 670, -3224, -1740, 2583, 2562, -3183, -2303, 757, 2232, 1425, -3889, 1318, 1349, 528, -629, -666, 2355, 216, -310, 590, -34, 2543, -2223, 1015, 1222, -286, 2181, -3519, 1729, -234, -448, 874, -4004, 1344, -1421, -769, -2573, -5363, -1150, -254, -1731, -6367, -5754, -2257, -787, -1895, -884, -4020, 1781, -3247, -481, 896, -1826, 2605, -3712, -117, 1559, -668, 1196, -2059, -1999, 1519, -1375, -2616, -1751, -10551, 1487, -6260, -456, -2258, -1066, 1966, -3019, 589, -2636, 819, 2356, -1004, 39, -3487, 1438, 2445, -993, -1235, -4447, 1845, 2441, -462, -2703, -3742, 2280, 2201, 496, -1995, -2080, 2322, 1166, 981, -201, 444, 1756, -1499, 868, 431, 1756, 806, -3667, -112, -238, 1637, -78, -1968, -1412, -2136, 109, -646, -3260, -733, -5007, -2825, -1485, -9342, 109, -10058, -5639, -4041, -4338, 254, -9527, -5977, -12869, -2969, 285, -5502, -5068, -4607, -1379, 469, -3507, -3972, -3367, -219, 405, -2348, -2465, -3265, -347, -173, -1863, -1051, -3589, -1807, -931, -1612, -414, -4401, -4781, -861, -1242, -673, -5615, -13421, -194, -944, -1880, -6549, -7062, 327, -1004, -4253, -7672, -4454, 748, -1496, -5510, -13924, -3132, 923, -2578, -3646, -7889, -2116, 404, -5211, -3170, -5116, -1094, -1253, -7590, -3962, -4729, -190, -4422, -3925, -4724, -5366, 176, -4380, -3646, -4135, -5588, -196, -2938, -6095, -2935, -4876, -1312, -2734, -8116, -2162, -4472, -3171, -3102, -10162, -2307, -5976, -5890, -3760, -5903, -3491, -9974, -7713, -4368, -1577, -6112, -5954, -5608, -3784, 30, -7232, -4160, -3885, -2656, 375, -4147, -1974, -3448, -2591, -104, -2696, -669, -4437, -3507, -1342, -2292, -787, -6889, -3156, -3878, -2933, -2172, -8951, -2564, -14786, -4893, -3482, -6806, -3435, -5097, -4805, -2796, -4327, -5656, -3335, -3204, -1890, -3247, -6490, -4428, -3529, -1462, -2997, -4216, -10286, -6461, -1467, -2295, -3052, -2273, -15047, -1709, -1113, -4487, -3, -7242, -1887, -336, -7340, 491, -3356, -2034, -380, -1820, -228, -857, -2469, -1405, -209, -1899, 295, -2879, 9652, 7124, -6527, 7067, 8584, 9372, 7627, 4321, 7288, 8635, 8507, 8128, 6618, 7542, 8691, 6993, 7912, 7318, 7372, 8450, 5156, 7030, 7061, 6655, 7534, 4824, 5754, 6076, 5354, 5562, 5020, 4152, 4597, 3849, 2168, 3748, 1157, 3080, 3905, -862, -888, -4556, 1962, 4386, 440, 1776, 1834, -482, 3628, 2068, 4814, 2591, -2346, 2446, 1044, 6083, 3325, 3300, 3420, -8072, 6245, 4934, 4483, 3509, 1315, 5062, 5033, 2977, 2414, 1922, 1231, 2650, -7803, 3735, 4001, -994, -396, 3097, 4750, 6221, 2117, 3058, 4447, 4182, 6836, 1332, 3289, 3808, 2267, 6175, -2967, 1953, 2041, -705, 4531, -3984, 268, 555, -6472, 2323, -252, -245, 1111, -3071, 1547, 589, 90, 2149, 168, 2513, -158, -521, 2545, 1469, 3099, -3443, -3551, 2239, 1852, 3305, -5347, -5659, 1439, 1681, 3407, -1643, -2718, 664, 1044, 3140, -836, -3775, 451, -421, 1750, -909, -8705, 356, -2317, -2939, -1755, -3895, 55, 313, -1306, -2954, -3244, 290, 2307, 1473, -2253, -2582, 1121, 2993, 1894, -1241, -812, 1586, 2776, 1418, -694, -196, 1431, 1897, 301, -354, -91, 871, 447, -2935, -300, 497, 132, -1759, -1713, -692, 664, -1077, -5634, 1413, -1322, -130, -2534, -9987, 2011, -1774, -1518, 21, -4793, 692, -783, -4924, 2058, -2960, -3722, 1082, -4365, 2653, -2402, -2916, 1796, -616, 2184, -3321, -672, 892, -837, 1125, -5352, -197, -2158, -4373, -104, -2044, -116, -4696, -799, -1885, 108, -455, -3788, 609, -3943, 912, -1172, -5821, -365, -3853, 922, -1494, -10726, -3632, -4144, 351, -1992, -13746, -7281, -6012, -870, -4088, -7003, -8955, -9928, -2215, -10930, -4801, -4130, -9607, -1677, -6667, -4013, -2026, -7841, -1256, -4379, -3478, -2305, -7516, -2244, -2726, -3069, -5169, -7457, -3927, -1566, -3072, -5952, -8071, -4662, -1407, -3683, -3284, -12012, -6466, -2627, -5559, -2466, -8503, -8260, -7049, -12068, -1939, -6263, -5644, -5535, -5532, -1498, -8145, -3326, -1547, -2922, -1460, -8897, -1785, -83, -2035, -1681, -3586, -1615, 262, -2335, -1801, -1720, -3506, 34, -3925, -1776, -1105, -7138, -351, -7320, -2071, -1136, -2049, -1030, -13759, -3510, -1246, -409, -2428, -11366, -7703, -1434, -345, -3435, -6548, -4630, -2223, -1301, -2075, -4725, -2506, -3777, -3015, -810, -3991, -2467, -5095, -5961, -163, -3725, -3751, -5199, -6350, -106, -4025, -4216, -6003, -3078, -822, -4461, -2049, -9318, -1990, -2599, -3994, -206, -8426, -2517, -5395, -3002, 684, -5990, -5066, -4987, -2271, 701, -4272, -9414, -2754, -1898, 125, -2779, -4829, -1562, -1654, -710, -2591, -4261, -1492, -1627, -1909, -3583, -5441, -2417, -2053, -3650, -2863, -2625, -3523, -2894, -4334, -1597, -473, -3340, -4067, -3633, -1699, 232, -2580, -4067, -2308, -3084, -1180, -6092, -4239, -1293, -4354, -36, -2800, -3728, -1102, -5333, 72, -1672, -1911, -1753, -4297, -556, -1852, -986, -3200, -4189, -1704, -2067, -1346, -5424, -6356, -3116, -1528, -2690, -6495, -5987, -3808, -981, -3077, -4233, -4180, -3316, -640, -2510, -2383, -6287, -2277, -429, -2864, -1384, -5192, -1512, -475, -3355, -1349, -966, -1403, -881, -2271, -2630, 389, -1847, -1543, -1237, -4508, 338, -2645, -1930, -979, -2698, -646, -3822, -1645, -1614, -1494, -1975, -5789, -1433, -3747, -1685, -2633, -8070, -1757, -8432, -3345, -3061, -5691, -1998, -3004, -8269, -4698, -4254, -1247, -599, -4812, -2980, -4254, -336, 249, -2421, -411, -4544, -81, -145, -2301, 396, -4487, -860, -1777, -4124, -241, -4998, -3200, -3160, -8355, -2338, -5146, -7469, -2295, -9141, -5032, -3662, -5895, -1874, -5905, -5154, -2514, -5081, -2382, -4328, -6181, -2148, -4711, -4073, -4849, -8862, -2655, -3913, -8250, -4878, -8104, -4369, -3010, -6854, -3375, -5052, -6610, -2190, -4762, -2965, -3345, -5969, -1668, -5101, -3189, -3193, -5337, -1630, -7802, -3245, -4524, -4370, -2125, -8453, -3168, -6898, -3635, -3126, -6650, -3888, -6152, -4153, -4874, -7013, -7049, -4643, -6797, -8176, -7959, -7043, -4792, -14044, -4507, -7943, -3770, -7443, -6466, -1643, -7323, -3277, -7378, -5406, -580, -7269, -4736, -4354, -6025, -960, -8876, -6648, -4096, -7668, -2995, -12681, -3646, -6702, -9556, -6765, -12470, -1753, -6742, -7613, -4703, -9559, -975, -2850, -4852, -3019, -7457, -1062, -1342, -2897, -2641, -6713, -1993, -831, -1659, -2941, -6644, -3833, -972, -1070, -3118, -6411, -6991, -1778, -1119, -3081, -6290, -8705, -2943, -1677, -3203, -7092, -5220, -2945, -2155, -3704, -7188, -3990, -2399, -2346, -4409, -5589, -4399, -2796, -3158, -4166, -5033, -6164, -4740, -5073, -3487, -5275, -8020, -9252, -5519, -3013, -5280, -7049, -6241, -4112, -2602, -5002, -4342, -4485, -3499, -2209, -5353, -2726, -3989, -3586, -1779, -7542, -2447, -3624, -4131, -1538, -10178, -3316, -3414, -4716, -1680, -6510, -4780, -3717, -4943, -1959, -5807, -5592, -4417, -5193, -2187, -6896, -5312, -4970, -5971, -2826, -9528, -4553, -5374, -7619, -4631, -11720, -4032, -6466, -10981, -9776, -9626, -3596, -7883, -7643, -7926, -9450, -3189, -6556, -4514, -5081, -10063, -3555, -5838, -3001, -4330, -5326, -5705, -6934, -2437, -4379, -3222, -13828, -8629, -2534, -4638, -3081, -6308, -7829, -3122, -4884, -4988, -4575, -8347, -4172, -5425, -12266, -3980, -12652, -5641, -6592, -8644, -3517, -9681, -6087, -8262, -6792, -3360, -7437, -5156, -9033, -6179, -3928, -7239, -4846, -7804, -6242, -5451, -7585, -5468, -6124, -7393, -7578, -6948, -6962, -4992, -10180, -8464, -5689, -10150, -5007, -9271, -9298, -5037, -12223, -7211, -6436, -12225, -5674, -6543, -12220, -5783, -11803, -8592, -4992, -5941, -3157, -170, -3957, 419, -2841, -3929, -1142, -4620, -314, -3270, -2281, -2919, -3992, -1859, -5558, -532, -5426, -4294, -4450, -10597, 248, -5391, -4548, -9407, -3583, -35, -3340, -3159, -7880, -1402, -1515, -2693, -2726, -6853, -692, -4796, -3774, -3899, -7827, -1072, -6084, -8339, -5251, -6331, -2497, -3400, -7077, -4072, -4268, -4882, -2502, -4276, -3589, -3245, -7636, -2608, -3600, -4090, -3282, -9546, -3455, -3308, -4841, -4708, -8275, -4656, -2979, -5731, -9120, -5274, -5088, -2714, -6845, -9933, -3065, -4837, -2564, -7328, -5654, -1960, -4820, -2365, -6734, -3859, -2256, -5088, -1539, -5890, -4024, -4679, -4334, -322, -4506, -10133, -2871, -2397, 300, -2445, -3656, -186, -1113, -244, -1247, -620, 543, -552, -2311, -1136, 177, -4, -276, -3337, -1706, -466, -1231, -500, -2301, -2313, -2774, -2075, -2132, -3227, -2650, -6498, -2054, -7939, -3448, -2781, -5073, -1721, -3973, -1305, -3086, -6035, -1765, -1945, -533, -4356, -16899, -2541, -1818, -706, -6369, -5265, -4491, -2578, -1216, -4346, -3699, -10344, -3971, -1983, -3044, -4514, -7241, -6979, -2824, -3433, -10366, -5372, -9833, -3742, -6117, -5688, -5513, -3639, -6728, -9176, -3372, -5632, -1562, -6172, -3954, -3871, -4747, -992, -3247, -2446, -7278, -3462, -1548, -3282, -1876, -5573, -2696, -2417, -4861, -1604, -2894, -2699, -1627, -3137, -1879, -1806, -3529, -636, -1494, -2835, -1315, -5640, -629, -1268, -3994, -1102, -7340, -1609, -2153, -4626, -1179, -3667, -3165, -4117, -4095, -1683, -1811, -4122, -7872, -3229, -2724, -1385, -3690, -10671, -2923, -4360, -2363, -2690, -6183, -3171, -6327, -5682, -2145, -4540, -3834, -6881, -12452, -2398, -4211, -4850, -5589, -7662, -2900, -5063, -5796, -4179, -7179, -2366, -6936, -5940, -3622, -3547, -1541, -6389, -6049, -4282, -2157, -1368, -4364, -7178, -6198, -2702, -2154, -3233, -9029, -6981, -5334, -4461, -2787, -7655, -3614, -9777, -7026, -2835, -5070, -1319, -8361, -4223, -3253, -3094, -448, -9863, -3240, -3538, -2131, -806, -18134, -3532, -2913, -2198, -1992, -9332, -4367, -2200, -3003, -2578, -7431, -5050, -2440, -3693, -2335, -6507, -5188, -4258, -3720, -2648, -5348, -4864, -6207, -3824, -3727, -4056, -4372, -4311, -4385, -5038, -3425, -3762, -4365, -5165, -6263, -3861, -2949, -5523, -5803, -7267, -5535, -2440, -3450, -6491, -6583, -7471, -2905, -2155, -7149, -5838, -7255, -5139, -2232, -6117, -5664, -7448, -9986, -3195, -5670, -6103, -9060, -5480, -4686, -7828, -7515, -11807, -4176, -6412, -10395, -8694, -8353, -4366, -7673, -6264, -7269, -4235, -5007, -7954, -5487, -5539, -2070, -5206, -7984, -5717, -4639, -1338, -5335, -9191, -5433, -4683, -1827, -6415, -13691, -4209, -5045, -3519, -8156, -12743, -3118, -4772, -6756, -6671, -9288, -2765, -4329, -8963, -6039, -8329, -3145, -4475, -6576, -7427, -8702, -3934, -5309, -6314, -5477, -3410, -3167, -66, -2262, -5855, -3498, -5408, -1286, -2858, -5521, -3041, -5328, -4032, -4533, -6361, -2287, -3867, -20243, -4777, -10200, -2155, -2661, -5044, -3543, -9783, -3018, -1798, -4161, -3724, -4886, -4616, -1429, -7303, -5895, -2396, -4869, -1700, -6545, -6492, -949, -3431, -2717, -2493, -2300, -565, -2311, -4681, -1593, -456, -1694, -1798, -8494, -2401, -264, -6883, -1563, -11681, -4056, -1761, -3721, -1230, -5505, -3650, -5053, -947, -821, -2387, -3506, -3741, -358, -624, -405, -3536, -2328, -642, -790, 472, -970, -2018, -1064, -1438, 77, 912, -1657, -583, -2990, -2015, 1734, -664, 340, -4616, -3717, 1779, 565, 722, -2975, -1722, 1200, 1446, 669, -2045, -1682, 17, 1739, 477, -2367, -3931, -1958, 1421, -69, -3265, -7861, -5522, 510, -1234, -3364, -5265, -17262, -914, -2866, -2765, -4489, -7162, -2282, -3834, -2555, -3742, -5362, -3331, -3263, -2447, -3105, -3817, -6616, -3147, -1883, -3630, -2625, -6406, -4667, -1269, -5446, -2050, -2187, -9455, -626, -7359, -1879, -1076, -5427, 148, -6831, -1534, -1283, -2948, 483, -4340, -944, -2099, -2338, -155, -3232, -947, -2821, -3413, -2428, -3920, -2179, -3242, -7184, -12341, -7016, -4100, -3160, -5233, -3558, -14145, -3318, -2490, -3249, -1710, -7597, -2832, -2170, -3325, -1787, -6355, -3936, -2602, -4810, -2898, -5908, -5624, -3795, -8726, -3745, -5841, -3629, -5146, -8145, -4212, -6266, -1858, -3569, -3990, -6194, -5008, -1244, -2718, -2468, -10348, -2920, -1426, -4559, -2215, -7165, -2210, -2518, -10184, -2919, -6182, -3111, -6181, -2783, -4790, -6442, -3864, -3545, -859, -16235, -6619, -1850, -595, -2, -3783, -5489, -641, 56, 310, -930, -3593, -440, -895, -13, -139, -2242, -907, -3589, -963, -691, -2010, -1697, -8947, -1732, -1890, -2865, -1927, -12190, -1474, -2324, -3764, -1104, -6571, -1214, -2128, -3762, -508, -5101, -1675, -1924, -4087, -850, -5613, -2976, -2142, -5175, -2255, -4302, -4548, -3586, -6211, -4518, -3139, -4060, -8390, -5934, -6325, -4610, -2357, -7488, -5683, -6163, -7341, -1213, -4894, -4927, -6371, -2692, -1206, -5002, -3591, -9952, -1444, -3129, -5790, -2942, -8019, -1823, -13260, -5479, -3063, -4223, -3022, -3420, -5042, -3514, -3078, -3803, -1685, -5575, -3754, -3408, -4172, -1592, -8212, -3633, -5294, -4751, -2493, -10080, -3281, -8064, -4468, -4490, -5562, -2984, -6170, -3963, -7899, -4475, -3326, -5320, -4466, -5433, -4894, -5054, -5898, -6387, -3080, -5548, -10698, -6944, -9742, -2464, -5787, -7323, -7028, -11875, -3031, -6788, -4895, -6152, -15868, -3168, -8866, -4532, -5277, -7629, -2080, -10652, -5437, -4903, -5330, -1388, -10577, -7358, -5212, -4795, -1010, -9603, -9015, -6117, -5454, -606, -8182, -9363, -6617, -7009, -517, -6436, -9368, -6261, -6469, -1053, -6020, -8244, -6454, -4848, -2195, 6928, 7161, 7582, 9663, 3009, 6574, 6930, 7288, 8942, 2336, 5736, 5959, 6643, 6362, 551, 4880, 4033, 6077, -2389, 1134, 4115, 3344, 5678, 3457, 2681, 3483, 3649, 5306, 3935, 2660, 2102, 2126, 4541, 2237, 516, -2154, -289, 2802, 3058, -1716, 3671, 2723, 322, 4541, 2205, 5567, 3995, -57, 4703, 3907, 5418, 4148, -1085, 3697, 5001, 3807, 4239, -3546, 1478, 6029, 1668, 4889, 818, -144, 6718, 1282, 5574, 2393, 1204, 6736, 1982, 5516, 2036, 1773, 5835, 1456, 4272, -5, 1474, 3807, -453, 1723, -367, 723, 1272, 1176, 589, 1470, -87, -532, 1951, 1410, 2149, -182, -2145, 820, 1516, 1956, 714, 1835, 1723, 1139, 1227, 1601, 3241, 4201, 697, 407, 1961, 2985, 5495, 625, 86, 1831, 1753, 5665, 644, 258, 1375, 101, 4633, 408, 428, 591, 101, 1964, 73, 586, -1114, 1791, -3599, 341, 1153, -5101, 2327, -3064, 1556, 1648, -5711, 1436, -3218, 2393, 1225, -6239, -1028, -2614, 2159, -112, -3314, -6108, -490, 634, -104, -935, -7254, 1131, -2714, 266, -725, -2490, 2436, -5403, -995, -1625, 141, 3343, -2207, -1860, -1732, 1613, 3657, -1396, -380, -920, 2091, 3269, -2605, -115, -694, 1471, 2147, -8207, -1260, -1161, -634, 487, -5559, -2514, -1353, -5645, -720, -3252, -1475, -1312, -5870, -873, -3397, -1416, -2092, -3917, -921, -4442, -3653, -3683, -3276, -1468, -2817, -6368, -4562, -2547, -2602, -945, -5453, -3824, -2102, -3643, -496, -10197, -3446, -2567, -3957, -1277, -5898, -4932, -4097, -3617, -2940, -3369, -12484, -5700, -3037, -4624, -2317, -5191, -6881, -2797, -4694, -1040, -3485, -9315, -3042, -3857, -200, -3721, -8256, -3425, -3250, -339, -3769, -6949, -3035, -2842, -1585, -1973, -5703, -2145, -2747, -3759, -602, -4099, -1649, -3167, -5274, -249, -3214, -1890, -4350, -6286, -1009, -3009, -3173, -7507, -6186, -3358, -3037, -6044, -9712, -3886, -9717, -2858, -4379, -4317, -3178, -6481, -2575, -1477, -2575, -4203, -5782, -2697, -165, -2142, -5758, -7880, -3698, -55, -2516, -4626, -9078, -6360, -1198, -3214, -4071, -7936, -8296, -3909, -3814, -5051, -7098, -4863, -6324, -4723, -6959, -5957, -3596, -5381, -6863, -5569, -4869, -3771, -5398, -9812, -3639, -3449, -5759, -6330, -7022, -2587, -2509, -9998, -7825, -5322, -2124, -2606, -5872, -7187, -4567, -1959, -3973, -4872, -7178, -4412, -1840, -7693, -6145, -8514, -5065, -1816, -10338, -9791, -6354, -6935, -2090, -5574, -7507, -5249, -10146, -2684, -4477, -6408, -5846, -8380, -3063, -4549, -7633, -7512, -6250, -2611, -4874, -9968, -9417, -5461, -2196, -5033, -10329, -9230, -5494, -2565, -5050, -7495, -7770, -5990, -3404, -4994, -5494, -7295, -6686, -3496, -5244, -5669, -7175, -7101, -3513, -5959, -9259, -6859, -6415, -4417, -6444, -6359, -1981, 7876, 7695, 8495, 8237, -2844, 7481, 7270, 7862, 7545, 1019, 6019, 5665, 6034, 5202, 3039, 2185, 2306, 5340, -953, 3467, -1751, 3379, 6516, -117, 3658, 2522, 4529, 6607, 2003, 4490, 2914, 3987, 5438, 1648, 5270, 2903, 3379, 3369, -873, 5512, 2931, 3175, 1822, -2892, 5008, 2496, 1168, 220, -3019, 3421, 1830, -4198, -2965, -1917, 2406, 1767, 2827, 1174, 509, 4688, 2281, 4282, 2522, -37, 5930, 2738, 4040, 2101, -5544, 6003, 2823, 2793, 766, -3529, 5412, 2160, 1395, -503, -2334, 4763, 194, 657, -1395, -5836, 4156, -4541, -263, -2714, -6537, 2816, -3596, -1707, -728, -2451, -1709, -784, 231, 1996, -855, -251, 214, 1987, 2531, 152, 3082, 342, 2359, 300, 813, 3486, 164, 1775, -2561, 1035, 2136, 271, 621, 2147, 408, -696, 702, -1360, 3150, -1099, -2018, 944, -8521, 3171, 847, -1162, 473, -2446, 3282, 2751, 143, -1128, 31, 3279, 2878, 1415, -2750, 35, 2765, 1139, 2366, 390, -2352, 1736, -3317, 2803, 2860, -7559, 611, -4770, 2225, 4179, -3502, -87, -5472, -484, 4644, -5787, -1006, -3457, -4922, 4405, -4343, -2748, -1305, 943, 3514, -212, -2991, -843, 2521, 2064, 748, -836, -1403, 3056, 516, 233, 886, -1366, 2921, -400, -794, 2005, -3, 1891, -1284, -1647, 2547, 456, -449, -3947, -3161, 2391, -251, -4949, -10357, -2631, 1181, -1484, -7207, -6178, -821, -2308, -2560, -5659, -11313, -580, -5646, -2848, -3473, -2267, -1680, -967, -2630, -2106, 56, -3239, -401, -3008, -2384, 407, -4374, -1663, -3304, -4877, -627, -4487, -4751, -4659, -9247, -2585, -2020, -9640, -8211, -5383, -3012, -327, -11648, -2926, -5704, -2565, 378, -6753, -1507, -7532, -3347, 483, -4807, -2080, -3945, -4303, 264, -4548, -4391, -2012, -3684, -187, -4851, -6521, -1326, -3289, -980, -4349, -5678, -1515, -2131, -2063, -3427, -6038, -2768, -864, -2668, -2829, -7045, -6107, -792, -2995, -2743, -6596, -12351, -2175, -3964, -3177, -5050, -7948, -4977, -3998, -3949, -3822, -7796, -6941, -3381, -4913, -3246, -4481, -7580, -4051, -6255, -3220, -2724, -7102, -5431, -6488, -3589, -2407, -5400, -5885, -4847, -4463, -2929, -4341, -6888, -4257, -6679, -3643, -3892, -5181, -5014, -18357, -3975, -4023, -3273, -6397, -5969, -4322, -4631, -3067, -6547, -3801, -5631, -4851, -4139, -5174, -3317, -8692, -4473, -5120, -3951, -3770, -9338, -4609, -5421, -3673, -4699, -8021, -5558, -6945, -4439, -5838, -9140, -6951, -8590, -6337, -7444, -14789, -8155, -6678, -9408, -9408, -12676, -8249, -5398, -12206, -9098, -11849, -6063, -4893, -14348, -8102, -14796, -3920, -5688, -8043, -8041, -11395, -3023, -9351, -5778, -8808, -9526, -3716, -11085, -4731, -10442, -9287, -7182, -8530, -3985, -15913, -9585, -9185, -10307, -3460, -10567, 6844, 8184, 3420, 5950, 6590, 5716, 7520, 2915, 5650, 5578, 1323, 5655, 1526, 4481, 1420, 2109, 4602, 938, 2294, 15, 4468, 5518, 3231, 2469, 3187, 5793, 5964, 4592, 3694, 3339, 6224, 5655, 4528, 4454, 2352, 5057, 4221, 3430, 5324, 971, 1833, -301, 2190, 5579, 373, 2644, 850, 1098, 4721, 980, 4056, 3616, -1585, 2925, 537, 4012, 4156, -3087, 1117, -3988, 3210, 4093, 1451, -2670, -2487, 1519, 3634, 2380, -613, -810, -2387, 2590, 568, 2761, -6471, -488, 1010, -5312, 3534, 340, 1823, -1565, 1888, 3010, 3257, 1775, -3382, 3422, 2002, 4252, -685, -951, 3397, 1173, 4308, -3154, 168, 2609, -479, 3921, 1052, 588, 1830, -3238, 3553, 2378, 610, 1794, -208, 3373, 2364, 113, 2254, 1288, 3176, 1322, -1241, 2383, 1270, 2722, -950, -4485, 1628, 102, 1826, -5666, -8227, -513, -1899, 410, -4133, -3782, -6552, -905, -1388, -2513, -747, -3604, 1420, -3010, -3860, 972, -216, 2714, -628, -2463, 1139, 963, 3132, 1691, 105, 357, 731, 2731, 2376, 650, 659, -968, 1401, 1577, -86, 1151, -5024, -280, -273, -1284, 615, -7242, 329, -1523, -2322, -285, -1319, 1239, -3131, -4030, -1557, 1273, 1204, -2623, -4930, -4765, 2533, 382, 31, -3846, -2702, 2810, -1149, 1031, -2436, -2306, 2244, -3404, 1046, 817, -8994, 1047, -4395, 638, 2113, -1506, 182, -2293, 232, 1249, 408, 245, -443, 303, -2615, -457, 2, 388, 1146, -1225, -3270, -964, 114, 1823, 69, -1130, -1849, -1146, 1661, -1202, -555, -1365, -2727, 687, -4664, -2784, -860, -4224, -719, -8293, -6623, -1237, -5927, -2521, -5505, -3504, -1674, -4074, -4433, -3443, -3662, -1029, -1584, -4872, -3436, -5480, -604, 87, -4061, -6831, -6373, -954, 895, -2930, -4665, -5970, -1481, 869, -3005, -1678, -6194, -1725, 102, -4007, -1213, -7330, -2515, -1336, -4220, -2492, -4365, -4748, -3634, -3468, -6231, -2036, -8618, -7015, -2416, -10932, -1345, -8476, -5322, -2055, -7350, -2131, -10709, -3277, -3007, -7164, -4938, -10398, -2347, -5087, -6032, -11826, -6451, -1985, -5375, -5476, -6386, -5870, -1782, -5321, -6190, -5095, -7148, -1297, -6906, -7337, -4828, -9918, -793, -7903, -6343, -5432, -7696, -862, -6090, -4809, -7046, -5531, -1731, -4551, -4415, -5858, -5221, -3339, -4088, -5435, -4033, -6463, -4688, -4882, -8282, -4049, -8560, -3891, -6749, -9165, -6707, -8658, -2887, -8564, -7138, -10402, -6502, -2670, -9858, -6370, -4903, -4838, -3343, -10015, -6338, -3947, -4444, -5240, -7141, -7775, -4739, -5188, -6116, -4346, -12681, -6528, -6728, -3824, -2500, -6372, -8095, -9228, -2730, -1680, -4190, -7241, -11071, -2502, -1914, -3767, -4542, -8579, -2851, -3341, -4537, -3365, -7100, -4257, -5807, -6160, -3938, -6677, -8386, -5363, -6487, -5417, -4831, -5399, -3595, -6606, -5220, -4098, -3955, -2996, -6791, -5518, -4339, -2958, -3813, -5029, -4855, -6573, -2456, -5830, -3627, -3990, -10242, -2583, -6572, -3503, -3955, -5694, -3498, -5733, -4531, -4720, -4080, -4973, -6642, -6336, -5565, -3660, -5397, -11244, -7572, -5403, -3796, -4399, -9624, -6943, -4976, -4501, -3341, -7751, -6284, -4998, -6524, -2623, -7953, -6400, -5125, -13720, -2499, -7962, -6581, -4922, -9675, -3201, -6947, -6428, -4554, -8044, -5125, -5239, -7512, -4496, -6154, -8552, -3600, -12902, -5097, -3938, -6733, -2506, -12785, -7219, -2296, -6245, -2448, -8098, -6875, -793, -7453, -4342, -2270, -1398, 579, -2516, -2953, 237, 929, 1489, 27, 266, 986, 1584, 1656, 936, 1345, 322, 829, 893, 681, 786, -1675, -1400, -934, -484, -1650, -4605, -5233, -3661, -2148, -8273, -7098, -7983, -5542, -3463, -6495, -9317, -6325, -6176, -3798, -6445, -10349, -4891, -7107, -3570, -7094, -11108, -4375, -7870, -3322, -4857, -10823, -4363, -8390, -3422, -3691, -7608, -4723, -10417, -4252, -3535, -5257, -5565, -11499, -5773, -3891, -4566, -6740, -9103, -6320, -4558, -5707, -7907, -7989, -6022, -5807, -10570, -8858, -6677, -6372, -7130, -8773, -8440, -6381, -6672, -7034, -6078, -8636, -9076, -6136, -7177, -5651, -8736, -9553, -5450, -7590, -6840, -7336, -5381, -5011, -6630, -14294, -7488, -4801, -4871, -5848, -6136, -10098, -6286, -5008, -6046, -3235, -11529, -8986, -5317, -6412, -2186, -7462, -8587, -5614, -5608, -2127, -5546, -5993, -5602, -4895, -2768, -4953, -3879, -5369, -5200, -4091, -5580, -3164, -5477, -6772, -6470, -7886, -3903, -6183, -9649, -11308, -9200, -6437, -7719, -8945, -10678, -6182, -9302, -11853, -7614, -9572, -5189, -7009, -10482, -7855, -10849, -5754, -6670, -7654, -7960, -10133, -8021, -8450, -7492, -6982, -9424, -10234, -15495, -8411, -6733, -10228, -7509, -11577, -8767, -7567, -9477, -6263, -9487, -9857, -8789, -7763, -6036, -8615, -16894, -9219, -6594, -6453, -7945, -10252, -9583, -5649, -7061, -7302, -7813, -10419, -4963, -7236, -6595, -7004, -10903, -4924, -7947, -6179, -6655, -10453, -5878, -10923, -6142, -6372, -9527, -7202, -14480, -6401, -6149, -9032, -6310, -9481, -6657, -5984, -9602, -5378, -7495, -6427, -5769, -9697, -5650, -6850, -6403, -5592, -7339, -7131, -7150, -7731, -5749, -5664, -8298, -6849, -11449, -6429, -4910, -7086, -6298, -10534, -7720, -4908, -6514, -6999, -10839, -9769, -5924, -6860, -9561, -13612, -11400, -9204, -6920, -14357, -8162, -11150, -11068, -6493, -12766, -6878, -13047, -6942, -6884, -9274, -7453, -15660, -5989, -8558, -7535, -9432, -9547, -6401, -9898, -7434, -14187, -7718, -7893, -9707, -8867, -13166, -7538, -10498, -11141, -10755, -9815, -8900, -12875, -16967, -9262, -9781, -12291, -11937, -15404, -8060, -13327, -13354, -9920, -12630, -7888, -12745, -11948, -8216, -10002, -7989, -8788, -11573, -7404, -9210, -6686, -15004, -3289, -6328, -7919, -10176, -10887, -3489, -4414, -6566, -8259, -9697, -4196, -4142, -5503, -5290, -11864, -5981, -5954, -4598, -5677, -11430, -11060, -14555, -3737, -8789, -6780, -7117, -8086, -3108, -8413, -5414, -4226, -8755, -3056, -6295, -5370, -2921, -10658, -3642, -5938, -5817, -2362, -5959, -4464, -6230, -6351, -2305, -4802, -5318, -5661, -7355, -2605, -4648, -6030, -4788, -8877, -3153, -4318, -5904, -4916, -9187, -3968, -3807, -6158, -6283, -7416, -4581, -3478, -7312, -8938, -5776, -4128, -3614, -8987, -8870, -4994, -3576, -4325, -11480, -8343, -4380, -3152, -4685, -5002, -9948, -2766, -2348, -3502, -1091, -2435, -586, -914, -1095, 924, 162, 874, 420, 766, 1496, 868, 1184, 908, 1411, 666, 95, 131, 390, 762, -1920, -2085, -2922, -845, -1280, -7756, -4454, -16110, -1966, -4698, -6715, -3873, -5983, -2930, -5724, -6404, -2975, -5321, -4831, -4148, -8149, -2771, -6242, -8405, -2985, -11642, -3082, -7557, -10505, -2280, -10096, -3383, -5472, -15643, -2315, -5910, -3512, -4542, -9302, -3544, -4161, -4119, -5871, -6931, -7014, -3807, -6345, -9365, -7016, -10307, -4311, -9961, -7929, -7821, -5691, -5163, -6055, -8191, -8082, -4467, -6171, -4793, -9507, -9009, -4679, -7184, -4796, -7642, -11541, -6390, -7723, -5518, -7267, -10546, -7902, -8212, -6977, -8316, -7941, -5667, -8984, -8527, -8988, -6911, -4411, -8643, -6370, -8980, -7105, -3989, -8007, -4233, -8228, -7891, -4022, -8794, -3315, -6300, -7934, -4546, -11341, -3481, -5193, -7635, -5755, -12427, -4738, -5205, -8025, -8019, -10792, -7259, -5891, -8796, -13258, -7564, -11530, -6159, -9580, -11920, -5757, -17389, -5882, -11718, -8114, -5523, -15594, -6008, -10143, -6180, -6780, -17090, -6855, -7510, -5038, -8817, -11814, -7704, -6483, -4638, -7888, -8637, -7401, -6001, -5064, -6890, -6993, -7147, -5609, -6385, -7082, -6207, -7481, -5691, -7961, -8353, -5988, -7837, -6738, -7876, -11189, -5943, -7604, -9331, -7787, -19199, -5825, -7175, -12307, -8505, -11676, -5962, -6404, -9173, -8273, -9909, -6757, -5111, -8220, -8439, -9529, -8310, -4397, -8781, -9601, -10027, -9518, -4853, -9488, -6396, -11585, -8235, -6822, -10060, -4537, -9577, -6889, -10416, -8115, -4244, -7183, -6916, -8712, -5559, -5065, -6404, -7819, -6786, -4732, -6745, -6723, -6229, -6014, -5754, -8068, -7727, -4706, -6080, -9574, -6889, -9382, -4416, -6628, -7227, -5957, -10909, -4928, -6618, -5124, -6000, -10310, -5733, -5841, -5155, -6098, -9824, -6774, -5344, -7076, -5466, -9382, -8830, -5583, -13008, -5116, -9364, -14598, -6627, -10457, -5703, -10925, -13134, -7897, -9338, -7078, -17766, -11047, -8228, -10926, -7312, -12329, -10043, -8854, -14096, -6377, -9246, -8903, -12360, -12308, -6179, -7824, -7904, -11876, -9138, -6918, -7406, -6685, -7622, -7962, -8100, -8250, -5658, -6581, -8677, -8669, -11653, -5213, -7600, -11726, -9502, -6275, -7459, -7000, -6470, -3903, -4611, -8854, -5266, -3553, -3567, -3870, -4951, -3609, -2416, -4242, -4366, -4804, -3320, -2270, -5967, -6275, -6972, -4166, -3256, -8507, -10171, -12115, -5676, -6261, -8439, -11299, -12043, -7006, -8492, -5927, -10517, -10697, -7794, -4872, -3723, -11855, -6608, -8993, -3744, -2358, -13710, -4703, -11678, -3516, -1921, -10297, -4260, -14057, -3549, -2336, -7447, -5051, -12593, -3527, -3366, -6283, -7371, -9834, -3390, -4634, -6581, -9859, -7409, -3297, -5936, -8880, -6768, -5974, -3285, -6690, -13443, -5505, -5455, -2978, -6634, -11797, -7806, -6402, -2254, -6693, -7806, -5050, -6959, -1229, -6141, -2174, -264, -2380, 89, -2592, 260, 1781, 74, 1016, -20, 921, 2414, 1007, 941, 1072, 9, 1957, 705, -553, 924, -2636, 564, -799, -4597, -202, -5387, -1546, -3587, -7025, -1771, -6066, -3644, -7205, -3911, -3331, -9450, -4568, -8048, -3349, -4854, -7175, -5245, -7936, -3646, -6327, -6008, -6570, -8861, -4621, -11767, -7183, -7459, -9946, -5893, -6739, -11369, -7622, -9559, -5931, -3608, -13936, -8468, -8911, -4742, -2750, -10183, -10097, -8682, -4374, -2987, -9181, -8548, -8794, -5678, -3069, -8990, -5410, -10167, -9059, -2481, -10011, -3681, -11519, -7713, -2240, -12961, -3158, -7402, -7225, -2629, -14315, -3664, -4975, -8061, -3591, -8715, -5158, -3513, -6182, -5211, -6693, -7881, -2674, -4835, -7763, -6634, -13779, -2476, -4538, -10107, -9065, -12637, -3083, -4685, -6531, -13953, -9700, -4730, -4943, -4833, -7463, -8389, -7154, -5426, -5212, -5979, -7985, -7362, -6888, -8907, -5809, -8836, -7039, -10232, -9569, -6110, -10164, -7723, -6606, -5848, -6181, -8551, -9132, -4796, -5085, -5711, -7127, -12411, -5076, -5321, -5106, -7060, -8607, -7079, -7071, -4767, -8634, -5752, -7579, -8468, -4796, -9544, -5016, -6526, -4435, -5263, -7770, -5677, -6851, -2722, -6394, -7830, -5973, -6828, -2351, -7826, -8200, -4993, -5965, -2867, -7129, -6373, -4708, -5973, -3666, -6375, -5292, -5314, -6838, -3734, -7316, -5384, -6269, -7531, -3386, -10330, -6284, -7143, -7886, -3446, -9316, -7264, -8282, -7969, -3961, -8354, -7454, -9326, -7048, -4575, -9967, -6846, -9308, -6015, -5682, -12094, -6182, -9574, -5562, -8455, -10098, -6251, -8823, -5788, -7933, -10115, -7438, -7179, -5798, -6256, -12729, -9670, -6641, -4424, -6670, -16869, -11702, -7349, -3136, -8626, -11379, -12571, -8894, -2706, -10776, -9858, -12632, -10360, -3202, -9852, -9656, -14351, -11892, -4516, -8120, -10112, -9196, -14718, -6029, -7326, -11073, -6167, -20010, -7015, -7571, -13288, -4933, -16628, -8164, -8158, -15866, -4808, -13887, -8859, -8671, -13006, -5320, -12181, -7866, -10275, -11071, -5975, -11702, -6915, -13457, -9700, -6806, -12271, -6528, -11149, -8831, -8396, -13721, -6934, -8250, -8454, -9442, -13972, -9042, -6740, -8719, -7705, -11615, -17335, -6696, -9993, -6648, -9134, -8087, -7929, 11499, 9653, 11787, 11865, 10918, 10750, 9748, 11068, 11240, 10364, 8109, 9531, 8698, 9336, 8658, -392, 8420, 3495, 6224, 6048, 4468, 6188, -2829, 2992, 4944, 4836, 2886, -1034, 852, 4834, 3423, -314, 929, -354, 3400, 2873, -1496, 1653, 65, -323, 689, -2183, 2935, 767, -6658, -226, -1673, 3889, 816, -6654, 5189, 544, 3523, 1694, 727, 7001, 1280, 3374, 3183, 4394, 7543, 2819, 4609, 4414, 6201, 7338, 5335, 5343, 5008, 6784, 6524, 6594, 5248, 4727, 6186, 4964, 6532, 4685, 3373, 4034, 2635, 5338, 4042, 439, -1698, 1519, 3675, 3143, -3463, -868, 1737, 2813, 1237, 612, 987, 1363, 2305, -3363, 2166, 1556, 1643, 2080, -5536, 2433, 1979, 2425, 2309, -3356, 2424, 956, 2375, 2323, -5877, 2676, -9137, 1643, 1847, -2948, 2781, 1636, 1445, 565, -278, 2290, 4161, 1827, -51, 118, 1184, 4603, 2057, 2119, -766, 999, 3517, 1918, 3192, -1961, 1741, 351, 1084, 2772, -5075, 1823, -9009, -3, 1315, -3513, 1715, -3156, 754, 666, -1, 2060, -6758, 1223, 3, 894, 2448, -4417, -629, -2904, 789, 2644, -1501, -4193, -1362, 779, 2463, -342, 741, -280, 657, 1614, 444, 1940, -2432, -386, 302, 300, 1661, -5600, -2648, -116, -1426, 728, -517, -5816, 42, -8691, -478, 1020, -5590, -492, -2680, -2624, 1193, -3778, -1788, 222, -9612, 248, -3523, -2310, 1328, -4828, -1791, -4731, -1546, 1500, -3774, -4803, -6916, -1462, 950, -6641, -4848, -8218, -1770, 222, -7771, -1963, -6686, -921, 557, -3923, -756, -4622, 123, 1229, -2846, -872, -3909, 554, 1169, -2433, -1846, -5745, 413, 243, -2080, -2755, -6614, -278, -1394, -1921, -2331, -1802, -1389, -2957, -2013, -1209, -272, -2419, -2893, -1213, -627, -236, -2201, -2356, -14, -707, -987, -752, -2093, 439, -940, -1989, 234, -1770, 82, -885, -3121, 317, -1690, -747, -680, -4513, -297, -2330, -1287, -546, -7327, -631, -3621, -1505, -658, -4254, -147, -4817, -2767, -1298, -1704, 213, -5047, -6312, -2616, -1171, 99, -4591, -4520, -3856, -2233, -602, -4570, -3047, -4603, -5501, -2062, -4365, -3248, -5468, -13943, -3893, -2743, -3891, -4549, -8014, -5236, -1218, -3439, -4507, -10182, -5271, -339, -2017, -6499, -6396, -3095, 51, -1278, -5234, -4433, -1926, 180, -1582, -4112, -5251, -1997, 117, -3012, -4723, -5486, -2358, -140, -6067, -5077, -2875, -2262, -540, -4332, -4377, -2761, -2777, -1175, -1347, -4245, -6137, -3431, -2252, 198, -5646, -2423, -1844, -3110, 896, -10059, 0, -490, -2063, 662, -7959, 293, -39, -1037, -1028, -5465, -943, -84, -1061, -5569, -3676, -3524, -278, -2353, -4143, -3071, -6214, -1188, -5856, -2726, -4220, -11237, -4123, -9832, -3171, -6078, -4947, -2949, -10897, 1986, 7534, 7994, 8395, 5655, 1586, 6803, 7469, 7696, 4993, 986, 4683, 6042, 5302, 3663, 1176, 4020, 4165, -290, 3540, 1354, 5071, 1972, 1624, 3711, 1165, 4944, -498, 2650, 3436, 1305, 3929, -780, 2245, 3125, 2022, 2784, 1021, 1914, 2896, 2842, 2606, 2544, 1909, 2503, 3458, 2577, 3509, 1162, 2278, 4319, 2777, 4320, -1679, 3341, 5631, 4337, 5485, 591, 4894, 6571, 5188, 6487, 2665, 5846, 6695, 4848, 6546, 2448, 6016, 6031, 3962, 5257, 374, 5518, 4941, 3891, 1946, -1263, 4519, 4092, 3892, -9767, -732, 3047, 3742, 2274, -3403, 28, 1256, 3246, -4496, -6805, 1456, 9, 2179, -172, -5004, 2240, -1027, 1634, -109, -3777, 2227, -2661, 1529, -2955, -4061, 1781, -4333, -54, 227, -4123, 1286, -2738, -3606, 548, -7285, 702, 202, -2746, -36, -1668, -116, 2048, -502, 1178, -760, 320, 3206, 1792, 1855, -4693, 1439, 3944, 3000, 1660, -2152, 1418, 4259, 3060, 927, -29, -23, 4053, 2125, -517, -1139, -1610, 3269, 301, -1313, -3676, -661, 1878, -2420, 858, -3865, 454, -397, -6488, 1913, -3258, 1317, -4907, -6205, 1205, -992, 1933, -2414, -2780, -2487, 70, 2028, 163, -680, -3970, 142, 1003, 843, 334, -195, -40, -3085, 301, 112, -43, -188, -1548, -1011, -1459, -1898, -666, 1611, -2204, -1343, -6526, -1699, 2298, -2599, 591, -7144, -2901, 1715, -1844, 1237, -4046, -3598, 179, -140, 759, -2406, -3075, -2445, 1180, -335, -1952, -1899, -5612, 1415, -1094, -2214, -1360, -1893, 203, -1459, -1069, -1757, 481, -3330, -2097, 752, -2767, 1624, -7473, -1792, 1782, -2900, 1889, -7712, -101, 1912, -2068, 1430, -5585, 1149, 1283, -1498, 397, -866, 1524, 568, -963, -1106, 495, 954, 497, -188, -3461, -19, -412, 139, 324, -10632, -2949, -900, -1303, -35, -4678, -7384, -163, -3549, -1866, -2417, -2039, -90, -4801, -7138, -2238, -767, -899, -3789, -5957, -2726, -570, -2445, -1632, -2991, -2995, -898, -4903, -717, -1806, -1742, -1512, -8493, -1379, -1798, 585, -1549, -5539, -3625, -3504, 1770, -763, -3517, -3105, -8456, 1591, -119, -3114, -1345, -7055, 92, -21, -4398, -782, -9520, -2433, -808, -6538, -902, -6864, -4298, -3229, -2854, -1191, -3592, -3995, -7376, -1294, -667, -3069, -3510, -3439, -1592, -26, -2002, -4369, -1857, -2227, -397, -443, -3309, -1476, -1091, -2056, 221, -1094, -2369, -668, -4218, -5, -716, -6260, -1626, -3114, -970, -2628, -5218, -2561, -1129, -2134, -2523, -2555, -2529, 148, -2205, 324, -2183, -3484, 433, -2391, 994, -2104, -4388, -687, -4433, -147, -1845, -2974, -4487, -13025, -4452, -1215, -1607, -5702, -5079, -4621, -8, -769, -2473, -2682, -1284, 552, -657, -1852, -1952, -775, -338, 3403, 4132, 7641, 778, 5289, 2552, 4145, 7421, 2383, 6068, 4670, 4212, 7130, 4931, 6997, 6328, 4373, 6985, 5898, 7176, 6003, 4155, 6359, 5214, 6490, 3584, 2785, 4682, 2921, 4968, -3986, -778, 1301, -742, 3260, -539, -3989, -6344, -2274, 2502, -875, -1955, -2882, -434, 1798, -3591, -1851, -1994, 1043, 958, 3027, -70, 38, 2360, 1125, 5424, 2700, 1757, 2968, 1329, 6100, 4469, 1807, 2654, 1037, 5305, 4858, -175, 2820, 2749, 2728, 3599, 755, 3658, 4815, -3318, 76, 2620, 3579, 5670, -6116, 599, 2350, 2258, 5308, -2952, 1593, -76, 344, 3740, -1295, 197, -7631, -293, 1431, -414, -2083, -4705, -32, 454, 1193, -1037, -2916, 140, -87, 2307, -23, -1998, -320, -18, 2491, 240, -1222, -2065, 924, 1975, -38, -567, -6414, 1177, 977, -812, -86, -2158, 1569, -272, -2074, 62, 217, 2576, -712, -3867, -198, 1022, 2926, -117, -3578, -924, 905, 2160, -125, -1289, -2054, 12, 982, -1563, -215, -2503, -1765, 993, -6099, -47, -1659, -4728, 1308, -6373, -203, -670, -5335, 1637, -2661, -739, 229, -3261, 1850, -1322, -2303, 947, -1527, 1748, -928, -5554, 1239, 616, 2135, -1827, -11079, 834, 2152, 2999, -5832, -6189, -473, 2630, 3320, -3403, -2728, -1400, 2094, 2477, -572, -1483, -13, 1139, -474, 25, -1786, 1043, 931, -2991, -845, -3318, 1407, 776, 1042, -2630, -4489, 1405, -256, 2424, -987, -2810, 1333, -2287, 2747, 512, -1553, 1549, -5824, 2282, 279, -2049, 1871, -3869, 900, -1724, -5113, 1702, -1201, -1600, -2784, -3388, 568, -172, -2220, -895, -1663, -2290, 292, -362, -418, -2568, -9930, 580, 503, -1227, -7070, -2603, 429, 437, -2729, -5947, -436, -295, -560, -2611, -3597, 571, -1311, -2955, -1634, -2500, 779, -2367, -6798, -1580, -1228, 83, -3626, -2730, -1961, -159, -1607, -4533, -689, -1789, 222, -2814, -4019, 358, -1588, -452, -1013, -4088, 995, -2319, -2726, 767, -6820, 974, -4507, -8398, 1631, -11130, -303, -2578, -6953, 1518, -6724, -3262, -327, -6716, 421, -8780, -1524, 193, -8230, -1594, -5833, 225, -690, -4076, -3241, -2524, 550, -3379, -1911, -2869, -975, 320, -6486, -1262, -3444, -392, -71, -2338, -1737, -7273, -902, -761, -805, -3112, -5322, -3132, -1739, -753, -4756, -3052, -3407, -2524, -1795, -7989, -2173, -957, -2388, -3114, -6050, -1001, -97, -1763, -3563, -1277, -227, -19, -1780, -4053, 280, -333, -629, -3246, -5652, -96, -1690, -2562, -4260, -11515, -3068, -6057, -6844, -1570, -6403, -7864, -5955, -5304, -902, -3614, -3309, -3410, -4326, -2882, -2501, -2023, -1490, -3336, -7164, -1740, -36, 312, -1321, -2026, -1151, 996, 668, -883, -890, -1372, 643, -586, -3064, -910, -3402, -4482, -2190, -1270, -4262, -3070, -4590, -2040, -2520, -946, -3274, -9669, -4249, -9697, -56, -3661, -5978, -4859, -3848, -493, -3439, -3542, -2771, -1509, -504, -3120, -3970, -2516, -560, 163, -2938, -6862, -2398, -958, 411, -2723, -11590, -1025, -3975, 1108, -3014, -6531, 310, -5335, 1975, -3553, -4511, 957, -1340, 1873, -3638, -4597, 887, -704, 258, -5787, -7724, 248, -1979, -4020, -5723, -4889, -576, -6030, -5557, -1752, -1896, -1048, -5583, -3021, -961, -879, -994, -2977, -1828, -2324, -1161, -756, -2567, -894, -8329, -3006, -890, -3048, -336, -2419, -12398, -1434, -2230, 342, 771, -2734, -174, 527, 1344, 2390, -223, 1634, 2317, 2073, 3055, 210, 2246, 2721, 1891, 2870, -912, 1627, 1673, 245, 1928, -3573, -115, -1050, -3564, 507, -6432, -3262, -4038, -2351, -1054, -6372, -8754, -4753, -938, -2769, -7193, -2761, -4473, -1032, -3845, -10328, -1095, -2632, -1692, -3653, -2631, -1126, -2259, -2446, -3893, -256, -2771, -3310, -2791, -4961, 361, -8126, -5707, -2611, -5749, -245, -7360, -6102, -2940, -5490, -1830, -6736, -4501, -4546, -5568, -4055, -6866, -4259, -6523, -5735, -6537, -2456, -3944, -4694, -5152, -6281, -791, -2729, -3326, -5147, -4384, -636, -1952, -3614, -6397, -3150, -1511, -1616, -7073, -4951, -2081, -2980, -1332, -7338, -2755, -1670, -4406, -1259, -3640, -1452, -2662, -5710, -1451, -3615, -261, -5548, -7769, -1585, -5654, 706, -3476, -12844, -1737, -4974, 1109, -1569, -10018, -2414, -4155, 931, -1372, -8834, -4007, -7511, 348, -2417, -19835, -6770, -5193, -391, -4759, -5253, -7132, -1173, -1144, -7689, -1769, -4823, 228, -1928, -6624, -170, -3580, 522, -2723, -5276, 133, -3197, 312, -3832, -5133, -786, -3275, 86, -6741, -5275, -2979, -3246, -15, -9085, -3240, -6076, -2781, -346, -4076, -2116, -6898, -1822, -1476, -2444, -2481, -5099, -863, -3556, -1673, -3676, -3843, -402, -3266, -1569, -4468, -2131, -551, -2215, -3039, -4968, -340, -1284, -2389, -8551, -5841, 652, -2084, -3633, -3304, -6153, 803, -1768, -9006, -1361, -4735, 202, -833, -4478, -1044, -3627, -1151, -16, -1493, -1415, -3147, -3442, 294, -1194, -2076, -3305, -6063, -281, -2926, -2664, -4702, -3915, -1898, -6565, -2405, -6927, -2282, -3991, -4178, -1692, -5166, -2072, -5567, -3102, -1571, -4346, -2848, -8095, -4080, -2244, -5297, -3728, -11771, -6981, -3029, -8705, -3791, -10247, -6713, -3057, -9979, -3672, -6229, -4608, -3131, -5419, -4169, -4738, -3996, -4066, -3853, -5631, -5869, -5689, -6247, -3266, -7684, -20323, -11907, -7206, -2894, -8001, -5255, -3943, -5052, -2472, -5833, -3593, -2379, -3961, -2063, -4117, -4113, -2539, -3763, -1759, -4145, -4780, -3799, -3579, -1678, -7482, -3796, -5995, -3003, -2008, -6027, -3836, -9554, -3075, -3017, -2896, -5702, -14625, -1504, -2360, -3044, -1487, -4265, -3225, -3986, -9075, -3210, -4127, -2464, -6521, -5388, -6423, -916, -408, -6156, -3486, -9355, -571, 552, -4207, -4319, -8203, -1147, 569, -2249, -4905, -6750, -937, -72, -543, -2242, -4041, -863, -1216, 432, 114, -2699, -2014, -3629, 418, 1352, -3433, -2727, -10814, -681, 1366, -6282, -1958, -2590, -2952, -6, -3716, -2224, -513, -6937, -3433, -2625, -4043, -163, -7808, -13572, -3488, -9508, -1117, -3808, -5312, -4816, -6499, -2760, -1250, -3357, -2952, -2767, -2385, 163, -1731, -865, -1248, -1202, 216, -691, -552, -359, -1048, -1285, -1002, -3070, 1192, -999, -682, -3304, -1531, 2877, 478, 1448, -1240, 1840, 3908, 1324, 1752, 1094, 2880, 4142, 771, 68, 1497, 2483, 3577, -1142, -4927, 401, 872, 2279, -3574, -4789, -1818, -1422, 578, -4474, -4161, -2381, -2721, -792, -3274, -4035, -1915, -2841, -1498, -1655, -3202, -2845, -1530, -2122, -731, -4220, -4852, -346, -3911, -488, -8410, -3948, 17, -11601, -1054, -6930, -2428, -223, -4265, -3181, -5540, -1608, -827, -2590, -7168, -6787, -955, -1883, -2828, -1763, -8574, -293, -4050, -3295, 197, -4504, 297, -6437, -3468, 640, -2015, 398, -3753, -4356, 188, -1034, -732, -2281, -6113, -672, -1381, -4975, -1556, -7557, -1508, -2985, -3857, -829, -5404, -2414, -5159, -1358, 231, -3005, -3667, -5494, -1721, 1210, -1657, -2840, -4258, -4395, 1572, -946, -1003, -4242, -6830, 1068, -494, -228, -7851, -4250, -530, -338, -381, -6428, -3621, -3439, -768, -1361, -3066, -4154, -4575, -2020, -3706, -2565, -5873, -4091, -3450, -8764, -3454, -11360, -3994, -2473, -2757, -5121, -9430, -2536, -1171, -226, -6409, -6764, -1856, -666, 1078, -4370, -4805, -2973, -793, 1676, -2813, -3727, -5223, -1648, 1649, -2899, -4746, -2938, -3744, 960, -4358, -6558, -1958, -7719, -587, -4615, -3112, -2844, -8827, -3886, -3787, -1491, -5185, -4575, -6683, -4287, -1159, -6972, -1822, -2712, -6079, -1790, -7969, -556, -1786, -7156, -3885, -6150, -504, -1647, -6708, -10546, -3778, -1648, -662, -6693, -4053, -3151, -2948, 216, -6619, -2100, -4161, -2211, 7, -6241, -2150, -7819, -1901, -1619, -5625, -4201, -9236, -2125, -5359, -4772, -20035, -6203, -1695, -8961, -3936, -4620, -8137, -1423, -7771, -3168, -2625, -7866, -1884, -10407, -2637, -2134, -3678, -2511, -4562, -2875, -2186, -2574, -2759, -1385, -4470, -2603, -2829, -2964, -151, -5713, -3902, -4024, -2960, -285, -4488, -7391, -6273, -2378, -1600, -5924, -6123, -8840, -1575, -4013, -10024, -3258, -8351, -1241, -8567, -3585, -2348, -6904, -2097, -7621, -2694, -2456, -5419, -5432, -2881, -4705, -3130, -4781, -9225, -949, -11217, -3993, -5228, -5395, -421, -3792, -4698, -6520, -6366, -1110, -2417, -5091, -7604, -8282, -3182, -2698, -5569, -7999, -6149, -3058, -1149, -2782, -5494, -1655, -5423, -4878, -2823, -425, -4758, -4616, -5470, -3528, 1229, -4878, -3694, -2318, -7757, 1559, -807, -1796, -428, -3529, 926, 319, -670, 610, -1132, -507, -59, -806, 775, -582, -1285, -1894, -1604, -11, -1141, -280, -4756, -2209, -1942, -1683, 395, -4392, -3263, -5611, -859, 232, -5596, -6205, -10941, 8, -890, -9871, -9277, -6377, 262, -3581, -4485, -3242, -3582, -180, -7947, -3244, -492, -2391, -1929, -2648, -2125, 1089, -2467, -7535, -184, -1467, 1949, -3488, -1853, 927, -1118, 2048, -5434, -232, 1105, 12, 1109, -8568, -1789, 588, 134, -54, -1893, -2458, 90, -2350, 1154, 1134, 1625, 861, -2206, 1874, 2340, 2891, 1827, 813, 1064, 2174, 2645, 2115, 1368, -1399, 752, 1734, 1801, 465, -4924, -1875, 1555, 987, -998, -3232, -5678, 1800, -332, -737, -1065, -4665, 1480, -1490, 7, -36, -2542, 608, -1714, -508, 265, -2403, -86, -2104, -2181, 70, -4109, 53, -2358, -179, -995, -5926, 423, -1358, 1566, -3229, -3574, 424, -385, 1563, -2794, -2277, -289, 57, 211, -1662, -1919, -2226, 214, -608, -2548, -1864, -5770, 128, -489, -5510, -1845, -4538, -522, -1573, -2361, -2327, -3159, -2097, -2126, -19, -3712, -2801, -5200, -529, 895, -4192, -3067, -14878, 331, 844, -2237, -4676, -5338, 164, -106, -889, -10372, -2762, -871, -1700, -574, -4661, -1659, -1252, -2037, -1288, -1745, -1741, -415, -1122, -1881, -221, -2879, -431, -795, -27, 586, -2664, -1936, -1383, 1453, 760, -877, -5747, -3279, 1713, 230, 48, -9848, -6121, 743, -1223, 33, -6267, -4083, -1491, -4338, -683, -3873, -3319, -3890, -10951, -1470, -2171, -4353, -4587, -6234, -1877, -1456, -6665, -4400, -6122, -2562, -1490, -9262, -2215, -8824, -2936, -2028, -5486, -970, -12518, -1587, -2449, -3870, -1006, -5513, -81, -1884, -5070, -1852, -2270, 846, -1583, -9725, -2673, -446, 1035, -2785, -3642, -3626, 299, 384, -4071, -1697, -5615, 0, -845, -1718, -1073, -7410, -1367, -1028, -814, -935, -6894, -3471, -398, -1648, -916, -3548, -6133, -728, -4499, -965, -830, -6958, -2693, -7097, -1111, 409, -3086, -6713, -4160, -1165, 298, -1895, -3881, -2976, -907, -1067, -2241, -1851, -2797, -502, -2215, -3381, -910, -3517, -345, -1448, -4587, -507, -4985, -745, -742, -5417, -460, -4953, -1722, -290, -5442, -719, -2865, -2546, -433, -6672, -1408, -930, -2768, -1687, -15512, -2698, 113, -3871, -4079, -5756, -4240, 71, -8233, -6080, -4337, -4508, -951, -6482, -6111, -5045, -3690, -1837, -3879, -3679, -6100, -3119, -1430, -3633, -2205, -5399, -3187, -1123, -4720, -2134, -4594, -3773, -1525, -7034, -3457, -4808, -4327, -2954, -13724, -6477, -6667, -4058, -6774, -6851, -6498, -11831, -3388, -5873, 4533, 15493, 7130, 11099, 10872, 8971, 15079, 7409, 10372, 10215, 10477, 13792, 7275, 7939, 8110, 10115, 11471, 5974, 2071, 4093, 8807, 7904, 3893, -401, 596, 7640, 6406, 2632, 291, 246, 6353, 7830, 1705, 498, -2133, 5933, 8178, -99, 1669, -1466, 7015, 7495, -3209, 1380, 906, 6642, 5809, -2085, 420, 2649, 3011, 3101, 467, 890, 4060, 2610, 1239, 3134, 2438, 5095, 6134, 4168, 4923, 3666, 5672, 6390, 6574, 5504, 4339, 5666, 5175, 7432, 4771, 4364, 4716, 3611, 6811, 2487, 3671, 2068, 2734, 4441, 897, 2214, -1551, 1422, -1480, 1980, 145, 404, -1713, -829, 1479, -1429, -400, -2830, -620, -980, -1508, -4595, -937, -4509, -5950, -843, -3942, -436, -956, -3109, -86, -2002, -692, 253, -1534, 309, -1370, -1942, -1167, -2427, 197, -874, -4390, -7899, -2739, -461, -450, -4445, -2005, 564, -1706, -673, -4643, 937, 1953, -3334, -2247, -9197, 2447, 1896, -3203, -7384, -2865, 3140, 702, -1405, -4796, -1206, 3044, -1300, -192, -2152, -1597, 2136, -2908, 125, -1193, -3364, 442, -2540, -592, -655, -6300, -1686, -1452, -2733, -319, -2385, -3504, -1146, -6747, -114, 418, -6151, -1916, -7425, -50, 1525, -8056, -3061, -8010, -273, 1413, -4908, -3606, -8036, -740, 45, -4499, -3707, -9333, -1100, -3493, -4605, -2349, -7706, -1075, -5940, -4116, -1488, -4490, -1074, -2420, -4716, -2222, -4322, -1688, -1937, -7574, -5472, -7708, -3210, -2954, -9068, -8547, -8071, -5093, -4749, -6216, -4839, -4324, -4994, -4740, -5370, -4755, -3714, -4619, -3586, -5709, -6445, -4542, -5527, -3203, -6705, -7296, -6022, -7614, -3491, -7190, -5463, -5318, -7737, -3294, -6641, -3769, -3574, -6598, -2733, -6292, -2699, -2511, -6223, -3322, -7125, -2528, -1985, -6367, -6489, -9032, -3192, -1758, -6932, -10492, -10363, -3831, -1862, -7547, -5582, -7436, -3718, -2684, -7591, -4955, -4703, -3850, -5169, -7156, -5282, -3324, -4932, -15759, -6365, -5603, -2636, -7772, -5235, -5242, -5591, -2536, -7604, -3910, -4440, -5019, -3328, -4982, -4552, -4531, -4227, -5154, -4938, -6666, -5498, -4315, -7384, -6805, -10403, -6424, -6270, -8430, -6066, -14886, -5957, -8237, -9381, -4709, -7991, -4773, -6516, -15946, -5086, -4770, -4046, -7510, -8213, -7473, -3115, -3811, -5936, -6036, -13292, -2612, -3598, -3212, -6093, -7140, -2970, -3330, -2197, -7069, -5339, -3798, -3249, -2596, -7484, -4894, -4503, -3658, -4898, -7717, -5436, -4681, -5182, -7703, -9217, -6569, -4421, -10267, -4587, -15266, -5999, -3847, -8154, -4051, -14168, -5103, -3525, -4809, -5255, -9670, -5175, -3853, -3862, -7668, -5919, -5897, -4642, -4121, -8586, -4629, -7287, -5715, -5258, -7177, -5460, -9161, -7852, -7043, -6614, -7702, -10597, -16619, -8897, -6982, -6417, -13152, -8491, -8037, -7590, -5676, -7926, -5771, -7079, 8378, 264, 6883, 11011, 8143, 7556, 1695, 6137, 10467, 7604, 4780, 3511, 3566, 8760, 5905, -1905, 4481, 1645, 5576, 3317, -5876, 4662, 3831, 483, 3090, -657, 4234, 4030, 917, 3836, 2385, 3349, 2513, 2198, 3803, 3375, 2196, -346, 2695, 3488, 3584, 819, -176, 2702, 3452, 2746, 335, -412, 2651, 3857, 1787, 2832, 1422, 3444, 4373, 5252, 4678, 5194, 4458, 4573, 7185, 5288, 6970, 4627, 4164, 7558, 4889, 7263, 3451, 2960, 6666, 3846, 6129, 1351, 758, 4646, 2817, 2960, 2364, -3368, 1865, 2292, -15868, 3155, -5752, -564, 1822, -116, 2577, -2844, -2178, 610, -161, 1399, -2842, -3605, -1454, -690, 520, -2531, -955, -1400, -539, -353, -1441, 1152, -124, -2240, -2051, -868, 1843, 464, -11447, -4585, -824, 1495, 678, -1738, -5301, -1185, 281, 745, -280, -5586, -1797, -1825, 459, -992, -6544, -2607, -5670, -649, -4226, -6437, -4093, -9434, -2416, -5874, -4257, -7643, -4370, -1347, -2625, -2606, -5330, -3094, 283, -2130, -1978, -2963, -3396, 824, -3189, -1573, -2398, -5621, 448, -5830, -798, -2397, -12478, -642, -10395, -161, -1970, -5002, -2176, -11549, -242, -785, -3316, -4916, -7381, -1520, 502, -2597, -9442, -4302, -5125, 1082, -1579, -3107, -2656, -2112, 665, -1043, -2269, -1962, 1021, -494, -1698, -4389, -2045, 2453, -1441, -4094, -4653, -3063, 2833, -2423, -13200, -2195, -5171, 2263, -4770, -6279, -2685, -4206, 699, -11234, -4126, -5226, -2200, -889, -6141, -3336, -2471, -1746, -560, -3305, -3339, -1170, -2899, -506, -3067, -4504, -2083, -7249, -1161, -4422, -7364, -6452, -7606, -1149, -5031, -7721, -5413, -4786, -466, -5029, -5662, -2999, -6071, -230, -5115, -4645, -3330, -11883, -811, -4326, -4105, -5245, -6769, -2428, -3992, -4199, -6936, -6518, -5211, -4770, -5177, -5351, -9277, -5506, -7365, -5638, -2906, -9850, -3555, -18071, -4137, -2140, -6688, -2506, -11084, -3154, -3833, -4152, -2146, -9314, -3232, -7623, -2662, -2270, -6701, -4756, -2688, -2446, -2726, -5357, -10055, -1806, -3670, -3392, -5184, -7186, -3235, -6329, -4180, -5034, -5349, -8245, -7533, -4973, -4501, -5329, -6564, -8702, -5175, -4938, -4572, -3817, -13587, -3909, -6498, -3654, -2700, -8833, -2464, -4797, -3378, -2376, -7217, -1812, -3428, -3628, -2944, -6491, -2063, -3960, -3761, -4608, -6658, -3034, -6518, -2849, -6431, -8580, -3801, -7431, -2009, -6121, -16045, -3344, -5560, -2096, -5897, -10675, -2850, -5160, -3323, -6165, -8817, -3093, -5969, -6089, -6663, -8860, -4081, -8848, -13227, -7866, -10554, -5060, -9306, -10594, -9882, -12794, -4854, -5107, -7765, -7546, -9109, -4704, -3508, -6253, -4799, -6608, -5836, -3334, -5350, -3322, -5327, -9282, -4326, -4660, -2846, -5363, -7109, -5836, -3927, -3251, -7120, -4339, -5865, -3254, -4504, -9555, -3564, -5144, 1256, 8194, 9051, 8438, 6129, 650, 7937, 8480, 7806, 6110, 593, 6913, 6782, 5746, 5680, 1396, 4326, 4193, 1459, 4087, 699, -3885, 2269, -3077, 178, -1300, 2669, 2316, -3257, 1229, -395, 4207, 1878, -348, 2806, -745, 3878, -490, 2326, 2043, -6821, 2190, -9079, 2726, -404, 2215, 355, -1577, 2680, 1752, 5378, 1813, 1864, 4276, 4284, 6994, 4431, 3807, 5208, 5306, 7530, 5770, 4359, 4429, 4896, 6988, 5456, 3166, 388, 2751, 5161, 2708, -623, -360, 3728, 1734, -3842, 1396, 2724, 6103, -350, 2628, 2636, 1996, 6816, -647, 3185, 1600, -2459, 6482, -3023, 2185, -1368, -3164, 5709, -7149, 372, -6559, -756, 4888, -5411, -2287, -12196, -1359, 3713, -2871, -4511, -9419, -3677, 1748, -2653, -5209, -5848, -5567, -924, -4604, -8946, -3825, -3525, -2421, -15332, -4285, -2637, -2461, -1599, -5356, -2543, -1760, -1539, -2080, -2989, -3332, -1242, -553, -7473, -2254, -4298, -1333, 51, -966, -2558, -1966, -1802, 158, 1360, -3677, -1343, -2179, -240, 1463, -4227, -2395, -2938, -1199, -487, -3520, -3483, -4805, -2796, -7193, -2827, -3956, -7252, -5226, -2860, -2057, -5333, -12403, -8461, -1370, -1333, -4898, -4867, -4416, -1209, -1339, -4761, -1651, -1420, -763, -2458, -3962, -610, 30, -99, -4593, -2531, -997, 341, -220, -6698, -3370, -2282, -267, -1783, -5861, -10912, -1765, -1616, -2858, -4350, -3667, -232, -3596, -457, -4035, -2491, -17, -4169, 839, -4041, -4380, -1642, -2772, 1037, -3197, -3931, -6408, -1924, 423, -1948, -1864, -4142, -621, -571, -1301, -2064, -2997, 731, -961, -1589, -4497, -4267, 1250, -926, -2992, -8958, -8864, 917, -1474, -7457, -6750, -7896, 44, -2788, -5957, -6933, -5080, -899, -4510, -2528, -7146, -4167, -1538, -5667, -2113, -6172, -3159, -2182, -5590, -3646, -5813, -2198, -3796, -5537, -7502, -5014, -1999, -8334, -5487, -8382, -4255, -2704, -10080, -4584, -7250, -4315, -4114, -7922, -3508, -7169, -4759, -5307, -12536, -2807, -5831, -4859, -4921, -8245, -2569, -4107, -4743, -4018, -5103, -3040, -3088, -5043, -3730, -3963, -4918, -2810, -6461, -4368, -3629, -10136, -2912, -10574, -6007, -3890, -5810, -3042, -11332, -8360, -4947, -3876, -3399, -7554, -10480, -6989, -3516, -4362, -5965, -12544, -6735, -3533, -5859, -5315, -14505, -4827, -3209, -7345, -5893, -14616, -4171, -3017, -9808, -8271, -13590, -4636, -3677, -14120, -9644, -9215, -6100, -5605, -12666, -8331, -6548, -8048, -7381, -10863, -10016, -5139, -7709, -5938, -6204, -15211, -4551, -6454, -4807, -4875, -8887, -4491, -6128, -3721, -5659, -7500, -4682, -6747, -2556, -7675, -6139, -4864, -7890, -1964, -6667, -4402, -5188, -8256, -2320, -4996, -3710, -6703, -7762, -3806, -4001, -4335, -11670, -7648, -6396, -3930, -6030, -5334, -8387, -8283, -5021, -7927, -3020, -9673, -7495, -8041, -6548, -6351, -4577, -6923, -7329, -8284, -6631, -4061, -7063, -5307, -8390, -6378, -4222, -7515, -4424, -7435, -5524, -5190, -6242, -5340, -6891, -6092, -6443, -4482, -9412, -6512, -8504, -7151, -3780, -6509, -6541, -7944, -7748, -4030, -3881, -7323, -6572, -8041, -5028, -3184, -8845, -7005, -7553, -6481, -3803, -8940, -8206, -6558, -7744, -6040, -6500, -8761, -6037, -7925, -10519, -5080, -9533, -6506, -7240, -9368, -4760, -9287, -8232, -7063, -10010, -4792, -7236, -12589, -7486, -9919, -5057, -5658, -8648, -7374, -7534, -6010, -4564, -5838, -5932, -5664, -6665, -3232, -6002, -4453, -3240, -4373, -1650, -13290, -3202, -865, -1386, -185, -2610, -1208, 688, 185, 948, 143, 530, 1179, 389, 1454, 963, 1243, 482, -607, 1088, 355, 836, -1785, -2522, -295, -1720, -758, -8318, -4503, -2747, -4915, -3800, -5798, -5229, -5997, -5149, -7227, -3822, -5190, -8891, -5027, -5935, -4036, -5501, -11012, -5751, -5296, -5407, -5933, -14699, -6245, -5838, -7147, -5933, -7333, -6323, -7869, -6831, -5364, -5247, -6471, -12393, -6155, -4895, -4878, -6556, -8509, -6499, -4992, -5571, -6484, -6755, -7576, -5429, -6747, -6782, -6913, -8912, -5640, -6000, -7704, -8167, -8864, -5128, -4469, -8921, -8017, -6624, -4493, -4273, -9640, -7406, -5049, -4473, -5991, -9343, -7561, -4418, -5066, -13268, -8643, -6815, -4450, -5720, -8838, -8074, -5190, -4799, -5812, -7425, -8578, -3930, -4919, -5457, -8368, -10504, -3413, -4635, -5151, -10434, -8473, -3847, -4677, -5001, -14928, -6745, -5601, -5846, -4794, -13557, -6224, -9763, -9292, -4507, -10355, -6021, -7168, -9656, -4467, -9557, -6503, -4641, -8241, -5059, -8694, -8687, -3764, -11422, -6437, -8146, -8778, -3950, -7103, -7453, -9133, -6146, -5314, -4463, -7307, -13477, -5448, -8279, -4093, -8118, -10718, -6447, -8181, -5475, -10931, -8180, -10001, -7192, -8322, -15204, -7878, -10771, -9099, -7508, -16281, -8573, -8246, -11432, -6265, -15411, -7892, -8576, -7119, -6237, -10841, -6883, -9984, -5696, -6866, -8892, -7123, -7987, -5549, -7763, -7957, -8032, -6305, -6345, -8954, -7489, -7324, -5799, -7600, -10486, -7290, -6169, -5854, -7392, -9232, -7372, -5691, -6019, -6508, -7284, -7752, -5822, -6340, -6327, -6590, -8314, -6392, -7067, -6831, -6989, -8911, -6713, -8579, -7890, -7869, -9445, -6372, -10999, -9800, -7776, -9341, -6414, -10052, -11851, -7401, -8415, -7597, -8164, -10261, -8170, -7870, -9737, -7401, -10459, -10877, -8278, -9718, -7889, -16067, -13568, -9071, -9638, -9811, -10978, -12213, -8858, -12121, -9877, -8305, -12370, -8594, -13135, -9242, -7339, -8537, -8928, -9409, -11784, -6960, -6211, -9573, -8126, -11065, -7114, -5472, -10652, -8225, -8324, -8287, -5949, -10635, -9908, -8492, -11586, -7270, -8860, -15514, -11024, -18718, -8410, -7806, -11134, -12072, -14639, -8466, -7747, -8489, -10385, -18810, -8197, -8742, -7493, -9563, -13499, -2908, -6699, -7247, -4378, -5073, -3327, -10845, -5664, -6704, -5999, -5316, -12007, -4681, -6668, -8456, -11358, -7040, -4423, -5286, -14984, -5540, -5199, -5265, -5211, -8728, -3696, -4677, -7107, -6611, -6682, -3638, -5055, -7761, -13025, -6529, -4707, -5934, -7805, -8128, -7618, -5980, -6600, -9058, -5764, -8213, -6226, -6227, -8087, -6096, -7454, -6407, -5201, -6920, -7532, -7107, -6511, -4581, -7163, -6288, -7064, -6532, -4870, -6736, -5605, -7004, -7435, -6602, -5552, -6552, -6745, -7886, -12200, -5388, -7769, -6227, -6979, -6980, -5654, -7796, -5688, -6463, -4928, -6064, -6473, -4840, -4803, -5437, -11898, -3453, -2951, -2292, -4249, -3831, -573, -738, -575, -1265, -669, 1261, 600, -18, -52, 336, 1930, 743, -753, -352, -12, 1425, -450, -3087, -2171, -1392, -310, -3143, -7103, -6068, -3344, -3185, -5780, -7571, -8065, -5057, -5027, -6312, -6455, -6798, -6420, -4856, -6105, -4670, -7252, -9081, -4674, -4671, -4106, -7864, -13386, -4465, -4086, -5220, -8621, -10281, -4309, -4242, -8559, -9005, -10797, -4498, -4461, -7752, -8497, -7325, -5414, -4277, -5370, -7797, -5059, -7937, -3897, -4982, -6640, -4296, -11752, -3836, -6238, -6072, -4338, -6354, -4438, -6660, -6407, -4700, -4666, -5675, -4453, -7390, -5256, -4511, -6533, -3547, -8897, -6522, -4832, -6306, -4020, -11184, -10382, -4960, -6389, -5959, -13516, -10335, -6209, -7820, -11066, -12590, -6437, -14322, -12986, -10320, -10129, -5207, -6874, -10885, -6944, -7587, -4943, -4813, -8883, -5362, -5973, -5279, -5283, -7056, -4170, -5508, -6155, -8576, -4767, -3337, -6284, -7542, -11029, -3905, -3103, -7915, -10062, -6884, -4627, -3659, -6884, -16473, -5993, -7170, -5101, -5139, -8567, -5852, -10715, -7398, -4371, -6536, -5670, -11270, -10348, -4382, -5992, -5626, -18778, -9143, -5134, -5752, -6121, -9399, -6596, -6755, -5309, -7402, -6917, -5445, -8929, -5428, -9935, -6312, -5132, -10054, -7106, -10118, -6658, -5255, -9667, -13075, -7099, -6394, -5653, -7872, -8792, -5678, -5288, -6438, -6763, -7146, -5493, -4663, -7384, -6729, -7684, -6347, -4530, -7160, -7379, -9507, -7291, -4559, -6680, -8148, -11206, -6599, -4802, -7142, -8712, -10361, -5839, -5422, -8417, -9661, -8222, -5888, -6181, -9920, -13604, -6597, -6609, -6751, -11337, -11829, -5824, -7493, -7258, -12042, -7840, -5990, -8131, -7717, -10880, -6602, -7278, -8949, -8032, -9651, -6747, -10059, -10509, -8548, -9624, -8103, -13261, -12531, -9616, -10733, -10395, -12730, -10939, -9319, -11676, -10460, -12527, -9983, -8093, -10785, -9309, -12955, -10411, -7973, -9245, -8938, -13295, -9574, -8281, -8789, -9000, -9805, -9090, -8248, -9757, -9125, -7776, -10044, -8898, -9633, -9117, -7390, -9505, -10617, -8342, -8800, -8461, -8786, -12609, -8822, -8115, -10808, -10312, -19216, -11882, -7526, -10971, -18444, -11727, -11604, -7828, -9439, -10460, -9691, -10746, -10399, -8907, -8269, -10319, -6878, -9851, -2641, -8407, -6705, -6866, -10729, -3982, -6529, -7147, -5880, -8550, -8117, -5432, -9053, -5592, -6433, -7111, -4552, -9303, -5849, -4964, -5221, -3781, -6290, -6387, -3769, -5732, -3360, -4621, -6109, -2878, -8342, -3383, -4350, -4191, -2694, -9240, -3989, -5223, -3001, -3438, -6009, -5375, -6996, -3143, -5046, -4195, -6291, -10745, -4699, -6768, -3080, -5204, -10279, -7260, -7703, -2416, -4464, -6950, -7035, -7753, -2151, -4372, -6527, -6596, -7208, -2333, -4532, -8309, -8248, -6634, -3117, -4632, -15361, -9623, -5373, -4999, -4484, -9217, -6905, -4820, -12682, -4436, -6508, -6933, -4762, -5006, -3898, -3783, -3713, -1910, -1481, -1738, -1064, -643, 227, 177, -122, 543, 585, 909, 595, 257, 852, 386, 309, -314, -640, -275, -1112, -1534, -3212, -2963, -3566, -3883, -4501, -7127, -6597, -9483, -7485, -7128, -4571, -7375, -4444, -11865, -7870, -5313, -7155, -3428, -11077, -7770, -9125, -8310, -3381, -7399, -6912, -8765, -11503, -3966, -6346, -6521, -7168, -11360, -5531, -7257, -7706, -7116, -7068, -7660, -12054, -10682, -8340, -5558, -7006, -8854, -9587, -9526, -6069, -6389, -7118, -9337, -5638, -9274, -6453, -8845, -12604, -3441, -10968, -6227, -14733, -10009, -2529, -10137, -5697, -8539, -7247, -2413, -12264, -5425, -8522, -6545, -2854, -6333, -5646, -12419, -7328, -3787, -4279, -6259, -8824, -9771, -4800, -3838, -6481, -7261, -8563, -4664, -4541, -6203, -7890, -6232, -4045, -6420, -6541, -6816, -5547, -3955, -9842, -7972, -5009, -5959, -4435, -10213, -10475, -4682, -6963, -5504, -7886, -11744, -5499, -7792, -7511, -7102, -11514, -5834, -7854, -9814, -7475, -13256, -4957, -7573, -8841, -7927, -13400, -4683, -7644, -7727, -7390, -9887, -5684, -8306, -7013, -6861, -7521, -8562, -10015, -6961, -6447, -5779, -15776, -10543, -8142, -6028, -4576, -14903, -7085, -10275, -5988, -4022, -9449, -6034, -10182, -6406, -4355, -7039, -7576, -10481, -6594, -5971, -6042, -10735, -12139, -6102, -10077, -5147, -6540, -9336, -5684, -13039, -4449, -5644, -7173, -5861, -10946, -4710, -6404, -6152, -6929, -12656, -6287, -6600, -5901, -9247, -8756, -9140, -5629, -6384, -11170, -6098, -9513, -5078, -7412, -10098, -4956, -7975, -4866, -7864, -9491, -4904, -7755, -4930, -7681, -8716, -5856, -9063, -5549, -8024, -7235, -7838, -10883, -6812, -8157, -5775, -11198, -10213, -8346, -7342, -5226, -16470, -8954, -9620, -7158, -5899, -10835, -8071, -10983, -8544, -7222, -10022, -7876, -13422, -12045, -7091, -14439, -8548, -15395, -10606, -6787, -10761, -10332, -12884, -8817, -7185, -8085, -10652, -10287, -8365, -7504, -8403, -8478, -8341, -8698, -7538, -8349, -7415, -7562, -8799, -7687, -6477, -7272, -7897, -8144, -8004, -5823, -7833, -8661, -8029, -8453, -6541, -9320, -8159, -8876, -9742, -9087, -11904, -7116, -10415, -10815, -14632, -10865, -6658, -11041, -7507, -8806, -9105, -6804, -9543, -5818, -7707, 10155, 12746, 13112, 9384, 6364, 9425, 12279, 12488, 8807, 5785, 6856, 10838, 10468, 7169, 4021, -1794, 8320, 6370, 5113, 1089, 3338, 4773, 2049, 3570, -2031, 4578, 1878, 3081, 2124, -3039, 4190, 2224, 1344, 426, -4825, 2790, 3118, -1476, -3958, -4895, 1593, 3326, -3336, -3215, -40, 1441, 2672, -2582, -63, 2254, -2078, 622, -2736, 1020, 3521, -1089, -6869, -1708, 2853, 4154, 1811, 1747, 62, 4384, 4192, 1339, 4130, -49, 4952, 3521, 776, 4507, -2725, 4560, 2308, 2035, 3068, -3883, 3154, 2592, 2099, -2045, -1190, 368, 3919, 780, -955, -1675, -4758, 4235, -493, 1643, -5914, -2613, 3299, -102, 2175, -3555, -576, 1433, 323, 1824, -2409, 554, -344, 524, 616, -3957, 1226, -3936, 628, -124, -3020, 1340, -3346, 361, 1304, -944, 997, 114, -405, 2360, 69, 317, 418, -1152, 2405, 535, -1268, -1198, -1069, 1531, 603, -5980, -5265, -577, -49, 269, -6258, -4021, -918, -1856, -616, -3713, -1023, -2786, -3457, -2425, -4304, 609, -1514, -5701, -4607, -6379, 1493, 253, -5339, -5188, -10266, 1581, 28, -1870, -4916, -5895, 550, -2190, -734, -3085, -3294, -2146, -4314, -1378, -3039, -1655, -2526, -1846, -3501, -6895, -253, -421, -642, -5841, -5964, 766, 65, -417, -6885, -2925, 1104, -557, -677, -3422, -2869, 680, -2226, -977, -1882, -4846, -307, -5870, -1316, -2482, -7492, -1746, -5986, -1963, -3896, -4590, -4094, -2960, -2495, -1718, -4834, -5027, -2262, -2106, -268, -14176, -4192, -2772, -1617, -161, -4262, -5206, -3131, -1845, -1199, -2457, -5959, -2018, -2950, -3579, -2876, -5138, -300, -4511, -8852, -4098, -5770, 1085, -5111, -8511, -4172, -8071, 1678, -4856, -3797, -3774, -9588, 1229, -5366, -1471, -3627, -6087, -643, -7686, -479, -3710, -3453, -3701, -5377, -581, -3755, -2312, -1745, -2660, -1705, -3430, -2398, -620, -1427, -4016, -2901, -3232, -1016, -1039, -7903, -2776, -4205, -2516, -1344, -7185, -3750, -5736, -4869, -2431, -5456, -6694, -7873, -7378, -4341, -5246, -10595, -12277, -6725, -5936, -6069, -6533, -6152, -4723, -5557, -6075, -3954, -2296, -3849, -4801, -4137, -2590, -1009, -4258, -4566, -2724, -2469, -1338, -5936, -5982, -2265, -3786, -3074, -8221, -11402, -2912, -6822, -5872, -8258, -4370, -5367, -4966, -7581, -7360, -2243, -6281, -3751, -6287, -7066, -1808, -2884, -5122, -5047, -6901, -2359, -1531, -9857, -5059, -5925, -3686, -1311, -7128, -6167, -4822, -6161, -1804, -6896, -5863, -4475, -6151, -2600, -9974, -4072, -5347, -3663, -2725, -15938, -3560, -8575, -2717, -1770, -10213, -4551, -7879, -2768, -787, -9373, -4406, -4310, -3255, -205, -9962, -2890, -2963, -3422, 1, -6661, -3392, -2844, -3029, -170, -4916, -8209, -3539, -3108, -942, -4675, -3966, -3962, -3867, -2982, -4586, -1818, -3373, -4092, 7465, 10363, 10751, 7892, -896, 6569, 9725, 10121, 7108, 489, 3261, 7811, 8164, 4473, -38, 1488, 4891, 4774, -1000, -2812, 3807, 1945, 981, -1314, -4478, 3427, -937, 259, -2409, -518, 2267, -4716, 342, -3855, 954, 2702, -1194, -894, -4800, 1416, 3355, 2541, -24, -4117, 1331, 3433, 3956, 950, -5606, 1135, 2957, 4417, -231, -2425, 1451, 1445, 4334, -740, -4, 1960, -2938, 3566, 1676, -36, 2061, -443, 1518, 2270, -1102, 1814, 2329, -4486, 1457, -1257, 1751, 3119, -2316, 873, -678, 2230, 2757, -404, 1232, 550, 2768, 1250, -906, 1095, 1159, 2764, -1686, -2178, 629, 491, 1950, -1012, -2263, 502, -1620, 151, 803, -1032, 320, -5347, -2789, 1188, -332, -302, -9984, -2968, 1024, -469, -936, -8802, -1426, 921, -1322, -874, -4464, -1272, 774, -3355, -300, -1727, -1962, 407, -4289, 192, -290, -2721, -63, -741, 414, -45, -2883, -413, 1133, 417, -1107, -2659, -597, 1776, 49, -3274, -3075, -661, 1373, -1110, -2215, -5329, -642, -89, -3609, -769, -10998, -851, -2524, -9132, -735, -5260, -666, -4873, -5634, -1800, -3680, 670, -5591, -1939, -3299, -4235, 1397, -7483, -350, -4024, -6442, 682, -10761, 74, -5944, -1923, -2142, -4543, 208, -6266, 39, -12373, -2914, 956, -2055, -71, -3681, -2241, 2248, -784, -2158, -2380, -1894, 3287, -867, -2712, -2920, -1889, 3491, -1740, -699, -3844, -2384, 2524, -3659, -485, -2494, -3500, 9, -4356, -2160, -1864, -3123, -1755, -2585, -8293, -2174, -1722, -256, -2470, -4448, -2638, -1516, -185, -4057, -2350, -3833, -3287, -1331, -7535, -2298, -6043, -7242, -2531, -11586, -3140, -4751, -2519, -1968, -9226, -3707, -3978, -1185, -1044, -6128, -3021, -5076, -1576, -888, -4336, -2184, -6571, -3061, -1757, -3834, -2065, -5168, -5343, -3763, -4201, -2827, -3367, -9239, -5769, -4884, -4592, -2241, -8583, -5319, -6652, -7865, -1871, -5208, -5235, -6257, -10939, -1962, -4412, -6054, -2774, -7764, -2222, -5460, -5720, -1289, -4814, -2796, -6417, -5008, -886, -3633, -4235, -4891, -5366, -1022, -4116, -7967, -4810, -6575, -1521, -4923, -11224, -7129, -7925, -2409, -3956, -6990, -17269, -8064, -3622, -3433, -5957, -8662, -6873, -4986, -3865, -5455, -5338, -6159, -7519, -4616, -5257, -3224, -7325, -9523, -4790, -5156, -2448, -9371, -3567, -4489, -5697, -2821, -5314, -1640, -4708, -8441, -3770, -3707, -1381, -6199, -8236, -3921, -3471, -2251, -8708, -4559, -3491, -3836, -3328, -8789, -3216, -3637, -4449, -3813, -9644, -3129, -4424, -5738, -4748, -7124, -3965, -4513, -6723, -5711, -4060, -5275, -3835, -4397, -3995, -2311, -5990, -4048, -3026, -2356, -1567, -5673, -5713, -2770, -1660, -1904, -5196, -10226, -2655, -1716, -3442, -3897, -6594, -1813, -2358, -5478, -2519, -3534, -912, -3236, 2816, 10853, 11130, 7971, 5305, 2639, 10384, 10551, 7334, 5102, 1951, 8983, 8721, 5502, 4500, 472, 6733, 5317, 2994, 3652, -2632, 4136, 846, -685, 2731, -942, 2498, 250, -2235, 1608, 1547, 2032, -817, 2360, 1113, 2142, 1255, -1477, 3248, 2007, 2181, -258, -1515, 2199, 2816, 2574, -934, -2617, -551, 3123, 3037, -17, -2686, 1598, 2910, 3264, 1765, 319, 3044, 1515, 3095, 3165, 1646, 2554, -4918, 2191, 3454, 1129, 531, 1550, 591, 2469, -2124, -1176, 4667, 243, 798, -3351, -1221, 6207, 202, 977, -39, -1104, 6777, -1813, 1461, 366, -318, 6336, -1875, 1209, -607, -15, 4776, 1149, 936, -2417, -791, 2440, 2332, 1056, -3948, -2974, 1560, 2195, 1417, -3292, -8100, 1569, 929, 1661, -1614, -3619, 997, -930, 1448, -901, -1155, -156, -1963, 846, -2205, -348, -1919, -2811, 257, -8398, -214, -3453, -4946, -206, -1537, -170, -7124, -10364, -164, 402, 115, -4540, -12621, 588, 652, 896, -1195, -16424, 900, 60, 1597, -1237, -7107, 278, -1201, 1633, -3867, -3272, -858, -4112, 939, -2844, -900, -1321, -10210, -263, -1175, 454, -1039, -4481, -2017, -716, 561, -736, -6075, -5001, -71, -1380, -522, -4911, -1851, 211, -5301, -51, -100, 645, -415, -538, 199, 1670, 1488, -1398, 29, -730, 1896, 1173, -1821, -2739, -3889, 487, -216, -2279, -6894, -6878, -3666, -2184, -3296, -2486, -6489, -1177, -1264, -4863, -3892, -11466, 696, 258, -4590, -6984, -3988, 744, 570, -2274, -3033, -2936, -16, -459, -1090, -1224, -4081, -1101, -2535, -1339, 120, -7075, -3108, -1752, -3254, 546, -14394, -7204, -355, -3727, -306, -8928, -4062, 58, -1666, -2335, -5461, -2334, 28, -982, -2879, -4177, -2322, -84, -990, -2306, -3866, -3444, -366, -908, -3226, -3878, -5506, -1203, -564, -6448, -4126, -11451, -2910, -152, -8746, -4208, -6954, -3861, 100, -5412, -3887, -4327, -2458, 36, -4128, -4020, -4759, -1580, -462, -3551, -4817, -5465, -1384, -1518, -3568, -5537, -2972, -1548, -2904, -4034, -5937, -1743, -2046, -3334, -4066, -7162, -1717, -2720, -2923, -3738, -10740, -2582, -2337, -2918, -4108, -10690, -4479, -1383, -3176, -5674, -9109, -8246, -1332, -2751, -8263, -9485, -10896, -2741, -2023, -8803, -4645, -7508, -5089, -2009, -7045, -2053, -5038, -2886, -2801, -4004, -1291, -3449, -1253, -3022, -2556, -2207, -3232, -859, -2392, -2889, -4765, -5100, -1269, -2410, -4490, -4375, -12314, -2208, -3197, -4435, -3202, -5109, -3341, -4380, -3450, -3109, -3996, -4346, -6059, -1620, -2968, -4817, -5390, -7471, 117, -2499, -5740, -6338, -5152, 752, -2173, -6120, -6169, -4065, 257, -2365, -8440, -4260, -4972, -1232, -3283, -8427, -2650, -7703, -3235, -5008, -4629, -2540, -7609, -4511, -5536, -3071, -5195, -7715, -2229, -7725, -3696, -1743, -3123, -402, -3041, -2461, -2227, -3511, 82, -1098, -1439, -2126, -3625, -604, -1073, -1291, -1826, -3226, -2174, -2719, -2504, -1520, -3114, -3895, -6905, -3542, -946, -4190, -5272, -7702, -2073, -304, -9118, -7403, -5800, -2159, -127, -4725, -6445, -6421, -5627, -774, -2103, -3377, -9635, -5046, -2299, -1817, -1608, -11314, -1802, -3645, -3641, -607, -7169, -1155, -3617, -5895, -97, -5934, -1594, -3750, -2787, -76, -5338, -2697, -4602, -1917, -767, -3873, -3565, -4736, -2394, -2683, -2203, -2411, -3080, -3139, -8290, -1188, -1566, -2246, -3717, -6051, -1043, -2144, -2269, -4135, -3166, -1736, -4665, -1541, -3420, -2445, -2807, -5714, -428, -1720, -2671, -3901, -3742, -133, -304, -3534, -6730, -4461, -635, 196, -4999, -9280, -10084, -1368, -461, -6250, -3601, -7678, -1850, -2531, -4963, -1718, -6610, -2500, -5824, -3788, -911, -10839, -4332, -5219, -3619, -707, -7788, -9632, -2921, -4230, -945, -5913, -8131, -1636, -5498, -1431, -6064, -7834, -1339, -7316, -1910, -6401, -7193, -1225, -7706, -2012, -5833, -4882, -998, -6730, -1463, -4220, -3883, -1552, -7327, -1007, -3446, -3715, -3291, -9721, -1335, -4379, -4961, -4267, -8177, -2680, -8030, -7886, -4251, -8146, -4898, -11524, -5527, -6364, -9818, -4962, -9179, -4559, -12750, -7549, -3475, -7716, -5543, -10002, -6633, -2922, -5897, -8312, -16142, -5658, -3029, -4932, -15307, -9516, -4894, -3818, -4216, -12433, -8084, -5217, -6432, -3736, -10402, -5130, -4942, -11180, -3459, -8452, -2451, -4563, -6610, -3042, -5685, -1321, -6302, -7019, -2659, -3931, -1369, -14280, -10820, -2711, -3088, -2285, -9053, -9099, -3352, -2633, -3749, -11980, -9436, -4253, -2509, -5009, -8102, -13941, -4320, -3419, -4522, -5168, -12003, -4059, -7399, -3655, -4747, -14360, -4608, -6510, -3954, -5312, -8539, -5475, -3113, -6467, -5601, -6161, -5400, -2508, -12457, -6038, -5294, -5312, -3169, -5293, -7629, -4882, -5578, -4175, -3787, -8540, -4697, -6554, -3984, -4043, -7789, -5165, -8141, -2751, -6578, -7592, -7204, -6154, -2242, -11739, -5629, -15877, -4579, -3361, -5185, -3711, -7014, -3568, -8555, -3553, -2900, -4905, -2461, -5455, -2903, -3147, -4420, -1824, -2925, -2480, -4606, -4717, -2029, -2581, -2166, -8433, -5083, -3066, -3064, -2108, -11378, -5143, -4636, -3586, -2551, -7590, -5327, -5433, -4131, -3709, -8176, -6163, -4356, -4980, -5464, -13694, -8437, -3324, -5727, -7051, -11130, -12397, -3008, -6211, -8993, -9184, -8892, -3231, -7306, -7476, -9969, -7742, -3573, -10203, -4634, -12684, -7927, -3684, -16659, -3624, -17243, -8584, -3813, -9568, -3837, -13002, -8983, -4193, -7514, -4636, -10462, -8864, -4036, -5969, -5485, -8704, -8689, -3081, -4683, -6535, -7310, -7888, -2436, -3996, -7866, -6560, -7437, -2539, -3992, -9937, -6985, -9075, -3531, -4695, -11614, -9521, -14498, -5769, -6377, -8750, -6250, -2388, -2382, -792, -3844, -5568, -4195, -2097, -1896, -4692, -3336, -7965, -2214, -4281, -6960, -2085, -4817, -2960, -4738, -14538, -2011, -4251, -4964, -4203, -9271, -2839, -6000, -9238, -3609, -8753, -4399, -4727, -9798, -2251, -8970, -7127, -2190, -7635, -1894, -5336, -4922, -1187, -6424, -3022, -3667, -2114, -1209, -5803, -5445, -3153, -1059, -1714, -5782, -6155, -2981, -1207, -1976, -6663, -6096, -2844, -2311, -2135, -7195, -8362, -2705, -4110, -3132, -3972, -14535, -2467, -5510, -5792, -1921, -7078, -2310, -4635, -4818, -1135, -5387, -2569, -3822, -2402, -1269, -4121, -3458, -4663, -1609, -2134, -2080, -5044, -10175, -1910, -3693, -420, -7921, -5837, -3250, -6267, 390, -11087, -2919, -5527, -11392, 354, -4261, -2479, -5466, -12193, -474, -1930, -3810, -4357, -7850, -1864, -1383, -4977, -4058, -6027, -2994, -2375, -3743, -3166, -5115, -2870, -4993, -4345, -2099, -4091, -1980, -7257, -8726, -2171, -3207, -1416, -4962, -7049, -4404, -3282, -1581, -2328, -4625, -11970, -4971, -2512, -957, -4192, -3732, -8884, -3966, -954, -4571, -2315, -4916, -3980, -2717, -4787, -2467, -2751, -2466, -10008, -4276, -3237, -1999, -1585, -3612, -3781, -3062, -2151, -1621, -1599, -3895, -2077, -3195, -2708, -1552, -4783, -1739, -5405, -5519, -2732, -5996, -2242, -6747, -8327, -4793, -6178, -3120, -5205, -4868, -6877, -5084, -3574, -4568, -3278, -8116, -4178, -3346, -3155, -2751, -9489, -3357, -2974, -1424, -3687, -8878, -2607, -3122, -724, -7232, -7028, -2531, -4177, -1287, -8077, -4775, -3380, -6154, -3483, -8296, -2786, -5279, -7446, -9742, -7717, -2005, -6688, -8091, -7778, -4203, -2509, -3835, -9854, -6041, -3579, -3402, -2103, -5315, -6127, -4537, -3127, -1887, -2927, -7252, -5946, -3274, -3282, -2280, -8381, -6652, -4967, -7575, -3073, -6001, -7409, -8732, -10256, -5786, -4500, -10375, -14838, -7218, -12124, -4221, -8848, -10338, -7181, -5745, -4837, -5972, -6104, -7131, -3726, -6107, -5315, -4291, -6432, -3057, -7145, -5953, -4118, -5286, -3563, -7131, -7803, -4913, -4846, -5573, -7630, -12685, -4135, -5862, -5860, -8251, -10917, -2629, -9106, -3478, -5686, -7278, -1934, -6210, -2447, -3660, -6232, -1807, -4019, -2351, -2685, -6934, -1713, -3831, -2811, -2361, -10394, -1327, -5543, -3893, -2399, -11271, -924, -12006, -6556, -2697, -8086, -980, -6260, -8052, -3147, -7675, -1867, -3905, -4646, -3523, -8270, -4120, -3468, -3723, -3978, -8272, -9603, -4622, -4360, -5092, -6699, -5698, -8289, -6575, -7691, -4966, -3395, -7250, -13723, -9388, -3800, -2684, -5014, -8438, -5655, -3298, -2890, -4606, -5398, -3834, -3409, -3617, -4354, -4354, -3106, -3951, -4212, -3430, -4542, -3071, -4575, -4677, -2538, -5841, -3489, -4923, -5681, -2124, -8023, -4274, -4900, -7264, -2333, -8982, -5708, -4813, -8796, -3313, -8289, -8689, -5138, -7854, -5175, -8156, -10859, -6117, -5752, -5528, -4471, -2652, -6196, -11727, -8669, -4997, -2925, -1220, -9177, -4889, -4601, -3001, 373, -6932, -2599, -2013, -2167, 571, -6367, -2479, -1175, -1324, -277, -4778, -3825, -2284, -1048, -2049, -2983, -3926, -5524, -1465, -4418, -2204, -2113, -3979, -2658, -6428, -2456, -1106, -2602, -4177, -8465, -3291, -1040, -2746, -4047, -10954, -3643, -1595, -3662, -3529, -5062, -3396, -2253, -5660, -4050, -2701, -3635, -3181, -7993, -5894, -1968, -5269, -5613, -4906, -11586, -2387, -6787, -19755, -3199, -7378, -3991, -3393, -7052, -2632, -4643, -7713, -1496, -6389, -2867, -3961, -5292, -933, -8342, -3994, -3450, -2399, -1669, -13083, -6695, -1822, -1225, -4265, -6013, -7647, -205, -1037, -6638, -3330, -5317, 707, -1597, -4335, -2858, -4621, 846, -2926, -4878, -4668, -4337, 262, -4596, -10910, -8174, -5034, -934, -3779, -6660, -4125, -9053, -2616, -2219, -4445, -2773, -8275, -4516, -1280, -4806, -2834, -5603, -5921, -916, -7097, -3696, -5307, -7555, -1364, -9936, -4798, -5744, -9207, -3079, -8646, -5690, -7252, -5003, -6585, -8770, -6410, -10935, -3488, -5610, -8659, -6744, -9245, -4543, -3736, -6559, -7362, -6667, -9999, -3573, -4302, -8965, -5489, -3734, -5494, -2963, -5703, -5456, -1880, -11408, -2594, -2907, -6858, -1770, -4699, -2890, -1549, -6535, -2640, -2857, -3453, -1154, -4094, -4328, -2189, -4074, -1541, -3391, -7130, -2055, -4605, -2792, -4375, -8446, -2633, -4459, -5634, -6677, -6922, -3739, -4190, -16075, -7423, -5863, -3600, -4931, -5658, -5893, -4679, -3076, -6630, -3613, -3718, -3507, -3927, -7514, -2568, -2615, -2837, -7290, -8002, -1719, -2934, -2845, -6953, -8216, -1143, -4435, -3538, -4074, -8730, -1125, -4456, -5120, -3464, -9807, -1668, -3324, -8996, -4488, -7542, -2334, -3513, -9803, -7113, -5666, -2808, -5626, -6177, -5883, -4286, -3672, -12648, -5514, -4407, -3453, -5572, -8244, -5411, -5150, -3455, -8737, -7283, -4425, -10922, -4379, -13654, -5561, -3741, -5647, -6222, -14264, -3558, -4234, -2762, -6842, -13732, -2974, -6441, -1961, -4929, -7858, -3630, -11656, -2401, -3825, -4479, -4823, -8689, -3994, -3620, -2891, -5125, -7594, -6922, -3746, -2095, -4262, -6938, -10203, -3831, -1822, -3487, -5721, -7810, -4420, -2297, -3764, -5273, -5157, -6377, -3705, -5866, -5856, -3896, -8346, -5827, -11724, -7327, -3817, -6118, -6657, -5614, -9996, -4462, -5188, -5069, -3567, -23608, -5227, -5446, -3785, -2982, -9908, -6383, -6470, -3373, -2828, -7664, -9051, -7122, -3856, -2319, -7283, -14350, -6048, -5148, -1901, -7891, -10559, -5218, -6995, -2190, -8009, -8803, -5223, -9427, -3309, -6301, -8108, -5472, -11170, -5393, -4919, -7391, -5316, -14433, -7828, -4693, -6097, -5145, -7918, -5216, -5792, -4923, -5350, -4639, -3623, -8660, -4158, -5483, -3482, -3677, -8145, -3554, -4932, -3589, -5313, -5483, -2925, -4456, -4440, -9515, -4467, -2589, -4890, 3118, 146, 1330, 6913, -8593, 2225, -2169, 4462, 6442, -5307, 12, -2240, 6211, 5121, -3754, 1312, 1078, 6366, 3616, -3143, 2963, 2155, 5076, 3021, -2276, 3466, 3005, 1414, 2465, -1894, 3025, 3214, -157, 740, -4887, 1293, 2110, 3189, -4219, -2132, -4556, -1005, 3860, -2021, 2117, -988, -6969, 3108, 306, 3776, 2001, -3941, 546, -137, 4468, 2875, -3603, -7925, -958, 4940, 2381, -2086, -131, 1799, 5298, -257, -19, 1104, 3233, 5130, -1436, 755, 202, 3141, 3946, 2103, -996, -1421, 1700, 660, 2879, -1924, -391, -73, -827, 1894, 2690, 319, 1207, 2394, -865, 4090, 511, 2256, 2674, -2225, 3748, 735, 2067, 1310, -805, 1920, 526, 1172, -336, 316, 162, -206, 561, -4199, 1989, 568, -1159, 654, 72, 3204, 150, -3201, 1390, 3714, 3505, -472, -9209, 1725, 4733, 2879, -171, -1469, 729, 4091, 1390, -691, 396, -2601, 1674, -810, -2626, 295, -7749, -4042, -3765, -4460, -1820, -3734, -3146, -8464, -6383, -8245, -1372, -2356, -3271, -5291, -2978, 733, -1947, -1560, -1302, -1978, 1491, -432, -2768, 154, -3479, 940, 126, -7540, 9, -7941, -284, -776, -2313, -1679, -4676, -294, -3182, -1244, -3582, -2537, -44, -2447, -1635, -2579, -1208, -961, -777, -1382, -3078, -74, -3733, -602, -943, -3659, 674, -12982, -1533, -1950, -926, 812, -5139, -3127, -3137, 55, 385, -4789, -4648, -987, -234, 565, -5526, -5624, -483, -47, 1504, -2684, -7560, -1628, 61, 1754, -738, -8574, -1004, -1997, 1217, 92, -2497, 756, -4957, 887, 251, -78, 1558, -1276, 1105, -37, 864, 1478, -1042, 1072, -963, 840, 515, -1753, 612, -3097, 141, -1088, -1256, -163, -5478, -1065, -2240, -1733, -901, -2319, -3035, -2699, -4870, -1569, -198, -5528, -3643, -3113, -3722, 748, -2815, -6049, -748, -8112, 813, -1249, -10768, -477, -1404, 223, -1639, -9965, -1843, 436, -587, -4400, -7743, -5307, 600, -1048, -9887, -4784, -6827, -371, -1397, -3433, -2408, -4764, -1549, -3179, -1722, -763, -4034, -1054, -5471, -2083, 41, -3624, 844, -613, -5535, -199, -3123, 2355, 787, -6442, -1793, -3035, 2846, 197, -1717, -5117, -4639, 2196, -2325, 310, -4472, -17536, 255, -7013, 1172, -1994, -3928, -3289, -9853, 1038, -379, -1702, -10583, -4825, 59, 694, -786, -4575, -2715, -1504, 1229, -290, -574, -2738, -2659, 1129, -455, 1086, -4577, -2561, 147, -1698, 1292, -6912, -2028, -2223, -3573, 147, -4034, -1176, -6949, -4009, -2647, -2021, -691, -7117, -1952, -4681, -1034, -173, -5394, 544, -2675, -487, 966, -1670, 2086, -1898, -583, 1526, 1029, 2718, -1984, -2698, 884, 2329, 2530, -2503, -3246, -933, 2231, 1490, -2589, 810, -2167, 188, -256, -1535, 1951, -1852, 4277, 8809, 8073, 8894, 6117, 3705, 8169, 7263, 8200, 5739, 2140, 6120, 4511, 5897, 4409, 220, 2412, -1604, 1340, 1445, 146, 481, -1372, 1083, -3380, 1598, 78, -303, 1172, -534, 1779, 437, 2339, -180, 102, -96, 3588, 3941, 1896, -338, -7107, 5326, 4951, 4069, -568, -1001, 5674, 5616, 4464, 116, 533, 4623, 5794, 2535, 2085, -90, 2337, 5337, -650, 3534, -2172, 3173, 4030, 3689, 3828, -2848, 4564, 1813, 4696, 3088, -83, 4455, 1995, 3875, 1675, 2758, 3043, 3189, 1410, 215, 4450, 479, 2920, -1555, -385, 4934, -2987, 1382, 245, 524, 4125, -3666, -1159, 1789, 2241, 2386, -582, -2739, 2611, 3599, 3106, 367, 503, 3170, 3851, 4087, -163, 2224, 3834, 2505, 3466, -1465, 2628, 4288, -600, 1277, -2497, 2187, 3945, 1691, 460, -1772, 1456, 2627, 3462, 1714, 507, 977, 1390, 4027, 1833, 2274, 325, 1221, 3987, 747, 3308, -1273, 328, 3319, -1813, 3771, -4158, -1971, 1860, -2041, 3738, -8238, -6137, 140, 549, 3185, -8916, -8056, -245, 1533, 1988, -3807, -2856, 8, 1112, 86, -2567, -1311, 257, -1158, -625, -4053, -884, 724, -8202, 204, -5880, -549, 1493, -3115, -338, -1423, -598, 2289, -2715, -2811, 211, -2133, 2723, -5070, -3071, 611, -8399, 2597, -3161, -2561, 692, -3892, 1767, -1189, -3756, 1144, -1831, -48, -728, -3358, 1838, -1321, -3653, -891, -2556, 2279, -818, -5325, -1002, -2309, 2273, -755, -1921, -970, -3974, 1745, -2182, -462, -1343, -6567, 595, -4975, -109, -2688, -712, 98, -2412, -786, -4322, 515, 930, -1467, -2608, -3287, -363, 881, -3112, -5276, -1939, -1794, -198, -6744, -6453, -1216, -868, -1136, -1844, -4225, -1144, -463, -2293, -40, -2040, -1808, -1214, -5789, 735, -1162, -4271, -3008, -8304, 1061, -1156, -6402, -4590, -6784, 835, -1738, -1396, -3877, -4845, -72, -3918, -375, -3647, -2302, -1608, -8159, -1533, -3457, -957, -3636, -2085, -3981, -2984, -393, -6563, -454, -4316, -2912, -391, -7770, -154, -8634, -3245, -852, -4968, -428, -2861, -3898, -1510, -4373, -1559, 310, -5401, -2226, -5840, -5442, 1388, -5982, -3498, -12001, -6296, 1478, -2471, -6107, -5912, -2775, 1040, -626, -5956, -2526, -2580, 37, -222, -3260, -729, -3968, -2029, -982, -2254, 52, -7660, -4143, -1877, -1721, 0, -9829, -3081, -1249, -993, -278, -7732, -3697, -1019, -611, -13, -9038, -9054, -2074, -485, 538, -3289, -6787, -3741, -897, 1122, -1718, -5178, -3493, -3183, 1177, -2659, -4875, -1197, -3555, -370, -7024, -2896, 359, -1109, -10480, -3403, -1167, 750, -742, -682, -1152, -273, 631, -359, 1694, -417, -631, 967, 650, 2436, -396, -3188, 1408, 1224, 2455, -890, -4362, 1385, 1311, 1974, -2045, 6241, 8127, 8154, 3329, 3450, 5414, 7353, 7504, 4539, 2359, 2893, 4853, 5406, 5810, 1415, -1407, 256, 1137, 6393, 2869, -4026, -1018, -3143, 6315, 2155, 1049, 1256, -932, 5055, -2328, 1888, 2348, -688, 522, 392, 1371, 1929, -161, 1861, -383, 1944, 436, 605, 4813, 1599, 2704, -665, 78, 5335, 4973, 2879, 316, -4132, 4860, 5703, 2508, 552, -2180, 3700, 5143, 1233, -840, 1420, 1344, 4776, -241, -3382, 2340, -973, 4692, 1402, -6939, 1903, 1856, 4098, 2648, -7534, 271, 2871, 3474, 2561, -2175, -3392, 2245, 3982, 1263, 431, -5024, -271, 5016, -803, 2239, -404, -4052, 5332, -1549, 3452, 1413, 285, 4676, -1912, 4399, 2200, 1950, 4041, -4243, 5284, 2722, 2343, 5254, -7932, 5851, 3446, 2058, 6540, -3096, 5792, 3984, 1509, 7012, -79, 5012, 3853, 851, 6625, 1757, 3676, 2829, -245, 5303, 2223, 2010, 665, -2602, 2883, 1032, -577, -3711, -5186, -375, -2619, -5703, -5238, -928, -593, -1219, -2876, -1840, 1076, 1431, 735, -2153, -756, 1646, 2671, 1002, -3381, -237, 951, 2829, 384, -4943, 284, -1173, 1765, -810, -2245, 794, -1385, -1118, -718, -879, 1043, 812, -1580, 712, -1844, 617, 1873, 391, 1316, -2229, -997, 2264, -60, 984, 724, -1524, 2405, -3089, 20, 2026, 1053, 2434, -4403, -739, 2167, 2422, 2259, -839, -659, 1578, 2632, 1650, 247, -828, 419, 1795, 319, -694, -1902, -798, -256, -1868, -4354, -3589, -864, -1973, -3668, -3444, -3657, -939, -447, -4164, -3165, -2500, -2023, 36, -5331, -7651, -2047, -2187, -969, -5920, -3386, -2484, -1053, -2807, -5063, -1625, -3744, -1227, -2107, -4562, -1828, -5324, -3535, -728, -5042, -2414, -4339, -4821, -435, -5803, -1451, -1994, -2642, -1112, -3598, 21, -334, -3353, -2078, -1599, 842, 223, -10118, -2764, -810, 845, -733, -5822, -4143, -1101, -5, -3691, -6578, -4775, -1730, -1606, -2260, -4415, -2597, -1198, -2413, -567, -414, -1047, -116, -1646, -993, 475, -162, 1059, -1526, -3779, -725, 354, 1978, -2684, -12033, -4345, 581, 2077, -5734, -6570, -7242, 245, 967, -9861, -2620, -13415, -1008, -2056, -3860, -341, -4412, -3183, -16484, -1046, 515, -1713, -3196, -5242, 290, 709, -847, -1213, -3672, 196, 859, -581, 130, -2007, -1415, 1056, -926, 842, -1128, -1339, 832, -1558, 1039, -1686, 429, -331, -120, 936, -4188, 662, -2454, 1262, 705, -4660, -622, -3390, 1469, -124, -3031, -3537, -1024, 687, -2587, -4361, -8373, 1268, -716, -3647, -8348, -7906, 2426, -1858, -1745, -2939, -3338, 2563, -1919, -2562, -1240, -1319, 1873, -1528, -8172, -740, -557, 537, -905, -5316, -928, -343, -1343, -382, -3196, -2312, -285, -3772, -710, -2727, -4046, -461, -2665, -536, -163, 1395, -2433, 1451, 700, 744, 289, -3430, 3049, 1103, 669, 769, -1953, 3410, 273, -1166, 1312, 104, 3125, -2569, -3797, 1211, 1460, 2553, -9160, 187, 970, 1832, 1920, -2243, 1512, 854, 1220, 1268, -1188, 946, 536, 262, 486, -2287, -1878, -373, -200, -702, -7091, -6246, -1769, -1183, -2357, -3416, -2110, -2397, -3818, -3072, -1011, -1305, -1881, -3042, -1255, -866, -1461, -1339, -1058, 828, -1576, -1817, -975, -769, 1895, -384, -1716, -768, -1761, 1759, 840, -483, -1031, -4489, 255, 635, 564, -2962, -4338, -2924, -1584, 561, -6641, -1145, -3653, -8057, -1020, -37, -382, -2246, -1516, -6472, 2152, -2088, -1904, 192, -4472, 2868, -3651, -1567, -85, -2669, 2764, 450, -990, -2113, -2535, 2310, 1626, -728, -874, -1695, 1779, 891, -1428, 971, -1296, 972, -2200, -4166, 1114, -1924, -589, -5780, -7825, 221, -2285, -3323, -1691, -3487, -433, -1145, -6073, -230, -2525, 154, -513, -7508, 585, -2832, 982, -1242, -6886, 1164, -3535, 1293, -3821, -2967, 1527, -2951, 1074, -3743, -1304, 1347, -1822, 720, -957, -1811, 494, -1426, 611, -92, -6989, -125, -2038, 500, -931, -3428, -303, -4554, -223, -4165, -768, -1666, -8290, -1602, -9042, -497, -5360, -2436, -1486, -5364, -1441, -9835, -372, -324, -4806, -3517, -7210, 429, -68, -4413, -9929, -2532, 63, -987, -4720, -4172, -1231, -2332, -2607, -7687, -1449, -1587, -10531, -2300, -6691, -997, -1616, -2487, -1538, -2714, -1635, -947, -2399, -1748, -1546, -1794, -870, -4803, -2651, -1760, -1825, -737, -1535, -4039, -2533, -1711, 154, -150, -5934, -2753, -484, 1019, -933, -7073, -2866, 5, 1070, -3637, -5680, -4080, -1145, -109, -2894, -3903, -7681, -5198, -2927, -1149, -3309, -13945, -4640, -7076, -712, -4112, -8977, -2381, -8465, -1063, -5929, -6661, -2103, -10346, -2170, -6951, -5306, -1922, -8416, -3844, -6126, -3923, -918, -6938, -3284, -5098, -1641, 232, -4789, -1976, -5542, -320, 584, -2403, -1930, -9068, -89, -478, -1271, -3167, -8062, -453, -3539, -1173, -4139, -5769, -675, -2442, -1128, -3323, -5757, -424, -655, -992, -3463, -5377, -141, -554, -1804, -4584, -4849, -221, -1415, -3947, -3942, -5664, -758, -2821, -5311, -2857, -7407, -1807, -4706, -4203, -2952, -7839, -3364, -7523, -2643, -4658, -7175, -4285, -10408, -1974, -8684, -5055, -3850, -10031, -3020, -4467, -3341, -3543, -10283, -8030, -2506, -2501, -3456, -9502, -4641, -2462, -2508, -3156, -8393, -1826, -4311, -3506, -2583, -6880, -1017, -10471, -5698, -1943, -5264, -1200, -6114, -8872, -1308, -3958, -2024, -3779, -9555, -714, -3006, -3196, -2756, -7642, -318, -2665, -4451, -2181, -7800, -232, -3248, -5932, -1995, -9862, -387, -5214, -7985, -2473, -5118, -634, -10596, -6671, -590, 828, 1140, 897, -4455, 836, -453, 1020, -805, -8201, 1240, -3314, 1013, -1857, -4285, 878, -10100, 575, -1714, -2248, -534, -4527, -1053, -2108, -1398, -3738, -3428, -5782, -2540, -1106, -8967, -1979, -7322, -2507, -1225, -4764, -375, -5824, -3301, -1909, -188, 210, -5874, -5913, -2966, 2004, 13, -2887, -11871, -3077, 2628, -182, -2256, -7499, -2382, 1941, -20, -2963, -6365, -2134, -214, 85, -3343, -6950, -2664, -5440, -97, -2891, -9609, -4111, -6051, -512, -1859, -6414, -4387, -2835, -991, -1289, -3253, -1811, -2261, -1819, -1961, -2581, -154, -3716, -3708, -4248, -2866, 428, -5957, -4586, -5717, -1388, 250, -1362, -2812, -4076, -46, -232, 202, -2495, -3994, 145, -473, -293, -2952, -5457, -607, -394, -2999, -2029, -5329, -1868, -402, -1902, -730, -2852, -2581, -860, 88, 94, -1471, -1763, -1976, 154, 599, -1287, -409, -3449, -1277, 655, -2383, 311, -2279, -4613, -296, -5104, -67, -199, -7294, -3867, -8220, -1944, 800, -3967, -4647, -7273, -3447, 759, -2999, -810, -6999, -836, -375, -3924, 91, -6887, 602, -3578, -9585, 263, -6229, 989, -4598, -5303, 443, -5622, 594, -814, -1778, 190, -5693, -602, 161, -20, -1138, -6369, -3280, -345, 693, -4110, -7452, -10517, -2039, 522, -6520, -10090, -1877, -3949, -111, -3046, -10215, 153, -3469, -1228, -858, -4303, 197, -3005, -4583, 20, -1881, -1980, -3873, -6635, -204, -969, -12129, -6634, -2248, -1165, -1067, -3411, -14424, -1216, -2162, -1806, -3472, -10512, -1015, -3433, -2713, -8785, -8797, -1523, -4765, -3220, -6674, -6629, -2753, -1521, -3010, -5032, -4341, -2046, 556, -2567, -5564, -2743, -961, 1157, -2728, -4715, -2157, -1369, 577, -3680, -2853, -2554, -3246, -935, -4763, -1830, -3949, -5571, -2846, -4939, -2357, -7216, -5189, -5632, -5028, -5879, -6176, -3218, -5355, -6656, -7252, -2515, -2071, -1519, -8773, -3268, -1159, -1901, 43, -6697, -2751, -1582, -2470, 251, -5832, -3593, -4347, -3784, -472, -4930, -4996, -2333, -5359, -1016, -3163, -5633, 387, -3609, -360, -1554, -4434, 1352, -1620, 357, -653, -2786, 1356, -955, 589, -304, -1947, 814, -1709, 232, -331, -2133, -95, -4579, -960, -981, -3216, -1523, -9511, -3151, -2752, -5009, -4028, -4287, -3325, -6326, -7580, -8835, -2825, -1915, -12577, -9888, -6154, -2438, -1518, -16095, -8728, -4523, -2806, -1754, -12740, -4331, -4205, -4441, -2262, -10771, -1767, -4063, -7782, -2945, -5524, -579, -3885, -4925, -3475, -2923, -415, -3872, -3641, -3227, -1621, -1265, -3880, -3911, -2963, -1030, -3607, -3291, -2867, -3751, -882, -10713, -2529, -1312, -6123, -944, -7948, -2416, -1050, -9084, -1181, -7284, -3032, -2472, -8240, -1961, -10394, -3808, -7257, -8586, -3656, -7317, -4037, -6884, -10044, -5869, -5150, -3836, -5947, -2580, -1817, -63, -1113, -9139, -3509, -732, 2203, -2243, -7660, -666, -399, 3078, -3463, -3819, 709, -1157, 2992, -3260, -3360, 978, -3220, 2087, -1007, -5895, 413, -6009, 198, 468, -7010, -938, -5300, -2032, 601, -3241, -3022, -4062, -1096, -266, -2400, -3961, -3889, -541, -976, -2954, -2619, -4510, -1088, -1482, -3296, -1694, -3411, -1747, -2278, -2002, -1510, -1566, -1565, -2514, -1351, -1842, -731, -667, -2777, -2532, -1939, -895, -195, -2897, -6893, -1062, -1717, -852, -4150, -2542, -28, -2440, -3422, -5473, -890, 332, -3761, -6847, -2396, -1703, -569, -8831, -1617, -2322, -6028, -4802, -1462, 155, -5542, -3449, -3114, 1202, 196, -3242, -1460, 157, 2223, -1741, -982, -1798, 999, 2258, -4027, -504, -2424, 1102, 1597, -309, -858, -1269, 835, 568, 1041, -1503, -573, 96, -538, 860, -2239, -1024, -476, -2009, -584, -3420, -2146, -1219, -4215, -3154, -5719, -2372, -4291, -5754, -5190, -10646, -2435, -8020, -6840, -4674, -10945, -3730, -3218, -7367, -2206, -6945, -6626, -2250, -5292, -295, -4357, -7260, -2140, -4918, 608, -2141, -4577, -3272, -6137, 700, -806, -4059, -8068, -7767, 67, -862, -2626, -6891, -9693, -1233, -2828, -190, -4005, -13823, -3004, -7741, 1078, -2999, -7404, -4510, -6447, 1406, -1940, -6131, -1874, -7410, 1286, -1144, -5664, 323, -9777, 931, -869, -4100, 1027, -5152, 3, -929, -3232, 550, -2988, -2172, -960, -3351, -688, -2065, -5764, -756, -3666, -2056, -1780, -2930, -674, -3646, -3854, -1655, -605, -1363, -3738, -5948, -1755, 749, -3931, -4082, -4189, -2218, 1260, -7893, -3659, -2275, -2730, 775, -2651, -2921, -1098, -2917, -955, -1833, -3719, -945, -3060, -4225, -3916, -10150, -1887, -3949, -4420, -7190, -3920, -2446, -6648, -3020, -2013, -1590, -1372, -9080, -3407, -786, -1784, -739, -6573, -5994, -1196, -4625, -954, -5556, -5302, -2991, -6013, -1596, -3238, -2435, -6571, -2527, -1443, -1401, -1446, -12956, -1688, -623, -692, -1449, -9256, -1925, -434, -936, -2392, -6646, -2804, -1317, -1929, -6513, -7742, -4992, -3521, -3534, -4806, -5703, -11473, -7166, -5587, -1267, -2751, -6370, -6135, -5950, -694, -2614, -5122, -3782, -4633, -1739, -4493, -4723, -2648, -3777, -4008, -2574, -3483, -2485, -3100, -5203, -825, -2691, -3275, -2515, -3061, -688, -2771, -4995, -2296, -1519, -1502, -3411, -4819, -2533, -989, -1955, -4571, -3057, -3199, -1354, -1337, -6963, -2599, -4289, -2705, -1162, -9032, -3603, -5197, -5798, -2242, -8257, -6241, -4827, -14563, -5396, -9561, -8319, -4668, -6812, -10119, -13471, -6541, -5009, -7422, -5365, -9996, -4516, -3651, -8204, -3802, -6835, -2656, -2308, -3295, -3198, -5994, -1602, -2187, -1432, -3289, -6904, -1313, -3172, -1048, -4012, -7904, -1301, -4601, -1706, -5041, -7724, -1318, -5221, 9893, 6950, 9734, 7998, -3265, 9282, 6868, 9246, 7306, -879, 7376, 6226, 7886, 5027, 487, 4021, 4447, 6120, 1103, 1111, 198, 1432, 4432, 1914, 1731, -41, 270, 2231, 2670, 2032, 765, 1266, -1073, 2285, 1999, 57, 2064, -1174, 1420, 1713, -4, 2528, 18, 208, 1011, 2531, 2550, -774, -987, 247, 4302, 2273, -1992, -512, 1069, 5292, 2765, 601, 259, 2656, 5511, 3997, 1922, 615, 3785, 4756, 4676, 1487, 1453, 4497, 2866, 4353, -1937, 1953, 5063, 1640, 2681, -406, 1008, 5555, 2238, -1792, 3028, -2156, 5709, 1660, -707, 4037, -1697, 5139, 1333, 1563, 3710, 144, 3461, 2740, 1301, 2213, 216, 279, 3573, -1012, -915, -575, -2572, 4101, -6155, -5955, -974, 776, 4613, -6417, -2489, -160, 3507, 4596, -3033, -2042, 376, 4807, 3740, -543, -3313, -291, 4973, 2331, 90, -4669, -1893, 4219, 1493, -1212, -3760, -962, 2868, 1060, -4321, -2394, 350, 1828, 136, -1545, -2829, 486, 1568, -150, 91, -6332, -233, 1223, 791, 955, -972, -1221, 404, 1432, 1927, 1262, -538, -576, 1452, 2499, 1585, 1448, -604, 990, 2197, 668, 2686, -106, 401, 527, -548, 2888, -561, 375, -5179, -647, 2015, -2836, 934, -1038, -715, -143, -6899, 1233, 1224, -2034, -4156, -4439, 707, 970, -5586, -6884, -3377, -790, -1534, -10400, -6638, -2846, -2670, -2224, -4720, -4488, -2764, -3121, -458, -2227, -2505, -3033, -2467, -895, -1393, -2155, -2927, -2708, -2651, -2073, -2826, -2188, -5623, -2440, -4684, -3015, -1380, -7691, -1396, -8090, -3008, -1330, -2732, -1107, -4133, -4632, -2552, -1529, -1286, -2098, -8551, -5014, -1830, -1746, -1218, -6037, -4872, -2835, -2461, -1528, -5820, -4374, -3178, -3227, -2825, -7996, -6427, -3596, -3601, -3179, -7516, -5452, -5289, -4098, -2506, -5674, -2494, -6585, -5832, -2239, -5129, -1965, -6739, -7895, -2245, -6075, -3593, -12704, -6431, -2473, -5989, -8011, -5722, -6393, -2616, -3421, -7615, -2983, -6584, -2418, -2383, -7676, -2490, -4175, -2544, -2873, -5523, -3387, -2302, -3566, -4987, -4964, -5383, -1518, -5393, -9860, -6669, -8023, -1758, -6861, -8351, -5303, -8833, -3061, -5485, -5551, -3952, -6464, -5607, -3324, -4449, -4393, -4230, -9981, -2401, -4229, -6714, -2955, -12310, -2517, -4169, -5225, -2739, -8967, -3045, -3946, -2176, -3315, -6666, -3395, -4325, -1027, -3142, -4725, -3617, -6432, -1090, -1997, -3373, -3991, -8417, -1858, -1347, -2983, -4736, -5653, -2642, -1435, -3830, -5918, -4329, -3166, -2324, -6439, -7517, -2801, -3681, -4403, -7189, -8238, -1590, -3374, -9389, -3213, -5115, -866, -2799, -9122, -880, -2473, -394, -3240, -5616, 298, -980, -554, -4377, -4575, 393, -443, -1834, -4171, -5295, -725, -757, -4530, -2532, -10057, -2845, -1725, -8647, -698, 3683, 4463, 1825, -124, 2917, 3531, 4227, 4240, 35, 2671, 2782, 3483, 5662, 524, 2710, 504, 2319, 5436, 1115, 3175, -3508, 963, 3424, 1254, 3130, 543, -871, -2756, 521, 2540, 1362, -2417, 1540, 422, 1314, 82, -1317, 3275, 2037, -1669, -2950, 414, 3145, 2608, -6893, -6719, 2433, 1962, 1679, -5415, -244, 4197, -253, -665, -1236, 3013, 5400, -2164, -3883, 1545, 4445, 5907, -791, -4302, 2164, 4659, 5654, -2012, -1539, 953, 4030, 4641, -1671, 1948, -2540, 3135, 2907, 2284, 4142, -1780, 2362, 508, 3697, 5003, -104, 1246, -2934, 3750, 4673, -57, -356, -7216, 2959, 2988, 324, -1990, -788, 1999, -1190, 1584, -6384, 1481, 1711, -875, 2793, -3376, 1938, 1773, 816, 3392, -910, 903, 1359, -1253, 2831, -1619, 1642, -188, -731, 255, -5239, 3956, -4493, 2828, -8619, -2533, 4856, -4998, 3833, -1001, -1084, 4393, -3073, 3923, 618, -1142, 2651, -4611, 4240, 1265, -881, 210, -5301, 4501, 1122, -499, 193, -4510, 3983, 262, -1048, 1801, -4984, 2540, -291, -2398, 2929, -4414, 757, 537, -2886, 3307, -4481, 103, 1723, -996, 2971, -4340, -56, 2378, 779, 1931, -1460, -617, 2165, 1457, 356, 324, -1165, 1014, 957, -219, 749, -1223, -80, -772, 268, -53, -1566, 7, -3643, 100, -2097, -3244, -380, -5296, -443, -5329, -3409, -1484, -4828, -764, -7308, -397, -2607, -4755, -1428, -5650, 1043, -4558, -3782, -2276, -4608, 1365, -4631, -3248, -2331, -4564, 937, -3603, -4689, -1848, -5570, -114, -4942, -6652, -1041, -8989, -1444, -4558, -4670, -768, -8841, -1623, -2698, -3964, -1574, -4905, -1545, -2709, -3772, -1889, -3496, -2481, -4800, -3080, -487, -3199, -2491, -6607, -2057, -99, -3860, -956, -4339, -1413, -1421, -5906, -119, -5179, -1661, -4126, -6756, -18, -9412, -2886, -3466, -4567, -490, -4385, -3190, -3539, -4647, -1720, -3269, -2601, -6575, -8530, -4143, -4104, -3705, -7531, -6789, -4666, -5399, -6984, -4920, -3645, -2381, -3745, -4689, -3534, -2175, -1047, -1526, -3752, -2596, -1387, -478, -439, -5222, -2893, -1772, -690, -638, -9504, -5060, -3742, -1752, -2606, -5450, -5338, -4699, -3223, -8253, -2526, -2665, -3154, -3203, -3882, -1171, -1418, -2852, -1799, -2719, -769, -956, -3830, -592, -3001, -893, -876, -6593, -122, -2411, -1366, -712, -6676, -453, -1599, -2241, -174, -5179, -1158, -1393, -3593, 190, -8457, -1606, -1738, -5732, -191, -5409, -1791, -2832, -8734, -1571, -1648, -1687, -4201, -8852, -4170, -527, -1602, -4051, -5823, -9139, -730, -1987, -3716, -3907, -11209, -1602, -2843, -3955, -3356, -8787, -2174, -3993, -4651, -3786, -10514, -2840, -4097, -4885, -5179, -7967, -4623, -2429, -3972, -9638, -4419, -2540, -1185, -3861, -8437, -2446, -244, -882, -5374, 2071, 5274, 358, 3097, 2901, 3087, 5290, 179, 2440, 4240, 4286, 5227, 2071, 2279, 5543, 4640, 4868, 3722, 3871, 5615, 4256, 4036, 3915, 4598, 4038, 3599, 2603, 2792, 4107, -820, 2694, 333, 669, 2386, 1352, 545, -2228, -1132, -297, 2616, -4617, 66, -478, 928, 1899, -3609, 2059, 1131, 3144, 3561, -2802, 2953, 1802, 4341, 5646, 176, 3275, 1193, 4703, 6660, 1689, 3389, -406, 4168, 6646, 1494, 3245, -202, 2362, 5312, 546, 2550, 672, -1315, 1314, 539, 1039, 99, -305, -1380, 537, -1736, -2001, 1107, 2170, -629, -4142, -3126, 824, 2788, -3120, -323, -1983, -1179, 3342, -5279, 1431, -1203, -15504, 3500, -8644, 1589, -289, -1264, 2896, -1443, 1085, 870, 683, 1977, 1646, 1753, 1766, 762, 1584, 2523, 2441, 2014, -410, 1828, 1733, 2143, 1665, -2458, 1779, -580, 1122, 1333, -2289, 443, -2330, -694, 1141, -851, -5301, -1406, -4307, 201, -240, -704, -1220, -1759, -349, -231, 1902, -3224, -1091, 1012, -494, 2122, -3760, -3942, 1430, -685, 606, -911, -2434, 572, -741, -1792, -827, 187, -959, -812, -1344, -3080, 1182, -2765, -1219, -396, -2854, 1454, -6097, -2278, 349, -346, 984, -5858, -1832, 586, 208, 185, -3048, -159, 35, -1482, 5, -482, 323, -1365, -9304, -245, 965, -492, -2805, -809, -578, 1008, -2378, -2286, 462, 348, 162, -3310, -1562, -1082, 1163, 61, -1521, -886, -10256, 1089, 201, -321, -304, -1749, 651, -802, -186, -472, -786, 487, -3197, -700, -1998, -2250, 30, -5741, -1330, -5332, -5894, -1304, -5224, -2301, -5321, -7508, -3500, -4848, -4435, -5400, -4138, -5353, -5387, -4648, -5943, -2636, -4929, -5749, -2260, -5960, -2548, -4522, -5910, -1570, -11322, -3391, -4287, -4582, -2262, -5475, -4224, -5056, -2469, -3304, -3208, -5285, -15497, -1671, -2481, -3233, -7761, -3302, -2240, -1290, -4304, -7305, -748, -3313, -959, -4685, -8587, -138, -2873, -1691, -5040, -9775, -750, -2175, -3745, -8771, -4605, -2461, -1900, -7811, -6671, -3613, -5205, -1659, -16669, -3382, -4566, -5873, -1742, -7431, -2962, -7979, -4609, -2757, -3770, -4067, -8369, -3708, -5023, -1628, -5470, -4799, -3005, -7284, -787, -4821, -3364, -3245, -8660, -1205, -3282, -2386, -5394, -21635, -2749, -3176, -1431, -9820, -6374, -4620, -5153, -994, -7799, -3404, -5608, -4621, -1549, -4089, -1986, -5269, -2318, -3083, -733, -1068, -3624, -1497, -3572, 905, -463, -2247, -1346, -2685, 1208, -663, -1894, -1327, -2314, 308, -1739, -2844, -1368, -2315, -1855, -2198, -5478, -1863, -2681, -4685, -2098, -9135, -3094, -4042, -6115, -3475, -7313, -4275, -7120, -11604, -4665, -5881, -3958, -4008, -5829, -2099, -5042, -3526, -1499, -3020, -955, -4614, -3889, -628, -2335, -978, -5090, -5198, -6693, -2397, -2436, -6940, 413, -3124, -1150, -1766, -4277, 569, -1716, -1089, -821, -3726, -133, -1335, -2118, -574, -4771, -1118, -1788, -4533, -1089, -6483, -1203, -3295, -7803, -1687, -7666, -782, -7035, -5120, -1532, -8367, -640, -8173, -3809, -1042, -5039, -758, -4992, -2834, -766, -2795, -1257, -4148, -1562, -1042, -1781, -2915, -3268, -924, -2126, -1678, -6465, -2094, -1358, -3889, -2569, -2978, -1369, -2705, -4702, -4670, -1376, -1192, -2399, -4298, -3541, -1823, -1405, -688, -4292, -1129, -4441, -1744, 165, -4909, -83, -8700, -2234, 64, -6111, -44, -5034, -3463, -1129, -8544, -933, -3916, -5216, -4297, -9496, -3055, -4060, -5058, -6889, -5530, -6880, -5043, -5511, -3563, -3947, -5509, -4620, -9826, -3077, -3703, -4110, -2473, -9109, -3073, -4321, -4340, -1237, -6172, -2252, -4721, -5560, -1206, -4919, -1714, -3427, -5315, -2540, -3081, -2010, -2043, -3547, -5688, -1806, -3034, -1653, -2336, -6185, -1448, -4324, -2606, -1612, -4627, -1750, -5049, -5608, -1617, -4301, -2017, -4837, -10434, -3121, -3926, -1761, -4320, -6408, -8827, -3809, -1742, -3933, -5517, -7753, -4951, -2753, -3445, -5975, -8179, -10358, -5800, -2992, -6739, -8190, -6338, -11959, -2968, -4780, -3609, -3461, -5121, -3250, -2908, -2881, -3423, -3601, -3812, -2465, -4197, -6068, -3341, -5352, -3239, -7876, -8982, -3038, -5348, -4535, -9111, -5954, -1789, -3284, -4922, -5043, -5908, -801, -2898, -4112, -2754, -6412, -731, -4210, -3444, -1365, -6418, -1557, -7601, -3078, -1010, -6761, -2828, -12376, -2903, -2004, -8207, -3801, -7601, -3812, -5223, -8936, -4466, -7246, -7516, -7407, -6897, -5080, -11590, -5389, -3402, -4261, -6361, -6756, -2689, -1936, -2229, -7673, -4149, -1919, -1751, -1495, -5312, -3567, -2082, -2883, -2053, -4058, -3840, -2715, -6105, -3758, -4086, -4213, -3681, -9655, -7278, -5025, -4966, -5049, -5135, -8523, -6913, -6019, -5251, -3028, -3299, -7882, -4942, -4176, -1766, -1731, -6423, -4198, -3960, -1243, -1617, -6221, -5419, -4669, -1382, -2249, -7777, -9966, -5818, -2018, -2800, -11253, -7221, -7299, -2961, -2481, -11771, -6067, -8673, -4298, -1633, -8038, -7159, -8733, -5798, -1147, -5952, -6394, -8592, -4579, -1465, -5627, -4546, -7981, -3215, -2877, -6026, -3884, -7634, -3317, -6058, -4868, -4166, -8562, -4982, -14775, -3836, -5090, -10727, -6290, -6773, -4127, -5961, -10665, -4646, -4232, -6169, -5847, -7353, -4010, -3031, -13470, -5311, -4702, -4576, -2828, -9168, -5029, -3332, -5408, -3340, -7328, -5208, -3058, -5153, -4181, -7644, -6256, -3696, -5304, -5532, -8713, -9250, -4765, -7600, -6878, -7966, -7504, -4952, -13402, -4994, -6511, -4579, -4783, -7267, -3893, -6276, -3691, -5962, -6824, -4245, -7964, -4287, -11713, -9145, -5564, -10924, -6544, -7722, -13292, -6756, -7277, -10999, -4536, -12303, -6903, -6011, -8762, -3384, -8783, -7266, -5094, -1758, 539, -1365, -4791, -4721, -2575, 280, -2241, -2165, -6321, -5738, -745, -3091, -1159, -8461, -5071, -2328, -3748, -1559, -5463, -2303, -4316, -4237, -2643, -4484, -1084, -7260, -4257, -2386, -5808, -502, -9351, -3275, -2278, -5282, -685, -5953, -2327, -4449, -2162, -2211, -4664, -2235, -11079, -874, -6058, -3890, -3257, -3600, -1054, -5523, -3336, -5205, -2252, -3012, -4600, -3611, -4839, -2429, -12304, -6370, -4213, -3251, -3541, -3974, -8535, -3213, -2980, -5442, -2141, -8424, -1759, -4405, -5868, -2593, -9943, -955, -5322, -4002, -5310, -10303, -894, -3296, -3313, -9276, -8628, -1514, -3113, -4392, -6355, -6785, -2784, -5316, -8109, -6109, -6047, -4949, -6070, -7465, -6936, -5086, -6889, -2832, -7369, -6030, -3774, -4208, -1253, -8404, -3820, -3682, -2389, -679, -3868, -2504, -5052, -2034, -1099, -1895, -2037, -4638, -3185, -3038, -868, -2173, -2866, -6430, -9804, -424, -2733, -2356, -7989, -5663, -811, -3507, -2854, -5952, -4975, -1880, -4178, -3808, -6414, -5351, -2707, -4521, -4528, -8718, -2235, -4135, -4597, -4677, -8254, -804, -6268, -4446, -3836, -9373, -640, -2699, -4008, -2669, -9369, -1061, -1315, -3832, -2167, -3958, -1699, -1593, -4476, -2625, -2028, -2486, -3115, -4525, -4117, -1429, -3197, -5245, -3167, -6147, -1533, -3729, -5266, -2557, -5763, -2090, -4646, -4320, -2833, -3939, -3538, -6731, -4405, -3527, -2938, -8177, -7466, -5799, -4107, -3175, -6661, -4212, -7763, -3838, -5107, -3701, -2595, -6778, -3437, -9132, -3471, -2411, -6444, -3854, -5967, -4620, -3650, -7721, -4753, -4224, -4841, -6932, -4576, -5572, -3361, -3391, -7439, -2177, -7651, -2442, -2727, -4821, -1431, -15264, -1812, -3167, -3935, -2009, -9428, -2125, -4544, -3858, -4016, -8822, -3363, -6455, -4417, -8595, -10716, -3291, -9719, -6556, -7831, -9129, -2689, -14961, -11897, -5334, -6140, -4082, -10302, -5638, -4772, -4843, -9858, -6458, -4837, -4478, -4410, -4187, -4183, -5874, -3020, -4188, -2493, -3906, -4757, -1700, -4013, -2692, -5375, -4042, -1573, -4192, -4489, -7997, -4416, -3228, -4402, -8039, -8710, -3564, -6046, -3384, -5108, -7259, -3197, -3036, -2377, -2994, -7188, -4405, -1827, -2444, -2195, -9858, -5077, -1842, -3757, -2257, -9107, -4206, -2181, -6015, -3182, -8494, -4305, -2950, -6589, -4508, -13431, -5429, -4654, -6104, -3609, -6191, -7352, -4738, -6426, -2113, -4235, -6788, -3346, -7461, -1490, -4282, -4553, -3139, -9259, -1646, -5598, -2930, -3924, -11458, -2406, -7733, -2064, -5018, -10187, -3546, -10919, -2177, -5494, -8587, -4725, -11695, -3399, -5475, -7729, -5695, -6528, -5951, -5992, -7138, -6525, -4372, -11951, -6613, -5776, -6964, -4011, -9602, -4965, -4208, -6534, -5737, -7235, -3685, -3411, -5973, -14497, -7473, -3750, -3294, -5934, -5699, -9083, -5165, -3318, -6469, -4112, -8797, -8091, -3206, -7289, -4758, -7385, -13164, -983, -2618, -1430, -6237, -6901, -2444, -3226, -1698, -4829, -7651, -3930, -3933, -2127, -4045, -9454, -3907, -4364, -3061, -5928, -9154, -4016, -4725, -3306, -10267, -6507, -4147, -6880, -2790, -3706, -5966, -4041, -8154, -2811, -1877, -6466, -3886, -4459, -2223, -1488, -7046, -3697, -2987, -1109, -2058, -7563, -3708, -2432, -971, -3695, -8193, -2804, -2787, -2060, -8280, -9323, -1595, -4177, -3683, -6437, -12501, -1280, -6059, -3919, -2800, -11453, -1949, -6527, -3085, -1425, -9891, -3501, -3659, -2804, -1343, -11028, -5985, -1959, -4378, -2792, -6076, -9615, -1845, -9014, -5251, -3560, -11352, -3228, -4238, -3017, -2309, -8728, -5041, -3193, -1803, -1228, -6368, -2893, -4937, -2003, -375, -5447, -749, -9557, -3031, -201, -5586, 505, -3438, -4368, -737, -5887, 1022, -1503, -5542, -1723, -6895, 933, -961, -7023, -2900, -11516, 625, -1297, -12475, -4248, -9750, 605, -2522, -7218, -5872, -6866, 534, -4454, -4463, -8378, -6013, -297, -4135, -4382, -14230, -4859, -2286, -2914, -7407, -9845, -3623, -4097, -2763, -5304, -9005, -3696, -2495, -3462, -2115, -8544, -5963, -1348, -3882, -987, -4457, -7470, -1439, -3310, -899, -2184, -5336, -2739, -3180, -1397, -1390, -5633, -3845, -4027, -2116, -1766, -6484, -3335, -5731, -2782, -2970, -5438, -3612, -7501, -3358, -3969, -4071, -5267, -6485, -3966, -4561, -2938, -8219, -4049, -4750, -6253, -2217, -9780, -2429, -5805, -7919, -1982, -7617, -1792, -7054, -5938, -2146, -6167, -1846, -8343, -5433, -2438, -5843, -1846, -9650, -6905, -2410, -7158, -1193, -9534, -10417, -2000, -12900, -399, -6743, -7047, -1744, -7605, -143, -4190, -4915, -2287, -4745, -836, -2500, -4223, -4594, -3315, -2877, -1744, -4608, -11793, -2157, -6722, -1960, -6021, -5013, -913, -6898, -3122, -7735, -3919, -49, -4869, -4548, -7977, -4797, 55, -4032, -4615, -6303, -6967, -623, -4596, -4538, -4574, -7977, -1834, -6415, -4690, -4360, -7051, -2900, -7709, -3442, -6105, -5977, -3239, -7452, -2039, -4954, -4467, -3367, -4470, -1369, -2568, -3856, -3578, -2824, -1408, -2082, -5095, -3258, -2876, -2106, -3241, -9538, -3047, -4457, -3370, -6342, -6241, -4427, -7243, -4289, -10023, -5125, -7772, -8947, -3484, -8418, -7120, -5262, -7066, -2664, -8736, -10187, -4987, -4961, -2399, -13039, -5705, -7055, -3659, -2047, -8617, -4646, -5492, -3211, -1724, -6067, -4670, -3438, -3741, -2229, -5475, -3997, -2771, -5357, -4129, -5380, -3021, -3085, -7386, -7047, -5142, -2896, -3938, -7699, -6699, -4483, -3973, -5248, -8577, -6873, -3673, -6820, -8722, -9155, -7596, -3153, -15415, -11084, -7236, -7217, -2845, -10475, -6924, -7289, -7188, -2861, -10334, -6502, -11166, -7858, -3324, -9201, -5974, -8784, -9039, -3723, -6916, -4568, -5916, -8996, -3705, -6047, -3705, -5480, -8428, -3879, -6029, -3437, -5810, -8973, -4596, -5666, -3464, -5546, -8858, -5801, -5238, 15165, 2220, 10293, 9886, 8359, 14767, 5638, 9599, 9189, 10163, 13535, 6920, 7288, 6853, 10144, 11358, 6285, 2129, 1303, 9299, 8385, 4271, 475, 1013, 8251, 7587, 1764, 688, 1984, 6512, 8553, 128, -249, -611, 3759, 8828, -867, 256, -6937, 5346, 8283, -328, -509, -264, 6056, 6842, 1506, 1386, 1412, 4279, 4689, 3435, 3697, 2469, -3939, 3292, 4896, 4869, 3037, 1643, 3547, 5663, 5200, 3137, 1847, 4912, 5548, 4834, 2720, -1288, 5655, 4299, 3914, 1229, -7067, 4971, 1763, 2803, -2426, -3092, 2336, 631, 1807, -2942, -2819, -836, 1185, 836, -1536, -5055, 1715, 493, 50, -1759, -1808, 2202, -1063, -527, -2432, -664, 1002, -2089, -1745, -6010, -296, -2271, -1179, -4133, -3901, 1201, -5958, -318, -3961, -898, 2363, -3331, -739, -3644, -745, 2815, -2835, -2475, -6246, -1696, 2777, -3418, -2199, -6704, -874, 2129, -6288, -653, -4689, -13, 121, -6716, -278, -5560, -415, -8130, -1474, -1032, -5326, -1839, -1879, 429, -3153, -3739, -3077, -201, 1026, -7811, -3606, -2202, -740, 728, -17050, -3349, -857, -1628, -260, -9764, -3061, -223, -1872, -1284, -5219, -3867, -554, -3348, -1211, -3364, -4911, -2136, -5185, -949, -3196, -6153, -3803, -4069, -1546, -4273, -11220, -2293, -5814, -3211, -5874, -9225, -1543, -7654, -4453, -6492, -8702, -2022, -3445, -3538, -5984, -11835, -3137, -2778, -3033, -5314, -7909, -4071, -3630, -3184, -5341, -5343, -5856, -4960, -3531, -6565, -3590, -10830, -5853, -3938, -7846, -2905, -4797, -4374, -4549, -6669, -3654, -3344, -2147, -5170, -6659, -4874, -3849, -841, -5242, -9633, -3131, -5622, -363, -4773, -11108, -1937, -7477, -427, -4271, -6912, -1979, -7271, -877, -4149, -5375, -2753, -6536, -2024, -4627, -4488, -3442, -6879, -4657, -5827, -4222, -3640, -8266, -9185, -7401, -4772, -4017, -8267, -7768, -7331, -6096, -5318, -6145, -7204, -6757, -7470, -8929, -4211, -6455, -7478, -7380, -8746, -2915, -6007, -11402, -6159, -5388, -2385, -5302, -10046, -4972, -4620, -2669, -4366, -5827, -4223, -5372, -3708, -4377, -4049, -3955, -7320, -5222, -5567, -3183, -4157, -10406, -6307, -7145, -2926, -4542, -15272, -5720, -7004, -3214, -4562, -9529, -5296, -6641, -4069, -4579, -8847, -6434, -8733, -5309, -5471, -11759, -9022, -9436, -6037, -8163, -10258, -7918, -3794, -5935, -12911, -7705, -6644, -1835, -5753, -8442, -7612, -6550, -1397, -5687, -7383, -8925, -7595, -2077, -5466, -7698, -9273, -9340, -3655, -5085, -7302, -8444, -9286, -6043, -5029, -5724, -8654, -9691, -11093, -5857, -4828, -10089, -13643, -10036, -7491, -4924, -11296, -12769, -6573, -5603, -5821, -10109, -9007, -5561, -4060, -7081, -9241, -7857, -5062, -4361, -8146, -8987, -7778, -4128, -6806, -9337, -8181, -8017, -3304, -13477, -9510, -6888, -7578, -3356, -8468, -7269, -6063, -7039, 8741, 3952, 6975, 8689, 7461, 7965, 4037, 6240, 8235, 7088, 5365, 3753, 3586, 6965, 5982, -709, 2291, -8624, 5319, 4748, -4470, -1068, 620, 4040, 4512, -2797, -1090, 558, 3121, 4183, -367, 1438, -3119, 1993, 3133, -592, 3228, -56, 84, 2502, -3397, 4205, 2057, -3665, 3187, -7182, 4323, 3214, -7878, 4075, 583, 4282, 4808, -2543, 4389, 3794, 4987, 6275, 193, 3820, 5394, 5719, 6925, 1546, 2253, 5734, 5810, 6541, 1361, -167, 4882, 5234, 4868, 613, -2154, 2816, 4206, 1450, 2241, -1280, 161, 2891, 1105, 3465, -94, -137, 982, 2355, 3369, -380, 154, -1515, 1786, 2095, -2752, -326, -166, -31, -185, -7063, -1308, 1459, -1995, -2564, -3374, -2490, 1997, -3375, -4284, -2141, -2608, 1926, -5535, -3928, -2394, -1395, 1648, -6430, -2423, -3605, -709, 1407, -5782, -3505, -4673, -1148, 1209, -7441, -5364, -4258, -3250, 862, -14465, -1560, -2896, -10573, 87, -6434, -360, -1859, -5823, -1257, -4715, -237, -1667, -3697, -2150, -4467, -520, -2329, -2695, -1664, -4289, -1902, -3308, -2223, -1493, -3401, -7242, -3745, -2694, -1736, -3402, -4590, -3741, -4302, -1632, -5902, -1390, -3761, -6770, -1434, -5788, -121, -3823, -8089, -1653, -3119, 547, -3750, -5731, -2427, -3391, 832, -4036, -3416, -3804, -6366, 572, -5602, -2191, -5673, -6006, -681, -10616, -1883, -7549, -4492, -4344, -8372, -2417, -7063, -5091, -6680, -6508, -3977, -5308, -5015, -2084, -6696, -7297, -4537, -3235, -970, -5048, -11384, -4676, -2338, -1043, -3625, -6729, -5139, -2746, -1931, -4086, -4856, -6156, -4940, -3320, -7477, -4850, -11532, -9552, -4050, -10210, -7748, -6825, -6017, -2984, -5601, -10312, -3707, -5121, -1871, -4374, -5851, -3115, -5930, -1696, -4228, -5661, -4027, -6161, -2534, -4901, -7737, -4717, -5627, -4341, -5874, -10902, -3761, -6915, -7455, -6447, -7895, -3654, -18720, -13483, -6889, -6565, -5180, -7222, -9348, -7138, -6865, -9112, -5547, -8639, -6701, -8530, -8968, -6065, -11853, -6201, -8321, -7126, -7279, -10446, -6732, -6220, -6626, -6673, -6152, -9638, -4512, -6631, -6094, -4599, -9879, -3458, -7760, -6785, -4192, -6707, -3481, -12012, -8925, -4470, -6211, -4762, -10526, -11451, -5108, -7719, -7049, -7306, -11076, -5739, -13789, -8367, -6461, -9835, -5993, -8478, -7185, -7141, -8315, -5675, -5652, -6084, -9976, -7564, -5021, -4584, -6254, -17176, -7346, -4589, -4718, -7559, -9942, -7128, -4647, -6373, -9423, -8840, -7063, -4976, -12287, -15035, -9816, -7145, -5328, -7967, -9515, -11203, -6917, -5561, -4906, -6676, -8212, -6556, -4962, -3648, -6157, -6806, -6157, -4169, -3571, -6516, -7052, -5704, -4041, -4950, -6261, -8524, -5911, -4554, -8975, -5784, -10226, -7143, -5486, -8860, -5819, -10541, -7835, -6689, -7483, -6120, -10127, -7749, -7490, -9826, -6313, -10173, -9714, -7104, -11192, 4458, 2870, 7118, 7575, -11243, 3348, 1685, 6636, 7254, -4944, -609, -1185, 5416, 6456, -1588, -1007, 1479, 4418, 5674, 1846, -1635, 2980, 4191, 5048, 4140, -5635, 3251, 3899, 4070, 5286, -975, 2726, 3097, 2906, 5483, -3298, 1238, 1617, 2440, 4715, -1532, -1686, -609, 1671, 2256, 3037, -3160, -3006, -1311, -3579, 5003, 1111, -937, -2107, 2997, 5863, 4373, 1221, 1334, 4453, 5773, 5938, 1434, 2093, 3956, 4642, 5925, -301, 2054, 2136, 2482, 4000, 794, 3022, 2635, 1047, -3405, 2476, 3858, 4138, 880, 467, 2019, 3438, 4503, -16, 1300, -669, 1587, 4082, -466, -1437, -4634, -1483, 3305, -533, -8420, -6667, -6500, 2350, -889, -2601, -5765, -5648, 864, -804, -2077, -1985, -2407, -1520, -198, -1745, -1615, -1994, -1470, 346, -1230, -3470, -2001, -12, 236, -1557, -10862, -1871, 353, -839, -2868, -6024, -2304, -86, -3463, -4276, -3767, -3760, -1369, -9859, -4134, -3319, -5611, -3591, -4525, -3073, -3684, -3931, -4325, -3927, -2727, -4850, -3074, -2305, -7892, -3983, -7513, -5005, -645, -4649, -6189, -13061, -6612, -176, -1450, -2832, -12060, -2315, -1227, -694, -1063, -7551, -1224, -4165, -1451, -781, -4934, -1604, -4534, -3464, -1419, -4606, -2728, -3025, -4085, -2318, -5605, -3903, -2358, -3239, -3209, -5515, -5165, -1846, -3741, -4852, -5936, -7169, -2057, -5461, -7091, -9465, -8962, -3333, -6245, -6562, -7129, -9671, -4477, -6273, -6751, -5552, -11221, -3905, -7579, -9701, -7571, -6112, -4143, -9314, -11239, -9671, -3291, -6937, -9167, -8239, -4276, -1935, -9456, -8446, -5746, -2875, -1615, -5504, -7196, -4037, -2975, -2231, -6170, -5945, -3717, -3918, -3490, -11158, -4926, -4759, -4549, -3561, -4858, -4167, -5523, -4314, -2564, -3533, -3755, -4182, -4855, -2477, -4788, -3605, -3583, -8525, -3652, -11478, -3554, -4205, -6096, -5556, -7369, -3680, -5724, -2706, -6369, -5545, -4411, -7552, -1721, -6916, -6312, -6501, -9040, -2130, -7502, -9788, -11790, -7529, -3799, -6730, -11512, -10105, -6241, -7233, -5022, -7393, -9046, -6171, -8237, -3758, -6358, -8040, -7227, -5758, -3342, -6662, -6714, -10113, -5566, -3729, -8050, -6617, -7486, -7133, -4795, -10028, -7793, -5152, -9578, -6239, -9313, -9877, -4713, -9609, -7260, -7252, -11532, -5531, -9312, -8461, -5703, -11067, -7127, -9298, -11221, -5150, -9746, -8573, -9261, -7140, -6157, -8772, -8980, -9628, -4919, -11494, -8258, -8132, -10059, -4307, -7427, -8265, -6819, -8427, -4611, -4321, -8843, -6113, -6823, -4983, -3504, -9175, -6057, -6212, -4853, -3996, -8911, -5606, -6328, -5217, -5402, -9312, -4622, -7036, -6732, -7241, -10592, -4093, -8669, -7196, -8304, -10786, -4047, -11327, -6214, -7631, -8903, -4054, -8959, -6600, -8118, -8014, -3898, -6536, -8753, -12148, -8668, -3674, -5627, -9694, -9457, -10135, -3660, -6112, -7095, -7659, -4829, -7102, -6498, -5768, -7102, -6936, -6734, -7755, -5765, -7561, -4010, -6378, -10869, -5938, -7981, -2349, -6027, -9615, -5920, -8148, -2201, -6023, -9381, -5366, -7391, -3445, -6148, -9821, -4920, -5938, -6092, -5824, -8314, -5159, -5012, -5167, -5281, -8243, -6280, -5023, -3392, -4739, -11745, -8310, -6182, -3030, -4111, -11193, -10530, -9371, -3623, -3622, -7625, -10460, -15111, -4370, -3745, -6713, -8825, -9433, -4118, -4924, -6975, -8062, -9147, -3587, -7154, -9096, -8549, -11286, -3679, -7569, -12180, -8767, -15624, -4455, -6400, -7286, -7822, -10345, -5084, -4614, -4905, -9334, -7582, -4162, -2134, -2845, -6630, -3609, -2167, -17, -740, -1735, -452, -502, 1187, 862, 480, 1284, 214, 1356, 1522, 1168, 1752, -121, 484, 1039, 556, 972, -1504, -1278, -845, -1431, -1274, -3916, -3357, -4865, -5202, -5812, -7535, -5205, -8171, -12697, -8842, -10191, -6426, -6474, -10853, -7187, -8928, -6003, -6521, -7274, -6582, -9937, -5139, -7692, -6007, -6221, -12284, -5021, -11105, -5926, -5930, -9419, -6087, -10641, -6514, -5528, -7850, -8223, -8236, -7463, -5493, -7054, -9559, -7551, -8722, -6216, -6346, -8339, -8193, -10419, -7790, -6011, -6303, -10805, -11837, -9272, -6640, -4770, -9711, -11618, -9646, -9355, -4113, -7521, -11748, -11232, -9333, -4237, -7380, -13581, -16033, -5474, -4666, -8751, -16529, -14081, -4155, -4990, -11089, -10811, -10738, -4401, -5478, -11609, -8690, -8725, -5911, -6111, -9299, -8324, -8702, -6955, -6697, -7727, -9391, -11741, -6187, -8326, -7471, -11304, -13708, -5902, -16418, -8593, -8898, -9336, -6526, -8725, -11389, -6642, -8172, -7757, -6779, -15746, -5817, -7703, -7228, -7294, -15452, -6349, -7830, -5863, -10127, -14359, -8933, -9199, -5960, -13144, -13676, -12484, -12232, -8559, -10365, -13134, -8452, -10297, -12472, -8164, -12280, -8102, -9018, -8343, -7143, -11929, -10335, -9879, -9266, -7373, -13421, -14360, -10807, -12668, -8397, -14255, -10952, -8965, -8240, -9241, -9871, -10460, -7929, -7171, -9145, -8414, -11568, -7746, -7378, -8297, -8713, -11369, -7947, -6951, -7257, -9695, -10045, -8383, -5811, -6687, -9494, -9430, -8879, -4912, -7073, -9061, -8905, -9013, -4489, -8822, -8683, -8541, -8780, -4744, -10384, -8191, -8858, -8695, -6062, -8407, -8082, -9874, -9036, -9017, -7240, -8356, -11460, -9588, -8399, -6772, -8776, -14374, -9760, -6181, -6490, -9244, -12994, -9444, -5628, -6383, -9540, -9428, -9244, -6381, -6598, -9933, -7944, -9549, -8644, -6929, -11073, -8064, -10229, -13556, -7220, -13279, -10255, -10962, -15329, -7872, -12613, -25624, -11789, -13159, -9007, -9435, -12071, -12529, -9989, -9948, -7981, -11921, -12561, -7856, -9965, -8073, -14185, -12093, -6894, -9528, -9832, -11276, -11549, -6884, -9140, -13116, -9690, -11024, -7704, -8890, -12101, -9682, -10647, -8939, -8893, -11875, -10968, -10730, -9519, -9104, -13947, -13496, -11562, -9776, -9449, -13752, -11391, -13395, -6389, -9624, -16465, -6442, -7466, -6840, -8839, -10579, -6320, -6329, -8537, -9431, -11509, -6801, -5775, -12776, -11379, -15505, -7008, -5151, -9260, -9727, -9754, -6292, -4510, -7001, -7445, -9310, -5955, -4042, -6402, -6402, -11807, -6881, -3903, -7043, -6345, -13333, -10060, -4227, -9048, -7133, -11438, -15372, -5080, -11930, -8676, -8836, -9456, -6219, -8870, -8569, -6909, -7821, -6827, -6598, -6804, -6603, -7425, -6689, -6119, -6132, -7994, -8306, -6495, -7395, -6363, -12395, -10567, -6375, -10852, -6267, -12735, -12963, -6237, -13169, -5422, -8806, -12784, -6011, -8836, -5921, -9344, -7571, -5404, -4695, -11035, -7611, -3635, -3964, -1767, -2650, -2313, -810, -1627, -153, 156, 10, 820, 120, 134, 1037, 737, 1271, 736, -1071, 492, 190, 517, 160, -4510, -1503, -1532, -1610, -1669, -11587, -5463, -4267, -5254, -4741, -8280, -15162, -7212, -6867, -7758, -8927, -12272, -8991, -6882, -7694, -6603, -11110, -9255, -7925, -6672, -4942, -10171, -7343, -9089, -6634, -4274, -9386, -6059, -9577, -6845, -4610, -9093, -6397, -9470, -6499, -6164, -9931, -8640, -9571, -6537, -7640, -13149, -9624, -10646, -7687, -7070, -15768, -7213, -14142, -10798, -7979, -13044, -6278, -11236, -14927, -12957, -15540, -6364, -7963, -10746, -7243, -13890, -7234, -6878, -9893, -5107, -9341, -8881, -7192, -11066, -4954, -7535, -11376, -8430, -12321, -6650, -6869, -15032, -9283, -9100, -14197, -6967, -15599, -7797, -8152, -8514, -7974, -11753, -5950, -9176, -6387, -10935, -9870, -5311, -10894, -6324, -16341, -9195, -6390, -11663, -7128, -10019, -9261, -11025, -11791, -7568, -9002, -9379, -8652, -9165, -7394, -9352, -8714, -6234, -8158, -7802, -9070, -7488, -5989, -9042, -9344, -8042, -6586, -6864, -12293, -10880, -7590, -6404, -8422, -10823, -10168, -7802, -6856, -9588, -7647, -9961, -8530, -7155, -9057, -6166, -11078, -9897, -6731, -8667, -5798, -14226, -12170, -6542, -9721, -6427, -16335, -13202, -7267, -13399, -7961, -11308, -11535, -9159, -17204, -9854, -9240, -10689, -11900, -12876, -11019, -8235, -11085, -12564, -9966, -10665, -7782, -13555, -11505, -8935, -8942, -7669, -14441, -11151, -10175, -7768, -7950, -10255, -12934, -12839, -7580, -8995, -8485, -17870, -11892, -7973, -12074, -7532, -11100, -16350, -7935, -14477, -6916, -9097, -11120, -7431, -9535, -6860, -8405, -8211, -7274, -8373, -7644, -8478, -8013, -7825, -8867, -8892, -9286, -9248, -9057, -10672, -9452, -11033, -9892, -10176, -13720, -10212, -14444, -9741, -10905, -15857, -11506, -18255, -10059, -11254, -11994, -10817, -13174, -10355, -11549, -10362, -10549, -10748, -10769, -14835, -10895, -11818, -9494, -11104, -12061, -14763, -13702, -9219, -11137, -9622, -10427, -15396, -9879, -11703, -9868, -7912, -13792, -11483, -13580, -11679, -7388, -10885, -13456, -23639, -12058, -8362, -9625, -13018, -12653, -11652, -11247, -9247, -11012, -10383, -11355, -17928, -9261, -9521, -10202, -11240, -15208, -9977, -9045, -11615, -12414, -10114, -3970, -8334, -5869, -8970, -9229, -4310, -13488, -5688, -9313, -7789, -4518, -13098, -6176, -6320, -6221, -4871, -11503, -6972, -5298, -5173, -5314, -10167, -8163, -5540, -4841, -5239, -10524, -10875, -6467, -5194, -4537, -9662, -12428, -7536, -6002, -3813, -6677, -8850, -8483, -6964, -3407, -5263, -6918, -9347, -8347, -3453, -4954, -5744, -10223, -10946, -4005, -5209, -5377, -11445, -14886, -4655, -5733, -5939, -11334, -14268, -4448, -6726, -7298, -9502, -10389, -4105, -8853, -8121, -8992, -8542, -4941, -11153, -8126, -9763, -8478, -7911, -8585, -8538, -12136, -8421, -9635, -5953, -6932, -11206, -5318, -5835, -3192, -3692, -4885, -2082, -2022, -652, -966, -1735, -91, 56, 997, 624, -174, 646, 569, 1520, 996, 80, 193, -421, 798, 70, -999, -1448, -3357, -1397, -2473, -3820, -4221, -12012, -4667, -7935, -10437, -7136, -8222, -5044, -15169, -7808, -7900, -8154, -6085, -15738, -6267, -7565, -9659, -9547, -10544, -5693, -7656, -8504, -8180, -8827, -5122, -9644, -6047, -7165, -7995, -4756, -13342, -4937, -8674, -7220, -4943, -8547, -5094, -16086, -6744, -5605, -7958, -6338, -8025, -6950, -6103, -10312, -8173, -6047, -7703, -6154, -11872, -9040, -5874, -8139, -6608, -7372, -8626, -6821, -8573, -7953, -5926, -8458, -8241, -10022, -9390, -6105, -9443, -8828, -12613, -9850, -7899, -11362, -8784, -12567, -12242, -10835, -9466, -9091, -9564, -11749, -9632, -7662, -9057, -7084, -8390, -8928, -7209, -7888, -5694, -8031, -9046, -7896, -7005, -5408, -10131, -8701, -9926, -7092, -6175, -15552, -8263, -14198, -8416, -7737, -10128, -7893, -19648, -12171, -8898, -8567, -6952, -12958, -14097, -9430, -8408, -5916, -8995, -10367, -11185, -9023, -5393, -7523, -10380, -13151, -10173, -5283, -8047, -13643, -9635, -11738, -5285, -10362, -15064, -7977, -12013, -5510, -7585, -10676, -7525, -10252, -6394, -5210, -9757, -7497, -9468, -8360, -4284, -10698, -7487, -10423, -11830, -4265, -12672, -7843, -14152, -16256, -4728, -11014, -8814, -10652, -14344, -5211, -9543, -10244, -8002, -10937, -5613, -8743, -13338, -7280, -9437, -6035, -8430, -14408, -8177, -8749, -6535, -8710, -9385, -11559, -7945, -7557, -9657, -7736, -17573, -7224, -8791, -12450, -7361, -12250, -7151, -7702, -15480, -7544, -10976, -7976, -6557, -10490, -7928, -9773, -9783, -6497, -9302, -9016, -9029, -12423, -7322, -9630, -11402, -8466, -14060, -8830, -10799, -12772, -8346, -11323, -11245, -10842, -13624, -9383, -9700, -15633, -10561, -14654, -11197, -9269, -11468, -10332, -10460, -10194, -8898, -9169, -8613, -8676, -9056, -8087, -8695, -7213, -8226, -8841, -7587, -9421, -6443, -8782, -9153, -8005, -10086, -6048, -10301, -9820, -9972, -9947, -6109, -12165, -10936, -15691, -10654, -6898, -12113, -13707, -12451, -12240, -8843, -11489, -16271, -10362, -10891, -13140, -11680, -10329, -9403, -9133, -14873, -12631, -8537, -8669, -8325, -13261, -13581, -8354, -8244, -8241, -15671, -13412, -9423, 8813, 10397, 10659, 8490, 6718, 8016, 9942, 10005, 7905, 6152, 5336, 8532, 7937, 6131, 4406, 2646, 6102, 4708, 3216, 1406, 3898, 3039, 3748, -79, -1617, 3079, 1561, 2902, -2100, -2952, 1341, 2545, 195, -3053, -11033, 2008, 3509, -1404, -1508, 91, 3027, 3571, -1222, 373, 2781, 2993, 2556, -2068, 1033, 3773, 1180, -249, -3393, 1549, 3892, -1764, -2551, -5508, 3372, 3544, -603, 2574, -5315, 4896, 2781, -1798, 4386, -3700, 5320, 1226, -148, 4572, -3826, 4542, -1227, 1932, 3323, -4813, 2329, 722, 1888, 248, -3533, -2016, 2718, -179, -2923, -978, -4124, 3098, -7186, -240, 829, -3245, 2120, -3145, 966, 1626, -3372, 108, -941, 1235, 1246, -2906, -3208, -446, 1013, -730, -2199, -3670, -1099, 775, -5065, -1910, 888, -3410, 562, -3306, -711, 1797, -3112, -131, -1919, 646, 210, -1290, -1860, -506, 648, -8568, -1965, -5820, 1012, -1470, -2090, -1702, -7525, 1603, -13126, -1030, -82, -2749, 1247, -2015, -1730, -1340, -1634, 414, -49, -693, -8504, -2743, -122, 377, 1062, -158, -7438, -409, -30, 1753, 991, -4883, -600, -115, 826, 387, -4172, -381, 605, -3979, -874, -6606, -627, 1205, -1725, -2647, -4240, -2689, 1415, 1168, -7682, -3140, -14648, 1137, 1515, -4479, -2758, -2630, 193, 427, -1744, -839, -862, -819, -2238, -1687, 103, -714, -218, -9737, -3465, -557, -1492, 439, -5712, -4673, -1832, -2782, 106, -4317, -3455, -177, -3986, -1112, -3988, -2608, 1099, -5197, -2516, -2516, -2493, 964, -5540, -3544, -1251, -3593, -604, -3070, -5482, -744, -7616, -3978, -1337, -12462, -1125, -7786, -8380, -742, -8535, -2774, -4063, -11811, -1018, -7103, -5773, -3582, -5192, -1771, -6211, -6737, -4687, -2416, -2447, -3962, -9365, -5494, -1557, -2921, -2362, -8857, -3950, -1830, -3256, -1536, -4470, -3112, -2783, -2844, -1492, -2905, -3625, -3987, -1998, -2360, -2419, -5022, -5214, -1659, -4169, -2912, -6536, -5247, -2094, -6068, -4404, -12883, -4173, -3040, -5744, -6282, -6009, -3920, -3782, -4821, -8265, -3423, -4906, -4196, -4536, -11284, -3433, -6995, -4462, -4385, -7178, -6038, -8637, -4578, -3974, -5469, -12730, -7578, -4933, -3589, -5236, -6031, -5920, -5391, -3457, -5734, -5707, -5407, -5162, -3782, -6514, -8844, -6256, -4151, -4442, -7372, -9864, -8398, -3579, -5075, -8072, -5520, -11035, -4064, -5974, -7418, -4383, -9173, -5413, -7400, -6295, -4422, -7142, -6321, -8876, -5980, -5285, -6607, -6100, -9986, -6726, -6866, -7026, -5898, -9719, -9170, -9123, -7579, -6793, -8407, -14646, -18011, -8116, -10370, -8259, -10472, -8183, -8928, -11228, -11437, -10430, -5390, -8883, -8491, -7834, -9696, -4587, -7441, -8322, -4980, -7794, -5017, -6123, -8598, -4332, -6821, -6314, -5720, -8598, -4967, -5271, -8158, -6420, -8336, -6520, -3875, -5633, 5939, 7498, 3816, -4110, -683, 4949, 6931, 3325, -2868, 505, 1173, 5324, 1999, -103, -833, 276, 3248, -27, 688, -4897, 2082, 1688, -1912, -381, -3131, 840, -120, -967, -2153, -1680, 262, -8665, -1243, -4695, -1078, 2055, 581, -249, -3880, -118, 2793, 3291, 1934, -1310, 732, 2875, 4391, 2177, -864, 1025, 2300, 4922, -22, 1560, 741, 209, 5020, 664, 3346, 174, -5471, 4348, 3231, 3735, -310, 664, 2497, 3428, 3167, -723, 2976, -596, 1225, 2238, -952, 3683, -853, -10966, 1769, -404, 3105, 129, 580, 2038, 690, 982, 575, 1900, 2110, 1487, -2467, 895, 1792, 1323, 1460, -1122, 695, 1478, -612, 98, -272, -430, 1702, -4604, -3266, -769, -1265, 2188, -9726, -3476, -2752, -435, 2395, -4439, -2936, -3515, -479, 2059, -3641, -4340, -1159, -2214, 1049, -3233, -5523, -933, -5408, -557, -1956, -6331, -3005, -3736, -2091, -1428, -5164, -7148, -1484, -2616, -2569, -6325, -3510, -129, -2039, -5926, -8524, -1105, 286, -1427, -4879, -3383, 539, -554, -1496, -3624, -1878, 1532, -3859, -1822, -4389, -1500, 1812, -6993, -1536, -6968, -1613, 1247, -2806, -1111, -12036, -2403, -315, -3363, -1365, -10198, -5101, -3183, -6179, -2557, -4521, -3642, -10706, -2277, -4067, -1316, -846, -6087, -392, -4254, 2, -513, -3761, -8, -2085, -262, -2486, -3954, -700, 279, -1985, -7065, -7600, -2532, 1410, -3414, -3956, -5137, -6374, 1188, -3260, -3883, -1687, -7568, -775, -4153, -3148, -403, -4011, -7901, -6251, -1121, 12, -2929, -3366, -9076, -538, -175, -3405, -1694, -10890, -1364, -1269, -5414, -2133, -11695, -3369, -3862, -4455, -3469, -13321, -5873, -5912, -2569, -4727, -12900, -7660, -4463, -2150, -5530, -10061, -6325, -4875, -2331, -6140, -8754, -5603, -6225, -2366, -6844, -9310, -7169, -6174, -2398, -8265, -8591, -9419, -5748, -2759, -11208, -6633, -8630, -4414, -3587, -6956, -6090, -11112, -3346, -4689, -5276, -6994, -12638, -3257, -5399, -6281, -8506, -7850, -3844, -4581, -12244, -8998, -5467, -4606, -3000, -7437, -11024, -3982, -5235, -2214, -5741, -14559, -3415, -5922, -2329, -5662, -8330, -3771, -7270, -2936, -5776, -6914, -5191, -9555, -3375, -5683, -7191, -8282, -11319, -2918, -5387, -8629, -11193, -14322, -1951, -4908, -10776, -7617, -10083, -1392, -4472, -11289, -6296, -7170, -1536, -4382, -8472, -6262, -6463, -2432, -4708, -6520, -7024, -7264, -4142, -5191, -5795, -7500, -9399, -6018, -5687, -6166, -6950, -11079, -5344, -6695, -7335, -6520, -9568, -4151, -9366, -7915, -6668, -7892, -3664, -11859, -7509, -7343, -6626, -3604, -8203, -7554, -8792, -5775, -3673, -7738, -8497, -8781, -5335, -3895, -10352, -12172, -6126, -5371, -4573, -10832, -11214, -4691, -5896, -6076, -7233, -7274, -4370, -6438, -8981, -6794, -6313, -4781, -6075, -13189, -8392, -6425, -2794, -5014, 2094, 4062, 775, 920, -1146, 2417, 2589, 4936, 3051, 1403, 3034, -10342, 6765, 3262, 2457, 3411, 2193, 6895, 1430, 2447, 3277, 3251, 5772, -1085, 1645, 2595, 1631, 3600, 407, 163, 1554, 580, 1491, 38, -2249, 561, 2839, 709, 1250, -4808, -409, 3087, 963, 3247, -3035, -3537, 1405, 2691, 3955, 288, -2711, 1159, 3357, 3626, 2891, 2046, 2533, 2067, 2343, 4115, 3543, 1477, 434, -88, 3895, 3370, -3691, 2722, -1088, 1912, 1934, 1207, 3667, 520, -1062, 770, 2300, 4338, 568, 928, 733, 877, 5272, -1201, 1467, -155, -3759, 5542, -4377, 614, -2033, -7205, 4832, -1541, -509, -3463, -4153, 3246, 619, -614, -4077, -3923, 1866, 1284, 58, -3159, -5763, 2323, 970, 376, -1191, -9738, 2746, 571, -167, 163, -2991, 2090, 518, -1675, 606, -1285, -9, -5, -3919, -66, -1182, -4671, -1455, -6022, -2343, -1636, -6281, -3871, -8176, -6628, -825, -2241, -6933, -6604, -3550, 737, -1412, -7588, -3941, -1937, 1675, -2996, -5979, -3184, -1677, 1721, -5206, -4511, -3779, -2436, 861, -2233, -3094, -4685, -4646, -1042, -1167, -1844, -4323, -12324, -5943, -1999, -1198, -3691, -5630, -4199, -7219, -1373, -3991, -2125, -623, -4238, -1845, -4512, 48, 499, -2786, -1957, -3037, 1229, 646, -6367, -2558, -2054, 1263, 280, -2470, -2945, -2372, -233, -556, -172, -2081, -3973, -2944, -1700, -275, -2455, -10596, -1288, -1024, -2207, -5302, -4313, -725, 450, -5139, -15950, -1506, -2403, 849, -4575, -11619, -1381, -5521, 241, -3617, -10848, -3952, -4205, -629, -2762, -9008, -10166, -4152, -1251, -2646, -13814, -3670, -7243, -2545, -4078, -6141, -2909, -7624, -5308, -7177, -4140, -3531, -3071, -7346, -6519, -4223, -4333, -1660, -7726, -5860, -5727, -4502, -1749, -7183, -6056, -7503, -4412, -3281, -4656, -5271, -6772, -4827, -7504, -3650, -3645, -5648, -5674, -9299, -3597, -2461, -5263, -5178, -6334, -3368, -2197, -5509, -3935, -7568, -2920, -2855, -6093, -3293, -11061, -3300, -3975, -6699, -3216, -6724, -5529, -4297, -7015, -3670, -5820, -8424, -3813, -6821, -5098, -6949, -4491, -3662, -6529, -8867, -9136, -3331, -4482, -6795, -12447, -9999, -3576, -6464, -8371, -8162, -10053, -4297, -6243, -11225, -7268, -8150, -4944, -5010, -7377, -7233, -6136, -5842, -5271, -5335, -8012, -5435, -6803, -6653, -4850, -9710, -6171, -6797, -8058, -5448, -11619, -7080, -5864, -8252, -6766, -11448, -5552, -5293, -7839, -8005, -9893, -4396, -5711, -7421, -8020, -8635, -4153, -7208, -6681, -7290, -7992, -4352, -8804, -5837, -7035, -7624, -4365, -8369, -5335, -7635, -7078, -3812, -8074, -5399, -9177, -6562, -2998, -8894, -6445, -13334, -6483, -2447, -9350, -9490, -11962, -6895, -2528, -7762, -14601, -8024, -7449, -3536, -6936, -11336, -7346, -8039, -5960, -7576, -12136, -9686, -7937, -8472, -9287, -3496, -7503, -8433, -8897, -10383, -4426, -5678, -6649, -7783, -6855, -7695, -4832, -4747, -6722, -5148, -7399, -4425, -3662, -6695, -4683, -4367, -4128, -3404, -7448, -5218, -3807, -3883, -3796, -8240, -6667, -4906, -3967, -4597, -8482, -9104, -7851, -4858, -5533, -8476, -10049, -10036, -6751, -6587, -8181, -7837, -7628, -6463, -8581, -7612, -7054, -7060, -4725, -11410, -7441, -7732, -8435, -4225, -7490, -8598, -9807, -9328, -5025, -5693, -12061, -14319, -6423, -7758, -5131, -9252, -16790, -5234, -17193, -4865, -7176, -12803, -5477, -7934, -4707, -6494, -11724, -6881, -6387, -5316, -6151, -11360, -9805, -6221, -7437, -5109, -10351, -13271, -7217, -9062, -3882, -9080, -7205, -10676, -7973, -3569, -9486, -5212, -11092, -9780, -4564, -12814, -4973, -8225, -13128, -7084, -12401, -6159, -7772, -7994, -9596, -10001, -8795, -7764, -6861, -9734, -8743, -13018, -8587, -6936, -10458, -7666, -16832, -13248, -7464, -11157, -6865, -13350, -8835, -8364, -12259, -6464, -10412, -6063, -9754, -10762, -6847, -8698, -5100, -11149, -9803, -8488, -7883, -4924, -10474, -11642, -13066, -7668, -5416, -8495, -11305, -13263, -8182, -6834, -8020, -8702, -9646, -9635, -7661, -9712, -8259, -8472, -10820, -6223, -12439, -8311, -7929, -10802, -5712, -8917, -8296, -8237, -10867, -6521, -6645, -9213, -9927, -9922, -7500, -5195, -10675, -10293, -8680, -6508, -4594, -9877, -8656, -7971, -5540, -4911, -7628, -8495, -7962, -5331, -6144, -6128, -9506, -8988, -5546, -8410, -5828, -10408, -12057, -5777, -11265, -6702, -9785, -14430, -5836, -8674, -8660, -8797, -10904, -5568, -6489, -10644, -8964, -10424, -4712, -5601, -9813, -11439, -11621, -3802, -5747, -8579, -11469, -11915, -3544, -6736, -8169, -8615, -9917, -4222, -7571, -8891, -7903, -9164, -5899, -7390, -11613, -8061, -9634, -7748, -7776, -12381, -8261, -10773, -7733, -10101, -9310, -8382, -11118, -7290, -13743, -8720, -8758, -9523, -7255, -9444, -9833, -9839, -8479, -7638, -8215, -11816, -11469, -8316, -8413, -8325, -11585, -11035, -8254, -8751, -9150, -11193, -9967, -8321, -8034, -10605, -11760, -9553, -9412, -7233, -14406, -11946, -9279, -11210, -6727, -12462, -12255, -8889, -10244, -6605, -8051, -15851, -8480, -9993, -7124, -6429, -14108, -8135, -12885, -8908, -6275, -11362, -7831, -14963, -12904, -7163, -12241, -7476, -10451, -9523, -8431, -23659, -7144, -9732, -8050, -9233, -10722, -6999, -10200, -8585, -9996, -8487, -7020, -11260, -9236, -11182, -8138, -7204, -13736, -8276, -10763, -9119, -7783, -18582, -7917, -9568, -11103, -9010, -14757, -8302, -9259, -14129, -10997, -14171, -8989, -9768, -14633, -13936, -12129, -11061, -10782, -10645, -20938, -10071, -19054, -11648, -9323, -16545, -9286, -10579, -11734, -9386, -14180, -9455, -9479, -11729, -10118, -13190, -10268, -10695, -11622, -11141, -12357, -11626, -14135, -9898, -12644, -12714, -13309, -18135, -8553, -14126, -16128, -13935, -11560, -8260, -13613, -15183, -13687, -5460, -5452, -11196, -9790, -6817, -6056, -5513, -9729, -8527, -7462, -6792, -6547, -8323, -8116, -7521, -7897, -8488, -7397, -7994, -6971, -9023, -9701, -7447, -8062, -7417, -9471, -8606, -8319, -8659, -8879, -9053, -7016, -9132, -9522, -9267, -8717, -5973, -9771, -9712, -8848, -8000, -5820, -10974, -9332, -8454, -7183, -6355, -9140, -9043, -8340, -7705, -7043, -6816, -7799, -9236, -11026, -8276, -5938, -6492, -11037, -13919, -12229, -6516, -6059, -12418, -10092, -11244, -9211, -6435, -12527, -10279, -8786, -16235, -7044, -12617, -10954, -8149, -9443, -7371, -12099, -10423, -6895, -7777, -8077, -10603, -10177, -5797, -6952, -9957, -11431, -8600, -5629, -6369, -10092, -13096, -6683, -6349, -5890, -7907, -8525, -5796, -7962, -5661, -7485, -7186, -5890, -10650, -5852, -9032, -7611, -6651, -9081, -6749, -12763, -8409, -7470, -7463, -9612, -12106, -7683, -7599, -8078, -13115, -12183, -6457, -7475, -9603, -7910, -17086, -5794, -8052, -7818, -7213, -14571, -6190, -9540, -7204, -8812, -11549, -7308, -10768, -8684, -14668, -10139, -7048, -10197, -12322, -13194, -9157, -6602, -9200, -12084, -10056, -8285, -7252, -8627, -12810, -7922, -7328, -8022, -8385, -11429, -6773, -6689, -7771, -8045, -8789, -7003, -6466, -7631, -7573, -8432, -8996, -6556, -8270, -7469, -10263, -11910, -7045, -9701, -8035, -15432, -10726, -7968, -9492, -8998, -12569, -11408, -8956, -7808, -9465, -9476, -11573, -9228, -7152, -8629, -7377, -9487, -8537, -7727, -7552, -6347, -7904, -7637, -10031, -7612, -6232, -6806, -7240, -15664, -9616, -6842, -6692, -7670, -9481, -10893, -8064, -7899, -9089, -7650, -7844, -10338, -9958, -11632, -7788, -6743, -15399, -9672, -14526, -9735, -6879, -9602, -9141, -14182, -9734, -7913, -7734, -9744, -13034, -7855, -10075, -7958, -10335, -12388, -7859, -12946, -10337, -9381, -12022, -9788, -8896, -15956, -8627, -11608, -12881, -7129, -11091, -9218, -11313, -10909, -7331, -9856, -12378, -10599, -9289, -8453, -10636, -14063, -9657, -8366, -7316, -14168, -9587, -9603, -7885, -6435, -12406, -8310, -10827, -7918, -6999, -9890, -8193, -13505, -8799, -8627, -9652, -8718, -16357, -10594, -10108, -11474, -9647, -11601, -9607, -9776, -16771, -10976, -8973, -7534, -8982, -12427, -12469, -7884, -6626, -9249, -10560, -12453, -7916, -6818, -11029, -9956, -11459, -8787, -8394, -14866, -10541, -11158, -10044, -12984, -16609, -13795, -11623, -11747, -11577, -15079, -15484, -11876, -18280, -9348, -13700, -10976, -11500, -12031, -9298, -12239, -9985, -10336, -9195, -9849, -11672, -10390, -9080, -8701, -9727, -10923, -11246, -8823, -9799, -8697, -8961, -9886, -9284, -12383, -7919, -7485, -7816, -9307, -15202, -8285, -6939, -6696, -9471, -12960, -10168, -7129, -6570, -10868, -10858, -11686, -7784, -7360, -12979, -9968, -10203, -8744, -8974, -13473, -9813, -9332, -10319, -11144, -14184, -10010, -8908, -14214, -12825, -16374, -10464, -8726, -12654, -12828, -21747, -11321, -8842, -9372, -12247, -13544, -12614, -9218, -9057, -9536, -11694, -10012, -10812, -9707, -14010, -13820, -12716, -10251, -6857, -14040, -13994, -9343, -12918, -5936, -9919, -10056, -7413, -13393, -6025, -8555, -6813, -6237, -9227, -5917, -9202, -5305, -5587, -7527, -5636, -14629, -4851, -5726, -6898, -6312, -9374, -5153, -6618, -7181, -8660, -6488, -5724, -7500, -8430, -12088, -5575, -6115, -7335, -8971, -12970, -5820, -6878, -5845, -7404, -11189, -7265, -9106, -4676, -6434, -8058, -11195, -11526, -4566, -6239, -6886, -12075, -9203, -5535, -6462, -6907, -8017, -8769, -7501, -6576, -7458, -6817, -9307, -10182, -6217, -8087, -7065, -9381, -14000, -5790, -9111, -7695, -9273, -14013, -5530, -9469, -6265, -7964, -8628, -5245, -7611, -5366, -6227, -6624, -4801, -6887, -6173, -5867, -6126, -4380, -8080, -8235, -7523, -6694, -4270, -12832, -8111, -10652, -7851, -4643, -11482, -8314, -8778, -9029, -5509, -8708, -8613, -9667, -9666, -6783, -7574, -6763, -15752, -8621, -8420, -6630, -5875, -10426, -7571, -11014, -5964, -6041, -8652, -7110, -16756, -6136, -6739, -7334, -7024, -8682, -7497, -7024, -6649, -7826, -6229, -9272, -6467, -6947, -10813, -5450, -9178, -6030, -7863, -13031, -5848, -9559, -6195, -8376, -10567, -7039, -11033, -7016, -8152, -13587, -8136, -12396, -8158, -7953, -11075, -9305, -14775, -8235, -8296, -6976, -9759, -12712, -8007, -9244, -5595, -7951, -10772, -9307, -8603, -5583, -7666, -10898, -11411, -6726, -6690, -9241, -12558, -9605, -5889, -8239, -9273, -16695, -9047, -6261, -8320, -8281, -12356, -8355, -7796, -8204, -9367, -9069, -6581, -10290, -9000, -12092, -7293, -5492, -12402, -10646, -11428, -6309, -5349, -13143, -13503, -11224, -5961, -5992, -12181, -11390, -11425, -6118, -6902, -10596, -9237, -9379, -6499, -6978, -10052, -9085, -7620, -6983, -6004, -9964, -10892, -6877, -7917, -4814, -9631, -13976, -6852, -9618, -4085, -10410, -10403, -7118, -11857, -4145, -16169, -9094, -7372, -14266, -5161, -10884, -9700, -7793, -11879, -7035, -8524, -12626, -8692, -9682, -7916, -8797, -15806, -9044, -8925, -7578, -11683, -11961, -8553, -8639, -8371, -13669, -11163, -8835, -8225, -10796, -11336, -10129, -9206, -7826, -11944, -11962, -8899, -9312, -7680, -11506, -13009, -8766, -11443, -7934, -14209, -11887, -9428, -15040, -8677, -16195, -10058, -9453, -9580, -9204, -11942, -8270, -9110, -7994, -8292, -11405, -7274, -9576, -7425, -7484, -11145, -7187, -10667, -7253, -7809, -10004, -7976, -10382, -7373, -9628, -9389, -9718, -9708, -8018, -13756, -9756, -13145, -10434, -10148, -25925, -11243, -16287, -13292, -19021, -16248, -14065, -11228, -23071, -9222, -13028, -12224, -9445, -14471, -7451, -13009, -9687, -8828, -11633, -7669, -19763, -8689, -8807, -10563, -9429, -13228, -8834, -9196, -10590, -11230, -10881, -9994, -9838, -10660, -10238, -10778, -11866, -10049, -10486, -9334, -11957, -12076, -9901, -10670, -9106, -15188, -10807, -10374, -11336, -9513, -16229, -10619, -11442, -12249, -10440, -12259, -12338, -11888, -11873, -11920, -8255, 8218, 8518, 4703, 137, -5140, 7753, 8166, 5106, 540, -3250, 6287, 7108, 5555, 791, -1631, 3470, 5348, 5428, 570, 1156, -2180, 2995, 4792, 899, 3233, -668, 588, 3980, 1142, 3964, 991, -1786, 3029, -304, 3094, 702, -8279, 1340, -3512, -478, -1112, -2044, -2134, 1037, -733, -2611, 604, -2068, 3033, 1683, -1222, 1844, 96, 3771, 1510, 67, 2656, 175, 4017, 111, 1671, 3035, -950, 3948, -1754, 2724, 2612, -511, 3152, -2003, 2721, 832, 1060, 745, -727, 1420, -4550, 1752, -1065, -971, -2190, -886, 1588, 2265, -2517, -4913, 1840, 1015, 3345, -3708, -1224, 2726, 1227, 2817, -8670, -906, 2485, 2340, 982, -2849, -1446, 1054, 3226, 62, 537, -684, -2201, 3490, -115, 1737, -56, -7898, 3096, -4738, 1778, -982, -6826, 2077, -1031, 828, -3160, -10160, 152, 2222, -1483, -1212, -4060, -4423, 3118, -5594, 248, -2787, -2026, 2878, -3903, 324, -3570, 406, 1755, -1324, -124, -2496, 719, -230, -71, 80, -720, 417, -1210, -232, 469, -854, 1272, 220, -1195, 159, -4591, 2291, 1101, -1698, -765, -3671, 2406, 1309, -821, -1862, -197, 1487, 1173, 791, -3180, 112, -262, 591, 1361, -5797, -1610, -1179, -998, 493, -6925, -5420, -742, -4666, -1194, -1936, -3467, -1125, -7554, -890, 178, -2146, -2983, -3930, -629, 876, -2217, -5998, -2068, -2152, 306, -2729, -7022, -1218, -7188, -2206, -3760, -5448, -1174, -7687, -10954, -4143, -3419, -1516, -5093, -3138, -2143, -1985, -2057, -4052, -2775, -1117, -1170, -2641, -2138, -5550, -995, -1224, -2670, -735, -9578, -567, -2007, -2219, -342, -7692, 524, -3086, -1683, -948, -7077, 1296, -5370, -1194, -2221, -3256, 1257, -4950, -1069, -3383, -1472, 233, -1693, -1771, -4892, -1180, -1980, -419, -3866, -6621, -2138, -5474, -156, -6157, -4795, -4213, -5127, -339, -4524, -3590, -6570, -3194, -780, -4325, -3557, -8074, -2608, -1703, -5544, -4800, -8634, -3328, -3206, -6749, -7973, -8729, -5125, -3443, -7786, -7871, -10310, -6026, -2155, -10906, -7845, -13434, -5541, -1414, -10743, -15660, -9978, -4354, -1374, -6485, -6403, -8967, -2751, -1939, -3752, -4951, -9769, -1632, -2963, -1807, -5986, -10566, -1131, -3689, -669, -9595, -13136, -1276, -3427, -415, -12170, -10248, -2242, -3000, -1194, -7320, -5671, -4156, -2917, -3317, -4703, -3638, -4702, -3214, -6274, -3608, -2845, -3237, -3756, -5799, -3894, -3093, -2684, -4211, -6050, -5378, -4583, -3074, -4323, -7715, -6447, -7930, -4186, -4257, -7771, -5940, -12505, -5731, -4563, -6867, -5028, -13601, -5859, -5985, -5732, -4149, -8554, -4586, -10478, -4734, -3890, -6391, -4026, -10602, -4790, -4268, -6069, -4167, -7309, -6658, -5053, -6613, -4131, -6262, -15018, -6338, -8256, -3866, -5088, -7044, -8316, -12071, -4221, -4230, -5000, 5922, 2877, -2652, 7225, -1942, 5515, 2353, 3865, 6686, 1766, 4165, 730, 5510, 4940, 3051, 1358, 904, 5010, 2671, 2092, -5564, 2646, 2289, 3628, -1862, -4151, 2909, 607, 4154, -5251, -1857, 1644, 3858, 3041, -1910, 10, -602, 4972, 1045, -3599, 1195, 605, 4873, 810, -9585, 1429, 2420, 3718, -155, -2336, 1055, 3117, 1407, -5780, -222, 808, 2803, 890, -817, 1013, 1218, 2085, 3289, 1366, 1234, 2027, 2761, 4672, 1799, 198, 3034, 3583, 5051, 1359, -1866, 4040, 3129, 4518, 319, -2769, 4706, 813, 3008, -854, -1545, 4699, -3603, 235, -113, -1184, 3630, -1158, -2969, 2063, -2284, 709, -774, -662, 3467, -4019, -992, -2120, 629, 3772, -6185, 1582, -4819, 128, 3272, -7246, 1865, -11520, -1190, 3004, -2061, 812, -2624, 278, 2945, -906, -60, -184, 1228, 1770, -859, 174, 294, 611, -203, 858, 249, -1086, -1130, 369, 2022, 241, -1940, -1573, 174, 1316, 853, 929, -1203, -2489, -2748, 1830, 2295, -2578, -11287, -3262, 2455, 2604, -3068, -6488, -1289, 2326, 2428, -89, -5309, -4264, 1290, 1918, 846, -5271, -4314, -320, 742, -190, -8586, -2029, -1024, -1542, -4638, -9557, -2594, -476, -4319, -4176, -6330, -1582, 565, -4829, -1713, -7113, 14, 1462, -5858, -2051, -10818, 631, 1639, -10144, -3800, -2388, 300, 683, -5406, -5103, 539, -1099, -2281, -2988, -3971, 1757, -3044, -12130, -3151, -2522, 1792, -3792, -3819, -4758, -1578, 714, -4145, -3659, -3347, -1303, -1851, -4225, -5126, -1984, -1914, -7118, -4073, -6039, -1921, -3745, -4571, -3449, -5360, -3066, -4057, -3408, -2754, -3995, -5962, -2056, -3713, -2999, -3494, -8482, -1508, -4204, -3874, -4233, -7004, -2412, -4300, -3411, -6686, -7724, -5074, -4663, -2566, -11435, -8951, -9769, -6523, -2522, -4694, -8805, -5417, -11164, -3203, -2571, -9365, -3728, -7995, -4366, -2390, -9768, -3197, -6963, -5469, -3829, -5474, -3229, -6954, -5628, -4607, -3508, -4104, -6926, -5201, -3017, -3258, -6781, -6688, -5292, -1676, -4259, -8702, -5994, -6273, -442, -6137, -8217, -5305, -7539, 275, -8081, -8464, -5335, -7354, 147, -8731, -3499, -5803, -6249, -888, -7789, -2032, -5607, -5626, -2776, -5259, -2924, -6184, -5689, -5352, -4394, -5429, -9887, -5982, -8624, -5787, -2827, -11662, -5790, -12709, -12312, -1539, -7007, -5155, -13300, -9568, -1918, -4272, -4926, -10232, -7642, -3585, -2757, -5668, -7063, -6153, -6748, -2676, -6399, -5254, -5138, -17375, -4308, -5488, -4550, -5500, -8419, -9177, -5281, -4523, -7549, -5931, -6620, -6823, -4509, -7848, -5396, -5237, -11409, -4001, -5616, -6506, -6804, -9460, -3360, -5102, -6861, -10260, -7357, -3247, -6051, -4702, -6499, -6841, -4070, -8027, -3936, -5306, -6850, -6079, -8982, -4609, -5490, -7067, -9131, -7701, -6456, -6575, -7263, 7862, 3577, -3578, 6519, 8233, 7387, 3047, -265, 6189, 8002, 5799, 1670, 1362, 5358, 7334, 2052, 840, 1291, 4485, 6244, -1155, 1285, -128, 3838, 4508, 3300, 1833, -1630, 2803, 2706, 4122, 2146, -633, 1071, 4250, 3709, 1664, 733, 1908, 5011, 3086, 48, 1542, 2952, 3427, 2686, -1076, 1275, 2652, -882, 1801, -599, -870, 1956, 3469, -227, -932, -10134, 1353, 4678, -4543, -2031, 84, 400, 4984, -3068, -3364, 2172, 945, 5524, 86, -5368, 2475, 1878, 5646, 1514, -4784, 1380, 1394, 5202, 1857, -1441, -806, -1002, 4984, 1045, 477, -635, -4379, 4954, -1648, 1641, 644, -2797, 4288, -3253, 2644, 972, -1322, 3020, 397, 3596, 687, -101, 2814, 1834, 4182, 349, 33, 3996, 2236, 4101, 852, -964, 4939, 1990, 3145, 1720, -2451, 5058, 1103, 1231, 1760, -3097, 3923, -603, -635, 322, -2722, 262, -3038, -1189, -4472, -2620, -1060, -2899, -2015, -3919, -3436, 2012, -984, -1798, -597, -2320, 1947, 383, -902, 216, 171, 124, 1242, -747, -309, 1428, -2713, 1657, -1183, -2483, 1433, -3601, 1756, -1977, -7766, 72, -2811, 1657, -2306, -10583, -3253, -2841, 1340, -2238, -6886, -4297, -3968, 519, -1825, -2592, -2136, -5200, -1223, -213, -715, -1543, -4770, -2527, 325, 291, -1608, -3019, -1503, -1502, 1062, -2140, -1168, -526, -6645, 1322, -3678, -154, -132, -1217, 627, -7430, -550, -1186, -480, -1285, -4158, -3529, -5876, -1895, -3438, -2063, -7058, -5493, -3733, -3336, -2027, -2192, -3358, -3342, -3693, -3797, -2182, -4358, -3690, -4396, -7597, -4956, -6387, -3553, -4124, -8527, -3015, -6323, -2577, -4534, -6396, -614, -4495, -3322, -6881, -3609, -8, -3697, -7313, -9857, -2506, -696, -4470, -5693, -9221, -3224, -2436, -6633, -4554, -7967, -5896, -3135, -4783, -6263, -6039, -5094, -2310, -2602, -6682, -6548, -3167, -2169, -1943, -6395, -13476, -2639, -2628, -2692, -6610, -7486, -2796, -3263, -5452, -3570, -5008, -3103, -4128, -14413, -2148, -4189, -2920, -5986, -6298, -2296, -3889, -2034, -9934, -5030, -3815, -3879, -1032, -9400, -5194, -6892, -3773, -352, -10041, -6318, -11567, -3246, -68, -11535, -8678, -11611, -2635, -19, -9312, -9926, -10994, -2358, -75, -16555, -8034, -10548, -2571, -458, -5942, -7471, -10320, -3233, -1499, -3288, -7675, -10172, -3883, -3313, -2820, -7216, -10202, -3874, -5729, -3540, -5958, -9375, -3945, -8679, -3976, -4982, -6867, -4869, -14072, -4032, -4766, -5660, -6485, -12797, -5370, -5521, -6325, -7500, -10770, -7950, -7705, -9406, -7495, -9962, -5439, -14339, -7057, -8173, -7902, -3887, -8710, -4512, -9782, -6912, -3828, -6140, -3589, -7110, -7707, -5054, -5275, -3751, -5350, -11512, -8205, -5413, -4861, -5301, -10081, -12683, -6424, -6305, -6681, -6900, -8432, -8580, -7125, -8259, -5725, -8012, -8535, -8108, -5274, -4485, -4669, -8641, -6926, -6248, -6259, -5340, -11387, -7950, -6505, -7441, -6765, -6574, -10861, -6476, -5437, -8423, -4254, -15479, -7169, -4629, -8620, -3606, -12207, -9201, -5047, -7602, -3747, -8709, -11083, -6616, -6982, -3893, -6456, -10302, -9628, -7076, -3962, -5050, -8471, -12842, -7508, -4693, -4689, -7345, -11734, -6814, -6884, -5827, -7439, -11003, -5609, -12702, -10190, -7761, -10101, -5059, -13157, -9423, -6792, -8744, -5142, -9739, -6426, -5961, -7578, -5798, -7210, -5659, -6137, -6867, -7190, -5969, -5808, -7719, -6570, -8674, -6533, -6466, -11384, -6787, -10674, -10207, -6446, -6049, -8001, -9156, -4805, -4379, -2756, -6357, -4016, -2200, -2543, -1038, -3515, -1868, -1601, -1907, -492, -2414, -1319, -2497, -2527, -1066, -2857, -2123, -4310, -4353, -2907, -4978, -4412, -4906, -5775, -6566, -9626, -8518, -5234, -5106, -10306, -12933, -10710, -6888, -5272, -8755, -11421, -11443, -8847, -6832, -9574, -10006, -14369, -8444, -8294, -12115, -10349, -17059, -8218, -6559, -12109, -12793, -14743, -8958, -5232, -10175, -11258, -13735, -8599, -5377, -8724, -9164, -15455, -7532, -7007, -8339, -8083, -13265, -7816, -9196, -8268, -7815, -11564, -9832, -9775, -6952, -7926, -13187, -13063, -10765, -5906, -7782, -15584, -12379, -10490, -6108, -8448, -12091, -9122, -7745, -7751, -11906, -13267, -7103, -6600, -10677, -10751, -17622, -6265, -7042, -12941, -9065, -14011, -6049, -8883, -9876, -10813, -20246, -5982, -9756, -7965, -14369, -10195, -5954, -8426, -8195, -13464, -7762, -6066, -7427, -10571, -16908, -7728, -6619, -6541, -17431, -10379, -10433, -8506, -5986, -12697, -9069, -11079, -12715, -6155, -8603, -9403, -7391, -8120, -7531, -6590, -9741, -6131, -6525, -10710, -5535, -10606, -5838, -6682, -8170, -4985, -13638, -6081, -7904, -6235, -4881, -13114, -6427, -9614, -6178, -5447, -11671, -6425, -10083, -7648, -6948, -11728, -6684, -8257, -10462, -9234, -10779, -8225, -6923, -12661, -10619, -9710, -13744, -6671, -16022, -11446, -9270, -10943, -7321, -12995, -13079, -9065, -8320, -8063, -9957, -11276, -9036, -7934, -8312, -9468, -8819, -9467, -8590, -8967, -10645, -7828, -10501, -9496, -10112, -11590, -8063, -11299, -8770, -10139, -10255, -8887, -10595, -7676, -9236, -9306, -8792, -9146, -7960, -8973, -8622, -8151, -7974, -10602, -10019, -8011, -7899, -7927, -14595, -12994, -7918, -8135, -9534, -10919, -13005, -8829, -9017, -14014, -12278, -11690, -11613, -9955, -15600, -15036, -12645, -19515, -9337, -14409, -10368, -12627, -13603, -8850, -15890, -9811, -10021, -14068, -9407, -16778, -11374, -8387, -13052, -10373, -14304, -14554, -8023, -11012, -10984, -11336, -16887, -9066, -10720, -12363, -9353, -14030, -11340, -11317, -15637, -8510, -12135, -12642, -11503, -16126, -8884, -12226, -13096, -11769, -12705, -10963, -14302, -13279, -13499, -9957, -19172, -16625, -12660, -15562, -8688, -13533, -15111, -11206, -13165, -8805, -11767, -13777, -10342, -11808, -10262, -11397, -12807, -10458, -6477, -8783, -9156, -7244, -9578, -6328, -9733, -13536, -7400, -7805, -7936, -9056, -8489, -8789, -6259, -11497, -8573, -7079, -7972, -5792, -7806, -8781, -7542, -4974, -6663, -6561, -8910, -10156, -3840, -9021, -7269, -8634, -12588, -4296, -11760, -9368, -8887, -8988, -6455, -9678, -11606, -9632, -8275, -8061, -6691, -10323, -9533, -9416, -6173, -4993, -7891, -9118, -12433, -5687, -4293, -6883, -9419, -16123, -6407, -4190, -7167, -9529, -14934, -8109, -4288, -8700, -7897, -9795, -12745, -4326, -12059, -6700, -7222, -10335, -4404, -16733, -6277, -6233, -6387, -5099, -11768, -5417, -6268, -5291, -8062, -6109, -3571, -5826, -6571, -8834, -2852, -1710, -3620, -8090, -3887, -1178, -580, -1986, -3856, -2366, -779, -430, -1643, -2432, -2403, -1609, -1343, -2671, -2818, -3680, -3795, -3377, -4520, -4806, -5870, -7664, -6535, -4420, -8343, -7916, -15536, -10653, -4084, -12695, -9889, -11828, -13098, -5003, -9736, -11340, -8721, -12170, -7176, -7383, -8885, -7056, -10148, -10846, -7232, -7236, -6012, -8370, -17930, -8908, -6677, -6057, -7995, -20861, -13738, -7012, -7767, -9371, -11406, -14260, -7883, -13412, -16421, -7421, -10815, -8644, -11246, -10137, -5665, -9564, -9488, -9443, -7578, -5485, -9463, -9239, -9567, -7295, -6693, -9922, -7080, -9377, -8432, -8617, -7936, -5892, -8845, -9031, -9569, -6097, -6073, -8837, -8300, -9826, -5514, -7909, -9189, -8287, -8081, -5938, -13439, -9856, -8392, -6871, -6969, -11578, -10508, -7797, -7008, -8090, -9814, -9997, -7225, -8278, -9567, -10223, -9397, -7195, -10334, -11868, -10981, -8329, -7907, -12488, -10352, -11151, -6826, -9507, -13503, -9198, -11249, -6094, -11238, -11431, -9771, -11613, -6580, -9476, -9627, -10380, -12747, -9020, -7275, -8856, -10247, -13736, -16003, -6086, -8414, -11570, -11831, -8566, -5962, -8008, -16748, -11574, -7193, -7054, -8048, -14475, -13484, -7650, -9263, -8539, -11817, -12244, -8730, -9245, -8822, -10515, -10283, -8339, -8075, -8612, -9537, -8883, -7938, -7841, -8409, -8677, -7755, -8264, -8050, -8787, -7793, -7192, -8081, -8359, -10367, -7308, -6991, -7332, -8931, -14232, -8007, -6797, -7132, -9800, -13835, -11501, -6596, -7893, -9831, -11601, -12887, -6679, -9853, -9139, -11078, -8894, -7338, -11703, -8684, -11386, -8556, -8925, -10719, -8095, -12223, -9890, -12600, -10678, -7601, -13352, -10997, -14219, -12580, -7914, -14900, -10834, -10587, -17160, -9606, -17509, -11831, -9792, -14535, -14620, -15935, -13545, -10180, -13387, -14109, -12626, -11733, -11259, -12852, -11649, -10359, -9112, -13805, -10874, -12114, -8940, -7478, -11162, -8905, -13014, -8389, -7070, -8300, -7873, -12301, -8759, -7897, -7516, -7945, -11441, -9479, -9758, -8260, -9257, -10055, -8912, -11370, -10436, -12243, -9002, -8078, -11958, -13352, -17471, -8733, -8008, -12959, -11729, -16054, -8775, -8649, -14557, -9828, -16015, -8934, -9793, -14432, -9459, -15591, -9838, -11052, -12957, -10547, -15496, -12015, -11458, -12524, -12694, -8230, -7691, -5468, -9481, -8670, -9001, -7408, -5868, -8990, -6591, -9581, -7771, -6956, -7195, -6580, -10393, -7327, -8931, -6473, -7471, -7970, -5549, -11685, -6128, -7159, -7631, -4150, -11748, -5513, -7929, -9741, -3795, -10485, -4303, -17918, -8069, -4614, -8971, -3127, -7586, -6064, -6814, -7951, -2698, -5489, -5580, -10569, -7771, -3189, -5469, -5785, -11898, -7226, -4466, -6865, -6114, -10132, -6694, -6073, -9733, -6129, -6873, -7455, -7364, -13436, -5859, -5163, -9935, -8014, -13410, -5672, -4931, -11197, -8088, -11952, -5759, -5908, -8516, -8227, -10857, -6700, -7381, -6294, -7948, -7578, -7593, -6226, -4093, -5630, -4017, -4501, -4020, -2154, -3361, -1993, -2598, -2742, -1072, -1949, -1330, -2120, -2586, -1063, -1517, -1931, -2742, -3767, -2267, -2219, -3885, -4222, -6305, -5003, -4359, -7515, -6275, -6329, -9340, -7607, -12642, -7451, -5676, -9219, -6602, -13829, -5922, -6883, -7370, -5890, -10794, -4729, -10218, -5433, -6630, -9067, -4538, -15278, -4265, -8349, -8557, -5277, -15622, -4066, -8880, -8228, -7025, -17999, -4908, -8895, -7876, -9730, -20204, -6995, -10528, -7947, -8986, -15609, -11480, -8558, -8529, -6973, -14060, -13132, -6336, -9480, -6072, -14891, -8563, -5576, -9787, -5940, -12477, -6978, -5672, -9075, -6201, -9322, -6417, -6451, -8859, -6523, -7573, -6467, -7443, -9016, -6973, -6791, -7238, -7352, -8515, -7959, -6689, -8750, -7373, -7939, -9814, -6907, -8398, -8020, -7907, -11790, -7184, -6899, -8017, -8015, -10770, -7572, -6198, -8602, -7580, -9305, -7928, -6155, -12835, -6869, -8482, -8451, -6730, -11413, -6489, -8152, -9575, -7862, -8206, -6709, -8087, -8522, -9050, -7654, -7533, -7890, -6803, -9935, -8072, -8451, -7253, -6535, -11353, -8295, -8740, -6322, -7893, -15348, -7725, -8988, -5476, -11460, -13262, -7221, -9483, -4995, -10780, -10224, -7251, -9437, -5058, -8963, -8837, -7649, -9570, -5841, -9093, -8473, -8169, -11427, -7607, -10154, -9463, -9020, -13397, -10596, -9380, -11766, -10451, -10172, -10965, -8168, -11446, -11564, -8940, -9038, -8329, -11145, -11019, -8637, -7810, -10112, -13124, -9888, -8452, -7159, -12460, -13661, -8969, -8120, -7365, -11740, -11131, -8617, -7994, -9199, -10800, -9901, -8864, -8338, -18405, -9328, -9597, -9573, -8683, -9092, -8348, -10440, -11231, -8532, -7338, -8315, -13288, -13336, -8470, -7996, -8943, -11069, -10472, -9040, -11538, -10138, -8492, -9458, -10575, -12131, -12718, -7794, -10389, -12879, -10330, -17404, -8374, -12979, -12355, -11566, -15374, -10212, -15777, -12279, -12726, -16126, -12892, -15051, -17251, -12160, -15098, -11206, -13405, -13200, -12773, -12624, -9967, -12677, -10384, -12458, -10770, -10191, -12112, -9969, -12304, -9488, -11298, -11629, -10552, -12837, -9005, -12997, -11904, -11543, -11254, -9555, -14936, -12024, -13036, -10176, -11863, -16570, -11122, -14227, -10661, -18824, -15736, -10527, -14187, -13092, -11981, -10996, -10305, -17064, -21464, -10450, -9195, -11056, 4273, -1175, 9553, 9450, 3052, 4463, 3879, 9185, 8848, 3751, 3691, 5671, 8199, 6996, 2976, -6, 5626, 6835, 3747, -666, 792, 4574, 5106, -1149, 3063, 2037, 4190, 3092, -4209, 3800, -358, 4688, 1661, -2811, 2384, 554, 4827, 2424, -2806, 1978, 2707, 4521, 3968, -690, 2707, 2711, 3757, 4130, 2386, 1913, 2064, 2494, 2508, 3667, 712, 2465, 1624, -715, 3416, 4000, 3141, 2531, -43, 2698, 6322, 3113, 4058, 1241, 3628, 7327, 2097, 4876, 2277, 4319, 7299, 1273, 4438, 3268, 3504, 6323, 1854, 3006, 3946, 376, 4314, 1023, 3672, 4062, -5035, 714, -3398, 4912, 3429, -584, -8156, -3245, 4998, 1886, 697, -982, 327, 4263, -1023, 1589, 1056, 3814, 3295, -5086, 2308, 1972, 5817, 2295, -2104, 3082, 2652, 6521, 377, -467, 3600, 3493, 6229, -3459, -114, 3379, 4039, 5186, 1078, -559, 2118, 3913, 3637, 3134, -594, -248, 2957, 1526, 3430, -111, -1222, 986, -1358, 2163, -472, 56, -2241, -835, -1865, -2532, 1237, -4694, -594, -748, -9471, 2363, -695, -6239, 2071, -3963, 3385, 1107, -315, 2712, -1725, 4066, 1139, 2838, 1943, -850, 4185, 385, 3798, -1034, -810, 3729, 409, 3633, -3631, -1834, 2835, 188, 2725, 946, -4437, 1381, -1223, 1115, 1704, -6992, -1534, -2586, -1552, 193, -4345, -4134, -2019, -2514, -5752, -3653, -1077, -1083, -444, -2084, -4006, -412, -207, 462, -456, -2819, -1217, 425, 537, -907, -1298, -3329, 342, 278, -2320, -650, -6489, -974, -53, -2929, -765, -4640, -4479, -814, -2364, -1373, -2710, -9811, -2690, -2639, -2160, -1708, -7460, -5063, -4249, -3165, -1116, -6249, -2842, -5023, -4942, -960, -3882, -1322, -3471, -8502, -1330, -3190, -894, -2532, -9041, -1644, -3392, -1071, -1851, -6633, -1087, -3902, -1602, -1002, -5609, -598, -5119, -2438, -522, -4698, -1066, -6220, -3522, -1088, -4180, -3025, -5845, -4633, -3574, -4309, -9354, -5815, -5317, -8883, -4318, -4059, -5763, -4295, -4753, -3956, -1188, -5059, -3028, -5161, -4196, -282, -4459, -2775, -9570, -4659, -623, -4394, -3602, -6541, -2769, -1731, -5262, -4933, -5054, -1102, -2424, -8236, -4875, -4457, -759, -1695, -5776, -4752, -4278, -1699, -657, -3225, -5190, -6168, -3979, -402, -2833, -3816, -9388, -7674, -1212, -3869, -2747, -4540, -11357, -3107, -5078, -3168, -3531, -8642, -5995, -4722, -5514, -4313, -5362, -8466, -3742, -12373, -6390, -3513, -7445, -3093, -5643, -8647, -2786, -5096, -3357, -3478, -8699, -3144, -3019, -4871, -3100, -8418, -4030, -1802, -7819, -4520, -8160, -3842, -1386, -9033, -9826, -8837, -3438, -1593, -5964, -4630, -9426, -3444, -2068, -3661, -1901, -7578, -3273, -2546, -2794, -963, -6642, -3195, -3431, -3491, -1447, -6127, -3465, -3316, -6683, -3872, -5921, -3687, -2004, -9602, 6954, 9472, -4937, 4408, 9914, 6202, 9072, -277, 4177, 9310, 3917, 7959, 2087, 3212, 7388, 683, 6428, 3014, 2072, 3868, 582, 4826, 3459, 2377, 1248, 2628, 3240, 3879, 2178, 2305, 3044, 2265, 4056, 802, 3017, 977, 2908, 4021, -218, 2782, -1481, 3752, 3866, 9, 1238, 1895, 3814, 3406, -734, -1246, 2452, 2890, 2862, -2419, -2154, 1980, 744, 2974, 458, -160, 2350, -3684, 3764, 1833, 1209, 2987, -188, 4442, 1831, 1820, 3272, 3009, 4590, 1979, 2915, 3663, 4306, 4297, 2743, 3739, 4182, 4135, 3864, 3231, 3347, 4460, 2066, 3431, 3057, 1366, 4330, -4188, 2732, 2029, -2450, 3903, 673, 1244, 597, -4712, 3501, 1868, -1737, 1065, -6321, 3025, 1724, -4798, 2014, -4691, 2115, 726, -4126, 2091, -2153, 873, -214, -4141, 2340, 833, -948, 3005, -788, 3695, 2866, -1217, 4662, 580, 4650, 3917, 1403, 4843, 599, 4670, 4315, 2157, 4046, 1278, 4078, 4281, 968, 2668, 1969, 3638, 3946, -3127, 868, 1315, 3439, 3449, -3484, -1794, -954, 2896, 2900, -913, -7509, -3831, 2195, 2366, -124, -8891, -3278, 2169, 1966, 447, -9929, -2773, 2353, 1726, 974, -7235, -4046, 1859, 1446, 1041, -4166, -4206, 167, 963, 362, -4972, -2035, -4366, 733, -1274, -4793, -1814, -2747, 1230, -3148, -1473, -3520, -65, 1452, -1912, -365, -4497, 161, 630, -1234, -1045, -2661, -1458, -1577, -2481, -4519, -1881, -2648, -5054, -7214, -6705, -1632, -918, -5935, -5615, -2820, -1622, -958, -7067, -2567, -3478, -2015, -3264, -8679, -1535, -8165, -2000, -5201, -6614, -1732, -1751, -1280, -3369, -6594, -3178, 554, -656, -3463, -5552, -6775, 1130, -171, -4938, -3561, -8282, 471, 41, -5423, -2609, -2999, -1300, -94, -3325, -2318, -1368, -3745, -379, -1975, -2221, -1283, -5095, -900, -1983, -2245, -2265, -4743, -2068, -3757, -2644, -3826, -3992, -4546, -8374, -3572, -5080, -4028, -10704, -6822, -3868, -5142, -5987, -4616, -6468, -2488, -4351, -9791, -2110, -7995, -1434, -3764, -4731, -1066, -5576, -1032, -3972, -3632, -1165, -2801, -647, -4636, -4538, -2905, -1633, -126, -4203, -4911, -9326, -1965, -14, -3423, -3255, -5919, -3705, -551, -3487, -2473, -5154, -6023, -1571, -4266, -2469, -9219, -7353, -2958, -4869, -2960, -9120, -8008, -5357, -5053, -3932, -6637, -6305, -7577, -4855, -5276, -6676, -3559, -5508, -3928, -8032, -5416, -1765, -4957, -3400, -7311, -3173, -977, -5631, -3807, -3876, -1883, -1052, -7343, -5107, -2784, -1889, -2034, -7426, -6933, -2888, -2758, -3039, -5105, -7268, -3435, -3180, -1892, -4394, -6583, -3779, -3925, -902, -5305, -7276, -4089, -6806, -1123, -7841, -8526, -5036, -5094, -2829, -12767, -7115, -6830, -3640, -4196, -6814, -6351, -5633, -5165, -2616, -4037, -7365, -3552, -12596, -2570, -3857, 5615, 3635, 5008, 8307, 8560, 5276, 3327, 4031, 7670, 8181, 4450, 2321, 1492, 5751, 7141, 3678, 319, 2251, 3453, 5936, 3177, -3642, 2484, 2769, 5359, 2469, -8211, 83, 1311, 5080, 1111, -4452, -710, -1942, 4119, -1054, -5164, 75, -988, 1760, -2503, -5947, -2624, 1559, 2341, -664, -399, -3492, 2666, 4350, 1598, 1249, -3523, 2324, 4896, 3228, 1656, -2654, -128, 5228, 4019, 2532, 406, -2052, 5724, 3668, 2788, -39, 2565, 5583, 1650, 1405, -870, 3978, 4515, -2496, 933, 2143, 3757, 2798, -1109, 2023, 2958, 2232, 2025, -625, 1457, 2016, 114, 2601, -1397, 894, 15, -1423, 2450, -2000, 2236, -1643, -11317, 1123, -1329, 2933, -2148, -170, -824, 557, 2647, -1452, 2212, -2245, 2466, 1557, -1140, 2175, -1229, 3422, -218, -1811, -164, 581, 3061, -2526, -3445, -5945, 1800, 1065, -5835, -5227, 176, 2800, -702, -8766, -4097, 2096, 3326, 706, -3323, -2528, 2868, 3305, 365, -1412, -980, 3057, 3440, -2261, -908, 566, 2721, 4059, -3183, -1116, 1551, 1749, 4440, -1772, -1045, 1894, 359, 4158, -2445, -643, 1789, -242, 3144, -4745, -967, 1530, -193, 1520, -4033, -2696, 1308, -892, 52, -2012, -5652, 978, -2084, 18, -1076, -4025, 301, -647, -37, -1324, -2462, -748, 993, -756, -4055, -1989, -1544, 1716, -216, -4336, -1713, -798, 1934, 646, -734, -585, 182, 1874, 632, -120, 181, 146, 1506, 245, -1036, -461, -1386, 874, 294, -1857, -2886, -4885, 226, 715, -1534, -4240, -3475, -156, 764, -1498, -4122, -2271, -228, 6, -1893, -7978, -2968, -98, -1350, -2696, -7527, -3951, 161, -2049, -4314, -4112, -2768, 377, -2023, -6945, -2920, -1353, 292, -2319, -8120, -2399, -663, -146, -3012, -6529, -2890, -708, -576, -3730, -5428, -5567, -1452, -537, -4195, -5525, -6484, -3160, -453, -4817, -7842, -2593, -7125, -1080, -5487, -7095, -1935, -11674, -2918, -3832, -3255, -3267, -7803, -5583, -1555, -1853, -3193, -4682, -4558, -248, -2116, -1765, -1967, -3151, 143, -4549, -2223, -635, -3122, -199, -11564, -4887, -375, -5590, -1244, -3692, -4172, -974, -6671, -3216, -1978, -1813, -2305, -2030, -4099, -1808, -942, -4570, -619, -1963, -2460, -1148, -8696, -699, -693, -2703, -2454, -6312, -2090, -404, -2307, -4238, -5549, -5742, -910, -2557, -4134, -8368, -6972, -1986, -3818, -4147, -5337, -2869, -2843, -5667, -5483, -2721, -1442, -2606, -6727, -5661, -2118, -1262, -2025, -6217, -4312, -2781, -2241, -1803, -5391, -4079, -3978, -4918, -2132, -5481, -4602, -4163, -8880, -3134, -7374, -4419, -3967, -5455, -4967, -8361, -3621, -3249, -4093, -6857, -4338, -2503, -1548, -3482, -6420, -2519, -1318, -657, -3514, -4889, -2151, -979, -1116, -5343, -2908, -3067, -2029, -3077, -8158, -1527, -6560, -5790, -3832, -2206, -4127, -3399, -4292, -4940, -4974, -2793, -2362, -2653, -10980, -5415, -3649, -2321, -1871, -4721, -2919, -4537, -2595, -2070, -2139, -2575, -1729, -2704, -3356, -1931, -3305, -753, -2510, -6063, -3729, -5163, -1706, -2349, -9383, -5256, -11377, -5034, -2566, -7340, -2712, -5787, -9046, -3593, -6261, -1699, -3302, -9886, -6186, -6696, -1792, -2738, -7512, -8622, -9946, -2511, -3281, -3572, -4661, -8071, -3873, -4912, -2319, -2313, -4209, -6451, -7637, -2129, -1412, -2828, -5466, -7336, -2281, -2182, -2979, -2911, -6517, -2539, -6309, -4981, -2174, -6412, -2590, -4489, -7737, -3255, -4516, -1907, -1229, -3607, -5026, -1662, -835, -276, -1725, -2208, 222, -152, -496, -1159, -920, 934, -298, -1543, -1731, -1278, 570, -1511, -3107, -3860, -2520, -665, -4148, -5063, -9601, -3563, -2338, -7677, -6647, -9347, -5738, -4128, -5612, -6055, -8722, -11473, -5027, -4799, -5335, -10194, -3950, -3216, -5976, -4666, -6511, -2263, -1858, -11547, -3776, -4016, -2056, -1812, -6608, -3305, -3151, -2510, -3001, -3221, -3992, -3655, -3160, -3823, -2022, -7049, -4559, -3915, -3231, -2280, -10880, -4556, -4119, -3716, -3862, -5402, -5662, -3493, -5324, -6761, -3992, -12154, -3430, -4389, -10854, -3634, -7926, -4819, -3306, -7653, -3998, -6180, -8424, -3646, -7246, -5270, -5766, -6096, -5140, -8179, -8096, -4530, -3860, -7042, -4222, -14070, -3643, -3048, -7790, -2448, -6400, -3436, -2945, -7516, -2289, -3818, -3584, -3237, -8134, -3080, -2611, -3866, -3720, -8361, -3900, -2253, -4413, -4300, -4948, -5062, -2574, -5451, -4891, -3104, -9966, -3473, -6412, -4902, -2675, -7509, -4489, -6146, -4202, -3286, -5122, -4607, -6019, -3941, -4588, -5910, -4538, -6926, -4744, -5937, -9521, -5491, -8071, -6459, -6309, -11466, -8106, -7592, -7168, -5891, -9960, -11277, -5992, -5987, -5797, -9214, -8528, -4722, -4286, -6720, -6405, -6920, -4206, -3205, -6913, -3869, -6418, -4041, -3431, -4272, -2550, -7061, -4052, -5496, -2653, -2424, -7305, -4873, -5290, -2181, -3493, -5061, -7351, -2919, -2649, -5876, -3521, -9266, -2294, -4077, -10095, -2802, -7212, -2773, -5907, -8717, -2538, -7541, -3682, -5534, -5626, -2788, -11674, -4209, -5122, -4904, -3801, -7671, -4054, -5863, -6040, -5899, -5640, -3933, -6746, -7308, -9937, -6103, -4673, -7159, -6200, -11302, -8101, -6783, -8030, -6107, -10018, -8576, -9051, -8822, -7101, -11354, -9780, -10360, -7996, -7714, -12917, -14236, -12235, -6338, -6552, -11621, -9197, -7458, -5166, -4849, -8419, -7984, -6006, -4844, -3899, -6185, -7370, -5861, -5552, -3962, -5079, -6536, -5921, -7571, -5142, -4988, -5869, -5594, -8610, -7533, -6242, -5003, -4945, -7103, -8357, -10606, -4213, -4411, -7081, -6808, -6725, -4030, -4417, -8126, -6290, -3779, -4559, -5224, -8156, -7091, -2724, -5747, -6887, -7593, -10336, -2890, -7675, -7564, -7008, -10528, -9120, -3096, -4727, -4287, -7491, -4825, -4498, -3189, -5400, -5052, -2316, -9808, -3096, -4647, -2070, -1095, -6897, -3549, -5188, -1297, -802, -4170, -4566, -6792, -1008, -1259, -3154, -7079, -7195, -699, -2081, -2734, -15953, -4835, -883, -3234, -2323, -6262, -3110, -1629, -6398, -2055, -4209, -3242, -2189, -8191, -2449, -3915, -5945, -2211, -3292, -3650, -4302, -8079, -2289, -1759, -5461, -3952, -6295, -2647, -1335, -7280, -3541, -8559, -3380, -1636, -6264, -3789, -13940, -5077, -2738, -4418, -4242, -9014, -9489, -4759, -3781, -4495, -5163, -5181, -6342, -4922, -5022, -3683, -2458, -8291, -7631, -6580, -4346, -1075, -8462, -2754, -4878, -3071, -243, -2870, -537, -1919, -316, 204, -1089, 0, -670, 949, 296, -995, -644, -856, 1038, -27, -2143, -1944, -2630, 177, -943, -3767, -2880, -7857, -1420, -2684, -4335, -3313, -6982, -3321, -5534, -4204, -3754, -4830, -5405, -9695, -4094, -4340, -5866, -8479, -13551, -3983, -5277, -8131, -10593, -13952, -3253, -5526, -5080, -10748, -15480, -2255, -3728, -3198, -8577, -12923, -1884, -2381, -2588, -6205, -8805, -2267, -2100, -3295, -5584, -7718, -2484, -2385, -6230, -5795, -5552, -1869, -2196, -8137, -4130, -3618, -1475, -1783, -4668, -2520, -3253, -1644, -2018, -3820, -2332, -4373, -2114, -3077, -3941, -3940, -5092, -2411, -4569, -4179, -8094, -3619, -2672, -4884, -4497, -4430, -2644, -4021, -3878, -5995, -2571, -2405, -8544, -3126, -13961, -2273, -2688, -7916, -2867, -5187, -2779, -3384, -6460, -2694, -2522, -3542, -4525, -8638, -2424, -1563, -4042, -6247, -15573, -2544, -1488, -4321, -7301, -10773, -3226, -1982, -4677, -5448, -7491, -3714, -2968, -4713, -3784, -4511, -3859, -4348, -4788, -3045, -2910, -4707, -5446, -6259, -3197, -2664, -6729, -5219, -8369, -4314, -3598, -10067, -4589, -5702, -6900, -4468, -14336, -4819, -4702, -15129, -3976, -12010, -5059, -4953, -8456, -3869, -11674, -3651, -5724, -6693, -4473, -12949, -2778, -7384, -6712, -4823, -12265, -3244, -8545, -6116, -4636, -12510, -5433, -7265, -4422, -4448, -10423, -12733, -7066, -3619, -3561, -7027, -7660, -6530, -3902, -2370, -5509, -5134, -6155, -4675, -1971, -5581, -4506, -7476, -5309, -2794, -7460, -5683, -10713, -6690, -5356, -12984, -11029, -9099, -8566, -9806, -12260, -7688, -7849, -6230, -7807, -9346, -5945, -8325, -4902, -7786, -6910, -7009, -8612, -5072, -9369, -5536, -10069, -6354, -6591, -10282, -5508, -8597, -4974, -9521, -9013, -7028, -7475, -4960, -12767, -7785, -11313, -6752, -6424, -12740, -7696, -11893, -5091, -9821, -12027, -8870, -7707, -3872, -8602, -12424, -10914, -5108, -3573, -6720, -12253, -11214, -3706, -4009, -6618, -10520, -8551, -3648, -4646, -8112, -8389, -6121, -5259, -4687, -12149, -7513, -4632, -10013, -3921, -11291, -8555, -4036, -8911, -3076, -9212, -12275, -4365, -7671, -2822, -8690, -8791, -5970, -9197, -3530, -8578, -6469, -5236, -4781, -6658, -2943, -1061, -7932, -4475, -8167, -934, -1390, -5860, -2757, -4476, -89, -2212, -2857, -2192, -2450, 167, -3011, -1371, -1832, -1663, -238, -3480, -972, -1294, -1547, -1734, -4059, -1244, -897, -1830, -3042, -5447, -1757, -863, -2291, -1205, -7176, -2443, -1068, -2025, -309, -6780, -3996, -1493, -1345, -773, -7187, -6478, -2689, -1326, -2301, -8534, -3977, -5782, -2000, -3862, -7084, -2219, -12366, -2773, -4157, -5134, -1684, -8569, -3243, -4514, -3676, -1609, -7788, -3766, -5119, -3547, -1606, -7236, -4041, -5522, -4209, -2205, -8857, -3681, -5065, -3096, -4882, -10267, -5416, -4456, -2720, -5063, -4605, -5564, -5785, -5154, -1789, -1874, -728, -5549, -5346, -1221, -874, 786, -2209, -2249, -2372, -1341, 650, -767, -1850, -3870, -3180, -695, -403, -3195, -3004, -5858, -2351, -602, -6531, -2624, -7577, -2869, -893, -7728, -3960, -8577, -3177, -1114, -5156, -6189, -9822, -3652, -1729, -4802, -4580, -9729, -3535, -3155, -6991, -3884, -9499, -3153, -4561, -8089, -3763, -8259, -3177, -3769, -5249, -3167, -6487, -3448, -2869, -6451, -2904, -5645, -3415, -2875, -6168, -3025, -5571, -2856, -3942, -2709, -3116, -6335, -2206, -6728, -1971, -2853, -8948, -2071, -11805, -3066, -1838, -12433, -2644, -6024, -5840, -967, -6445, -3627, -4214, -8153, -878, -4446, -4481, -3426, -6547, -1549, -3317, -5099, -2609, -5216, -2762, -2450, -5268, -1988, -4438, -4504, -1871, -4618, -2094, -3854, -7470, -1826, -3355, -2869, -3289, -17753, -2802, -2154, -3651, -2710, -7254, -5823, -1379, -3810, -2387, -4293, -7421, -1022, -3262, -2595, -2864, -4888, -984, -2695, -3096, -2603, -5210, -1266, -3076, -3220, -3347, -6868, -1982, -5280, -2894, -3896, -7007, -3145, -17998, -2759, -3266, -7738, -4097, -6380, -3554, -3183, -10779, -3979, -4415, -6024, -4240, -12735, -3976, -3511, -9161, -6071, -12265, -5311, -2484, -10379, -6941, -7090, -10284, -1505, -12420, -5684, -4708, -7921, -1099, -7151, -3929, -4140, -4845, -1423, -7725, -2906, -5352, -4079, -2415, -10884, -2767, -9575, -4751, -3868, -4996, -3267, -11989, -7115, -5006, -3391, -3812, -11979, -10810, -5188, -3586, -3784, -8891, -6382, -5441, -5553, -3438, -5727, -3479, -5894, -12436, -3191, -4619, -2024, -5517, -7064, -3122, -4018, -1711, -4483, -4948, -3381, -3236, -2307, -3707, -4471, -4159, -2468, -3365, -3586, -4439, -5249, -1958, -4202, -4446, -4159, -5909, -2016, -4686, -7049, -3815, -5830, -2881, -5316, -8985, -3897, -5727, -4315, -6894, -6111, -4099, -6446, -5802, -10967, -5680, -3778, -8126, -8852, -12693, -6969, -3660, -9269, -11311, -8799, -8984, -4230, -10135, -6885, -6827, -8416, -4706, -12410, -6134, -6142, -7269, -4802, -11045, -6734, -6913, -6875, -5306, -7901, -7838, -8307, -6747, -5268, -6268, -8514, -7424, -6007, -4627, -6013, -7963, -6595, -4887, -4943, -6881, -6893, -6953, -4348, -6424, 8312, 5887, 763, 6240, -363, 8294, 6155, 1032, 5545, -1258, 8007, 5877, 1907, 2928, -1251, 7048, 3746, 3572, -1938, 911, 5242, -371, 4533, 2396, 1978, 3126, 3069, 3923, 2713, 1787, 2172, 4094, 719, 14, 481, 3186, 4027, -121, -4285, 838, 4514, 3804, 2625, 180, 2550, 4919, 3657, 2521, 1067, 3483, 4582, 3362, 258, 2969, 3998, 4482, 2739, -6911, 4973, 4239, 4254, 3194, -2381, 5869, 4139, 2316, 4698, -612, 5539, 3654, -2238, 5395, -864, 3736, 2454, 913, 5114, -2219, 274, -5, 1216, 4154, -2132, 1318, -2522, -67, 2602, -1085, 2215, -2412, 131, -283, -886, 1268, -4026, 1186, -8097, -1710, -1149, -6953, 1561, -4291, -3347, -4797, -2354, 1522, -1303, -3727, -6138, -433, 1412, 133, -2083, -4125, -87, 815, -292, 172, -1455, -1082, -27, -3173, 1392, 845, -3508, 747, -2476, 1285, 1824, -1900, 1521, -1280, 820, 1686, 181, 1523, -4127, 1264, 491, 504, 1582, -1000, 1071, -3544, -907, 1450, 2030, -655, -2890, -3654, 3, 2817, -492, 659, -651, -4158, 2016, 1441, 818, 725, -10322, -840, 1979, -1194, -2, -8915, -5398, 1183, -1790, -2223, -6956, -2149, -1520, -56, -1105, -3460, -2442, -10631, 261, -303, -1559, -3357, -1627, -200, -1439, 167, -1243, -98, -570, -2185, 1208, 270, -178, -341, 51, 1412, 678, -1143, 5, 1425, 1216, -292, -1832, -159, 1825, 1256, -3538, -1494, -1115, 1555, 1587, -1977, -404, -2659, 1059, 1717, 80, 665, -3520, 841, 1159, 162, 792, -3107, 657, -448, -835, -464, -2113, 58, -3922, -1838, -3144, -1636, -806, -10528, -1556, -2638, -2444, -1534, -4173, -477, -1284, -3701, -2217, -3028, 311, -1290, -1968, -2833, -2955, 532, -2286, -406, -2998, -3034, 207, -3360, 179, -3012, -2639, -619, -2785, -62, -3928, -1952, -1977, -1827, -1392, -7686, -1681, -4262, -1592, -5592, -9053, -1987, -8758, -2354, -5422, -6045, -2718, -7035, -4539, -1752, -6965, -3828, -5662, -10232, -853, -7632, -5907, -6125, -6723, -855, -6549, -8259, -5978, -3467, -1133, -6529, -4785, -4562, -2279, -1386, -6847, -3401, -3669, -2823, -1427, -7821, -3833, -3606, -6032, -1374, -8088, -6000, -4148, -7704, -1368, -5769, -7785, -4977, -4936, -1565, -4181, -5556, -6132, -5997, -2140, -3599, -3794, -7335, -13081, -3091, -4133, -2413, -7218, -7692, -4501, -5860, -1528, -6840, -6739, -7249, -6578, -1438, -8422, -8001, -17811, -5284, -2387, -10105, -7352, -7847, -4947, -4342, -5643, -6214, -7228, -6386, -5210, -4781, -7105, -8778, -13916, -4956, -6509, -11004, -8787, -7620, -5986, -13650, -7198, -9389, -6170, -8564, -12574, -5441, -18478, -7578, -14813, -12988, -5656, -9929, -14786, -9762, -8635, -6950, -8535, -8450, -6373, -7771, -7891, -9058, -5077, -5412, -8878, -7258, -9097, -3639, 1446, 4870, 5496, 3432, 778, 2169, 4055, 4926, 2644, 1374, 2487, 1165, 2583, 1077, 1593, 1238, -9366, -4050, 2166, 1722, -1745, -4241, 2422, 3098, 2608, -1709, -11737, 3101, 2365, 2776, -656, -3138, 698, 90, 1600, -336, -1552, 42, 1775, 821, 87, -2168, 3276, 3289, 2542, -194, -1324, 4464, 2620, 4013, -3154, 646, 5129, 658, 5289, -802, 2092, 5542, 3390, 6094, 2705, 3242, 5233, 4793, 6071, 3909, 3952, 3664, 4131, 5190, 3726, 4040, -489, 463, 3738, 2159, 3503, -3730, 867, 2626, -1511, 2218, -177, 3882, 2668, -891, -258, -454, 4726, 2825, 821, -1874, 271, 4810, 2074, 230, -1089, 2122, 4593, -88, -2783, -2625, 2683, 4179, -4117, -7287, -3032, 1897, 3611, -3947, -3767, -1114, 377, 3060, -3057, -3805, -1994, 650, 2579, -4042, -6118, -6273, 1787, 1891, -5161, -6898, -5117, 1980, 863, -4271, -2408, -6868, 696, -89, -3863, -556, -3126, -4108, -359, -1906, 282, -431, -1615, -145, 439, 855, 479, 930, -166, 1445, 1122, 957, 828, -616, 1130, 775, 1433, -1303, -1174, -415, -162, 1415, -1521, -1711, -2517, -798, 37, -129, -1913, -2753, -848, -5232, -1012, -1887, -1764, -1762, -2590, -3901, -2498, -512, -2482, -429, -2118, -3514, 660, -1072, -597, -614, -4241, 1327, -790, -1868, -22, -3086, 1275, -2170, -2804, 433, -738, 732, -5131, -1557, 660, 408, 493, -6968, -83, 401, 317, 544, -3263, 920, -609, -882, 79, -592, 1584, -2882, -2961, -889, 747, 1898, -6333, -3936, -1213, 1066, 1671, -4477, -3040, -1196, 501, 605, -3687, -2741, -2076, -948, -1863, -3725, -3608, -3615, -3514, -8203, -2846, -5675, -4626, -7676, -5780, -2051, -5646, -4864, -7906, -4712, -1879, -4707, -4460, -8375, -6614, -2083, -5367, -4632, -16250, -14775, -2613, -7158, -5467, -7373, -10453, -3500, -9096, -6113, -6672, -12921, -4584, -8025, -7107, -9112, -8602, -5586, -6671, -8545, -6273, -4569, -6001, -6944, -6493, -3572, -3106, -5768, -6814, -5466, -2070, -2986, -5942, -6051, -6991, -1191, -3900, -7742, -5497, -10539, -980, -5624, -12196, -4103, -5565, -1540, -7062, -9523, -2878, -3827, -2988, -7111, -10643, -2372, -3418, -5831, -7249, -6598, -2449, -3770, -9218, -7702, -3064, -2873, -4524, -5252, -7390, -1470, -3361, -5234, -3699, -6322, -1108, -3863, -5805, -3796, -5425, -1798, -4517, -5806, -5718, -5233, -3353, -5104, -5088, -8064, -5966, -4350, -5365, -4661, -4926, -7452, -3960, -5678, -4644, -3868, -8402, -3993, -6276, -4768, -4497, -7430, -4679, -6686, -5100, -6680, -6008, -5367, -6348, -5765, -9584, -5354, -5330, -5759, -6800, -8074, -5635, -5118, -5631, -8313, -6312, -6572, -5525, -6352, -9706, -5356, -8122, -6676, -8115, -9754, -5232, -11807, -8113, -11082, -8604, -5830, -12132, -9036, -11127, -6709, 6577, 2520, 4753, 4151, -6277, 5589, 1368, 4321, 3621, 3271, 1874, 1192, 3362, 3087, 5773, -3867, 3437, 3263, 3753, 6554, 33, 4131, 3884, 3777, 6045, 1716, 3607, 3956, 2241, 4189, 2850, 2007, 3377, 1367, 1161, 1951, -1589, 2473, 3501, -395, 715, -2136, 1248, 4026, 2129, 3597, 349, -3343, 2390, 4017, 5389, -34, 904, 1934, 3345, 6038, 2492, 4607, 4228, -325, 5722, 4891, 5595, 3828, 4094, 4293, 5306, 4624, -1214, 5181, 1633, 3550, 792, 2721, 3531, 821, -5316, 717, 4457, 1230, 1080, 1384, 2685, 3550, 4020, -580, 2553, 2205, 205, 4954, -2816, 1369, 590, -8658, 4742, -1698, -1211, -629, -6616, 3828, -646, -3831, -237, -7037, 2574, -273, -4698, 467, -3754, 2042, -103, -5349, 849, -1731, 1984, 182, -8257, 951, -381, 1267, -129, -15880, 728, 94, 47, -1664, -9613, -14, -844, -405, -4780, -6293, -1484, -3930, -408, -5712, -3936, -4110, -1411, -383, -5165, -3535, -12188, 935, -295, -5321, -4553, -5474, 1539, -921, -1715, -3578, -2731, 969, -1541, 604, -1873, -1981, -490, -371, 1661, -1224, -2605, -2349, 191, 1867, -915, -4072, -4724, -641, 1362, -614, -5444, -7437, -1715, 46, -997, -7221, -4130, -770, -2305, -2440, -4308, -2677, -259, -4370, -3465, -1358, -2415, -715, -2586, -2698, -199, -2647, -834, -516, -1834, -588, -2857, -569, 258, -1793, -2251, -2194, -1192, -898, -1937, -2191, -852, -2583, -7152, 351, -1356, 102, -3698, -2950, 1852, -1932, 359, -6144, -1220, 1854, -2172, 55, -6653, -2009, 546, -1185, -340, -2419, -4113, -1290, -1150, -478, -1239, -6890, -2098, -2300, -959, -1842, -9870, -3081, -3299, -2614, -4334, -6524, -5286, -2315, -6323, -8689, -6324, -7051, -1389, -9340, -7912, -11485, -6039, -1331, -5992, -8125, -7089, -4737, -2125, -3981, -10595, -4020, -4177, -3806, -3357, -10943, -3272, -5259, -6807, -3837, -5883, -3671, -7274, -11253, -4242, -4281, -4544, -3604, -11765, -3483, -4209, -5169, -1853, -10870, -3008, -4896, -5876, -1572, -6055, -3923, -5510, -7833, -2223, -4625, -8226, -5841, -12540, -3583, -5274, -6509, -6567, -8375, -5407, -8003, -3287, -8715, -6207, -7424, -13138, -2446, -9753, -5663, -9630, -15199, -2672, -7218, -6661, -6037, -12704, -3539, -6174, -10491, -3939, -8698, -4719, -5061, -8431, -3339, -7629, -5801, -3775, -6080, -3854, -8518, -6103, -3128, -5811, -5276, -7916, -5332, -3191, -6563, -6015, -7152, -4632, -3752, -7412, -5063, -9671, -4680, -4701, -7650, -4302, -9953, -5723, -6167, -7995, -4104, -6363, -8287, -8535, -10190, -4399, -5858, -9631, -15346, -16341, -5128, -6659, -6771, -9534, -9119, -6612, -7005, -5858, -6761, -7614, -10632, -5834, -6800, -5861, -5931, -9280, -4667, -11591, -5616, -4315, -6135, -4309, -8330, -5613, -3928, -5865, -4985, -5460, -6193, -6200, -8553, -6508, -7937, -3343, -9220, -7479, -7092, -7098, -3815, -7377, -7211, -10560, -7407, -4573, -4819, -7566, -10829, -9354, -4967, -4005, -9157, -7836, -11251, -4939, -4060, -12517, -7841, -9124, -5106, -4032, -9702, -9763, -8266, -5876, -3708, -8169, -12969, -8955, -7321, -4019, -8001, -13153, -12277, -7778, -5533, -8327, -10652, -9170, -6266, -8421, -8485, -7668, -6262, -5238, -12272, -9176, -5981, -5445, -4819, -11447, -10176, -5855, -6189, -5005, -9051, -7100, -7117, -8724, -5961, -11311, -5790, -8166, -15544, -6816, -9360, -5149, -8190, -8935, -5866, -9914, -6606, -9288, -12789, -10198, -444, -785, 22, -512, -111, 3825, 3700, 4011, 3732, 4105, 5934, 5876, 6050, 5867, 6151, 6562, 6530, 6678, 6554, 6749, 5860, 5810, 6005, 5934, 6042, 3714, 3491, 3871, 3867, 3881, -362, -1720, -451, -332, -462, -8244, -5334, -9966, -11060, -13928, -14965, -3825, -7231, -7838, -7538, -14237, -5644, -11454, -9635, -12447, -11333, -7218, -10735, -7740, -14281, -7785, -7484, -7030, -8134, -10768, -7984, -8501, -5343, -10237, -8640, -10149, -11186, -5127, -16213, -8201, -9637, -11594, -6077, -11188, -8957, -7394, -11445, -8346, -8459, -9894, -6577, -12171, -11157, -7507, -9402, -7244, -8254, -10331, -7807, -8790, -9451, -6069, -11115, -9174, -9743, -15000, -5165, -15623, -9049, -13810, -14946, -4951, -14153, -7619, -17394, -12244, -5271, -10076, -7398, -15090, -10956, -6246, -8342, -8767, -16558, -10643, -7892, -8455, -11276, -11013, -12434, -9863, -11098, -10564, -8306, -14245, -11683, -14496, -10210, -7352, -10358, -11766, -9902, -11844, -7797, -8521, -9587, -9240, -12672, -9598, -7539, -8180, -10056, -9348, -11558, -6969, -8082, -10771, -7471, -10510, -7045, -8843, -10586, -6675, -9127, -8457, -8768, -9414, -6932, -8309, -12611, -7940, -7554, -8612, -8127, -10569, -7552, -6501, -11995, -8345, -8661, -7566, -6721, -11127, -8660, -8710, -7776, -8403, -9893, -9024, -10124, -8184, -9859, -9545, -8899, -13021, -8806, -8623, -9544, -8291, -12631, -9539, -8508, -10086, -8184, -10718, -11079, -9891, -10988, -8798, -9846, -15501, -12770, -12005, -9506, -9090, -11859, -16988, -13076, -9577, -8205, -10545, -15281, -12434, -9458, -7601, -10825, -15101, -10698, -9846, -7697, -9290, -15813, -9752, -11370, -8616, -8167, -14591, -9649, -15588, -9597, -8495, -15462, -9906, -14673, -9892, -9926, -20536, -9793, -11426, -11057, -10986, -12734, -9231, -10131, -14054, -10780, -10743, -8703, -9892, -13703, -10864, -10543, -8545, -10911, -13096, -11370, -11418, -9104, -13976, -11827, -11626, -12918, -11025, -13271, -9958, -11491, -14768, -15232, -11312, -9615, -11615, -13200, -12779, -11637, -10649, -12531, -11272, -11775, -13881, -10788, -13604, -10618, -12568, -17230, -9775, -13103, -10832, -13373, -17598, -9893, -12065, -11959, -13262, -15866, -11391, -11454, -14518, -13114, -14350, -13728, -11407, -14804, -13246, -14622, -13285, -11845, -13064, -12030, -18307, -11760, -12159, -12305, -10412, -15123, -6324, -9477, -9400, -7057, -5710, -6352, -8487, -9278, -5078, -6096, -6298, -7707, -8482, -4442, -8448, -5661, -7246, -8358, -4752, -12692, -5302, -6206, -10007, -5788, -7182, -6166, -4983, -13270, -7494, -5273, -8510, -4454, -10594, -9438, -4780, -10193, -4690, -8615, -10919, -5125, -11052, -5489, -7798, -13036, -5854, -12236, -6499, -7745, -7401, -6635, -10632, -7170, -7794, -4840, -7557, -11145, -7431, -7733, -3910, -8096, -11765, -8948, -8494, -4135, -6962, -9891, -12542, -10049, -5225, -5766, -10963, -10163, -8393, -7226, -7008, -9025, -7379, -6072, -8597, -9535, -13454, -7980, -10483, -10619, -10454, -524, -357, -673, -521, -913, 3774, 3850, 3806, 3801, 3726, 5896, 5951, 5941, 5949, 5967, 6539, 6579, 6562, 6618, 6666, 5850, 5857, 5818, 5968, 6006, 3680, 3600, 3535, 3900, 3852, -704, -1039, -1074, -41, -442, -20425, -13137, -8880, -7008, -7180, -7676, -7249, -9812, -10616, -7360, -10279, -5481, -10821, -11285, -6744, -11031, -5069, -9065, -12055, -6518, -9991, -6225, -8756, -16333, -8667, -10592, -8419, -8312, -11250, -10011, -12191, -13430, -7967, -10377, -10608, -12739, -13080, -6812, -11457, -12300, -13509, -10314, -6313, -16158, -13876, -18989, -8759, -6995, -16806, -12813, -11600, -7944, -8763, -18811, -7810, -8523, -8087, -8626, -13671, -5455, -7530, -9310, -6986, -10603, -4667, -7855, -10926, -6627, -10213, -5114, -9406, -10426, -7630, -10276, -6652, -10178, -9082, -9365, -9640, -9105, -8955, -8049, -10069, -9361, -12141, -8768, -8044, -10018, -10155, -15871, -8742, -9890, -9962, -13161, -22128, -8200, -13833, -10789, -16792, -13824, -8273, -10713, -12965, -14624, -10183, -8548, -10172, -10605, -20387, -7962, -7851, -11897, -8350, -13740, -6838, -7172, -13924, -7292, -11677, -6817, -7315, -12211, -6859, -11522, -8153, -8547, -10846, -6858, -11643, -11284, -10893, -10119, -7332, -10993, -11217, -11394, -10115, -8360, -10006, -9632, -11033, -10993, -9848, -9822, -9397, -11758, -12169, -11656, -11314, -9647, -10253, -11377, -15028, -17323, -9926, -8792, -9976, -15320, -14192, -10389, -8646, -9355, -11446, -12505, -11423, -9549, -9778, -10204, -13602, -12870, -11143, -11814, -10021, -18248, -12820, -12849, -14717, -10517, -16157, -11201, -13626, -10610, -12078, -13136, -9927, -13163, -8579, -14304, -11833, -9257, -12540, -7856, -12246, -10955, -9144, -12407, -8209, -10861, -10350, -9797, -13195, -9967, -10891, -10379, -11896, -15556, -14905, -11801, -11591, -19418, -16477, -13344, -11845, -15351, -14372, -14073, -11411, -10850, -18659, -12416, -13199, -12060, -10790, -15823, -12264, -12718, -14280, -12046, -18986, -12902, -11598, -15084, -12664, -17066, -13984, -10396, -15153, -11569, -16303, -14781, -9857, -17401, -11389, -22830, -13452, -10185, -27068, -12151, -13558, -11746, -11330, -16623, -13653, -11224, -11074, -13063, -14198, -16091, -10707, -11621, -15303, -13355, -14189, -11493, -13829, -17195, -14040, -11965, -13852, -18027, -14642, -17286, -11045, -17219, -15206, -12429, -22284, -10583, -15085, -14255, -5111, -8181, -6549, -4897, -8234, -8490, -18312, -7810, -5765, -17195, -9800, -10653, -8301, -7841, -9189, -8646, -14834, -8803, -9710, -7281, -9213, -10024, -8625, -9340, -7338, -8926, -7689, -7824, -9330, -9147, -8812, -8023, -6553, -11359, -13026, -9700, -9056, -5691, -13529, -8406, -8745, -9062, -5610, -9201, -6813, -7212, -9078, -5853, -7526, -6881, -7424, -9496, -6434, -7064, -7710, -9464, -9887, -8019, -8062, -9180, -11192, -8688, -9004, -14243, -11558, -10074, -6315, -7134, -10315, -9984, -10918, -5924, -6393, -10145, -11123, -9806, -6673, -6775, -7294, -7563, -10028, -6767, -6627, -6054, -8211, -673, -269, -153, -410, -462, 3658, 3899, 3790, 3794, 3863, 5808, 6013, 5839, 5920, 5990, 6444, 6660, 6471, 6571, 6643, 5689, 5989, 5790, 5895, 5987, 3325, 3884, 3647, 3761, 3929, -1754, -187, -639, -440, 50, -8211, -8616, -11834, -10163, -5789, -7590, -10466, -8996, -13313, -6715, -11943, -10600, -9727, -8406, -6591, -9097, -9376, -8364, -7190, -6668, -9015, -8462, -8907, -8539, -6303, -8460, -7343, -9806, -10953, -6011, -7663, -6472, -10571, -9496, -6413, -6880, -6655, -11790, -8082, -7031, -6522, -8223, -11268, -8737, -7692, -7118, -10117, -11663, -12041, -8448, -9533, -9593, -15313, -12392, -9478, -18602, -8816, -11429, -8895, -12054, -11179, -8822, -9217, -7784, -14643, -9564, -9603, -8496, -7855, -9020, -8861, -10482, -8191, -8705, -7733, -9082, -10202, -8062, -11167, -8627, -11604, -8907, -8473, -16546, -10658, -11858, -7812, -9627, -9355, -8890, -8190, -7538, -10633, -7706, -7730, -6849, -8080, -9108, -7559, -8057, -6720, -9112, -7655, -8306, -9830, -7647, -9889, -7064, -9763, -12763, -10007, -9471, -7045, -11985, -12538, -15469, -8243, -7479, -13782, -13003, -15736, -7151, -8434, -12474, -20353, -12992, -6507, -9800, -11537, -12301, -10376, -6345, -10815, -11652, -9995, -9366, -6590, -10528, -12500, -9541, -10271, -7098, -9549, -13197, -9750, -10632, -7794, -8985, -12956, -10146, -8248, -8486, -9275, -12169, -11215, -7216, -8669, -10398, -11343, -13727, -7454, -8569, -11756, -11006, -18229, -8521, -8946, -12224, -11114, -19315, -9737, -10248, -12077, -11015, -19702, -10458, -12370, -12977, -10475, -14351, -10803, -11973, -16841, -9938, -11685, -11222, -10314, -13740, -9705, -10829, -11841, -9569, -11818, -10113, -11856, -11386, -9666, -11946, -12096, -16134, -10401, -10214, -12794, -20737, -13145, -10467, -10065, -13294, -10923, -11149, -11854, -9264, -13455, -8919, -11022, -12777, -9041, -13589, -8787, -12370, -11861, -9846, -15421, -10085, -14716, -11869, -11867, -17826, -12719, -11822, -12688, -15281, -12752, -15662, -10433, -12735, -18034, -11246, -19506, -10818, -12305, -15670, -11170, -13583, -11790, -12741, -14857, -11642, -11180, -10749, -14781, -16906, -11816, -10866, -9400, -21844, -15369, -11386, -12020, -8669, -18289, -11859, -10840, -13480, -8294, -17206, -10414, -10607, -13398, -8217, -16096, -10103, -10802, -13232, -8573, -14197, -10582, -11426, -13681, -9469, 13787, 14482, 4978, 9252, 11837, 13142, 13944, 4781, 8623, 11115, 11041, 12305, 4122, 6636, 8769, 6500, 9549, 4653, 3113, 4014, 364, 6117, 5897, 1273, -1449, 4622, 4026, 5912, 1807, -4079, 4377, 4233, 4397, 762, -2972, 2131, 4306, 2088, -94, -1821, 731, 3764, 2965, 2827, 2767, 3262, 3394, 4029, 4634, 4859, 3406, 3613, 4412, 5302, 5672, 1375, 4227, 4558, 5029, 6061, -3400, 4918, 4488, 3616, 6377, -5761, 5197, 3982, 355, 6282, -1053, 4744, 2957, 363, 5315, 1144, 3424, 2115, 2646, 3131, 1395, 1044, 2637, 3056, 656, 956, -3300, 3401, 2110, 1208, 105, -6609, 3508, 681, 1312, -4040, -3827, 2964, 2051, 978, 1360, -3994, 2019, 3680, 1426, 4160, -4790, 653, 4368, 1589, 4987, -2691, -1786, 4311, 977, 4326, -936, -2880, 3675, -26, 1433, -152, -260, 2708, -1196, -3895, -336, 944, 2077, -1140, 1532, -1804, 1016, 2018, -230, 1660, -1298, -2, 1662, -783, -759, 725, -2655, 492, -2131, -5217, 1363, -4750, -1417, 88, -5661, 1034, -2778, -3746, 1317, -4242, 311, -3574, -8503, 817, -373, -340, -2916, -7619, -68, 2394, -443, 58, -4328, 1397, 3818, -149, 1292, -2863, 2312, 3943, -590, 1294, -1452, 1738, 2645, -2903, 176, -1242, -587, -913, -3009, -2557, -3482, -6100, -3543, -97, -9954, -8191, -6916, 150, 820, -8630, -3025, -6507, 1377, 444, -7535, -2068, -5282, 1773, -1119, -5293, -1568, -3256, 1565, -4468, -4636, -860, -2027, 631, -6159, -6005, -239, -1157, -1430, -4037, -5551, 152, -397, -5342, -3689, -2472, 10, 41, -3431, -3131, -596, -819, -40, -1561, -2261, 413, -2281, -549, -1152, -1936, 780, -3916, -1306, -1405, -1886, 549, -3835, -2180, -1917, -1818, -387, -2792, -3422, -2357, -2055, -2215, -2501, -6241, -2373, -2782, -4704, -3033, -8393, -2033, -4217, -6929, -4108, -6246, -1681, -8068, -11620, -5597, -7465, -1732, -6024, -6720, -8259, -13971, -2807, -3209, -4535, -10705, -11232, -6537, -2961, -4340, -6189, -8549, -6525, -4973, -5306, -4475, -6917, -3450, -8409, -6693, -4114, -8079, -3555, -4950, -7082, -4463, -11262, -6691, -4196, -5694, -5222, -4124, -9836, -4855, -3625, -6954, -1699, -5164, -4765, -1928, -14286, -663, -4169, -4080, -956, -6668, -472, -3927, -4223, -808, -4050, -927, -4054, -4659, -1518, -3273, -2043, -4659, -4806, -2857, -3485, -4026, -5012, -5753, -3289, -4506, -7114, -4157, -8458, -2383, -6814, -8776, -3046, -10124, -1919, -9729, -8006, -2438, -8481, -2476, -7223, -8942, -2651, -8119, -4495, -6713, -10699, -3729, -9751, -9391, -8462, -9084, -4869, -12085, -14189, -11420, -7217, -4537, -9290, -6958, -10445, -5602, -3890, -8713, -2884, -7885, -5075, -4081, -6824, -993, -5433, -6297, -5445, -6813, -581, -4298, -11537, -8013, -10279, -1352, -4068, -9035, 8985, 6518, 7563, 8877, 9046, 8234, 6594, 7027, 8347, 8532, 6331, 5677, 5772, 6952, 6924, 5024, 981, 5111, 5260, 4061, 3806, 2037, 5742, 3558, 440, 967, 4386, 6629, 2409, -783, -883, 3656, 7114, 1283, -349, 2952, 2413, 7141, -2137, -67, 5129, 3158, 6509, -1857, 1100, 5734, 3958, 4491, -2596, 2334, 5404, 4255, -814, -4981, 2856, 5080, 4016, 3871, 763, 3031, 5362, 3360, 5969, 2332, 2827, 5563, 3133, 6510, 2666, 2052, 5428, 3497, 6210, 2579, 1018, 5290, 3136, 5414, 2374, 388, 5181, 962, 4383, 1588, 226, 4666, -8481, 3193, -1021, -410, 3159, -2200, 1715, -119, -2705, -842, -2369, 539, 2781, -10846, -1682, -8065, 649, 3237, -2652, 2167, -6821, 272, 1411, -187, 3126, -4139, -1393, -1419, 809, 2593, -188, -2666, 1660, 526, 549, 1751, -2642, 2880, -2175, -3542, 2355, -1774, 3630, -3843, -7162, 2117, -33, 4132, 594, -10058, 1187, 935, 3783, 1152, -5997, -1100, 903, 2279, -742, -2986, -9530, -343, -685, -1943, -1738, -800, -4534, -5764, -203, -1451, 1532, -3386, -6807, -385, -1934, 2482, 154, -5475, -748, -492, 2676, 1176, -4795, -405, 1741, 2257, 901, -4046, -832, 3050, 1426, -528, -2648, -2209, 3695, 768, -3119, -495, -2869, 3888, 478, -7138, 1492, -1466, 3557, -528, -7174, 2892, -1106, 2438, -2650, -3884, 3745, -2364, -20, -2147, -2024, 4007, -3977, -5755, -2340, -122, 3501, -3717, -2271, -6275, 838, 1949, -2174, -28, -2191, 445, -1442, -698, 540, -615, -1399, -6006, -537, -92, -1203, -4365, -1382, -2154, -1656, -2113, -3715, -389, -7872, -2267, -1547, -2291, -928, -3354, -1762, -1495, -2020, -2464, -599, -1845, -2575, -2336, -4021, 372, -2314, -4497, -2622, -4010, 282, -2952, -6128, -2952, -3405, -535, -3805, -5759, -4534, -3411, -1497, -3776, -4343, -9672, -3453, -2263, -3392, -3115, -3355, -2792, -3364, -4273, -2577, -1414, -2260, -5289, -5577, -3117, -1496, -2341, -8298, -4319, -5022, -3242, -2912, -10586, -3495, -6735, -4189, -3526, -8272, -2519, -5886, -3111, -3694, -6397, -1252, -4882, -4093, -3443, -5273, -804, -4317, -8079, -3204, -5308, -1356, -5169, -5436, -3218, -6950, -2610, -7845, -5021, -3555, -7503, -3948, -7689, -5972, -4387, -6617, -5066, -6911, -3284, -5760, -8977, -5918, -6541, -1693, -5689, -10069, -5800, -5469, -1504, -3599, -6215, -5202, -4553, -2416, -2353, -5588, -4994, -3747, -4273, -2588, -5373, -5430, -3370, -6208, -5044, -4717, -6317, -4029, -6065, -5950, -4743, -6737, -6835, -5706, -3061, -5988, -6782, -8754, -7073, -2705, -8530, -6424, -4552, -7345, -4113, -12075, -5777, -3244, -3463, -6001, -15697, -6055, -2947, -1629, -6014, -9874, -7633, -2862, -1191, -6825, -7375, -9082, -2771, -1903, -6828, -6079, -12057, -3123, -3750, -5684, -5858, 7254, 3780, 5352, 8324, 7066, 7171, 3086, 5094, 7895, 6213, 6727, 851, 4354, 6526, 3843, 5390, -2087, 3193, 4117, 3207, 2262, -2314, 1654, 2565, 3126, 2013, 745, -46, 3361, 1325, 4042, 3062, -104, 3836, 2767, 4176, 3288, 1227, 4010, 3783, 3360, 1017, 1727, 3485, 2176, 2138, -2184, 1294, 1347, -6664, 531, 1541, -80, -1763, 1195, -1041, 2582, -3103, -380, 1419, -1732, 2633, 1146, -1351, 1509, -3214, 1956, 3383, 707, 3109, -4593, 393, 3552, 2910, 2673, 1140, -2294, 1842, 3182, 2083, 3269, -1350, -478, 1649, 4232, 3696, 858, 1509, -3165, 5058, 2523, 1699, 2458, -4177, 4411, -2484, 2717, 2408, -2617, 2814, 58, 3860, 2037, -6038, 2143, 3316, 4150, 1901, -3622, 2863, 4118, 3282, 2190, -1326, 3523, 3616, 979, 2192, -1138, 3638, 1956, -3769, 1246, -1925, 2589, -1005, -4772, -664, -3082, 144, -4808, -5487, -1236, -3921, 1631, -3920, -4314, -289, -1963, 3125, -997, -878, 536, 568, 3125, 1100, -87, 1132, 2375, 2481, 2173, -588, 916, 3384, 1815, 2460, -1252, -670, 3538, 1108, 2340, -1871, -4154, 2703, 850, 1950, -2672, -4339, 499, 1269, 1169, -3861, -2132, -4124, 1562, 169, -6132, -261, -2596, 1437, -843, -2396, 722, -781, 871, -1632, -1151, 484, -292, -168, -807, -2771, -188, -270, -1242, 784, -14377, 384, -752, -1214, 1457, -2334, 652, -2146, -1095, 669, -88, -423, -4151, -2159, -1953, 663, -2218, -4541, -2894, -2170, 348, -3093, -5154, -892, -404, -488, -3708, -4906, 109, -283, -802, -2311, -3105, -386, -1719, -713, -1343, -2995, -2943, -6075, -972, -1948, -5119, -4035, -6812, -2209, -3295, -11489, -1136, -4506, -5033, -2868, -7918, -847, -5278, -7842, -2304, -3639, -2461, -4408, -11924, -2104, -1206, -4600, -2108, -7483, -1639, -277, -4610, -1091, -4659, -1884, -464, -3838, -1260, -5409, -3828, -1361, -2961, -2613, -11108, -7331, -2289, -3521, -5412, -5253, -5834, -2362, -7268, -7961, -3699, -5927, -1680, -7667, -6690, -4054, -7101, -1061, -4319, -6204, -4494, -5229, -805, -4567, -6323, -4150, -3547, -893, -8945, -6568, -4867, -2577, -1066, -7158, -7404, -8847, -2021, -890, -4696, -10328, -8292, -2006, -644, -5885, -7639, -5119, -2603, -1086, -10119, -4971, -4890, -3480, -2684, -5412, -4289, -6038, -4012, -5439, -4182, -4826, -6486, -4081, -6591, -4286, -6108, -5920, -4195, -6369, -4245, -8101, -5814, -4660, -6888, -4094, -8298, -5812, -5539, -7734, -4961, -5751, -5919, -6810, -8659, -8082, -4912, -6634, -7885, -10439, -10783, -5265, -8314, -7614, -11534, -7287, -5005, -10458, -6328, -7728, -6504, -3880, -9864, -5156, -6502, -6430, -3550, -9472, -4517, -7652, -6597, -4643, -8696, -4595, -11083, -7127, -7788, -6724, -5271, -8046, -8521, -10178, -5892, -5092, -6057, -10780, -9513, -5852, -2958, -4130, -5138, -9591, -4239, -4771, -4595, -3537, -7593, -4988, -6791, -6457, -3617, -5186, -9184, -8984, -9752, -5332, -3757, -9695, -8023, -9904, -8192, -3567, -7496, -5663, -6636, -10251, -4988, -10139, -4265, -5209, -8259, -7312, -10026, -4064, -4842, -5919, -6798, -9178, -5491, -4279, -5506, -4718, -6877, -7453, -4436, -4938, -5641, -10793, -7051, -8165, -5146, -6237, -5783, -3706, -5657, -6567, -6163, -7552, -5332, -4544, -7934, -4428, -7473, -7132, -2816, -3669, -7263, -5272, -6182, -5161, -8287, 1297, 1380, 382, 427, 1207, -5695, -8279, -4121, -8316, -6680, 8561, 8618, 8700, 8553, 8437, 13004, 13007, 12983, 12916, 12893, 15159, 15134, 15101, 15057, 15049, 15814, 15765, 15745, 15709, 15700, 15123, 15045, 15056, 15018, 15001, 12934, 12800, 12884, 12824, 12786, 8481, 8155, 8507, 8337, 8234, -6212, -3159, -3672, -8783, -6067, 355, 1573, 140, 692, 704, -6870, -5118, -3656, -13381, -7976, -3363, -8489, -2432, -4041, -3085, -13187, -6128, -4945, -14447, -7311, -7663, -3928, -4995, -7782, -6564, -11356, -5002, -6850, -10812, -11615, -6916, -5388, -8674, -8337, -12006, -7994, -4573, -8011, -5441, -11762, -8180, -4139, -6462, -4421, -16667, -10089, -4886, -7481, -4405, -7607, -13750, -5921, -8591, -4365, -5118, -9873, -7548, -9934, -5196, -5328, -8781, -10656, -14920, -6792, -7727, -9037, -11447, -11389, -8594, -14847, -9884, -10947, -8958, -9617, -6934, -9289, -10973, -8780, -9326, -5223, -7221, -8742, -8512, -9119, -5599, -6083, -6824, -7067, -9787, -7035, -6014, -5755, -6035, -12388, -7980, -7264, -5557, -6080, -13525, -8373, -10795, -6081, -7427, -10104, -7020, -11727, -7375, -11093, -7431, -5927, -8775, -8995, -13316, -5955, -5824, -8544, -9358, -9168, -5567, -6647, -11194, -9332, -7582, -5880, -8291, -12999, -10338, -6506, -6668, -9652, -8827, -10795, -6129, -8010, -10285, -7865, -9139, -6920, -9528, -11676, -7471, -8425, -8858, -9571, -11366, -7427, -8712, -10255, -9618, -10512, -8751, -8954, -9471, -11316, -11523, -14983, -9112, -8722, -16038, -13343, -10452, -10208, -9099, -11641, -9484, -7683, -10772, -11344, -9792, -7278, -7034, -11116, -15446, -10288, -6693, -7359, -16187, -12218, -11828, -7788, -7894, -9483, -11724, -10789, -12571, -8252, -6930, -13333, -10655, -11221, -8965, -6238, -12123, -12075, -8249, -10092, -6645, -9684, -12421, -8088, -9963, -7965, -8294, -11999, -9632, -8837, -10239, -7443, -12000, -13315, -8706, -11505, -7439, -12416, -14043, -10646, -10071, -8528, -13571, -10865, -15017, -8877, -10497, -11921, -8804, -11247, -7730, -13069, -10791, -7478, -11828, -6398, -15423, -12001, -7192, -20448, -5201, -16101, -13201, -8376, -13641, -4585, -14289, -9748, -13001, -13041, -4645, -11616, -8328, -11523, -14627, -5170, -11110, -8451, -8356, -13502, -5950, -12049, -9883, -7761, -10373, -7152, -12526, -12659, -8455, -8713, -9156, -11939, -16142, -9589, -8459, -12138, -11687, -14965, -9961, -10498, -4366, -6670, -6268, -6777, -7229, -6131, -9281, -8240, -7699, -8929, -7196, -10164, -9029, -7444, -11207, -7603, -9629, -8669, -5848, -6033, -7414, -11634, -7184, -5213, -4398, -8612, -8062, -6308, -5370, -3304, -13810, -6177, -7408, -4579, -2825, -7811, -5579, -7973, -3825, -3546, -6430, -4992, -8108, -3809, -4781, -4527, -4429, -6506, -4269, -4491, -4848, -3487, -4891, -7768, -3571, -7588, -2584, -3465, -8846, -7026, -5220, -5205, -4060, -11604, -5445, -2622, -4630, -3540, -3661, -13629, -16253, -13092, -4810, -7932, 231, 618, -82, 543, 843, -6248, -7054, -4917, -3788, -8231, 8605, 8622, 8675, 8654, 8498, 12929, 12970, 12956, 12954, 12918, 15061, 15099, 15067, 15070, 15063, 15710, 15741, 15699, 15705, 15706, 15022, 15042, 14988, 14999, 15003, 12839, 12842, 12761, 12787, 12794, 8398, 8357, 8181, 8271, 8320, -6355, -9827, -5114, -8031, -11445, 742, 449, 897, 548, -492, -6196, -9566, -10589, -7494, -5073, -8525, -3144, -3699, -3026, -2223, -5070, -7672, -10938, -5874, -3889, -3862, -8293, -8123, -6864, -3393, -7232, -5562, -14238, -6677, -5029, -8078, -4318, -11472, -7169, -5990, -6359, -5438, -12955, -9248, -7282, -4699, -6061, -8298, -7138, -7975, -4437, -5255, -4977, -7199, -7408, -4404, -5040, -4346, -6498, -8164, -4424, -5932, -5922, -6287, -13094, -5022, -6947, -8673, -7353, -11799, -6385, -7265, -8889, -6892, -9465, -7244, -8190, -8641, -5854, -8326, -7533, -11441, -8925, -6478, -7704, -8121, -12430, -8424, -8580, -8303, -8555, -9459, -7952, -11706, -10874, -8801, -7781, -7932, -11601, -11746, -9392, -6681, -8702, -9492, -10771, -8897, -6269, -11134, -7989, -10751, -7531, -6453, -13250, -7211, -8926, -7404, -7610, -10312, -7486, -7607, -8600, -12793, -8181, -8674, -7479, -10202, -9162, -6921, -8904, -7697, -11286, -6098, -6608, -7722, -7804, -11937, -5398, -6998, -6592, -8510, -11931, -6006, -7656, -5732, -10168, -11643, -7700, -7865, -5153, -9670, -11404, -9945, -7621, -4734, -7718, -11938, -10592, -7930, -4469, -6955, -14370, -10031, -9183, -4556, -7329, -15667, -10284, -10498, -5050, -8892, -12373, -11084, -10118, -5802, -11839, -10744, -9393, -8932, -6557, -10599, -9939, -8174, -8555, -6929, -8379, -9147, -8371, -9724, -6772, -7539, -8646, -9213, -12563, -6454, -7698, -9055, -8331, -11230, -6225, -8717, -10672, -6809, -10830, -6241, -10608, -14785, -6331, -14765, -6812, -12383, -14279, -7241, -12980, -8388, -10530, -11516, -10115, -9969, -11681, -8633, -11517, -17696, -8967, -17098, -7730, -9999, -15671, -8469, -13164, -7734, -8058, -16219, -8806, -10957, -8309, -7622, -12298, -10108, -10766, -8402, -8250, -10221, -11010, -13232, -7994, -8410, -9360, -11065, -14546, -7912, -7768, -9280, -10873, -10923, -7989, -7800, -10287, -9905, -10087, -8439, -9129, -12060, -9325, -10332, -10265, -12743, -9949, -9270, -9962, -11686, -19639, -8180, -9033, -9152, -9150, -14519, -7532, -8746, -9194, -8408, -10822, -6541, -4087, -5366, -7217, -12242, -8318, -3539, -5595, -5565, -10054, -10115, -3416, -6678, -5715, -9487, -10487, -3463, -9138, -5286, -11194, -7805, -3598, -8649, -4087, -14458, -5912, -3513, -5294, -3330, -15491, -5595, -2995, -4509, -2842, -9703, -5078, -2744, -5044, -2878, -6441, -4684, -3510, -5504, -3700, -5324, -5093, -4428, -5770, -3850, -7746, -5534, -4368, -9431, -3672, -6965, -5120, -3532, -8148, -3980, -5835, -12972, -4140, -6914, -7836, -3209, -4326, -4421, -2653, -4978, -4388, -5867, -4333, -6509, -8827, 759, 1307, 1420, -92, 441, -7569, -6729, -8428, -3816, -5727, 8547, 8521, 8509, 8797, 8689, 12911, 12937, 12918, 13017, 12962, 15045, 15072, 15054, 15101, 15063, 15687, 15707, 15695, 15716, 15688, 14985, 14996, 14991, 14996, 14973, 12773, 12778, 12783, 12769, 12751, 8257, 8274, 8289, 8231, 8207, -5729, -13222, -9847, -7725, -6606, 365, -216, 347, 366, 774, -5794, -4154, -13970, -10100, -11214, -3024, -1610, -5056, -3311, -4302, -8556, -5486, -9925, -10494, -10449, -8816, -15377, -7035, -9377, -10897, -9692, -6966, -10351, -7962, -7623, -6415, -5614, -6263, -6224, -6176, -8085, -6004, -8928, -7974, -8482, -8961, -6683, -15713, -8733, -11044, -8909, -9524, -9595, -6530, -10027, -9220, -16761, -7156, -6052, -9278, -8183, -10191, -6519, -8056, -10499, -7503, -8314, -6524, -9726, -8568, -7912, -7454, -6168, -7788, -6564, -8006, -7323, -6360, -6623, -5660, -7513, -8958, -7956, -6270, -5558, -7624, -12761, -8830, -6275, -5664, -9072, -13250, -8080, -6211, -5807, -11441, -10268, -8066, -6481, -6255, -11688, -8512, -8791, -7602, -6731, -9345, -7804, -8950, -9074, -6544, -7603, -7631, -7568, -9252, -6544, -6215, -7159, -6531, -8562, -7341, -5194, -6266, -6163, -8140, -8458, -4865, -5520, -6092, -7987, -7760, -5326, -5329, -6243, -7926, -6852, -6405, -5870, -6721, -8345, -7595, -7663, -7234, -7119, -10125, -10775, -8350, -8534, -7286, -16410, -8787, -7965, -7840, -7968, -12117, -7281, -7110, -7247, -9360, -9899, -8670, -6584, -7114, -10510, -9248, -13548, -6732, -6288, -10753, -9136, -8383, -7539, -5229, -10635, -9847, -7519, -8798, -4756, -9004, -10133, -9215, -10716, -5047, -7250, -7926, -15045, -11737, -6079, -6478, -6366, -13869, -9279, -7261, -6801, -6041, -12884, -8079, -7599, -8272, -7054, -12862, -8067, -7855, -10268, -10148, -11724, -8568, -8570, -10879, -14031, -10273, -8699, -9357, -11814, -9495, -8848, -8366, -10098, -12661, -8400, -7876, -8351, -10997, -11791, -8652, -7701, -8922, -10359, -10201, -9356, -8575, -9593, -9505, -8288, -9822, -11194, -10080, -11126, -7323, -10529, -21742, -10828, -10949, -7205, -11905, -11172, -12073, -7210, -7450, -13675, -9491, -14562, -6110, -8045, -13884, -9622, -13397, -6723, -9438, -11220, -11368, -11545, -9052, -12156, -10030, -16389, -12288, -12561, -18890, -10493, -15268, -16791, -11629, -15410, -12913, -14502, -14921, -11217, -12042, -19888, -28647, 13098, 8550, 12481, 11510, 6595, 12477, 8828, 11738, 10975, 6030, 10405, 8846, 9290, 9300, 4418, 5407, 8596, 4699, 6340, 3498, 4144, 8868, 3899, 2446, 4495, 6787, 8970, 2932, 1036, 4904, 6608, 8465, 1355, 3923, 4740, 4907, 7665, 1149, 4657, 4591, 551, 6910, 744, 2513, 4346, 634, 6196, 1842, -279, 3940, 3736, 5306, 2460, 4698, 3741, 4214, 4093, 2261, 6028, 3943, 2999, 3252, 2051, 5861, 4558, -1126, 3221, 2513, 4490, 5250, -2272, 2371, 2501, 2731, 5767, 1238, 375, 1447, 3380, 5850, 1900, 2377, 1045, 3946, 5011, 2334, 3950, 2051, 3233, 2580, 3282, 3982, 2613, 1159, 159, 3710, 2869, 2481, 487, 1210, 3661, 1243, 1716, 2588, -657, 4677, 1926, -421, 3542, -546, 5690, 3141, -7300, 3727, 2018, 5486, 2751, 1503, 3443, 2021, 4042, 1177, 3537, 2839, 305, 2858, 2208, 3935, 2313, -2395, 2622, 2907, 3506, 1766, -2201, 820, 1286, 2877, 816, -25, -2138, -2230, 2460, -253, 1158, -185, 2089, 2181, -948, 1834, -429, 3619, 1837, -1815, 2181, -2963, 3555, 1253, -3382, 1436, -7497, 2318, -221, -1989, -2519, -3937, 466, -5658, -553, -383, 130, 109, -2147, -554, 2605, 1478, 993, 944, -327, 2950, 1038, 1962, 1665, 621, 1470, -1293, 2675, 1147, 637, -1902, -6527, 2557, -113, -766, -2756, -2414, 1072, -1280, -3066, -1732, 176, -407, -1687, -1358, -1275, 1793, 1532, -1903, 714, -738, 2727, 2283, -2128, 1424, -1013, 2830, 1480, -1826, 1085, -2187, 1872, -748, -1223, 504, -1724, -540, -3577, -1331, 302, -372, -3290, -3077, -2456, -212, 453, -1665, -2179, -2590, -1244, 769, -958, -2758, -1194, -2220, 646, -1298, -5466, -206, -3085, 298, -2484, -13396, 244, -3976, -448, -5072, -6577, 67, -3844, -1491, -15234, -3075, -866, -2785, -1116, -7562, -1541, -2665, -2528, -294, -7910, -1687, -5553, -3298, -160, -10161, -3578, -10016, -3192, -472, -3439, -5625, -9486, -2319, -951, -1201, -4550, -9342, -2459, -1431, -458, -4420, -6978, -3757, -1541, -854, -3911, -4840, -6298, -1450, -2480, -2853, -3829, -7433, -2031, -5517, -2518, -2354, -5552, -3672, -8558, -2856, -980, -3831, -4039, -6818, -3270, -177, -2357, -3496, -4436, -2980, 111, -1947, -5155, -3473, -2306, -187, -2633, -5752, -3380, -2078, -1182, -3664, -3089, -3429, -2692, -2826, -3918, -2817, -3812, -4573, -4250, -3465, -4590, -5220, -9117, -4231, -3124, -8516, -7993, -11830, -4338, -3576, -11939, -7717, -7077, -4823, -4840, -12315, -4104, -4608, -4103, -4752, -7408, -1875, -3730, -3127, -3489, -5600, -790, -4849, -3237, -3361, -3940, -662, -9472, -4932, -4740, -2668, -1493, -4366, -5298, -7908, -2498, -3603, -2126, -3150, -9119, -3642, -8609, -1767, -2772, -5899, -6106, -6767, -2754, -4208, -3280, -5059, 6690, -8153, 10131, 7048, -919, 6500, -1237, 9535, 7554, 1466, 5763, 2689, 7584, 8134, 2435, 4781, 4620, 3350, 8012, 1830, 5661, 5048, 658, 7105, 778, 6783, 4105, 3704, 5783, -74, 6618, 2593, 4285, 5187, 720, 5186, 2589, 3617, 5421, 1199, 4084, 2423, 1579, 5335, -518, 3879, 2804, -894, 4502, 692, 1989, 4329, 1791, 2961, 3354, 1889, 5035, 3692, 1175, 4608, 4214, 4861, 3955, 476, 5123, 4452, 4207, 2604, 1752, 4949, 2423, 3388, 1864, 3468, 3937, -2942, 2577, 4006, 4407, 2053, 2979, 2078, 5120, 4232, -451, 4465, 1539, 5069, 2721, -2834, 4398, -366, 4056, -1059, -4394, 3825, -1555, 2553, -3650, -4648, 3783, 984, 1518, 220, -2108, 4223, 1564, 1432, 1126, -416, 4287, 927, 1765, 985, -266, 3353, 180, 1171, 1319, -1422, 700, 323, -1087, 2497, -1730, -3577, 986, -4078, 3156, -379, -145, 804, -5633, 3189, 347, 692, -838, -2836, 3184, 591, 372, -3742, -1062, 3175, 815, 775, -4880, -1859, 2491, 1139, 1429, -2167, -6691, 487, 1412, 1693, -494, -3217, -4289, 1377, 2490, -297, -193, -6386, 972, 3451, -977, 1287, -4593, 571, 3687, -1970, 2053, -4635, 521, 3061, -3478, 2249, -3130, 572, 2009, -2216, 1942, -2060, 642, 1428, 431, 1191, -2079, 677, 1189, 1781, 15, -3089, 122, 430, 2063, -996, -816, -1523, -2164, 1360, -575, 1708, -3664, -6231, -374, 368, 2832, -4666, -355, -2308, 889, 2960, -3159, 1093, -1614, 588, 2495, -820, 1216, -287, -1047, 1888, -233, 463, 180, -5792, 1396, -1210, -1699, -456, -5831, 827, -1932, -4360, -1542, -3116, -181, -1081, -1611, -1293, -2754, -1835, -1012, -752, -892, -3009, -3416, -1665, -1331, -1022, -3744, -2976, -2081, -3307, -1008, -5304, -1919, -2296, -6978, -599, -9515, -1543, -2617, -2689, -324, -5503, -2134, -2837, -849, -552, -2105, -4034, -2991, -641, -1427, -987, -9344, -3313, -1334, -3026, -1507, -5572, -3958, -2143, -3900, -4232, -2728, -4591, -2131, -2097, -11497, -1606, -4683, -1188, -635, -4314, -772, -4588, -392, -95, -3143, 504, -5553, -420, -401, -3153, 1642, -12972, -1425, -1560, -3376, 2085, -5530, -3346, -3278, -3476, 1682, -3339, -6006, -4696, -2954, 318, -3931, -8714, -4326, -1709, -2490, -3776, -10887, -1777, -777, -10400, -1479, -12866, -745, -686, -5189, -826, -8513, -1537, -1478, -4025, -1742, -7835, -3353, -2888, -5665, -3837, -6347, -2788, -3952, -17953, -6267, -4056, -2692, -4012, -4997, -8544, -3186, -4337, -4604, -2943, -5270, -3660, -6473, -9815, -2948, -2994, -3978, -7759, -4141, -4830, -1837, -2409, -9588, -365, -8098, -1245, -1044, -7724, 1152, -7450, -1150, -518, -3907, 1373, -5088, -1650, -941, -1635, 501, -2392, -2714, -2385, -835, -1466, -920, -3973, 8763, 8553, -1506, 9043, 5045, 8329, 7818, 4856, 8679, 5189, 7124, 5235, 6475, 7547, 4899, 5539, -2724, 5978, 5518, 3051, 4243, 1960, 3948, 2257, -764, 3257, 2827, 3653, -4867, 3192, 1750, 1546, 4642, -1789, 4821, -503, -1688, 4092, 759, 4430, -877, -10154, 1867, 814, 540, 675, -6481, 292, -964, 1989, 2501, -5274, 1801, -2428, 5702, 3249, 984, 1939, -1699, 6847, 2841, 3143, 325, -4114, 7089, 2120, 3203, -449, -1716, 7005, 1932, 879, 1514, 1679, 6616, 1470, -1494, 1524, 2209, 5686, 383, 1209, -1306, 129, 4051, -917, 274, -2145, -4903, 1958, -3227, -10316, 421, -2018, 2525, -6570, 1371, 165, -7468, 4230, -1425, 3275, -1489, 652, 4741, 506, 3377, -3377, 3027, 3845, 1603, 2098, -3518, 3347, 845, 2379, -1130, -505, 2476, -1302, 2437, -2395, 1055, 832, 1731, 1313, -13, 1424, -1240, 1930, -1705, 66, 1181, -2536, -493, -10492, -1451, 1033, -3839, -1341, -10204, -4003, 1254, -2854, 2599, -4882, -4488, 1321, 1188, 3988, -429, -2851, 976, 3064, 4135, 1534, -2062, 521, 3641, 3510, 2383, -2765, 362, 3398, 2477, 2512, -4557, 551, 2803, 1501, 1934, -2537, 731, 2299, 1677, 334, -1009, 638, 1833, 3102, -2805, -1109, 447, 969, 4139, -2513, -2382, 332, 160, 4254, -556, -4855, 342, 1225, 3384, 230, -9011, 901, 2469, 1469, 344, -1342, 1682, 2800, -1616, -299, 1071, 1871, 2211, -4908, -1796, 1832, 1146, 841, -4058, -3723, 1510, -467, -884, -1918, -4119, 501, -1711, -2314, -531, -2890, -225, -1369, -3129, -539, -2156, -60, -1479, -3522, -2704, -2097, -308, -2167, -4943, -4489, -2310, -2024, -1823, -6980, -1326, -2668, -4405, -951, -3549, -759, -3620, -2580, -708, -1778, -1286, -4578, -2603, -1275, -1417, -1385, -4056, -6586, -2563, -2143, -1543, -3927, -5338, -3925, -3430, -2858, -3746, -2880, -4848, -3057, -6455, -3291, -3926, -5108, -1669, -7064, -3807, -11714, -3433, -786, -2551, -3780, -5750, -2579, -553, -530, -2358, -3964, -3609, -1075, 313, -1908, -4017, -7855, -2455, 274, -2862, -4266, -6328, -4246, -274, -4876, -3763, -3283, -5502, -747, -4153, -2845, -1491, -8382, -1394, -2877, -2209, -403, -9169, -2948, -2452, -2235, -95, -4587, -3623, -1834, -3028, -594, -2742, -2108, -1247, -4172, -2123, -1891, -1002, -1352, -4534, -5646, -1920, -289, -2096, -4388, -7798, -3139, -214, -3092, -5273, -5865, -6345, -1249, -3905, -8090, -9013, -7257, -4051, -3610, -4638, -7809, -5399, -7985, -2443, -2722, -4250, -5762, -4407, -1562, -2710, -3316, -6933, -2448, -1343, -3403, -2966, -9019, -1554, -1776, -3475, -3180, -8528, -1840, -2636, -4344, -4117, -2747, -3535, -3723, -9379, -4126, -312, -3640, -5202, -6598, -3572, 711, -1680, -6312, -3807, -3978, 831, -1188, -4245, -4310, -7584, -1936, -2416, -3598, -3759, -6397, -1902, -1112, -4363, -2385, -4368, -2542, -971, -7739, -1412, -4526, -2295, -1956, -5969, -909, -9751, -1952, -3951, -3203, -1013, -5079, -2482, -5007, -2823, -1841, -2115, -3485, -3893, -4508, -3042, -1813, -3944, -2476, -8390, -3065, -3524, -3411, -1102, -5568, -2684, -5474, -2825, -289, -5226, -3652, -2696, -2998, -310, -5345, -8172, -1250, -4284, -1246, -3334, -6708, -857, -7354, -2712, -2274, -3151, -1019, -9777, -2957, -2140, -2087, -1432, -5676, -2471, -2637, -2178, -2087, -3877, -2453, -4159, -3341, -3348, -3197, -2388, -7626, -5980, -5700, -3484, -2026, -4123, -5319, -5244, -4475, -1800, -1513, -2944, -2875, -4371, -1973, -696, -2443, -2122, -3853, -2977, -1062, -3546, -2808, -4503, -5683, -1769, -6391, -4870, -4615, -6658, -1760, -9873, -6902, -2950, -4382, -1757, -8724, -7033, -1944, -4151, -2451, -6731, -8317, -1880, -5179, -3833, -5847, -8860, -2768, -5707, -5330, -5913, -6610, -4725, -4401, -5875, -6154, -6022, -5516, -3292, -6049, -6410, -6349, -4202, -2875, -6326, -6422, -5028, -3904, -2945, -6690, -5428, -4164, -4081, -3296, -7285, -3982, -5411, -4086, -4066, -7589, -3160, -9155, -4876, -6195, -8635, -3481, -6154, -7075, -13717, -17795, -5003, -5407, -6101, -4434, -6576, -5973, -6237, -4436, -2085, -3952, -5654, -5689, -4266, -1523, -3278, -7182, -4895, -5054, -2485, -4046, -8509, -5342, -6065, -5898, -5987, -3994, -6742, -6265, -7377, -5848, -2032, -6876, -4901, -3902, -4456, -1474, -5497, -3380, -3330, -4201, -2127, -4147, -2510, -4583, -4967, -4416, -3244, -1952, -8653, -6811, -11506, -3228, -1339, -6706, -10673, -7462, -4530, -996, -4300, -9813, -5660, -7329, -1301, -3779, -7764, -4954, -5833, -2200, -4394, -8093, -4546, -4186, -3206, -5595, -9355, -4807, -4028, -4239, -6176, -8076, -5462, -4511, -6117, -5945, -6543, -5732, -4528, -9712, -5220, -5844, -5094, -4086, -9797, -4710, -5940, -3813, -4005, -6182, -4521, -7039, -3016, -4075, -4228, -3924, -8014, -2996, -3576, -3577, -3383, -6866, -3434, -3182, -3886, -3540, -6838, -3964, -3752, -4418, -4241, -8312, -4467, -5897, -4328, -4970, -7845, -4810, -10414, -4067, -5665, -7341, -5217, -8887, -4270, -6873, -8852, -6348, -9758, -5437, -10058, -9898, -8191, -11707, -8987, -10901, -9673, -6973, -7642, -9459, -6637, -15261, -6045, -7429, -5868, -5225, -6272, -7219, -10226, -4687, -5036, -3421, -10001, -13849, -4330, -5559, -2544, -8478, -12205, -4389, -6394, -3113, -7046, -11090, -4939, -7445, -5228, -6198, -9975, -6280, -9031, -9711, -5579, -11368, -6788, -10330, -11091, -5669, -10241, -4890, -8679, -8822, -6936, -7734, -3785, -6695, -7786, -7611, -6787, -3772, -5455, -7664, -6296, -6440, -4766, -5136, -8690, -6163, -5953, -6939, -6212, -9519, -7597, -5168, -8792, -10846, -8362, -11220, -4762, -7115, -7982, -8059, -14884, -5349, -6460, -5340, -4174, -1237, -4037, -530, -4954, -4174, -2522, -3614, -994, -6100, -2920, -3954, -2632, -2247, -9287, -1616, -4426, -2914, -4583, -5939, -845, -4044, -3528, -6908, -2561, -797, -4028, -2921, -4638, -1136, -1577, -4795, -2614, -3579, -1038, -3496, -5431, -3322, -3708, -2270, -7766, -4628, -3843, -4251, -5138, -7506, -3381, -3110, -4437, -7679, -4581, -2569, -2639, -4356, -7414, -3575, -2247, -2931, -4870, -6583, -3313, -2108, -3925, -6622, -4064, -3390, -1943, -5490, -7479, -2462, -3729, -1799, -7472, -5139, -1960, -4159, -1785, -11648, -3484, -2290, -4479, -1986, -10230, -2910, -2944, -5338, -2099, -6642, -4165, -4211, -8715, -1448, -5782, -8041, -8232, -8483, -722, -5205, -3221, -5106, -4944, -913, -4297, -1544, -3085, -3364, -2204, -3838, -1820, -3118, -1824, -2690, -3507, -4098, -3537, -968, -1757, -2774, -21301, -3335, -1385, -1588, -1829, -4718, -2810, -3704, -1814, -1186, -3376, -2211, -21827, -1887, -1290, -4445, -2342, -4557, -2236, -2360, -8339, -3652, -3064, -2763, -3372, -6379, -6009, -3624, -2998, -2490, -4106, -8994, -6324, -3087, -2093, -4128, -13751, -9152, -2466, -3083, -7281, -11801, -4567, -1805, -4833, -8001, -10322, -3041, -2281, -3630, -4067, -9236, -3017, -4560, -1911, -3684, -8263, -4517, -10479, -1119, -5675, -6364, -10327, -20358, -1023, -10732, -4767, -6247, -8368, -1528, -4746, -4216, -2983, -4246, -2913, -2574, -4841, -1884, -2734, -6145, -1727, -7198, -2100, -2697, -11135, -1772, -7530, -3580, -3827, -7508, -2708, -4040, -6147, -6024, -7296, -4290, -2445, -7961, -8740, -5872, -4995, -2092, -7900, -10261, -4057, -5117, -2828, -5617, -9008, -3259, -6224, -4583, -4048, -7363, -3309, -7746, -6672, -3700, -7212, -4105, -7622, -9777, -3554, -8676, -6131, -6578, -5873, -2582, -10892, -12501, -5608, -2886, -1768, -7949, -6930, -5185, -2165, -1734, -4853, -4810, -5409, -3225, -2563, -3271, -4393, -6393, -6190, -4328, -2921, -4492, -5464, -6662, -6721, -3605, -4504, -2806, -5473, -7027, -5113, -4566, -1484, -5975, -6032, -6411, -5262, -1418, -7516, -5429, -5497, -7180, -2201, -8448, -5025, -4215, -8562, -2727, -7362, -4902, -3800, -7443, -2685, -6053, -5415, -4525, -7229, -3456, -5082, -6395, -6904, -6703, -5888, -4365, -6522, -9974, -5301, -7193, -3975, -5716, -6555, -4081, -6234, -4262, -4815, -4722, -3544, -8030, -5932, -4538, -3835, -4174, -10042, -12196, -5802, -3681, -7210, -5852, -8365, -11229, -4208, -10922, -4575, -6589, -6415, -5101, -5875, -4948, -7750, -4057, -6052, -5357, -6997, -11230, -3570, -7159, -6148, -12133, -7698, -3994, -8878, -6703, -11760, -4551, -4813, -13831, -7419, -7405, -2793, -5913, -12081, -9096, -5796, -2280, -7953, -9445, -8924, -5801, -2982, -14337, -9974, -7061, -6966, -4944, -8875, -10837, -5828, -7896, -8018, -6489, -8304, -5412, -7048, -8014, -6504, -6799, -5686, -6278, -6303, -8279, -6485, -6170, -6540, -5936, -5547, -3390, -4884, 313, -2275, -5205, -3825, -4419, -712, -6002, -6433, -4252, -3189, -2211, -7314, -9619, -4710, -2507, -3601, -3322, -6767, -6094, -2362, -3490, -2405, -4586, -10020, -2379, -3266, -2906, -3675, -10631, -2392, -4206, -4625, -3173, -8286, -2611, -5431, -5448, -2849, -8566, -3250, -4016, -2558, -2961, -7528, -4419, -2752, -883, -4098, -5385, -6192, -2356, -731, -8262, -3910, -8129, -2542, -2219, -5083, -2952, -5691, -3190, -5673, -1978, -2423, -2901, -4317, -4986, -924, -2528, -1423, -5413, -3747, -850, -3729, -1128, -4775, -3680, -1003, -7519, -2264, -3471, -3324, -746, -8795, -6607, -2657, -2284, -461, -4480, -6069, -2310, -1272, -796, -3395, -3008, -2363, -836, -1808, -3736, -3082, -2986, -1026, -2795, -5576, -5211, -4724, -1269, -3337, -11530, -5590, -9675, -898, -3985, -7161, -3814, -7127, -399, -4453, -4459, -3717, -4424, -272, -4145, -3612, -4997, -3564, -698, -3620, -3438, -7013, -3593, -2199, -3800, -3317, -8395, -4469, -7607, -5528, -3399, -7366, -5659, -4618, -14263, -3532, -5910, -5974, -1672, -5954, -2692, -4889, -4994, -1074, -3646, -1954, -3507, -3351, -1526, -3297, -2598, -2770, -2700, -2589, -3889, -6451, -3521, -3070, -4159, -4155, -5944, -6990, -3590, -6149, -3818, -2166, -9168, -4215, -7917, -3963, -1372, -4878, -6426, -7147, -4834, -2278, -3570, -10798, -4734, -5753, -5726, -2839, -6221, -3579, -5617, -9161, -2446, -4039, -3903, -4882, -4570, -2575, -2848, -5119, -4334, -4000, -2973, -2471, -5503, -4278, -4478, -2937, -2861, -6736, -4598, -5032, -2978, -4320, -9367, -4628, -6017, -4192, -10281, -4014, -4672, -8068, -5377, -5145, -1725, -5761, -10937, -3245, -2092, -688, -4328, -10058, -1908, -1239, -363, -1743, -6145, -1607, -1582, -580, -715, -4074, -2175, -2512, -1221, -956, -3665, -3863, -3144, -2089, -1971, -5056, -4436, -3419, -2881, -2545, -9684, -2025, -3608, -3396, -2396, -12097, -994, -3362, -3588, -2442, -10976, -1438, -2872, -3295, -3008, -11353, -3386, -2753, -2876, -4564, -8431, -7063, -3675, -2700, -9427, -7128, -8582, -6544, -2614, -7480, -6192, -8026, -6297, -2497, -4253, -4874, -8420, -3969, -2731, -3707, -3623, -8860, -3467, -4105, -4764, -2854, -8585, -3975, -7415, -5983, -2595, -7169, -4972, -5572, -5020, -2861, -5735, -6013, -3911, -4773, -3655, -5287, -7482, -3890, -5173, -4776, -6153, -10354, -4815, -4027, -5856, -7702, -8618, -6613, -2938, -6685, -6564, -6505, -8551, -3061, -7454, -5335, -5890, -6235, -4488, -8389, -5273, -6417, -4250, -6685, -7292, -6254, -8490, -3528, -7534, -5091, -8071, -16270, -3670, -8866, -3933, -8751, -10555, -4230, -13174, -3898, -7635, -7917, -5234, -11510, -4896, -6785, -6733, -6968, -9992, -6789, -6312, -6186, -6140, -10876, -9400, -6279, -6354, -4174, -14447, -13489, -6691, -7307, -3387, -9865, -9254, -7337, -6874, -3650, -8955, -6250, -8217, -5054, -4855, 6703, 3204, 1586, 6835, -3668, 6345, 2720, 1801, 6394, -1134, 5365, 1177, 1741, 5107, 1061, 4119, -2197, 898, 3222, 2289, 3167, -8615, 284, 1169, 2993, 2409, -2027, 1073, -2036, 3106, 1086, -1293, 1938, -5374, 2331, 547, -1753, 2523, 5, 797, 1067, -24, 2946, 1931, 656, -1071, 1855, 2833, 2952, 2201, 1457, 3108, 1416, 3439, 3749, 4705, 4256, -32, 3213, 5112, 5749, 5414, 2752, 1872, 5989, 5477, 6280, 3819, -160, 6105, 4546, 6504, 2810, 1047, 5312, 3980, 5820, -433, 1945, 3821, 3567, 3844, 2125, 1419, 2976, 2419, -320, 3857, 176, 2403, 1613, 164, 3877, -1456, -24, 2528, 1172, 2732, -3532, -1812, 2889, -517, 1047, -144, -435, 2003, -408, 292, 1904, -883, -362, 1147, -1093, 2728, 1437, -5296, -94, -8915, 2993, 2659, -7021, -10282, 1091, 2931, 1639, -4613, 811, 3232, 2468, -3024, -2828, 2863, 3548, 1460, 1274, 126, 3568, 2711, -394, 3262, 1813, 3683, 1363, -4406, 3223, 2242, 3312, 403, -1225, 1673, 1474, 2497, 23, 1854, -1056, -1611, 1466, 825, 3183, -2861, -3901, 473, 1839, 3504, -5223, 1113, -398, 1868, 3128, -6163, 2229, -1538, 795, 2285, -3406, 1855, -2338, -252, 1237, -3807, 544, -276, -252, 395, -4846, -970, 948, -1082, -25, -2043, -860, 533, -2352, -229, 9, 484, -1634, -993, -505, 1165, 1547, -3511, -590, -974, 1707, 2050, -2970, -2518, -1589, 1697, 2108, -5249, -2631, -2542, 1152, 1867, -7052, -177, -3760, 137, 1291, -3246, -75, -3836, -1175, 229, -3124, -2183, -2316, -2709, -1316, -3948, -6511, -993, -4539, -3187, -2271, -6249, -588, -4778, -5457, -695, -10341, -1169, -3864, -4383, 156, -7273, -2097, -4081, -2309, 567, -4283, -1895, -5611, -1484, 490, -3179, -1638, -6577, -1538, -352, -2336, -2480, -5376, -2014, -2253, -1795, -4154, -4983, -2025, -3769, -2038, -3711, -5141, -1714, -2523, -3799, -2234, -4715, -2128, -1522, -9073, -1593, -3986, -4264, -1285, -7244, -1632, -3726, -5375, -2149, -8677, -1852, -4676, -1688, -4917, -7194, -1826, -8096, -492, -12282, -2964, -1637, -7885, -1091, -6994, -2175, -1556, -5414, -3828, -5926, -3777, -1687, -4540, -20328, -5444, -8621, -1951, -4144, -6359, -4912, -3849, -2310, -4653, -5526, -4968, -2186, -2929, -6903, -5798, -5746, -2091, -4192, -8093, -5356, -6310, -2948, -6581, -5592, -4002, -6308, -4391, -7763, -5412, -2773, -7445, -5002, -6596, -8029, -2051, -14411, -4477, -7266, -10649, -1923, -8147, -4639, -10554, -7352, -2289, -6031, -5873, -13132, -8828, -3032, -6298, -7359, -9153, -7857, -4502, -7934, -7195, -6047, -4379, -7915, -9677, -5741, -4285, -3318, -9178, -9480, -4826, -3693, -3636, -5388, -7589, -5189, -4258, -4850, -4741, -5690, -7230, -6325, -6145, -6763, -4460, -9858, -11254, -6214, 1293, 6143, 1369, 3002, -6919, 2589, 5625, 2395, 2359, 1396, 3514, 3919, 3497, -60, 4035, 2884, 548, 3781, -7328, 5095, 458, -776, 3353, -198, 5134, 590, 749, 2328, 1795, 4407, 3217, 1141, 412, 2568, 3058, 4693, 983, -4580, 2762, 858, 5438, 119, -3118, 2391, -2306, 5534, 1281, -1659, 1589, -3437, 5182, 4135, -72, 1068, -106, 5599, 5719, 3958, 1330, 2715, 6580, 6093, 5937, 1590, 3934, 6784, 5487, 6334, 1391, 3827, 6024, 4268, 5213, 2532, 2476, 4725, 2996, 1936, 4331, -143, 3626, 1903, -1202, 5311, -3511, 2869, 75, 1116, 5583, -4604, 1661, -5912, 358, 5407, -3736, -1659, -312, -3236, 4889, -4575, -6926, 993, -10314, 4077, -4774, -2910, -919, -8073, 3183, -3574, -2594, -1749, -4815, 2386, -4578, -223, 2025, -402, 1379, -3131, 1151, 3552, 1653, -307, -1652, 1588, 4067, 2550, -1863, -2704, 1634, 3913, 2716, 128, -4038, 1601, 3233, 2298, 1743, -976, 1691, 2509, 1212, 2014, 106, 1861, 2459, -545, 910, -530, 1893, 2695, -1881, -2392, -3240, 1653, 2586, -1497, -7493, -4522, 1314, 1810, -577, -1369, -554, 1343, -279, -149, -17, 1383, 1717, -1704, -736, -337, 2342, 1784, 1357, -2468, -1523, 2672, 1083, 2579, -4590, 301, 2526, -625, 2299, -4465, 2389, 1926, -3639, 566, -2154, 3378, 857, -5484, -3344, -534, 3636, -375, -2516, -12965, 58, 3478, -860, -379, -4807, -35, 3069, -38, 1062, -567, -587, 2468, 1059, 1903, 1600, -1397, 1548, 1590, 2101, 2320, -1832, -55, 1443, 1640, 1993, -2134, -1309, 726, 561, 1127, -3168, -521, -312, -1202, 354, -4864, -373, -945, -4005, -663, -6055, -1355, -869, -4117, -2990, -5865, -3041, -902, -2457, -8170, -5027, -4746, -1442, -2935, -10249, -4432, -5016, -2340, -7190, -6067, -4864, -4258, -3037, -6829, -2751, -6363, -3300, -3169, -4239, -1698, -5350, -2072, -3388, -5548, -2701, -3534, -1137, -4792, -7117, -7722, -2995, -814, -8137, -3626, -6399, -3808, -1096, -7043, -2003, -4058, -6258, -1518, -6399, -1569, -4900, -9322, -1486, -6839, -2077, -8802, -7117, -1405, -5116, -3519, -8928, -5047, -1596, -3431, -5787, -5447, -4194, -1928, -2840, -6319, -3920, -4545, -2079, -3631, -4603, -3377, -5533, -1722, -6507, -3148, -3755, -5508, -1590, -10105, -2108, -5016, -5074, -2436, -9812, -1715, -6540, -5372, -4575, -11719, -2270, -6622, -6098, -6740, -5126, -4204, -5991, -7256, -5343, -3221, -8612, -5590, -9812, -4101, -3040, -8594, -5369, -9472, -3783, -4275, -6415, -5323, -8459, -4783, -6485, -5315, -5352, -9788, -9495, -5953, -4822, -5571, -10721, -6150, -5775, -5135, -6381, -10666, -3189, -8294, -6049, -7777, -12603, -2586, -7554, -6878, -8223, -10970, -3410, -5760, -6977, -5866, -9642, -5563, -6499, -6528, -4094, -9282, -9337, -8436, -6019, 6460, 8585, 6506, -1671, 2320, 6263, 7904, 6607, 4638, 4738, 5687, 6070, 6838, 6771, 5155, 4927, 4654, 6804, 7110, 3835, 3991, 3955, 5957, 5941, 436, 2319, 1879, 3752, 2813, -1564, 1025, -2462, 1189, 481, -1290, 1768, -6966, 2144, 1278, -4873, 1698, -2827, 2060, 2646, -3446, 695, -839, 2309, 5169, 1280, 485, -121, 3583, 6523, 3448, 1856, 216, 3940, 6911, 4334, 2638, 242, 2952, 6260, 4036, 2291, -887, -240, 3493, 2322, 858, -4898, -6552, 1023, -1619, -2154, -1399, -694, 5282, -1276, -6278, 670, -750, 6114, 394, -1566, 783, -2170, 5681, -62, -1027, -185, -2775, 5170, -2306, -3586, -1760, -3144, 4729, -7322, -3833, -3287, -1245, 3711, -19766, -589, -3358, -222, 2242, -8093, 27, -3191, -970, 1022, -4243, -1122, -3548, -3359, 209, -3298, -4685, -2986, -5363, -298, -4225, -7646, -1347, -5386, -964, -8173, -6611, -132, -5248, -1823, -6344, -5415, 315, -4457, -999, -2598, -2179, 144, -3868, 105, -1560, -1501, -509, -3549, 279, -2197, -2952, -1794, -3053, -246, -3620, -5376, -3607, -2577, -1222, -2705, -4183, -4144, -3278, -3791, -1762, -2836, -2395, -6206, -5145, -1087, -2115, -305, -1526, -1274, 104, -2627, 818, 929, -498, 781, -4614, 704, 1460, -1142, 253, -4524, -603, 434, -2681, -2192, -2584, -777, -2499, -5398, -5049, -1574, 712, -11590, -2509, -2376, -1586, 1435, -3710, -250, -3423, -1846, 1829, -1418, 701, -2715, -487, 2131, -1248, 1073, 867, 716, 1818, -3331, 1106, 2047, 902, 523, -12523, 682, 1608, 253, -1466, -6181, -499, -528, -912, -1687, -5199, -2605, -6409, -2194, -639, -4671, -4952, -5239, -3145, -138, -4332, -7433, -3721, -3566, -337, -4663, -12593, -5254, -3552, -1391, -4762, -7195, -8644, -3370, -3758, -4647, -6089, -5053, -3458, -6957, -4791, -6491, -3648, -4299, -5356, -4950, -5986, -4012, -6366, -4894, -5337, -4762, -5765, -9859, -5770, -6680, -4250, -7849, -8077, -6539, -8993, -4049, -7880, -5595, -7021, -7878, -3440, -7817, -4289, -9246, -6359, -2550, -7828, -3690, -14931, -5444, -2002, -6701, -3536, -8096, -4238, -2251, -5883, -3852, -7104, -3132, -3703, -6021, -5128, -8187, -2707, -7868, -6281, -9567, -9829, -3158, -8433, -6121, -7803, -9826, -4530, -4120, -6513, -4211, -8745, -6605, -2590, -7734, -3280, -8554, -8064, -2129, -8656, -3965, -8337, -8232, -2411, -7856, -6265, -5359, -8473, -3191, -6319, -7133, -3973, -8603, -3961, -5119, -5602, -4297, -8081, -4038, -4657, -4597, -5804, -7912, -3391, -5386, -4008, -6926, -8704, -2602, -7435, -4229, -8161, -11275, -2156, -7266, -5466, -9710, -14398, -2307, -7574, -7933, -7565, -8732, -3190, -11110, -10776, -7046, -7437, -4874, -5258, -8394, -8759, -8230, -6787, -3350, -6713, -15560, -10338, -6749, -3291, -6291, -10373, -10250, -6686, -8081, -3861, -7544, -12242, -5296, -4990, -3638, -6283, -9534, -4842, -4384, -3611, -6077, -7659, -5782, -4796, -3644, -6173, -6376, -8535, -5620, -3851, -5851, -6373, -7229, -7298, -4720, -5509, -7419, -6000, -7694, -6763, -5797, -6459, -6692, -5630, -10988, -6929, -4902, -7763, -4236, -14770, -8883, -4496, -7651, -3452, -10059, -11134, -5015, -7245, -3129, -8703, -10550, -5908, -5993, -3172, -8592, -8335, -6287, -4910, -3536, -8320, -7303, -6516, -4655, -4341, -7341, -6919, -7810, -5046, -6037, -7272, -6556, -9608, -5551, -10399, -8040, -6681, -8608, -5595, -11077, -7942, -7533, -8245, -5352, -7727, -7381, -8621, -9242, -5506, -7582, -6260, -8946, -12264, -6541, -9181, -4954, -6697, -9602, -8278, -11606, -4501, -5073, -6425, -8221, -10750, -5169, -4816, -5116, -7345, -8677, -7055, -5554, -4801, -7546, -6583, -8102, -6044, -5165, -9019, -5398, -6459, -5659, -6100, -11315, -5408, -5590, -5940, -7048, -10794, -6623, -5433, -7994, -6872, -9456, -8768, -5395, -11278, -6691, -8343, -10468, -5121, -8059, -7592, -7063, -9210, -4766, -7158, -9540, -5863, -7060, -4729, -7870, -9096, -5170, -6140, -5375, -10321, -6839, -5354, -6402, -6812, -17832, -5637, -6724, -7307, -7519, -9106, -5496, -8705, -7919, -6604, -7291, -6224, -7896, -8120, -6267, -7301, -7367, -7235, -7994, -6827, -8576, -7996, -7929, -7577, -8062, -10179, -7451, -9083, -7175, -9730, -10866, -6625, -8186, -7108, -10845, -10002, -6490, -6085, -7891, -10350, -8082, -6925, -4784, -9322, -9988, -7385, -7246, -4706, -9306, -9214, -8374, -7127, -6081, -8930, -7544, -11900, -6299, -9353, -8191, -6706, -12636, -5464, -8912, -7071, -7185, -9948, -5367, -7078, -7114, -8801, -8905, -6146, -6768, -9244, -9259, -7689, -7835, -6756, -14682, -8430, -6448, -10286, -6334, -9283, -8936, -5805, -10398, -6232, -8215, -11595, -5907, -8780, -6925, -9266, -12734, -6654, -8245, -8377, -13011, -10854, -7601, -9180, -10070, -16819, -9726, -8044, -13164, -10194, -12386, -8277, -8308, -11393, -8966, -11102, -7739, -9389, -8107, -7966, -9149, -8758, -12630, -7110, -7712, -7642, -12974, -16843, -7381, -8716, -7506, -12816, -12094, -8807, -12294, -9444, -9445, -12427, -11430, -13088, -13175, -9000, -11861, -13592, -11056, -8018, -9609, -8138, -13507, -13650, -6437, -9416, -6223, -13215, -10254, -6645, -8461, -5572, -11994, -7187, -8797, -8068, -5900, -11103, -6167, -12028, -8353, -7192, -10938, -6353, -8272, -9002, -9690, -9898, -7507, -7329, -9624, -12416, -8870, -9500, -8506, -10184, -12048, -9132, -11676, -11289, -10610, -13399, -10614, -12017, -9963, -10329, -17632, -12277, -10225, -9342, -10059, -11794, -12810, -8551, -11024, -11152, -9739, -10594, -7666, -13738, -16279, -9015, -8973, -7541, -10362, -14029, -8803, -8840, -8188, -8717, -11141, -8518, -10270, -9868, -8657, -10411, -8097, -13847, -13647, -9581, -10752, -7837, -17834, -19148, -9836, -12529, -7931, -20091, -13792, -9977, -11735, -8497, -13887, -12597, -5991, -3744, -8902, -11410, -8909, -5391, -4875, -9033, -8824, -11574, -4686, -7483, -10082, -6786, -9772, -4221, -8386, -11713, -5534, -7215, -4427, -7160, -11370, -5162, -6295, -5663, -6160, -9608, -5567, -4910, -8094, -5465, -8462, -6479, -3906, -10248, -5571, -7955, -7540, -4028, -12081, -6664, -7881, -8728, -5443, -11211, -8168, -8236, -8905, -8792, -8369, -8285, -8463, -7148, -12392, -7433, -7569, -6835, -6183, -8421, -7292, -7064, -5297, -6863, -7661, -6998, -7198, -5058, -10533, -8750, -6326, -8437, -5922, -10417, -12173, -5678, -11215, -5797, -7091, -13441, -5301, -12537, -4946, -6199, -9546, -5184, -10470, -5456, -6234, -8400, -5204, -9073, -7572, -6855, -8838, -5254, -8304, -8123, -8270, -9406, -5340, -6641, -7515, -10446, -8337, -5466, -4801, -9911, -9273, -7318, -5471, -4036, -10924, -7826, -6955, -5336, -4542, -5788, -7617, -7424, -5559, -6493, -4346, -7735, -8804, -6796, -10525, -4645, -7064, -9692, -8022, -24960, -6532, -6083, -8804, -5864, -12193, -8419, -5556, -7612, -4576, -9891, -7835, -5563, -6365, -4740, -9331, -8463, -5905, -5533, -6383, -9772, -10027, -6335, -5503, -10656, -11335, -8994, -6706, -6632, -12304, -14695, -8003, -7338, -10125, -8839, -10698, -8142, -9166, -11785, -8201, -8931, -8256, -12605, -7731, -8399, -9187, -7673, -13029, -6747, -8740, -10575, -6812, -18001, -7123, -9667, -10123, -6003, -8773, -8340, -10541, -9335, -6346, -6194, -9319, -7978, -8672, -9434, -5109, -9667, -6188, -7126, -11739, -4909, -10658, -5687, -6117, -7850, -5786, -12360, -6263, -6042, -7688, -7843, -10842, -7874, -6553, -7756, -7997, -9353, -10055, -7000, -6986, -6754, -9075, -10057, -6836, -6558, -6460, -9185, -8933, -6373, -6269, -6889, -9051, -8414, -6409, -6204, -7961, -9056, -8596, -7465, -7027, -9355, -10020, -9444, -9167, -9397, -10302, -13686, -10432, -8710, -12956, -12171, -13586, -10825, -7945, -10608, -20602, -9473, -11381, -8347, -9115, -11084, -8096, -11883, -9886, -8625, -9771, -8113, -11845, -12840, -9157, -11089, -9648, -13506, -17357, -11322, -15611, -10725, -12426, -12935, -11703, -15018, -8182, -9198, -11329, -8610, -14320, -6861, -8047, -12005, -7322, -9497, -6595, -8139, -16254, -7258, -7208, -7013, -8970, -11442, -7916, -6760, -8093, -10028, -9065, -8420, -7990, -10361, -10859, -9035, -7877, -11779, -17250, -11230, -11400, -7004, -17858, -11925, -11498, -11424, -6944, -12917, -9719, -12969, -8998, -8374, -11280, -9195, -13799, -8777, -12118, -10145, -9121, -10062, -10183, -12353, -10403, -9174, -8311, -11381, -11711, -11370, -9726, -7643, -9668, -11575, -10860, -10616, -7382, -8398, -9651, -10141, -9582, -7492, -7666, -8988, -10232, -7922, -8451, -7308, -10074, -11430, -7321, -10715, -7654, -12915, -12854, -7852, -10677, -9120, -11435, -11781, -9380, -8932, -12507, -9987, -11731, -11085, -9085, -16788, -10218, -12420, -11560, -12065, -13337, -11069, -11049, -11568, -15013, -12380, -10784, -10065, -11213, -10293, -11080, -10060, -10459, -10470, -4645, -7279, -8322, -10262, -8200, -7235, -10412, -8067, -11503, -7272, -7172, -11788, -8851, -12891, -5541, -5762, -10109, -10237, -24390, -5888, -5896, -11184, -11610, -11714, -8864, -8080, -13501, -12644, -10258, -8987, -10534, -9757, -11648, -13154, -6682, -6602, -7124, -11465, -13310, -6786, -5208, -5621, -14978, -9388, -9169, -5411, -4955, -14351, -8002, -12895, -7435, -4944, -10748, -6909, -8310, -12699, -5243, -9682, -6661, -7229, -8543, -5389, -9297, -7954, -7459, -6961, -5349, -9556, -11466, -8024, -6584, -5736, -11375, -10080, -9118, -6553, -7427, -10460, -7665, -10338, -6999, -11786, -7307, -6465, -8590, -8550, -13963, -5895, -6046, -7109, -10132, -14164, -4839, -6536, -6678, -7674, -8115, -3733, -8272, -7110, -6862, -6329, -3312, -11836, -8294, -7997, -6689, -3960, -10943, -9089, -9066, -8144, -5551, -8517, -7720, -8118, -8383, -6593, -7131, -6316, -8435, -8351, -6436, -6196, -5747, -9933, -9374, -7091, -5701, -5978, -9258, -11383, -10144, -5677, -6655, -7256, -11110, -12618, -5888, -6986, -5780, -10439, -7687, -5980, -6480, -4776, -8935, -6403, -6059, -5546, -4204, -6751, -6283, -6454, -4842, -4038, -5731, -6589, -7155, -4825, -4279, -5682, -6878, -7933, -5746, -5162, -6189, -7117, -9120, -7767, -7193, -6874, -7464, -11775, -10395, -9418, -7089, -8237, -10760, -10105, -8380, -6914, -10549, -8362, -8312, -8602, -7812, -14282, -7759, -7345, -11042, -11655, -9857, -8144, -7312, -13243, -12635, -9634, -8513, -7797, -12732, -10126, -12235, -8198, -8174, -13280, -8696, -11478, -8139, -8563, -13062, -7110, -10727, -9314, -9222, -17312, -6665, -13161, -12697, -10077, -11454, -7278, -14893, -13504, -12326, -7911, -8250, -8763, -11000, -13215, -6521, -8694, -6221, -10134, -9276, -6203, -8828, -5189, -10501, -7422, -6533, -9168, -5264, -13122, -6549, -7343, -9686, -6382, -14479, -6508, -8844, -10154, -9085, -10108, -7377, -10863, -10607, -17692, -8197, -9145, -10507, -11689, -9599, -7331, -11922, -10398, -11527, -8239, -7226, -16751, -13203, -9232, -9399, -7455, -11164, -13717, -8828, -13202, -7527, -8539, -11117, -11690, -10044, -7620, -6948, -11590, -12705, -8974, -7925, -6103, -12496, -8686, -10038, -8381, -6360, -10878, -8348, -12467, -8828, -8132, -9960, -9718, -13730, -8801, -11835, -9764, -10661, -11965, -8838, -14391, -9139, -10330, -10710, -9810, -12038, -7957, -10940, -10779, -11834, -8383, -7025, -12421, -11755, -13472, -6596, -6669, -12898, -13153, -14344, -6041, -6955, -12086, -15793, -14101, -6451, -7941, -11562, -21332, -10627, -8039, -9853, -12192, -22607, -8947, -11731, -13727, -15488, -17383, -8963, -12440, -17614, -16423, -13197, -10609, -11382, -13433, -12505, -11141, -13491, -14398, -12776, -11681, -10186, -13165, -16676, -12033, -11957, -10227, -11562, -13239, -11000, -11789, -11349, -10535, -13464, -10916, -10743, -12834, -10362, -12974, -11947, -10160, -12579, -11610, -13058, -12664, -10771, -12170, -16505, -12734, -11097, -13525, -11957, -12217, -10174, -9629, -13331, -11881, -9968, -8909, }; +//int32_t position_embedding[1936] ={196, -7348, -7382, 1712, -10706, 1192, -2694, 1918, -6099, -3297, 121, -2851, -5180, -4712, -1750, 13596, 9600, 3479, -260, -4836, 1525, 4241, -2302, 4529, -900, 3399, -6545, -1652, 3663, -9180, 4876, 3043, -2909, -1064, 4044, 3782, 9062, 1131, -11358, 1565, -1527, -360, -8696, -9012, 1582, 12600, -3776, -1521, 5412, 2481, 1324, -4161, 13922, 5353, -4342, -1956, -1648, 2128, -11661, -6865, 6676, 3476, 3854, 8205, -6787, 6070, -2006, 2531, -13202, -4385, 2898, 2619, 7081, 7595, -1546, -9370, -2303, 2956, 6760, 5943, 4413, 4207, -3058, -4963, 6809, 5599, 3394, 460, 6411, -4390, -2761, -3172, 9835, -7277, -1952, 1675, -7690, 3179, -9750, -7583, 5347, 10512, -1649, 1281, 11435, -5484, 9637, 3355, 1422, 1506, 4282, -3563, 1374, 3387, 1124, -8658, -2358, -4699, -4142, 490, -3377, -2415, -7181, -1534, -597, 12306, 5111, 16385, -4726, -7888, 2951, 81, -2326, 7865, -5223, -6500, -3798, 4601, -3666, -618, -11033, 12947, -534, 10781, -9595, 6606, -209, 130, 1359, 3264, -4327, 2847, -302, -4247, -8282, 402, 7925, -2107, -2138, 8384, 2522, 6636, -777, 96, 3798, 8934, -10498, 2998, -1701, 4036, 4295, -6322, -4076, -118, -4425, 7939, -127, 2611, -3533, -13055, 776, -1126, -7048, -2041, -1031, -2451, -1461, -15072, 1542, 185, 22, -8805, -4022, 348, -5263, -5852, -8468, 6756, -3619, -4270, 2868, -5721, -4657, -3375, -2366, 7595, -591, 2305, 1837, 4089, 7194, 1445, 9971, -5729, -11176, -188, -6837, -3708, -7535, 8617, 3044, 10526, -2912, 2707, -5639, -671, 7353, 2677, 6239, 9202, -9854, -3893, 834, 2775, -7384, -2147, -2039, 9885, 1003, 3164, -7241, 6396, -3139, -10976, 8473, 1252, -10979, -1952, -134, 1954, -4129, -6521, -129, 1874, -234, -675, 1052, 14765, 896, 2509, 1602, -1855, -13043, -10309, -2265, 2743, -4266, -2706, 836, 2445, 512, 18564, 2667, 7664, -10884, -4509, -1825, 5502, -2222, 8628, -1803, -15446, 5921, -1472, 11098, 4316, 5132, -7807, -2586, 5918, -2599, -2611, 3376, 2489, -1817, 4732, 3388, -1536, -1365, -10085, 8422, -2155, 6762, -2014, -8955, 4150, 439, 4460, -1990, -2740, -1333, 349, -8757, -2081, -7922, -4516, -3423, 3926, -4, 1547, 979, 9047, -6177, 568, 1446, 6488, -6201, -2358, -7308, -391, -349, -4329, 2976, 8472, 5717, 2301, 5198, 1549, -3488, -6818, 896, 5382, -12555, -320, -1272, -1351, -11423, -5350, 114, 5480, -1229, 109, 2501, -11900, -944, 5306, 3113, -6048, -3661, -5327, 1334, 10289, -9589, -2279, -1588, -3509, -6272, 10002, 5967, 5551, -6935, -4327, 2791, 9216, -9959, 4473, 1978, -15959, 2149, -7863, 307, -4521, 9051, 6015, -897, 5300, -6371, -260, -800, 2709, -5341, -110, 9833, -7331, -49, -4877, 6976, -4835, 9914, -3133, -4385, 4190, -5738, -465, 2371, 9339, -7956, 6917, 550, -4353, -6041, -4530, 1078, -264, 7846, 3506, -3651, -6858, -126, 1678, 7383, 6218, -2889, 299, 2333, 651, 7628, -751, 2680, -1033, -2285, 7088, 1915, 3198, -17, -11549, 8693, 814, -2438, -2575, 134, 5825, -10139, -1796, 5422, -328, 3026, 7844, 7875, 151, 5205, 6808, 2670, 7859, -12952, 786, 3422, 7597, -6877, -8084, -5465, 532, -10992, 14251, 8151, -2947, 9253, -2637, 10375, 6905, -6967, 6725, -1279, 6702, -3149, 2110, -6067, -4028, -3569, 3633, 1111, -4331, -1496, 5413, 7091, 1720, -8921, -978, -1209, 829, 255, 1729, 1379, 307, -3612, 6083, 5152, 10108, -1758, -12600, 7086, 10504, -9339, 8476, 213, -3269, -8160, -720, 8930, 7891, 205, -2909, -1424, 2115, 8759, -2722, 4276, 10615, -4849, 1589, -6607, -6358, -16955, -355, 2535, 10376, 4434, 4805, 5135, 1439, -3213, -5002, 5087, 687, 1086, -4681, -2821, -14266, -11179, -2582, 7730, 104, 8271, 6464, 4981, 3696, -5874, -5849, 1397, 1046, -12206, -1665, 2201, -439, -2283, 2989, 6710, 167, 3424, 226, 5465, 1487, -3130, -5497, -2878, 3131, -4859, 1596, 4630, -7875, -3226, -7328, 5413, -1135, 3646, -3147, -4163, 1187, 6921, -4376, -394, 2658, -2362, -2453, -2948, -5, 2681, -9107, -1191, -11249, -9502, 2395, -4479, 5486, -9094, 4493, 2749, 9093, -13265, 1179, -2309, -4304, -943, 763, 7495, 1353, 6170, 5194, -2838, 5307, -6865, -789, 3717, 2676, -3582, 5513, 2849, -6748, -929, -452, -74, 10928, 4100, -2011, -4080, 7555, -5922, -4585, 2941, 5010, -9571, 3639, -7514, -8163, -9381, 6471, 6542, 10530, 1936, 12466, -8631, 2326, -2711, -5686, -3652, 9719, -5176, 4973, 3079, -2078, -3088, -1273, 4810, 7839, 4100, 2226, -10032, -1859, 3094, -588, 3594, -4821, -12113, 4966, -199, 8597, -5230, -9595, -2768, 1170, -7238, 6502, 3566, 1014, -859, -2509, 8922, 5700, 3053, -5515, 2418, -9141, -11804, -6197, -485, 3796, -3860, -249, -3930, 6901, -6496, -10185, 3596, 2732, -1355, 983, -527, -6415, -11871, 5991, 1217, 3176, 1131, 3719, 1786, -4878, 2575, 301, 1830, -1133, 1374, -3349, 164, 3352, -1368, -7919, -7348, 5071, -949, 9665, -510, 1889, -5429, -11519, -367, -329, -4465, 3694, -4588, 2112, 638, -7040, 3411, 6658, -1359, 6764, 1210, -5077, -1410, 11878, -1644, 7113, -1193, 424, -3177, 1180, -1788, -194, 2381, 7231, 583, 12532, -2873, 10938, 499, -1249, 5818, 4605, -4712, 4018, 8740, -4365, -45, -5998, 7774, -12177, -2624, 2729, 3998, -108, -8892, -3748, 5248, -2207, -5953, -1195, -2204, -11208, -7020, -3089, 591, 2701, 3647, 4811, 5174, -793, 1089, -4844, 3268, 42, -8431, -6365, -473, -6021, -7345, 4530, 1754, 9097, 1264, 3335, -4713, 5214, 8575, -4620, 4652, 4686, -5145, 4579, -5352, -7520, -5546, 5278, -1174, 3277, 5639, 6893, -6939, 889, -2533, 4578, -2099, -2107, -1194, 7229, 3163, -12403, -15160, 9385, -1258, 4658, 7070, 6925, 2730, 9222, -5450, -7277, 4427, 10517, 5277, 5046, 3242, -4736, -6004, -4718, 2550, -2531, -1704, -4376, -1463, -4121, -2849, 3464, 2406, 8299, -1272, -5814, 5850, -5042, -7367, -7965, 718, 6263, -2666, 4066, -1047, 10409, 4553, -2990, 13574, -1465, -9180, 5031, -2361, 828, -3184, -9065, -927, 9733, -2748, 1466, 4699, 5731, 6123, -6454, 195, 5271, -14124, -2202, -1832, 2, -12207, -3771, 420, -6557, -1144, 9838, -2994, 821, 5869, 4339, 2391, 11899, -8278, -4483, -2896, -1849, -8299, 5111, 260, 10086, 3929, 5539, -6377, 13205, -3131, -1461, 1465, -207, -6114, 1402, 5214, -7641, -973, -1233, -4298, 9744, 2985, 14273, 143, -2463, -1160, -7427, 6119, 7836, -4500, 921, 2153, -287, -5492, -7355, 322, 8465, -1047, 2054, 497, 10097, 7018, -4490, 2046, 6496, 1872, 3413, -9124, -779, 6169, -6458, 1514, -3490, -10698, 3100, -1862, 2875, 6368, 1318, 658, 1050, 219, 3709, -10295, -2636, -4041, 5012, -61, 4480, -3406, -2850, 302, -7649, 5732, 7661, 7424, 5693, -2459, -7557, -6075, -1802, -11208, 3080, -7096, 6845, 1575, 5391, -2403, -2489, -1433, 2278, 7747, 4970, -13012, -5878, 6852, -9159, -4405, -374, 4644, 948, 8329, 4469, 2672, -812, -5394, -11335, 5476, -1149, 831, 1394, -4572, -5319, -8258, 3435, 1955, -972, -4931, 4098, -362, 10748, -4493, -7594, 7251, 7377, -5753, 5011, 5545, 812, -9204, -5784, 3585, -2369, -2755, 6910, 3144, 9649, 1338, -4350, 8637, 10729, 4980, -2094, 2339, -9914, 4376, 1377, -3161, -9768, 10043, 2351, -5890, 3685, -5198, -198, 9585, -2097, 251, -271, -6207, 2402, -7706, 2448, -2452, 4762, -2401, 8514, -3997, -3465, -1079, -1985, 1855, 12959, -3239, 3580, -7527, -141, -10696, 1692, -1395, -4360, 3321, 8854, -1479, -556, 2118, -6509, 1766, 3286, 6377, 587, 2108, -3565, -4028, -1202, 6234, 10107, 4402, -3022, 1785, 11342, -2046, -8556, 10844, 9710, -6141, -2186, 7498, -6214, -10161, -706, 10836, -3416, 1141, 7550, 10477, -2297, -2264, 2035, 4234, 3055, -8828, 677, 4606, 5708, -8930, -12070, -3840, -1422, 7871, 3303, -1806, 3930, -8954, -14512, -6258, 3705, 2788, 7841, -5298, -2605, 9229, -6623, 6570, -1780, 8058, 2401, 82, 3209, -2819, 5653, 4950, 11482, -815, 2924, 13697, 538, -2681, -6465, 6221, -14698, 4160, -1397, -1421, 3050, -2808, -4229, 8893, 8020, -16289, 2108, 42, 1162, -7427, -6701, 7883, 8297, 1597, 5038, -2443, 931, -4441, -6867, 6905, 3184, -18314, 3272, 3904, -4514, -2738, -3360, 8473, 11965, -1353, 12774, 643, 3839, 3358, 2682, 8232, 6960, -4297, -836, -6527, -1543, -6549, -2445, 586, 11268, 246, 18235, 13, 1016, -1328, -669, -3472, 7036, -1343, -2877, 1927, 4696, -8023, -4754, 8818, 3667, 6334, 7176, 3254, 5146, 5763, -887, 1357, 5270, -12799, 5511, 7894, 830, -3383, -12477, -5669, 1653, -2524, 2412, -7996, -6546, -4264, -8583, 6337, -2213, -802, -2847, 2, -3954, -8564, 604, -1101, -887, 1889, 5294, 2636, 8182, -2383, -2636, -3763, 9006, -3445, -4557, -453, 6281, -10285, 493, 461, -237, 7249, 4140, 2612, 9505, -1959, -3777, 791, -1044, -5313, -5067, -1969, -4218, -5337, -761, 1536, 10589, 4648, 16378, -2512, 1416, -5251, -7837, 5860, -4262, -4829, -9612, -1219, -4834, -8699, 1980, -3450, 6160, -3204, 6195, 3463, 9506, -5485, -8112, -4138, -724, 1512, 918, 1741, -10433, -14466, -6574, 12705, 2220, 11707, -4228, 346, 10643, -2137, -4149, -1762, 5518, 7242, 5374, 1826, -2245, -30, 586, 4427, -10485, -212, -4218, 3951, 8882, 932, 1660, 1355, 2252, 250, -7325, 1686, 2198, -6366, -7720, 853, -3684, 972, 3909, 2243, 7001, -484, -1258, 3933, -1780, 1998, -2576, 3712, -10146, -1859, 694, 4870, 10322, 6968, 2166, -3058, 4834, -3061, -582, -2964, 8615, -4992, 11852, 1768, -9018, 221, -5394, 3845, 5675, -3122, -3868, -1592, -879, -7691, -2872, -424, 2273, -4646, 923, 3113, -4257, -10901, 3142, 4453, 943, -2176, -1475, 1806, 5221, -5723, -12716, 1026, 5810, -7981, 898, -4108, -3235, -9229, -3181, 5933, -3481, 1041, 8501, -8344, 7251, -346, -8282, -3530, 4398, -6469, 331, -1543, -7201, 5033, -3596, 2641, -2910, 5563, 3475, 3365, 8598, 3284, -9382, -1039, 8790, -3126, 4164, 9639, -8403, 4317, -9679, 12168, 1929, 4278, 13619, 2864, 3590, 532, -5407, -4325, -1887, -3285, -443, -2136, 4922, -13579, -1682, 3007, 1898, -5139, 12461, -1291, 3241, 2362, -4873, 4000, -1434, -4710, -4441, -1077, -9310, -3098, -2394, 8959, 2132, 3326, 10103, 7219, 7674, -3532, -3918, 2722, 4192, -7496, 3443, -2661, -5911, -13391, -6098, -6935, 3533, -4270, 9580, -2819, 10422, -1715, -6566, 1072, 7238, -7981, 5947, 6971, -2932, -8276, -6662, -2739, 1783, 7551, -822, 714, 6140, -2272, 1579, -1586, 2848, -4921, -5685, 2468, -4065, 8038, -1181, 3849, -7741, 8319, -4081, 540, -331, 2632, -8020, 3331, 2738, -10207, 10376, 1578, -6226, -7393, 1824, -3637, -2150, 4912, 3303, 97, 7901, -3422, -11877, 11709, 7670, 1157, -1433, 14410, -4035, -5654, -2636, 1646, -3398, 4553, 3448, 1590, 6668, 1229, -631, -639, 7354, -5577, -1004, -4027, -4623, 1226, -6965, 6190, 5682, 6399, -2992, -5282, 4553, -301, -5865, -1087, 5129, 372, -397, 7112, -11645, -7985, -3391, 886, -665, 1259, 3809, -7332, 3309, -5446, -1452, -3214, 7524, -7810, -4991, 6479, -5773, -2147, 504, 8548, -414, -1342, 4170, -2569, -570, 4688, 6138, 2469, 7672, -1794, -4615, 2466, -2698, -1092, -8501, 2056, -9155, -3875, 4456, -5823, 6540, 1286, -5507, 604, 3683, -5865, 1624, 10940, 397, -7894, -3904, 7932, -3332, -1916, -453, 4174, 9373, -8885, -11755, 2603, 1730, -4719, 2118, -3560, 2020, -5513, -828, 4869, 6686, 1224, 2484, -1048, 1258, -6406, -9003, -1844, 7966, -5982, 2834, 257, -12060, -2571, -399, 7284, 2855, 2137, 7453, -228, 8378, -5410, -7611, 2233, 10363, 959, 204, 6403, -2208, -9057, -1205, 10133, 6597, -3193, 1573, -9256, 1178, -1660, 423, 3115, 8276, -10066, -9202, 1808, -1862, -6246, -8949, -9359, 3781, 7604, 6050, 328, -2843, 1670, 5750, -1362, 490, -1824, -1695, -6753, 7309, -2915, -3351, -835, 4938, 1274, 839, 6488, -2967, -6740, -2742, 9887, 9589, -4916, 569, -583, -1105, 1792, -554, -677, -5544, -1202, 9332, 7015, 4194, 847, -5562, 6385, 7952, -13964, 3095, -2044, -4642, -12211, -11113, 803, 6275, 3938, 11288, -3246, 7863, 5390, 1234, -2093, 10643, -7571, 9591, -1187, -6426, -10116, -2729, -1892, 11679, 2705, 383, 5100, 290, -1186, -5636, 3468, 8022, -4437, -7619, 1079, -6484, -5701, -6167, 5154, 2463, -4677, -678, 1465, 2782, -1074, -3588, -1667, 8992, -10088, 5435, -2560, 3760, -13964, 941, -3134, 7520, -5560, 4607, -6430, 7678, -7308, -4429, 6823, -24, -6644, 9550, 8560, -8120, -6287, -1422, 5070, -3360, 10365, -1586, 2224, 2928, -6037, -9535, -4078, 7441, -2257, -2203, 3939, -2139, -854, -1630, 1062, 1906, 910, 510, -6428, 6919, -2506, -12797, -3276, 822, 1002, -2871, 8174, -8013, 47, -2337, 6914, -1141, 1825, -5894, 2829, 9621, -1258, -1760, -7474, 4528, -4157, 4937, 3116, -6704, -6168, 357, 11296, -721, -2325, 4340, 6459, 4289, -4798, -3662, 2985, 6979, -5045, 1388, 7683, -1556, -1681, -8961, 12688, -6371, -5467, 1561, 11487, 169, 5750, -6795, 3916, -2576, -10949, 6332, -7643, -3722, -8052, -6156, -2037, -713, -4781, 15583, 1208, 2386, 460, -923, -1273, 2499, -2653, 2952, -3185, -6835, -5247, -3670, 4576, 2211, 5279, -313, 806, 3856, -12356, -4425, 2318, 4636, -281, 4072, 11650, -4005, 3906, -4887, 10698, -2211, -1905, 191, }; +//int32_t encoder_out[1936] ={-3006, -13563, -12330, 18429, -5740, 7757, -11785, 19611, 5385, -14561, -4444, -13231, -273, -10749, 1769, 14144, 6853, -7264, -3989, 9728, 6174, 14216, -13342, 20866, 8739, -9327, -15258, -12849, 11503, -16206, 6678, 4712, -3368, -10248, -323, 17739, 14650, 9631, -22149, 18791, 8398, -12585, -14408, -19795, 9133, 7335, -2016, 218, 3745, -8689, -3055, 8517, 19150, 15896, -17422, 15479, 8259, -11139, -19673, -16118, 13716, -2489, 4658, 10756, -8425, -1803, -6892, 18482, -7281, 2743, -5683, 20533, 17587, -5318, -5861, -19906, 5187, -1484, 11114, 7230, 228, -6363, -6655, 9139, 10365, 14506, -7711, 16482, 16422, -16187, -11228, -14695, 18943, -13552, 882, 2345, -11537, -6686, -11743, 7935, 7791, 17995, -10134, 17477, 20963, -15352, 3390, -7308, 7919, -5904, 5447, -2132, -1507, -5768, -3574, 4260, 2652, 4375, -17098, 18282, 7600, -16904, -13845, -10678, 3984, 7624, 6440, 18787, -4814, -13887, -3132, 16328, 2480, 14219, -15608, 12369, 9305, -6755, -9780, -9805, -5951, 7635, -752, 10670, -12533, -1822, -5518, 14468, 5185, 10349, -16181, 20586, 11674, -16543, -15452, -10119, 14549, -6957, -6, 9185, -723, -2247, -6201, 13563, 6180, 16249, -20590, 20376, 10058, -7715, -3023, -17945, 3895, -5125, -2581, 8922, -2947, -8726, -6576, 454, 5031, 8435, -17115, 13176, 8105, -15541, -9771, -26546, 11608, -5647, 2820, -7509, -6901, -8206, -9755, 8543, -4364, 13458, -13971, 14118, 14418, -17485, -10573, -13533, 3500, 3417, 1789, 2659, -978, -5582, 1754, 15694, 16021, 4131, -25353, 19627, 4040, -17391, -14517, -908, 8276, 5537, -632, 4351, -5816, -9106, 1921, 17213, 11727, 17095, -21631, 14579, 12311, -9099, -14541, -11745, 4595, 4505, 1362, 3649, -8561, -4528, -7242, 1546, 12875, 10656, -23093, 14368, 9969, -10482, -12326, -17341, 8191, -4029, 394, 1754, -4055, 5990, -5765, 14625, 4312, 6787, -27034, 9123, 10688, -12565, -11754, -11023, 5809, -1559, 1929, 21333, -4137, -3938, -12844, 10591, -577, 14611, -11639, 24979, 7176, -26631, -1815, -11506, 18175, -2329, 7633, -5593, -5884, -4737, -5611, 11342, 7139, 11005, -11085, 19903, 12770, -13858, -8696, -21227, 17759, -8275, 9465, -767, -10777, -3937, -4997, 19747, 3537, 5078, -11440, 19340, 2302, -15039, -12820, -14607, 2856, -841, 3066, 3019, -3662, -1769, -10455, 13468, 4293, 16466, -18227, 16129, 3082, -13989, -7767, -13065, 8357, 2831, 6949, 5188, 3071, -9636, -7742, 5922, 5691, 15255, -25481, 17238, 8637, -13963, -19659, -15803, 6774, 81, -32, 1563, 2272, -18979, -5995, 21439, 8942, 882, -13145, 12693, 12852, -1774, -13667, -12866, 4715, -8892, -4644, 11093, -422, -5046, -10092, 9053, 4390, 18136, -20282, 20232, 11824, -28001, -6060, -18339, 7227, -10905, 11389, 7704, -5617, -4712, -9613, 13707, 2698, 10574, -14994, 15975, 19634, -19674, -6834, -15951, 15005, -10525, 13284, -2557, -7022, -5978, -9209, 13370, 5896, 17525, -17853, 23255, 10249, -15506, -12905, -14879, 7564, -6889, 9077, 4961, -5693, -13709, -3604, 18055, 9899, 13762, -11124, 16051, 12696, -9712, 1954, -12613, 9317, -8709, -1939, 8967, 1074, -7952, -4365, 1336, 14539, 11503, -16097, 14413, 10291, -7622, -18878, -11665, 12678, -6553, 3328, 10297, 6128, -7062, -776, 21889, 6628, 14075, -23131, 19239, 16078, -4247, -13226, -18217, 1223, -3829, -9830, 14185, 7628, -11920, 4644, 13153, 16201, 15229, -17074, 24769, 9515, -4742, -10565, -9459, 1060, -10122, -2606, 3948, -1114, -12072, -5986, 20459, 11262, 9498, -19128, 16965, 9743, -10716, -4806, -8878, 6640, -6002, -2477, 7561, 1982, -2676, -5055, 535, 11206, 21236, -22742, 25469, 9341, -15296, -17869, -11445, 16623, 1860, 1645, -1316, -3186, -7917, 3771, 11779, 10191, 20504, -18291, 20597, 3803, -19284, -25289, -9539, 8301, 5012, 5881, 5836, 423, -9288, -6980, 9044, 9488, 11661, -12011, 13275, 6737, -27917, -19263, -11345, 12851, -6200, 10087, 8955, 805, -7845, -9519, 6972, 5407, 11348, -25740, 15166, 12016, -13473, -11119, -7590, 13181, -6210, 4865, 1932, 1081, -9226, -6301, 8222, 638, 11695, -14984, 17147, 14184, -20129, -11090, -19273, 14319, -6545, 7140, -2883, -7634, -6844, 1066, 10066, 2738, 9623, -11962, 14367, 9260, -13035, -5203, -21472, 9516, -15976, -5773, 1460, -9266, -4569, -13189, 17706, 5167, 17608, -25065, 18705, 8341, -16412, -8140, -8555, 12759, -4921, 7306, 7143, -5731, -4578, -9634, 13517, 8002, 10713, -12955, 22717, 12124, -18190, -5714, -10473, 5509, 5176, 6163, -359, -8158, -2435, -10629, 8846, 6458, 14548, -23898, 22129, 3490, -21086, -17176, -1972, 10069, 4788, 2566, 15234, -10502, -7098, -6553, 8756, 422, 16611, -15354, 21749, 13913, -13106, -9909, -11836, 11777, 2514, 5699, 2834, -9025, -9450, -2209, 14080, 8578, 1880, -21538, 21410, 11247, -3034, -10588, -21030, 5698, -3899, -6210, 8263, 1423, -8707, -5358, 11613, 14847, 15042, -9044, 13159, 12370, -21378, -18525, -16342, 6187, -1641, -1324, 601, -6478, -3701, -10467, 3996, 8764, 12689, -15030, 19272, 9605, -18728, -19845, -3559, 5652, -3275, 1863, 5597, 953, -12340, -1849, 15916, 6577, 6932, -6837, 14165, 10642, -8840, -5685, -19038, -506, -466, 640, 11242, -2583, -8288, -9136, 1140, 3106, 8936, -15763, 19152, 5437, -10478, -6910, -17981, 11343, 596, -535, 9676, -956, -11538, -6862, 27331, 3241, 13859, -10920, 19079, 8564, -10570, -5761, -9812, 7378, 2110, 3067, 13426, -7632, 1378, -4034, 12624, 8594, 11389, -14816, 19965, 20021, -16429, -7859, -18291, 17532, -17084, 1335, 2532, -230, -10488, -12058, 9814, 9352, 7707, -17859, 16019, 7254, -23813, -13478, -12000, 4898, -3686, 4841, 7461, 2075, -11495, -3560, 8605, 9092, 10922, -23374, 13014, 9729, -19426, -15298, -4780, 6518, 3642, 2751, 5038, -7917, -4041, 3806, 10222, 9947, 13664, -18028, 22791, 5628, -20491, -13863, -4558, 4180, -2485, 7495, 8047, -8674, -6502, -7094, 20470, 4307, 5030, -11802, 25527, 13764, -24719, -19127, -150, 2611, -1029, 10121, 7295, -564, -2071, -8611, 7205, 7906, 19158, -4511, 22058, 12822, -15749, -13811, -15922, 10977, -8554, 572, -3316, -3058, -12151, -7466, 17638, 7109, 15570, -11320, 12053, 16600, -16480, -12338, -18142, 7339, 1133, -639, 4681, -2768, 563, 140, 10280, 18510, 7490, -20426, 21980, 7790, -12230, -10133, -20188, 7033, 4754, -724, 3781, 1123, -4142, 542, 6839, 4322, 13990, -27587, 16011, 10164, -13827, -21794, -13802, 6966, -11049, 212, 10254, -5240, -7852, 48, 18922, 7869, 20456, -21871, 15636, 8900, -14475, -15940, -3293, 4716, 4900, 4879, 5831, -10344, 5091, -8364, 12194, 5127, 6790, -17157, 19659, 17195, -20674, -6316, -10681, 818, 5437, 5760, 15987, 26, -12619, -5085, 5931, 11086, 16895, -15453, 17332, 11797, -11451, -12670, -18508, 8468, 2444, -226, 3621, -4802, 518, 1732, 9351, 3782, 13992, -8001, 21509, 2538, -13698, -2189, -17680, 11326, -8055, -7364, 2616, -4362, -5926, 1259, 17264, 6588, 10125, -11527, 23188, 336, -15507, -11028, -5887, 6504, -827, -376, -1999, -1245, -15610, 133, 23226, 13612, 13851, -13972, 12359, 5370, -14127, -16831, -6162, -1943, 1322, 3421, 5663, -5809, -11947, -5660, 15584, 12366, 13584, -25102, 11684, 17176, -21626, -11137, -10079, 10452, -5009, 10119, 5420, -65, -11647, -8754, 3245, 10677, 9533, -12684, 18626, 4942, -17226, -16617, -6602, 7393, -8438, -4143, 6338, -2537, 284, -9020, 5285, 10882, 15554, -17336, 21522, 16400, -11034, -17315, -17011, 11620, -7641, -1386, 8084, -2420, 69, -2624, 10573, 11725, 19946, -5672, 15176, 12457, -22436, -3894, -8411, 4078, -16955, 12734, 4176, -6871, -5084, -10675, 13733, 14814, 6282, -11763, 18189, 5281, -9665, -13267, -7431, 3116, -1217, -1328, 10698, -4987, -11999, -6191, 13751, 6734, 21035, -14470, 21428, 3669, -10964, -18630, -7913, 3893, -11562, 3538, 9623, -2585, -10690, -1158, 8651, 8416, 13162, -4612, 17794, 11025, -16093, -10889, -11824, 14167, 4031, 7210, -1987, -2342, 118, -6577, 4108, 14469, 19290, -20145, 15233, 18126, -18927, -19462, -10776, 17850, -8965, 2825, 8776, 9353, -12187, -6053, 16045, 10053, 11844, -18217, 17431, 14030, -6834, -14632, -22585, 3625, -7252, 9905, 4965, -6913, -6715, -10856, 1146, -4132, 13295, -5848, 22031, 3541, -14635, 853, -16929, 14867, -10080, 10242, 5538, -2911, -5900, -6975, 20120, 9190, 18659, -9922, 19385, 24080, -11026, -9187, -18048, 15138, -20644, 7384, -1591, -3322, -7729, -7178, 7882, 12850, 17169, -29152, 18653, 10324, -11162, -15366, -16757, 15256, 2707, 2295, 7212, -5099, -8408, -8961, 5473, 10208, 11194, -31132, 19405, 14988, -16836, -9705, -13365, 15011, 6886, -322, 15129, -2238, -4700, -2510, 15719, 12068, 15263, -17201, 18006, 5600, -14695, -13099, -10819, 5409, 6557, 1060, 20661, -1231, -8256, -6287, 13102, 1531, 15969, -12840, 14428, 12701, -8763, -15013, -14635, 16024, -1976, 8039, 8323, 1163, -4029, 1295, 13050, 5608, 12345, -22125, 21563, 18581, -11256, -10267, -24770, 3444, -2881, 479, 2431, -8476, -15408, -8011, 6272, 12904, 6282, -12405, 13611, 10172, -15424, -14768, -9625, 4751, -8107, 2882, 6915, 558, -1968, -7735, 11214, 1121, 18832, -16162, 14475, 10584, -7412, -18754, -9101, 6134, -5932, 8014, 5473, -2118, -128, -7230, 8462, 4284, 8683, -19400, 13767, 9541, -19055, -12613, -9168, 5520, 6085, 5818, 19566, -4967, -8263, -10320, 5186, 11308, 5608, -19345, 9650, 10010, -18178, -15500, -7019, 875, 728, -2431, 8600, -489, -1635, -8656, 6244, 627, 9692, -10156, 17995, 10687, -24421, -22420, -16582, 19462, -3430, 14473, -2169, -4748, 299, -5356, 11832, 777, 13351, -1567, 22147, 12026, -13901, -7808, -10741, 13146, -16640, 3079, -3068, 751, -285, -4640, 15415, 6281, 11059, -11255, 11059, 12984, -12162, -13589, -17987, 8424, -8545, 4051, 4753, -1922, -2756, -4453, 12951, 8903, 7796, -10048, 15724, 13579, -23594, -8454, -9019, 10395, 5265, 9772, 3949, -7364, -5175, -6215, 14174, -650, 14808, -12845, 28486, 12197, -19556, -5598, -16908, 11933, 1177, 331, -3723, -3169, -10619, -11448, 11612, 5069, 10765, -16340, 18499, 12963, -15722, -17082, -7403, 10093, -5279, -483, -1019, -2179, -6192, -9761, 138, 4022, 16176, -21635, 17535, 6239, -16161, -19177, -13231, 12251, -9925, 1566, 10893, -14047, -2666, -4217, 5942, -1564, 12132, -16661, 16392, 9506, -19765, -3372, -14345, 10870, -8606, 8542, 4691, -1876, -1064, -1200, 3602, 1012, 16364, -13975, 19559, 20924, -21303, -4196, -21408, 21603, -2487, 7945, 14237, 1470, -5301, -5154, 7858, 792, 6535, -16442, 18356, 9757, -8942, -21051, -11587, 8733, -2330, -4570, 13093, -5873, -6572, -2524, 8223, 7618, 8123, -18128, 12879, 9984, -23137, -11363, -12249, 15711, -3050, 5569, 12160, 4083, -2078, -8447, 9337, 6811, 12941, -19345, 21916, 8262, -18851, -20268, -15872, -1733, -1214, -2670, 11017, -4959, -157, -5468, 6929, 5662, 15289, -18151, 22569, 16912, -15083, -15593, -17894, 5010, -3382, 9746, -40, -5306, -3361, -6415, 16370, 952, 11072, -14498, 11353, 12985, -17035, 618, -11686, 12166, -13891, 12010, -3450, -1176, -9985, -753, 6891, 9043, 11060, -20824, 26305, 11316, -17920, -14594, -9230, 2777, -8907, 6890, 3935, -2320, -2538, -7024, 1691, 16832, 16628, -10460, 15082, 24286, -16158, -13634, -13556, 9365, -9506, 6446, 4493, -3193, -4061, -2893, 13112, 2437, 16475, -16245, 16377, 6162, -18041, -6740, -17056, 14220, 288, 9610, -2208, -8660, -4425, -4622, 8500, 3326, 12309, -10290, 16961, 18099, -23750, -14866, -14424, 8017, -5322, 4468, 3755, -11645, -5534, -10514, 12200, -474, 13851, -19413, 12801, 18684, -17540, -9202, -9935, 15524, -4871, 1224, 3998, -5864, -7892, -1162, 20918, 6517, 14193, -11343, 12942, 14462, -15089, -7462, -19859, 10933, -14142, 98, 3743, -7844, -3084, -3274, 8235, 5354, 10502, -16842, 17912, 22126, -11752, -15506, -15935, 17307, -7699, 1119, -935, 961, -2984, -12227, 813, 6519, 13134, -18401, 19312, 5803, -11180, -14533, -10765, 10838, 366, 1436, 5799, -6026, -9234, -9767, 4700, 524, 16873, -18033, 19048, 10559, -23621, -11091, -10671, 13415, -3442, 3701, 9035, -2814, -2557, -9638, 5850, 6306, 18884, -11488, 18210, 17064, -13909, -16839, -11630, 17459, 1751, -1371, 2436, -11033, -7206, -6848, 14214, 7744, 16099, -20816, 8966, 13109, -14437, -12666, -18172, -3320, -1772, 8626, 7304, 10, -11047, -3896, 21065, 4666, 9300, -11349, 16631, 3824, -5909, -7915, -14171, 7029, -667, 3960, 1565, 2782, -12537, -10300, 11758, 12762, 18572, -15625, 17045, 9661, -11897, -5784, -10756, 5216, -13503, -805, 11559, 3901, -6574, -3466, 6907, 10363, 17436, -26414, 20128, 8295, -17817, -20323, -20804, 7154, 1155, 5136, 13470, -5469, -1455, 807, 15944, 2686, 18128, -17961, 27966, 9550, -18449, -16653, -13179, 4493, 7287, 5197, 760, 1500, -10621, -5921, 7359, 7581, 17717, -17649, 10306, 11416, -18892, -14387, -16829, 13281, -2882, -1957, -351, 1159, -6311, -6635, 10989, 3535, 16933, -22238, 24300, 9058, -7718, -21583, -9173, 2480, 2573, -5305, 4740, -9380, -2832, -9839, 9766, 11385, 8620, -16707, 25052, 17508, -20031, -13020, -12162, 12100, -10151, 12370, -79, -1518, -7732, -9555, 4088, -686, 15800, -13213, 14653, 14378, -13888, -8837, -12851, 8542, -3624, 3106, 1206, -10739, -3570, -5822, 1881, 634, 8596, -9144, 13755, 18369, -20422, -7515, -13588, 15796, -6124, 5742, -5391, -2255, -170, -5938, 12486, -4898, 12070, -15414, 22543, 14595, -19373, -14154, -11389, 18806, -4725, 1237, 4293, 2099, -6089, -9000, 9513, 5640, 14807, -15826, 16983, 18406, -13532, -9893, -21230, 22742, -11495, -2039, 1731, 7707, -9512, 957, 6361, 8277, 5846, -22667, 24396, 3553, -17504, -15340, -16114, 3937, -5080, -2916, 16451, -2466, -7719, -3050, 13639, 2875, 11755, -13224, 19848, 6314, -19502, -12653, -14361, 11483, -3612, 7826, 924, -3683, -6214, -15062, 9777, 4574, 11937, -9206, 19258, 21549, -14860, -2556, -16578, 19355, -8190, 907, 1251, }; +int32_t prototypes[32] ={-1394, -5770, -6778, 762, 4001, -653, -5906, -20, 1220, 3795, -73, -3028, 635, -448, 7677, -6204, 5745, 3112, 1206, -1120, -3618, 1076, -649, 943, -3896, 2462, 4658, 2494, 3996, 1220, -1144, -1013, }; diff --git a/sw/applications/trans_versasense/data_cpp/signal_fft.cpp b/sw/applications/trans_versasense/data_cpp/signal_fft.cpp new file mode 100644 index 00000000..0a6d510e --- /dev/null +++ b/sw/applications/trans_versasense/data_cpp/signal_fft.cpp @@ -0,0 +1,5 @@ +#include "stdint-gcc.h" +//int16_t raw_signal[63840] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5849, 4599, 5297, 6397, 5747, 4963, 4620, 3465, 2077, 2170, 2567, 1298, 224, 918, 1134, 70, -1176, -1533, 78, 1668, 1019, 357, 1399, 2719, 2875, 3113, 3791, 3588, 2993, 2855, 2823, 2518, 2054, 1534, 860, -389, -1264, -562, 1080, 2241, 2661, 2351, 1737, 2055, 3061, 2955, 2289, 2336, 2151, 1510, 1127, 606, -153, -422, -454, -1221, -1970, -1413, -298, 909, 1961, 1931, 1654, 2362, 3193, 2845, 2308, 3734, 5038, 3509, 2292, 2940, 3575, 3513, 3498, 5355, 7998, 8626, 7894, 7480, 7145, 6723, 5763, 4679, 4948, 5339, 5245, 5243, 4910, 4141, 4096, 5108, 5209, 4333, 4346, 4077, 2613, 1609, 1184, 901, 431, -316, 208, 1103, 1317, 1968, 1945, 1032, 1340, 2938, 3570, 3053, 3442, 5119, 6528, 6137, 5669, 6507, 7084, 6895, 6640, 6863, 6633, 5728, 5797, 6282, 6061, 5313, 4562, 4310, 4016, 3754, 4358, 4912, 4568, 4439, 4676, 5123, 5417, 4891, 4855, 5804, 5863, 5025, 4791, 4370, 3575, 3600, 3355, 2517, 2197, 2242, 1751, 1445, 1912, 2360, 3166, 4624, 5452, 5575, 6714, 8939, 10366, 10538, 10580, 11097, 11980, 12026, 11472, 11360, 10425, 8238, 7539, 9333, 10745, 10337, 9847, 10492, 10754, 10355, 10923, 11822, 12505, 14193, 16086, 17168, 18432, 19662, 19885, 19388, 19917, 21699, 22569, 21976, 21168, 20377, 19213, 18977, 20876, 22280, 21136, 20103, 20425, 21003, 21743, 21721, 21049, 20909, 20955, 20691, 20009, 18784, 17146, 16232, 15409, 13174, 11056, 10207, 9992, 9412, 8479, 8065, 7894, 7360, 6357, 4829, 3949, 3855, 2811, 1517, 581, -691, -2031, -3121, -3504, -3962, -5158, -5555, -5670, -6859, -7535, -7233, -6869, -6010, -5300, -5781, -6418, -7125, -8381, -9371, -9471, -8972, -8554, -8777, -9076, -8820, -8896, -8819, -8343, -8549, -9153, -9116, -9148, -10496, -11843, -12227, -12749, -13587, -13799, -13327, -13176, -13678, -14113, -14438, -15019, -15753, -16449, -16143, -15676, -16217, -15462, -13743, -13779, -14065, -12564, -10591, -9655, -9212, -8564, -7890, -6956, -6316, -6713, -7017, -6771, -6694, -6403, -6350, -7558, -8371, -8131, -9638, -11930, -11575, -10754, -11631, -13128, -14557, -14878, -14086, -13482, -13214, -13098, -13242, -12869, -12087, -11955, -11531, -10487, -10501, -10855, -10500, -10328, -10252, -9738, -8739, -8154, -8277, -8035, -7748, -8174, -8612, -8631, -8428, -8038, -8024, -9091, -9476, -8662, -9308, -10349, -9563, -8710, -8727, -8508, -7945, -7717, -8212, -9068, -9257, -8640, -7854, -6892, -5905, -5452, -5320, -5762, -6461, -6944, -7980, -8565, -8065, -8405, -9283, -8486, -7376, -7555, -7690, -7060, -6798, -7168, -6926, -7321, -9701, -11275, -11203, -11563, -11730, -10869, -9957, -9163, -7796, -5798, -4732, -5190, -5673, -5138, -4623, -5408, -6481, -6883, -7499, -7387, -5469, -5129, -7158, -7817, -7148, -6878, -7210, -7706, -7435, -6757, -6231, -5823, -5540, -5569, -5712, -5348, -5014, -5819, -6900, -6310, -5204, -5783, -6790, -6958, -7025, -7462, -6961, -5191, -3814, -3894, -4524, -4853, -4823, -4001, -4012, -5785, -7291, -8329, -9425, -10275, -11352, -12781, -13700, -13934, -14429, -15287, -14843, -14035, -14678, -14840, -14011, -14153, -14961, -15037, -14470, -14022, -13910, -14044, -14314, -13802, -13000, -13249, -13768, -13442, -12209, -11192, -11248, -11264, -10793, -10864, -10954, -10327, -10050, -10381, -10620, -10692, -10863, -11190, -10859, -9830, -9275, -9157, -8730, -8352, -8280, -8124, -7930, -8046, -8475, -8786, -8611, -8281, -8509, -8656, -8586, -9117, -9496, -8916, -7935, -7261, -7328, -6744, -5010, -3815, -3676, -5087, -7297, -8405, -7933, -7386, -7712, -7153, -5672, -4975, -5080, -5492, -5970, -6618, -6879, -6568, -7061, -7070, -6009, -5800, -6320, -7189, -8359, -8545, -8225, -8893, -9872, -9030, -7780, -8030, -7998, -7114, -7205, -8469, -8509, -7267, -7623, -7872, -5537, -3448, -3213, -3570, -3242, -2121, -2080, -3313, -4262, -4437, -4728, -5830, -6445, -5600, -5069, -5687, -5322, -4458, -5042, -5821, -5249, -4359, -4159, -4559, -4926, -4565, -4065, -4518, -6069, -6763, -5275, -4518, -5702, -6307, -5730, -5059, -4729, -4972, -5613, -6657, -6904, -5409, -4272, -4174, -3623, -2763, -2910, -2971, -2156, -1677, -1815, -2873, -4257, -4516, -4544, -4971, -4939, -4714, -4510, -4278, -3505, -2372, -2575, -3646, -3727, -3408, -3408, -3220, -2934, -3129, -3519, -3292, -3095, -3232, -3278, -3828, -5033, -5427, -5044, -5495, -6031, -5891, -6129, -5848, -5016, -5547, -6113, -5390, -5900, -6780, -5589, -4797, -5384, -4516, -3560, -4122, -4366, -4059, -3439, -3097, -3794, -4902, -5031, -4596, -5015, -5432, -4991, -4457, -3936, -3412, -3419, -3509, -2561, -1463, -1304, -1267, -1425, -2227, -1970, -612, -303, -1532, -3212, -3506, -3270, -3741, -4225, -4192, -4300, -4206, -2786, -1041, -1215, -2773, -2792, -2059, -2698, -2909, -2498, -3426, -3768, -2399, -1849, -2450, -2703, -2602, -3014, -3240, -2841, -3088, -3759, -3676, -3291, -3646, -4069, -3935, -3920, -3878, -2864, -1419, -1130, -1945, -2812, -2705, -2105, -2381, -3190, -3190, -2605, -2287, -1703, -988, -1219, -1757, -956, 361, 776, 420, -325, -692, -526, -505, -714, -706, 60, 1414, 1542, 391, 644, 1703, 1168, -125, -309, -205, -651, -1037, -1379, -1364, -477, 390, 570, 977, 2175, 2655, 2638, 3066, 3117, 3054, 3498, 3715, 3661, 3816, 3867, 4185, 5564, 6020, 4367, 2936, 3117, 3963, 4029, 3141, 2293, 1434, 463, 618, 1355, 853, -266, -642, -242, 591, 618, -539, -1603, -1630, -832, -752, -738, 124, 355, -188, -245, 555, 1004, 843, 1426, 2020, 1528, 1878, 4052, 4730, 3017, 2534, 3487, 3498, 3669, 4787, 5030, 4616, 4822, 4853, 4776, 5640, 6016, 5025, 3901, 3897, 5536, 6555, 5762, 6268, 7903, 7185, 5356, 5980, 6920, 5042, 3575, 4040, 3793, 3511, 4426, 4038, 3199, 3813, 3966, 3207, 3087, 3799, 3218, 1066, 1225, 3368, 3500, 2488, 2810, 3724, 3722, 3033, 2339, 1615, 485, -859, -1269, -718, -782, -1357, -984, -342, 139, 1213, 2030, 2293, 3060, 4187, 3736, 2823, 3444, 3633, 3184, 3630, 4298, 4220, 3853, 3877, 4185, 4277, 3796, 3366, 3412, 3335, 3234, 3533, 3350, 2255, 1751, 2336, 2835, 1740, -131, -743, -325, -273, -1324, -2983, -3430, -2937, -3045, -2686, -1855, -1134, -325, -323, -990, -633, 491, 334, 114, 1302, 2161, 1952, 2612, 4264, 3467, 1280, 2688, 5130, 4719, 3567, 3873, 4697, 4389, 2920, 2372, 2801, 2579, 2290, 1938, 862, 205, 910, 2316, 2217, 568, 370, 905, 21, -1016, -500, 677, 949, 1108, 1977, 2704, 2762, 2754, 3367, 3232, 2099, 2574, 4164, 4535, 3935, 4300, 5037, 4070, 3128, 3500, 2569, 800, 487, 1223, 1655, 1357, 1022, 1041, 1107, 304, -1069, -755, 97, -482, -1285, -1673, -1667, -1046, -590, -926, -843, 176, 1349, 3045, 4450, 3787, 2493, 2545, 3044, 2705, 2236, 1921, 1680, 1700, 1384, 791, 498, 873, 1823, 1456, -280, -1056, -954, -533, 296, 406, 497, 1139, 410, -429, 595, 41, -1875, -1416, -1091, -1490, -355, 595, -231, -1279, -833, -170, -182, 1080, 1878, 1344, 2197, 3713, 4259, 4677, 5649, 6662, 6920, 6335, 6229, 7327, 8007, 7345, 6985, 7802, 7883, 7103, 7232, 7229, 6498, 6206, 6043, 5473, 5087, 4308, 2605, 2171, 3305, 3415, 2547, 2673, 3735, 3653, 2376, 2591, 2829, 1197, 355, 626, 1119, 1231, 48, -733, 140, 882, 506, 347, 691, 720, 969, 1504, 1481, 1467, 2091, 2958, 3239, 2498, 1734, 2127, 2323, 1180, -553, -2014, -2200, -2117, -2617, -2301, -1393, -1464, -1557, -600, -24, -848, -727, 1180, 2199, 1693, 1593, 3033, 5052, 5942, 5685, 5547, 6170, 6169, 5161, 4219, 3686, 3898, 3787, 2897, 3019, 3403, 3219, 3351, 2953, 3350, 4521, 3324, 1694, 2400, 2760, 1943, 1910, 2298, 2388, 2636, 3200, 3851, 4154, 3213, 2217, 2625, 2145, 854, 1443, 1914, 1013, 1629, 2811, 2300, 2185, 3715, 5150, 5797, 6038, 5772, 4851, 3791, 3311, 3412, 4183, 5533, 5511, 3868, 2999, 3559, 3936, 3198, 2230, 2177, 2365, 1980, 1928, 2397, 1990, 994, 475, 722, 907, 259, -396, -1127, -1462, -1463, -1973, -1732, -582, -820, -1840, -1734, -802, 500, 1408, 1074, 217, 293, 1655, 2588, 1656, 755, 1457, 2243, 2720, 3545, 3506, 2689, 3145, 3689, 2764, 2321, 2722, 2717, 1938, 1523, 1945, 2126, 2304, 2084, 1256, 1311, 1489, 1332, 2118, 2485, 2504, 3658, 3430, 1653, 1156, 1343, 1798, 1933, 872, 230, 486, 1235, 2190, 2460, 2801, 3989, 4549, 3207, 1401, 998, 1383, 1329, 1389, 2118, 2356, 1970, 2368, 3736, 3797, 2635, 2381, 2646, 2620, 2442, 1803, 1195, 1129, 856, 594, 644, 77, -1090, -820, 50, -651, -1727, -2236, -2409, -2290, -2152, -2005, -1600, -1614, -2137, -2218, -868, 1320, 1992, 1545, 1588, 1832, 1992, 1272, 356, 977, 1823, 1215, -142, 120, 1293, 1097, 1237, 2117, 1668, 1006, 1098, 792, 54, -327, -437, -691, -676, -339, 118, 486, 680, -240, -1893, -2077, -1245, -1756, -2514, -1500, -385, -253, -425, -955, -1649, -1751, -1166, -670, -875, -1652, -2254, -2011, -1781, -2499, -3147, -2636, -1289, -365, -752, -1154, -943, -1747, -1621, 412, 969, -244, -807, -382, 15, 321, 674, 472, 266, 791, 914, 1001, 1892, 3094, 2874, 1505, 2140, 4053, 4483, 4020, 4559, 5342, 4205, 3632, 5242, 5336, 3270, 1530, 604, 894, 2134, 3182, 3765, 3378, 3176, 3939, 3173, 1848, 2982, 4162, 2625, 1178, 1856, 2205, 1581, 1337, 846, 71, 236, 692, 122, -660, -103, 1036, 720, 468, 1569, 1512, 920, 1884, 2681, 2215, 2365, 3327, 3962, 4691, 5147, 4422, 3338, 3211, 4071, 4450, 3892, 3434, 3457, 2866, 2254, 2771, 2803, 2440, 2869, 2645, 1944, 2089, 2576, 2634, 2398, 2724, 3029, 2001, 1278, 1560, 988, 413, 949, 1131, 931, 1241, 1564, 2012, 3384, 5019, 5247, 4489, 4731, 5353, 4926, 5667, 6426, 4654, 3479, 4173, 4383, 3557, 3418, 4656, 5653, 5156, 4105, 3548, 3451, 3652, 3370, 1660, -195, 229, 1640, 1362, 754, 1338, 1569, 888, 898, 1250, 359, -923, -1711, -1818, -1392, -1582, -2085, -1769, -1384, -1178, -445, 578, 1597, 2763, 3361, 3103, 2486, 2535, 3325, 2839, 1987, 3064, 4315, 4615, 5050, 4917, 4116, 4189, 3663, 1506, 818, 2619, 3563, 2654, 2088, 2148, 1735, 1283, 1990, 3497, 3745, 2817, 2733, 2761, 1046, -869, -169, 1405, 1063, 464, 891, 1592, 1915, 1672, 1525, 1629, 1044, 872, 1632, 1554, 846, 714, 744, 780, 965, 448, -734, -782, 548, 1318, 1451, 1517, 1031, 616, 1189, 1712, 1149, 650, 578, 573, 432, -647, -1406, -717, 82, 346, 766, 1126, 671, 33, -354, -356, 234, -20, -987, -326, 656, 316, 28, -60, 68, 319, -65, 269, 1759, 1925, 854, 701, 1240, 1650, 2191, 2473, 1857, 686, 31, 37, -520, -1714, -1833, -1317, -2062, -2626, -1732, -1155, -1436, -1514, -1664, -1876, -1398, -950, -181, 1259, 1360, 813, 1755, 3037, 3292, 2752, 1894, 1968, 2757, 2476, 2246, 2614, 2781, 3693, 4666, 3774, 2776, 3195, 4010, 4011, 2838, 1783, 1631, 1718, 1580, 1373, 1603, 2132, 1118, -748, -159, 1689, 1404, 873, 2072, 2619, 1568, 1146, 2164, 3175, 4087, 4701, 4523, 5023, 5873, 6409, 7465, 7663, 6560, 5562, 4259, 2760, 2250, 3191, 4640, 5110, 4673, 4049, 3832, 3362, 2310, 1851, 1487, 381, 336, 1951, 2248, -139, -2022, -1943, -1789, -2290, -2281, -1807, -2447, -3474, -3603, -2874, -1199, -91, -815, -1765, -2034, -2021, -1852, -1924, -2264, -2703, -2514, -1767, -1870, -2230, -2004, -1726, -1834, -2251, -2694, -3100, -3077, -2289, -1141, -261, -27, 626, 1655, 1131, 46, 180, -821, -2901, -3746, -4263, -4340, -3506, -3698, -4008, -2452, -1267, -1334, -433, 1499, 1509, -340, -771, -380, -1004, -1713, -1728, -1303, -862, -1288, -2090, -1960, -1502, -1083, -992, -1628, -1375, -703, -1353, -2680, -3445, -2725, -1102, -1274, -2728, -2437, -2157, -3743, -5407, -5731, -4562, -3585, -4115, -3540, -1365, -411, -14, 646, -287, -1706, -1501, -387, 936, 1677, 260, -1139, -211, 1251, 1597, 1265, 1297, 1536, 1661, 1350, 266, 311, 2366, 2707, 1391, 1623, 2463, 2216, 1903, 1968, 796, -736, 271, 1135, -753, -1840, -1361, -1728, -2465, -1961, -668, -387, -775, -1486, -2401, -1768, -189, 130, -75, 164, -49, -53, 341, 341, 762, 1563, 1395, 491, -321, -1245, -1226, -200, -799, -2257, -1823, -606, -155, -32, -226, -262, 468, 699, -614, -1968, -1947, -943, -753, -1288, -491, 499, 40, -301, 461, 1616, 1595, 304, -1087, -1886, -1293, 52, 470, 67, 178, 1004, 1558, 1595, 1555, 1073, 254, 224, 361, -291, -427, 227, 1047, 2215, 2814, 2044, 1837, 2428, 2004, 1465, 1613, 1074, 466, 759, 271, -1553, -2269, -1015, -285, -1116, -1914, -1747, -1521, -2036, -2939, -3438, -2640, -1515, -2073, -3578, -3557, -2258, -2439, -3276, -2308, -1115, -1286, -1287, -994, -1734, -1615, 512, 1244, -60, 75, 1385, 1240, 520, 887, 1884, 1973, 668, -194, 517, 1823, 2633, 2528, 875, -805, -382, 377, -359, -423, 323, -312, -470, 1071, 1363, 461, 944, 1601, 1112, 645, 718, 842, 984, 1436, 988, -363, -630, -609, -1581, -1674, -1061, -1506, -1113, 74, 815, 1737, 2667, 3008, 1908, 202, -408, -93, -80, -639, -764, -318, 552, 1703, 1588, 156, -1041, -1148, -790, -1921, -3649, -3812, -2357, -1079, -1603, -2245, -1394, 60, 606, 21, 105, 845, 607, 452, 1454, 2231, 1913, 1703, 2153, 2386, 2169, 2305, 3177, 3696, 3201, 2487, 2364, 2503, 3014, 4223, 4684, 4287, 4689, 5097, 4159, 2887, 2231, 1171, 155, 434, 354, -984, -718, 1733, 2034, 1214, 1960, 1080, -434, 634, 1226, 129, 51, 640, 984, 1948, 2080, 1197, 2233, 3614, 2245, 439, 569, 967, 547, -307, -788, -159, 718, 1239, 1456, 1834, 2446, 1721, 333, 678, 589, -1688, -2688, -1802, -1309, -1551, -2502, -3552, -3267, -2742, -3136, -3143, -2903, -3043, -2054, -984, -1741, -2291, -874, 970, 1329, 621, 921, 1796, 1452, 1033, 1299, 1451, 1654, 2487, 3165, 2323, 1305, 1887, 3206, 3727, 3146, 2210, 1431, 1193, 2063, 2984, 2783, 1336, 635, 1784, 2351, 2198, 3020, 3490, 2139, 441, -302, -27, 1373, 2233, 1887, 1438, 818, 1449, 2984, 2642, 2232, 2572, 2124, 2247, 3172, 3989, 4954, 5473, 4893, 4274, 4087, 3639, 3199, 3397, 3208, 1974, 1567, 2552, 3323, 2703, 1514, 1977, 3309, 3136, 2090, 1704, 1295, 58, -648, -163, -202, -831, 410, 1958, 1310, 1034, 2175, 1927, 223, -275, 798, 1514, 1061, 1585, 2804, 3220, 3751, 4550, 4054, 2425, 2201, 3419, 3007, 1221, 1332, 2955, 3232, 2339, 2527, 3721, 4037, 3276, 2928, 2075, -162, -1721, -1703, -805, -88, 19, 601, 908, -169, -984, -1111, -1574, -1569, -580, 21, -143, 59, 1077, 2076, 1730, 789, 772, 958, -303, -1640, -1418, -712, -1137, -2210, -1802, -438, -137, -544, -486, -163, 281, -103, -731, -272, 296, 428, -22, -972, -1659, -1085, -372, -947, -1354, -790, -295, -519, -714, -153, 814, 1076, 483, 231, 633, 1566, 2501, 2159, 1114, 1201, 2194, 2007, 593, 163, 1225, 2115, 1125, -789, -1149, 130, 1007, 329, -1162, -1709, -630, 44, -349, 95, 737, -505, -1922, -1133, 264, 449, 220, 596, 1007, 486, -36, 410, 853, 739, 747, 965, 232, -1050, -710, -106, -1070, -2173, -2312, -1999, -600, 945, 324, -402, 657, 1605, 340, -2419, -3242, -2290, -1854, -1897, -2335, -2793, -2533, -2135, -2191, -2551, -2940, -2251, -1335, -3169, -5287, -4603, -3705, -3495, -2552, -1976, -1571, -190, 427, 123, 412, -580, -1800, -1339, -1578, -2043, -1679, -1678, -1850, -2104, -2798, -2826, -2144, -3019, -4758, -4975, -4600, -4037, -3800, -4540, -3998, -2601, -2284, -2289, -2984, -3621, -3506, -3845, -3880, -2953, -2048, -1782, -2248, -3587, -4905, -4508, -3138, -2767, -3458, -3610, -2521, -1891, -1650, -958, -1595, -2174, -625, -528, -2642, -3533, -3356, -3773, -4602, -4605, -3989, -3956, -3624, -2177, -1102, -927, -1699, -3369, -3861, -2638, -2331, -3469, -3916, -3794, -4157, -4109, -3887, -4732, -5542, -4215, -3720, -5770, -6066, -4859, -5040, -5304, -4225, -3010, -3293, -3676, -2688, -2022, -1526, -214, -289, -1294, -1236, -1056, -823, -403, -284, -436, -1230, -1807, -1881, -1939, -800, -68, -1540, -2767, -2756, -3388, -3740, -3032, -3411, -4212, -3644, -3489, -3716, -3437, -4542, -5311, -3499, -1801, -2127, -2389, -1653, -1204, -876, -400, -480, -401, 234, 677, 707, 361, 608, 1122, 768, 593, 237, -1174, -1823, -968, -747, -1594, -1294, 158, 648, -535, -2148, -2817, -2709, -2857, -3153, -2644, -1987, -2047, -2116, -1779, -1507, -1867, -2995, -3981, -4174, -4737, -5731, -6390, -6401, -4829, -2607, -1378, -976, -405, 220, 161, 598, 1296, 1103, 772, 971, 1107, 1086, 1365, 1304, 1190, 2173, 3113, 3039, 2758, 2875, 2866, 2427, 1948, 1914, 1924, 2213, 3156, 3664, 3111, 1832, 755, 722, 945, 141, -812, -1033, -1203, -916, -356, -1207, -1990, -865, -281, -149, 1474, 1889, 307, -588, -84, -100, -1636, -2308, -997, -464, -1564, -1604, -255, 17, -405, -251, -1386, -2655, -1781, -1409, -2220, -2549, -2841, -2181, -1040, -1807, -3445, -3744, -2730, -1842, -2521, -4395, -5103, -3904, -2366, -2341, -3527, -4152, -3472, -2434, -2079, -1633, -1715, -2608, -2264, -1425, -1200, -880, -680, -606, -626, -397, 371, 653, 138, -527, -21, 1654, 1427, -222, 36, 1394, 1874, 888, -166, 17, 38, -796, -273, 1987, 2206, 33, -611, 85, 277, 854, 1128, 832, 993, 1350, 1508, 2092, 3666, 3459, 1525, 1411, 1900, 1799, 2059, 1827, 1869, 3075, 3035, 1398, 564, 706, 1145, 1668, 1380, 2073, 3775, 3347, 2229, 2189, 1554, 151, -816, -1605, -2371, -1851, -348, 394, -633, -1730, -684, -62, -1260, -895, 524, -59, -1867, -2382, -1591, -1374, -1500, -560, 831, 1427, 2387, 3339, 3371, 3406, 2885, 1940, 2349, 3203, 2124, 326, 218, 1135, 871, -155, -192, 20, -685, -105, 2188, 2227, 909, 1474, 1987, 1753, 2461, 2553, 1104, 139, -49, -1036, -2294, -2194, -2639, -4155, -3528, -1449, -382, 84, 2, -892, -1224, -781, -524, -756, -1134, -639, 182, -232, -325, 938, 1075, 476, 466, -550, -1131, -195, -464, -1623, -2071, -2346, -2682, -3318, -3351, -2415, -2080, -2310, -1238, 26, -1779, -4902, -5247, -3809, -3420, -2637, -837, -949, -2431, -2913, -3122, -3850, -4877, -5340, -4701, -3674, -3064, -2966, -2539, -1531, -996, -662, -303, -216, 421, 1112, 259, -1417, -699, 1768, 1441, -1430, -2661, -1640, -706, -1555, -2922, -3081, -3305, -4432, -4827, -4300, -4475, -4376, -3726, -4686, -6809, -7315, -6624, -6780, -7218, -6529, -5376, -4856, -4600, -4436, -3530, -1916, -1470, -2316, -2250, -1388, -1376, -2204, -2249, -1396, -1324, -2054, -2425, -2640, -3359, -2869, -1347, -1489, -2552, -2327, -783, 758, 1194, 744, 650, 1477, 1518, 754, 757, 906, 1441, 1743, 111, -1282, -1909, -3061, -2856, -2558, -3255, -2834, -2778, -3698, -3179, -2761, -4228, -4958, -3450, -1674, -2170, -3794, -3779, -3041, -3392, -3398, -2633, -2227, -1272, -377, -704, -912, -152, 1468, 2368, 1086, -438, 64, 509, -1161, -1842, 137, 913, -390, -853, -646, -211, -459, -2811, -4465, -4016, -4001, -4843, -6492, -8236, -7942, -6347, -5217, -5334, -4792, -2927, -2167, -1473, -302, -130, -839, -1173, -771, -1159, -1901, -1329, -751, -1471, -2654, -3195, -2527, -1471, -1260, -1533, -1964, -1142, 461, 490, -414, -1239, -2263, -2542, -2171, -3623, -5484, -4126, -1014, -146, -569, 364, 1290, 989, 548, 312, 487, 1283, 2929, 4536, 4145, 3902, 4192, 3012, 1645, 442, -825, -1658, -2378, -2676, -1894, -1665, -2789, -3649, -4180, -4326, -3887, -3363, -2096, -1004, -2596, -4754, -4730, -4295, -4581, -5180, -6391, -7704, -7418, -5164, -3224, -2625, -2420, -1799, -977, -202, 851, 473, -977, -477, 256, -307, 304, 1389, 1640, 2604, 3565, 2368, 324, -649, -365, 702, 953, -926, -3127, -2475, 137, 834, -729, -1933, -1333, -25, -566, -2377, -2628, -2310, -3480, -5163, -5593, -4877, -4057, -3252, -3334, -4766, -4960, -3693, -2827, -2034, -1214, -589, -464, -636, -176, 772, 1536, 2133, 2041, 884, 1148, 1946, 769, 900, 1198, -1351, -2543, -338, 1334, 410, -384, 182, 322, 322, 1190, 1464, -141, -1172, 1123, 2668, 924, -178, 101, -37, -348, -201, -293, -70, 248, -833, -812, 397, -301, -822, 72, -910, -2529, -2056, -1854, -2948, -3380, -2218, -1056, -2666, -4346, -2502, -923, -1930, -2399, -2136, -2674, -4117, -5292, -4758, -4250, -3963, -2767, -1995, -2297, -2125, -1322, -1809, -2880, -2292, -1798, -3652, -4772, -3729, -4385, -6236, -4987, -2567, -3561, -4580, -2905, -3136, -4929, -4936, -4584, -5393, -6250, -5798, -5300, -5846, -5900, -5287, -5520, -5035, -2627, -1826, -3321, -3378, -1722, -1049, -1076, -1533, -3083, -4259, -4543, -4385, -4240, -4584, 470, 568, -697, -2202, -1785, -1240, -1939, -2764, -2575, -2264, -3131, -4303, -5020, -4305, -2088, -1483, -2849, -3352, -2638, -2058, -1469, -759, 175, 428, -474, -1392, -1190, -385, 233, 1285, 1869, 1187, 310, -562, -1561, -411, 2040, 1828, 151, 173, 429, -81, -272, -647, -833, -574, -1384, -2225, -1869, -1982, -2447, -1555, -895, -2600, -4200, -2952, -1578, -3065, -4472, -3734, -3071, -2678, -2811, -4313, -4147, -2366, -1289, -491, -1071, -2810, -3158, -1779, 85, 813, -69, -472, 899, 2066, 1149, -330, 326, 1867, 2325, 1795, 585, 268, 1001, 1685, 1703, 673, -406, -384, 535, 1534, 1274, -519, -1448, -1236, -1422, -1972, -2463, -2516, -2245, -2531, -2758, -2459, -2141, -1764, -643, -169, -1567, -2712, -1725, -216, -430, -995, -298, 606, 557, -344, -978, -599, 9, 402, 294, -944, -1534, -282, 759, -55, -1302, -601, 862, 853, 81, 58, 400, 679, 949, 544, -303, -954, -928, -225, -418, -2025, -3571, -3461, -2195, -1868, -2834, -3101, -1806, -1331, -2361, -3068, -3552, -3569, -1961, 59, 697, 640, 419, 65, 265, 1327, 1732, 214, -238, 2388, 4737, 4110, 2994, 3971, 4626, 3316, 3390, 5572, 6435, 5276, 3990, 4163, 5472, 5518, 4507, 4611, 5278, 5450, 5883, 6780, 6573, 4815, 2902, 2938, 5868, 7149, 3799, 1855, 4710, 6629, 5173, 4104, 4766, 4798, 4419, 5908, 6999, 5215, 3461, 3901, 4902, 4709, 4047, 3494, 2835, 2325, 1291, 92, -534, -315, 387, 554, -542, -2150, -2350, -940, -548, -1483, -1964, -2972, -3792, -3125, -2642, -2495, -2394, -2669, -2442, -1747, -1731, -1287, -710, -1098, -1024, -669, -966, -330, 1440, 2013, 873, 67, 604, 1342, 1372, 757, 186, 517, 1506, 1425, 575, 824, 2087, 3356, 3371, 1654, -160, -938, -852, -1306, -2611, -3185, -2233, -1171, -1297, -1796, -2035, -1921, -1157, -976, -1959, -1826, -844, -1049, -1011, -799, -1369, -1197, 241, 1031, 422, 246, 905, 1381, 2124, 2487, 1169, 276, 324, -1032, -1886, 700, 2419, 307, -950, -750, -1834, -1940, -41, 1172, 50, -1800, -2631, -2012, -1127, -1288, -1856, -2190, -1663, -70, 265, -2003, -4913, -5670, -4117, -2312, -1935, -3877, -4968, -3189, -2142, -3061, -3649, -3428, -2768, -1924, -1711, -2556, -2969, -1396, -780, -3521, -5719, -4675, -2725, -2565, -3857, -3692, -2013, -1133, -1109, -1219, -1595, -1912, -1656, -583, 1227, 1068, -1103, -1925, -1004, -901, -2092, -2600, -1694, -808, -1574, -2829, -2752, -1313, 557, 1286, 1322, 2340, 1757, -885, -2357, -2609, -2665, -2740, -2936, -2762, -2292, -2124, -1610, -379, 950, 1146, -570, -2234, -1186, 152, -1573, -2143, 1566, 3462, 1025, -1031, -1173, -1306, -1182, -453, -740, -2094, -2954, -2204, -559, -325, -1166, -483, 888, 1160, 1203, 660, 179, 1550, 2670, 1609, 75, -679, -206, 985, 1762, 1984, 1816, 749, -671, -497, -731, -2993, -2179, 1550, 2642, 1238, -313, -896, 39, 2140, 2624, 779, 598, 1569, 972, 976, 2241, 2381, 1323, 775, 1169, 1556, 1153, 477, 487, 813, 474, 43, 468, 1357, 1518, 575, -290, -315, 651, 2053, 1608, -782, -2047, -883, 93, -170, -873, -1583, -914, 246, -595, -2424, -1809, 818, 1199, 305, 1003, 723, -877, -1243, -1107, -1722, -2104, -975, 562, 135, -1745, -2283, -1301, -703, -526, -349, -757, -816, 1017, 2433, 865, -436, 967, 2373, 2641, 2613, 1949, 1480, 1959, 3005, 3446, 2316, 1843, 3664, 4485, 3231, 1874, 2087, 3696, 4811, 3801, 1703, 826, 699, 884, 1142, 348, -352, 243, 1389, 2132, 1560, 122, 228, 1735, 2327, 1855, 1010, 1165, 2789, 3788, 2619, 880, 1156, 2552, 3195, 3029, 2349, 2012, 2121, 2425, 3026, 3099, 2365, 2361, 2841, 2710, 1866, 1181, 1833, 2933, 3292, 3767, 3732, 2123, 1307, 2364, 1988, 611, 1099, 1794, 2194, 2355, 982, 844, 2388, 2090, 127, -762, 208, 1216, 1376, 221, -1090, 624, 2620, 1303, 314, 601, 136, 17, 1256, 2060, 1052, 243, 1132, 2296, 2489, 1615, 520, 166, 1136, 2424, 2038, 493, 13, 904, 1201, 489, 1272, 3018, 2565, 298, -1347, -1874, -1768, -1532, -2216, -2655, -1921, -1535, -622, 210, -1128, -2792, -1201, 1700, 1289, -834, -708, 509, 588, 142, 137, 1193, 2125, 2423, 2406, 1543, 452, 251, 1118, 1501, 699, 1335, 2946, 2282, 758, 1262, 2153, 1689, 1454, 1662, 1643, 1446, 623, 512, 892, -242, -1655, -2391, -2459, -2035, -1624, -1679, -1567, -874, -535, -243, -98, -472, -996, -708, 302, 794, 314, -262, -382, -289, -284, -1194, -2585, -2129, 189, 1199, 40, -930, -286, 1197, 1658, 619, -439, -501, 320, 981, 1019, 974, 1202, 1342, 962, 160, -31, -287, -1497, -2482, -2742, -2280, -1363, -1208, -1503, -840, -1087, -2050, -824, 342, -1629, -3794, -3002, -1263, -917, -2126, -3280, -2846, -1766, -1710, -2131, -2429, -3312, -3757, -3410, -3958, -4509, -3624, -2720, -2309, -2394, -3326, -3328, -1888, -1185, -1459, -1729, -1235, 637, 2405, 2180, 608, -169, 406, 377, -34, 603, 1287, 1260, 956, 371, -1185, -2240, -1563, -1080, -1436, -1227, -894, -1734, -2390, -1522, -714, -1271, -1555, -604, -10, -180, -361, -745, -521, 710, 1125, 282, -190, 352, 314, -366, 111, 740, 178, -484, -137, 232, -593, -2044, -2618, -1408, 42, -394, -1858, -1524, -527, -1397, -2066, -825, -13, -592, -1908, -3232, -3187, -2489, -2030, -1655, -1937, -2736, -2393, -748, 489, -526, -2310, -1905, -608, -121, -446, -1279, -992, 352, 1315, 1027, 288, 1405, 2658, 1058, -924, -1786, -2200, -1199, -2, -305, -899, -1077, -774, 654, 825, -1349, -3189, -3427, -3170, -3396, -3908, -3423, -1728, -859, -2075, -2937, -1168, 701, 330, -645, -848, 42, 1669, 2568, 1799, -256, -994, 1040, 3065, 3323, 2977, 2784, 2401, 1914, 1785, 1122, -271, -153, 1072, 1196, 987, -698, -3095, -2183, -573, -2115, -3494, -2557, -1398, -2146, -3036, -2289, -2141, -1441, 709, -376, -3621, -3496, -1544, -1029, -1270, -1563, -1501, -1404, -1252, -236, 989, 1875, 1957, 265, -404, 667, 629, -153, -45, 539, 221, 431, 1754, 721, -1968, -2291, -1083, -286, -295, -1961, -3236, -1659, 603, -142, -2550, -3200, -3273, -3661, -2751, -1091, -580, -1455, -1033, 1623, 2346, 498, -296, 43, 635, 1590, 2015, 1234, 685, 2248, 4408, 3333, 116, -139, 1770, 1844, 176, -1102, -457, 938, 1031, 669, 678, -51, -1085, -1076, -453, -261, -634, -1263, -582, 1211, 872, -1676, -2148, 981, 2712, 853, -793, -345, 1272, 1833, 628, 305, 1124, 2137, 2991, 2746, 2291, 2266, 2188, 2318, 1668, -8, -544, 161, 810, 1524, 1283, -16, 7, 1019, 594, -625, -1293, -1598, -722, 282, -326, -1558, -838, 1234, 730, -1438, -1644, -1137, -1649, -2429, -2362, -2084, -2746, -3038, -2282, -1844, -2048, -1911, -855, 1150, 1837, 578, 361, 975, 1242, 1664, 885, -1026, -1357, -112, -550, -1741, -1091, -479, -243, -547, -2491, -4159, -3493, -2704, -4150, -4837, -2478, -470, -1054, -1738, -1463, -1438, -1707, -597, 1071, 334, -1584, -1523, 697, 2726, 2411, 381, -786, 787, 2650, 1691, -76, -233, 989, 2449, 3184, 1994, -146, -630, -573, -1914, -3009, -2042, -745, -476, -318, -739, -1785, -1336, -77, -791, -3121, -3553, -1527, -226, -246, -326, 1, 516, 506, 1199, 1999, -7, -1935, -379, 1313, 525, -988, -1159, -526, 245, 682, -299, 423, 2929, 2098, -464, -228, 1065, 1167, 662, 373, 111, -557, -782, 238, 1221, 184, -921, -125, 744, 548, -808, -2684, -2632, -483, 0, -2124, -3621, -2972, -2182, -2147, -1933, -1730, -1414, -275, 949, 1259, 591, 244, 750, 879, 543, 769, 426, -1485, -2146, -657, 169, 126, 1051, 2296, 1337, -1369, -2308, -1251, -1304, -2176, -2197, -1695, -794, -985, -2258, -2431, -1675, -720, -281, -1628, -3644, -3544, -2028, -1983, -3005, -3351, -3043, -2845, -2742, -2052, -1920, -2711, -2066, -587, -711, -1381, -1411, -1261, -23, 1178, 141, -442, 1088, 1588, 315, -311, -32, -263, 59, 1470, 2195, 1512, 859, 978, 1339, 1469, 278, -1147, -792, 168, 207, -694, -1009, -501, -521, -1130, -1709, -1868, -1749, -1394, -521, -788, -2639, -3135, -1904, -1591, -2139, -1609, -1217, -1701, -1789, -1015, -35, -378, -1141, -228, 596, -46, -27, 1065, 1635, 1333, 398, -394, 1126, 3429, 2538, -1077, -2517, -1138, -1139, -2792, -3657, -3669, -3425, -2092, -691, -1609, -3840, -4020, -2249, -1915, -2597, -1840, -851, -570, 352, 1048, 472, 357, 491, -820, -2788, -3902, -3125, -769, 164, -1201, -2019, -1314, 356, 1189, 137, 38, 1247, 1087, 466, 1683, 2307, 938, 60, 425, 762, 576, -257, -1812, -2253, -1212, -869, -1715, -2076, -1498, -730, -1020, -1754, -1709, -1464, -1016, -395, 143, -12, -1691, -2850, -2771, -3174, -3489, -2710, -1482, -1352, -2597, -3424, -1996, -896, -2582, -4448, -3909, -1534, -62, -1044, -2367, -2115, -1139, -120, 46, -435, -99, 173, -905, -1838, -1188, -324, -91, -92, -143, 178, 152, 191, 1556, 1503, -1089, -2226, -1248, -532, -546, -1448, -2045, -1009, -757, -1040, 513, 1087, -681, -1263, -101, -598, -2258, -2329, -1499, -970, -1098, -1825, -2009, -786, 655, 617, -606, -1468, -1492, -1010, -209, 468, 11, -1040, -598, 210, 24, 745, 2791, 2726, -159, -2081, -1872, -1312, -736, -140, -163, -453, 323, 1088, 430, 528, 1989, 1961, 960, 658, 595, 902, 1431, 1707, 2381, 2843, 2344, 1398, 520, 258, 746, 255, -1868, -2759, -1531, -72, 242, -170, 30, 568, 364, -533, -1372, -840, 394, 1538, 1486, -388, -870, 268, 464, 125, -940, -2081, -947, 452, 230, 837, 2912, 2838, 916, 979, 1470, 593, 308, 720, 836, 140, 8, 1177, 1110, -679, -2260, -2553, -2456, -2151, -853, -468, -1948, -1716, 473, 673, -513, 104, 1391, 1121, 479, 887, 1187, 1063, 2443, 3010, 613, -481, 663, 549, -18, 1883, 3649, 2322, 2057, 3735, 3075, 1847, 2582, 3458, 3292, 2294, 1552, 2805, 3950, 2254, 298, -168, 177, 1285, 2605, 2840, 1725, 614, 498, 1262, 1849, 1562, 726, -243, -471, 1062, 1726, -415, -1425, 502, 1598, 30, -1666, -2271, -2281, -931, 939, 615, -1256, -2028, -805, 392, 394, 287, 646, 969, 106, -1017, 18, 1312, 470, -1269, -2074, -1143, 297, 45, -1402, -1824, -571, 509, 203, 458, 1119, -224, -1225, 977, 2674, 729, -973, -172, 140, -650, 34, 2125, 2533, 1175, 1366, 2373, 1263, -85, 1063, 2397, 1207, -793, -1741, -1386, 120, 1122, 47, -1103, -659, 418, 1188, 943, 138, 356, 1476, 1080, -267, -1017, -1321, -737, 784, 989, -1175, -2637, -1892, -879, -1218, -2291, -2142, -1421, -2139, -2085, 196, 474, -1621, -2270, -2023, -2874, -3112, -1524, -322, -925, -1996, -1923, -1521, -1335, -1170, -1702, -2442, -2336, -1787, -1179, -1319, -2089, -1973, -769, 188, 24, 72, 1046, 1351, 416, -781, -754, 602, 1342, 909, 634, 1014, 1929, 1777, 665, 745, 293, -521, 297, 951, 225, -464, -633, -400, 129, -152, -1239, -811, 501, 387, -316, -512, -795, -733, -3, -120, -1262, -1980, -1470, -279, -250, -1788, -2853, -1338, 1556, 1921, 676, 1566, 2731, 2051, 866, -345, -609, 840, 2907, 4064, 2575, 224, 1052, 3343, 2949, 1429, 1483, 2098, 2239, 2623, 3432, 3513, 2374, 1383, 1576, 1654, 833, -101, -1065, -1587, -783, -266, -193, 527, 1687, 3286, 3662, 2283, 1464, 1563, 2082, 2521, 2594, 2992, 3019, 2144, 1662, 1757, 2018, 2801, 3561, 3233, 1943, 150, -684, 695, 2003, 1503, 1089, 1453, 2027, 2728, 1309, -1145, -148, 1744, 324, -2390, -3534, -2510, -1644, -2307, -2959, -2308, -1095, -430, -414, -434, 133, 1369, 2311, 2201, 1839, 2070, 2462, 2687, 2802, 2011, 788, 492, 1275, 2649, 2785, 788, 157, 1088, 895, 649, 1846, 2701, 3163, 4279, 4276, 2553, 1079, 439, -144, 206, 1634, 2732, 3120, 2219, 1286, 1160, 567, 739, 2010, 1924, 1073, 1013, 1232, 1580, 1844, 1383, 999, 645, -61, 847, 2265, 983, -890, -101, 1554, 1368, -285, -729, 211, 1125, 2093, 1954, 797, 849, 1710, 1703, 1374, 2181, 3578, 3561, 2153, 1479, 2281, 3879, 5970, 6442, 4202, 2539, 2200, 1809, 1579, 1910, 1884, 1048, 1237, 1741, 1147, 1263, 1553, 802, 289, 451, 1648, 3128, 2479, 339, 47, 1627, 1787, 1622, 3751, 5055, 3564, 2857, 3311, 2758, 1552, 617, 943, 1530, 393, -1659, -2254, -1382, -947, -1439, -2524, -2594, -1607, -1759, -1799, -1031, -1139, -2454, -3396, -3215, -3497, -3895, -2737, -2094, -3013, -3133, -2442, -2639, -2961, -1752, -96, 59, -1139, -2037, -1394, -221, -298, -1400, -1548, -594, 343, 451, -646, -1693, -1545, -777, -170, -976, -3004, -3834, -3344, -2912, -2075, -1102, -1413, -2288, -1640, -984, -1761, -1101, 515, -105, -1411, -1649, -2030, -2912, -2923, -1558, -533, -907, -605, 185, 109, 1134, 2512, 2055, 1263, 1991, 2719, 1247, 470, 2853, 4224, 1962, 304, 2276, 4630, 3697, 1525, 1233, 2199, 3056, 3054, 2274, 1463, 491, -170, -281, -1257, -1795, -234, 2119, 2534, 950, 1425, 3633, 3435, 1337, 600, 1584, 1866, 556, -797, -1153, 295, 2576, 3484, 3020, 2233, 1678, 2061, 3100, 2655, 1255, 1421, 2645, 3896, 3419, 1392, 516, 643, 549, -233, -1809, -2759, -2546, -1919, -1104, -1642, -3528, -2334, 1649, 2717, 702, -463, 89, 1329, 2389, 2248, 1016, 506, 1566, 2299, 1468, 453, 582, 989, 666, -117, -670, -183, 1196, 1945, 1233, 53, -259, 39, 1071, 2370, 1700, 696, 1207, 631, -376, -224, -929, -1492, -353, 79, -551, -1185, -1272, -474, -237, -978, -830, 301, 139, -1338, -1809, -1413, -1359, -1281, -1424, -1846, -1768, -1161, -982, -1538, -2023, -1764, -1333, -1994, -2585, -2105, -1976, -2453, -2258, -1553, -724, -361, -1970, -3492, -2244, -757, -1432, -2460, -2306, -2088, -2657, -3237, -2976, -1661, -1418, -2955, -4078, -4881, -5348, -3960, -2065, -2161, -3828, -3991, -2303, -1600, -2000, -2554, -2834, -1719, 167, 1417, 1660, 746, 166, 1091, 1860, 903, -459, 488, 2736, 2533, 329, -906, -70, 2599, 4078, 1803, -620, -260, -229, -1239, -1748, -2949, -3296, -1353, -487, -1815, -2073, 477, 3759, 3993, 1617, 147, 440, 839, 826, 653, 122, 149, 1623, 4167, 4878, 2017, -322, 992, 2379, 1520, 1258, 1430, 187, 194, 2398, 2225, -59, -513, 1727, 3869, 2508, -870, -1844, -899, -1879, -3511, -2781, -1386, -656, -71, 17, -229, -333, 695, 1919, 1060, -268, -280, 381, 2095, 3234, 1166, -1302, -252, 2352, 2646, 1687, 928, 306, 917, 1242, -140, -775, -20, -18, -185, 217, 135, -411, -260, 583, 264, -1642, -3194, -2637, -1608, -2265, -2514, -1789, -1864, -2700, -3358, -3851, -3567, -2087, -2012, -3749, -4357, -3927, -3834, -3693, -3189, -2563, -2945, -4064, -3482, -2475, -3181, -4024, -4562, -4585, -3297, -2344, -2723, -2660, -2100, -2127, -1145, 82, -727, -1356, 437, 1028, -1177, -2567, -2216, -1669, -998, -887, -1407, -1556, -1100, -1377, -2584, -3193, -2636, -1834, -2037, -3046, -3708, -3714, -3240, -2847, -3111, -2841, -1141, -222, -883, -824, -64, 1605, 3690, 2371, -660, -907, 808, 1516, 1169, 1184, 1350, 1630, 2103, 2312, 2193, 1703, 1515, 1076, 321, -760, -1925, -1253, 645, 1232, 618, 906, 2183, 3166, 3922, 4234, 2914, 532, 245, 2121, 2547, 1407, 1429, 2580, 3575, 3899, 2993, 1540, 2111, 3555, 2763, 2663, 4301, 4679, 3376, 2015, 2304, 3377, 3708, 3836, 2591, 315, -245, -72, -785, -312, 1462, 1084, -248, 1639, 4071, 2760, 879, 1134, 2010, 2564, 2785, 1943, 715, 1772, 3537, 2827, 1347, 889, 1187, 2170, 2604, 1723, 576, 502, 1743, 2340, 1911, 1994, 2147, 917, -809, -974, -1018, -1823, -1078, -21, -1045, -2235, -2688, -3050, -2501, -1007, -896, -2347, -2165, -1194, -1981, -2492, -1484, -1336, -1779, -1600, -1677, -1594, -1081, -854, -579, -306, -1525, -1926, -593, -1514, -3455, -3277, -2354, -891, -201, -1455, -1019, 456, -1007, -3342, -3951, -3541, -2882, -2796, -3222, -3373, -3466, -4091, -2901, -248, -1432, -4774, -5149, -3977, -3732, -3173, -2541, -2710, -2372, -1920, -2940, -4495, -4336, -2671, -1667, -2818, -4805, -5417, -4450, -3261, -3537, -4566, -4705, -3872, -2120, -926, -979, -1101, -1222, -296, 676, -394, -1666, -966, -197, -1020, -1595, -1011, 529, 1487, 440, -799, -254, 583, -339, -1464, -1225, -2379, -4442, -4283, -3399, -3141, -2025, -675, 383, 1897, 3079, 2377, 881, 731, 1155, 192, -597, 961, 2107, 1303, 1182, 1365, 728, 769, 1823, 1783, 471, 716, 1926, 1618, 474, -190, 856, 2388, 1099, -898, -817, -639, -1164, -963, -712, -1894, -2576, -1845, -1606, -928, 177, -357, 35, 2166, 1615, -777, -1276, 31, 649, 422, 993, 1008, 16, -24, 888, 877, -409, -382, 1128, 981, -367, -1403, -1919, -1112, 89, 345, -326, -2347, -3430, -1450, -144, -739, -684, -581, -1621, -2404, -1897, -2222, -3581, -2770, -1161, -1491, -2838, -3280, -2299, -1355, -1635, -2252, -3197, -4016, -3458, -2800, -2938, -2321, -1289, -1741, -3110, -3502, -3104, -3031, -2574, -2280, -2813, -2877, -3097, -4001, -4697, -4454, -3973, -3808, -3052, -2461, -3206, -4225, -4258, -3874, -4348, -4996, -5769, -5663, -3743, -3669, -5274, -4827, -3072, -1732, -1990, -2695, -2781, -3429, -3030, -1701, -3358, -6701, -6351, -3689, -3581, -4876, -4914, -4598, -3843, -2550, -1734, -1099, -345, -1012, -2035, -973, -164, -179, 290, 659, 853, 644, 115, -348, 590, 2321, 2335, 1058, -187, -809, -871, -1588, -1869, -1351, -1281, -1368, -1483, -1571, -1877, -1306, -9, 709, 1308, 1595, 1850, 3265, 3656, 545, -1942, 370, 2795, 2226, 1779, 1858, 1712, 2533, 3633, 3794, 3228, 1569, 941, 3130, 4358, 2563, 1335, 2344, 2259, 403, -350, -537, -1535, -1921, -1307, -937, 185, 1452, 1050, -24, -201, 2107, 5537, 5802, 3889, 3268, 2622, 767, 1157, 4292, 4089, 677, 1298, 3842, 2167, 150, 958, 1236, 480, -368, -383, 404, 419, 927, 1472, -252, -2790, -1938, 1324, 1319, -1093, -2453, -3059, -3472, -3184, -2874, -2904, -1663, 763, 1136, 111, 894, 2151, 1729, 1323, 773, -1060, -1340, 222, 1091, 1824, 1678, 624, 2483, 5301, 4408, 1954, 1406, 2238, 2975, 2570, 1510, 1808, 2790, 1755, 316, -139, -570, -672, 325, 1273, 164, -1204, -279, 944, 495, -242, -977, -1865, -1789, -599, -1055, -3010, -2964, -1212, -342, -959, -902, 1119, 1937, -45, -1083, -475, -565, -479, 755, -446, -2676, -1585, -713, -870, 1182, 2245, 76, -2112, -1403, 278, -20, -239, 1129, 1720, 1725, 2251, 1637, 780, 1739, 2562, 1688, 984, 399, -160, 114, -159, -310, -155, -710, -720, -484, -1403, -1719, -654, 599, 715, -1441, -2452, -637, 181, -198, 46, -134, -25, 1769, 2867, 1514, 606, 3204, 5823, 6155, 5608, 4050, 2848, 3072, 3563, 3727, 3163, 2592, 4114, 5685, 4611, 4138, 4990, 4381, 3433, 2847, 898, -572, 436, 1394, 347, -218, 1070, 1630, 2274, 4010, 3452, 2177, 3882, 6551, 6900, 5806, 5834, 6034, 6349, 8205, 8706, 7374, 6038, 5332, 5434, 4916, 4143, 4559, 5399, 5574, 4473, 2967, 3883, 5474, 3819, 1220, 723, 1516, 1772, 1010, 191, 1103, 3897, 6051, 5391, 3069, 2711, 5065, 6277, 6025, 5732, 3978, 3221, 6479, 8134, 4236, 1955, 4363, 5720, 4131, 2447, 2523, 2894, 2045, 1839, 3005, 3089, 3082, 3500, 2897, 3005, 3420, 2454, 1057, -62, 384, 1553, 1460, 285, -1744, -1505, 1368, 1215, -994, -253, 2629, 3940, 3598, 3885, 4533, 4132, 2000, -675, -680, 2331, 3928, 3911, 3878, 2639, 2322, 4132, 4657, 3404, 3809, 6137, 5258, 1311, 662, 3101, 3561, 3055, 4481, 5446, 3637, 2359, 3511, 3654, 1273, -1908, -3054, -902, 247, -1803, -1699, 714, -138, -2503, -2886, -2361, -1239, 151, 306, 380, 1126, 969, 1358, 2946, 2777, 746, -70, 1859, 4436, 4282, 836, -2022, -1103, 1026, 2233, 1503, -774, -1302, -290, 112, -192, -214, -467, -1900, -970, 3602, 3882, -169, -1254, -409, -465, -208, 837, 1600, 1566, -75, -1179, 985, 2550, 798, -363, 201, -425, -946, -635, -943, -1033, -1083, -1019, -529, -1099, -1774, -742, 257, -706, -2018, -1253, -781, -1672, -898, 958, 26, -1598, -49, 2169, 2150, 2028, 3328, 4660, 5990, 6696, 5086, 3407, 4909, 6570, 4361, 2229, 4430, 6750, 5780, 4418, 3425, 2748, 3561, 3659, 2110, 439, -741, -266, 1210, 1726, 1374, 1014, 867, 2405, 5027, 4809, 2524, 2367, 4072, 4671, 4518, 4735, 5282, 5737, 5163, 5385, 6012, 5002, 4108, -3548, -1479, -2286, -3170, -2321, -2701, -3688, -2838, -1346, -1707, -3535, -2208, 1670, 1324, -2107, -2801, -1298, -988, -2331, -4072, -4413, -4365, -7318, -8733, -4053, -662, -2307, -3003, -930, 840, 1619, 1791, 1349, 821, 1029, 832, -1213, -2532, -2126, -2747, -3567, -2377, -1162, -1947, -2950, -1992, -620, -1408, -2512, -2789, -4187, -5590, -5518, -4124, -3178, -4494, -5946, -5510, -4699, -5276, -6923, -7312, -5478, -3819, -4216, -4650, -3999, -5221, -6172, -2339, 853, -754, -1420, 1558, 3561, 2394, 381, -1488, -2017, 210, 1439, -1069, -3003, -2166, -1360, -1141, -1624, -3155, -3021, -45, 1744, 987, 55, -1984, -4454, -3320, -1182, -1790, -2971, -3489, -4111, -4482, -4459, -4686, -5989, -6558, -5635, -5661, -8073, -10108, -7952, -5141, -5828, -7627, -7300, -4382, -3062, -4991, -5114, -2899, -1776, -2126, -2016, -2424, -4374, -4436, -3616, -4419, -5454, -5546, -4182, -2679, -2974, -3485, -2431, -1451, -1318, -2479, -3771, -2046, -306, -2352, -5096, -6201, -6324, -4320, -1161, -889, -2378, -2294, -817, 26, -1022, -3445, -5467, -5703, -4312, -3151, -4020, -5429, -4456, -3103, -3266, -1540, 968, -193, -3595, -4938, -4847, -5108, -4373, -2634, -2350, -4241, -5960, -5514, -4009, -3854, -4082, -3150, -1987, -1270, -1653, -3460, -5349, -5310, -3966, -3464, -3562, -3337, -4249, -4492, -2975, -3561, -5229, -3980, -1025, -1106, -5001, -6620, -3136, -94, -170, -584, -969, -1361, -724, 7, 223, 77, -1296, -1941, -1686, -3562, -4246, -1591, -231, -1252, -2710, -3721, -4475, -5877, -6970, -6455, -5425, -5412, -6667, -8260, -7291, -4249, -3790, -5703, -5755, -4918, -6059, -6909, -6289, -5827, -4215, -2687, -3567, -3311, -1197, -1083, -2150, -2767, -4148, -4555, -2110, -129, -733, -1955, -2537, -2203, -2019, -2470, -2314, -2176, -2382, -1926, -2216, -4633, -6371, -4027, -718, -888, -2692, -2346, -231, 1064, 1250, 1142, 1031, 1667, 2999, 3398, 3121, 2757, 2303, 1832, 649, 636, 1759, 1946, 1838, 1498, -145, -1344, -325, 923, -129, -2564, -4090, -4010, -3075, -2841, -3921, -4671, -4596, -5708, -6465, -4120, -2451, -4135, -4774, -3240, -2792, -3174, -2782, -1841, -1010, -1760, -2931, -2524, -2776, -3486, -2783, -4413, -7261, -5242, -1252, -439, -2272, -4318, -4814, -3926, -3781, -5116, -5613, -4775, -4286, -3855, -3385, -3985, -4348, -3024, -2297, -5418, -8886, -5787, -1364, -2965, -6039, -5427, -2817, -2162, -2872, -2087, -827, -141, 1106, 2477, 2785, 972, -2449, -2387, 2062, 4288, 1826, 836, 3214, 2985, 548, 863, 2032, 1979, 2734, 4031, 3835, 3095, 2295, -770, -1653, 2657, 5057, 3498, 2537, 2525, 1785, 1292, 1568, 1884, 2290, 2988, 3540, 4077, 4806, 5361, 4958, 4230, 5459, 6430, 3732, 584, 2387, 6979, 8064, 6144, 4286, 2903, 1878, 1112, 1345, 1862, 1129, 591, 2334, 3911, 3339, 3356, 5024, 6873, 5809, 2248, 1710, 3155, 3157, 3455, 3810, 2720, 1818, 2552, 4158, 5487, 6839, 7398, 5886, 5038, 6302, 7324, 7267, 7015, 7273, 7496, 8088, 8105, 6709, 7112, 8596, 7516, 6397, 7184, 6494, 4915, 5783, 6970, 6531, 5844, 5343, 4764, 3370, 2061, 2068, 2260, 2178, 1538, 626, 660, 1487, 2421, 1584, -800, -83, 3539, 4575, 2241, 879, 2250, 3818, 3816, 2819, 1864, 2009, 3514, 4545, 3036, 1614, 1755, 1410, 2235, 4116, 3463, 2153, 3165, 3947, 3196, 1442, 34, 900, 2517, 2595, 1515, 77, -113, 611, 484, -74, -415, 2145, 6201, 6777, 4514, 3199, 3976, 4798, 4854, 5110, 4469, 2663, 2881, 3844, 1920, 783, 3877, 7004, 6769, 4824, 3026, 3404, 5445, 5546, 4510, 4460, 4664, 4697, 4889, 4716, 2979, 245, 1056, 5443, 6132, 3059, 2519, 3208, 2373, 2600, 3758, 4182, 4690, 4473, 4032, 4360, 3822, 2754, 3671, 6371, 7040, 4651, 3497, 5082, 6026, 5191, 4875, 5860, 6093, 5426, 5250, 5664, 5631, 3480, 1475, 3199, 5551, 3693, 104, -685, -402, -706, -518, 171, 1122, 467, -971, 1215, 4500, 3764, 1577, 1816, 2811, 3455, 4580, 3153, -261, -1646, -1440, 1019, 5007, 6243, 4705, 3963, 5072, 6290, 5814, 4111, 2733, 2861, 4605, 6293, 5811, 3901, 3049, 3381, 2646, 1742, 2904, 4134, 3364, 1137, -69, 1579, 4487, 5589, 4112, 2777, 3747, 4553, 4247, 3672, 1385, 1534, 5667, 7378, 6176, 4601, 3778, 5110, 5824, 2904, 1131, 4029, 6775, 6370, 5413, 5424, 5427, 5710, 6533, 6076, 4231, 3667, 4656, 3428, 730, 1836, 5168, 5557, 3015, 1809, 3292, 3793, 2664, 2303, 1901, -477, -2508, -663, 2362, 2048, 639, 1402, 3705, 4819, 4166, 3758, 2407, -402, -440, 2587, 3765, 2450, 2096, 2944, 4329, 5919, 5736, 2979, 1405, 4020, 6857, 6402, 4686, 3758, 3572, 3621, 3154, 1113, -361, 1805, 4791, 4394, 3177, 4299, 4451, 2999, 2650, 2251, 1230, 303, -911, -618, 2086, 3644, 2754, 1008, -675, -250, 1932, 2136, 1642, 2236, -28, -2033, 2212, 6086, 3940, 1397, 1865, 3106, 3740, 3131, 2240, 2470, 1450, -452, 826, 2526, 1329, 1466, 3020, 2244, 339, -838, -1269, -695, -261, -1640, -2543, -777, 1390, 2663, 3356, 3261, 2544, 2667, 3672, 3860, 3955, 3764, 1463, 95, 2203, 4542, 4871, 4505, 4375, 4112, 3854, 4162, 4266, 2947, 2522, 4065, 4114, 3443, 4326, 3955, 1266, -764, -275, 1079, 1602, 1407, -211, -858, 1122, 2076, 1316, 1201, 1896, 2162, 1419, 766, 1438, 434, -3420, -3826, 903, 3206, 260, -1638, -714, -336, -797, -1094, -660, 262, -952, -4046, -4124, -909, 1660, 1576, -1016, -2780, -1663, -490, -928, -1417, -1383, -2605, -2780, 1269, 3600, 938, -980, 19, 755, 878, 1208, 1503, 2565, 3532, 1547, -1227, 186, 3256, 3593, 2528, 1496, 733, 399, -412, -665, -9, -1386, -3307, -1394, 2581, 3044, 934, 1489, 3748, 3403, 1331, 302, 1635, 3761, 2800, 659, 947, 4135, 7414, 6535, 4467, 3827, 3444, 4080, 4968, 3218, 465, -477, -731, -322, 909, 745, -400, -598, -657, -1804, -2371, -2746, -5103, -5253, -872, 392, -2970, -3369, -866, 133, 157, 958, 1700, 1721, 1944, 981, -2132, -1459, 3361, 4661, 2231, 839, 1952, 3497, 3493, 3864, 5430, 5130, 2637, 2883, 6105, 6860, 4944, 4121, 4456, 3673, 1619, 297, 1173, 351, -2160, -428, 2165, 742, -468, -454, -1962, -3074, -1457, -538, -3629, -4861, -1125, 1127, 27, -691, 8, 221, -5, 1859, 4138, 2545, -261, 2132, 7485, 8593, 5405, 2315, 1779, 2974, 3516, 2438, 203, 475, 4266, 5580, 3141, 1401, 1974, 3183, 3029, 1793, 500, 501, 1249, 148, -133, 1656, 1751, 1119, 1377, 1764, 1524, -30, -1663, -836, 707, -797, -1325, 2322, 4913, 3338, 1139, 2535, 5318, 6287, 6435, 5309, 3281, 3653, 5106, 3332, -334, -731, 2551, 4004, 2407, 1903, 1153, -1414, -2441, -984, 5, -1655, -3887, -1970, 1827, 2250, 1687, 1861, 1898, 2015, 1403, 727, 668, 1107, 944, -2020, -3121, -218, 391, -1201, -918, -227, -985, -1331, -220, 561, -39, -1552, -1257, 2274, 4256, 3040, 2595, 2365, 1181, 914, 896, -805, -2395, -2720, -3852, -4029, -2661, -2755, -3683, -3925, -3925, -3531, -2988, -2375, -2757, -4348, -3212, 147, 1748, 2463, 3492, 3151, 2060, 2841, 4563, 3712, 523, -1612, 255, 4784, 6749, 4920, 3239, 3849, 4052, 1934, -34, -349, -1406, -2743, -755, 1286, 1281, 2384, 2515, 800, 972, 2132, 832, -160, 1380, 1004, -1375, 163, 4123, 3706, 460, -307, 629, 1503, 1852, 1679, 2060, 346, -2649, -679, 2737, 890, -2415, -2417, -63, 1847, 1619, 752, 733, 1359, 605, -3586, -5670, -2231, -720, -3485, -4188, -2550, -2753, -3730, -3204, -1724, -1028, -1819, -685, 3250, 3657, 137, -647, 1689, 2648, 1014, -1567, -3154, -1942, 716, 1535, 759, 237, 62, 280, 449, 806, 1736, 1829, 1923, 1810, -132, -148, 2219, 1592, -653, 26, 1296, 400, -597, -684, -1945, -5015, -6565, -4233, -1095, -436, -1763, -2556, -1432, -415, -646, -585, 646, 1410, 85, -1843, -1236, 2023, 5332, 5892, 2955, 261, 476, 1127, -244, -2627, -2448, 130, 1665, 2680, 3231, 1121, -886, -22, 1421, 1286, -220, -1606, -1768, -1904, -2822, -1581, 1318, 1496, -378, -732, -525, -1741, -2675, -1491, -502, -1711, -3302, -4820, -5585, -2911, 105, -711, -1566, -340, 625, 501, -877, -2309, -3069, -3411, -2545, -1638, -3304, -3440, 1526, 4654, 3016, 1959, 2300, 683, -1037, 346, 2199, 1226, -724, 1438, 4879, 3116, 229, 1211, 2878, 2688, 1600, 981, 2251, 2935, -319, -3206, -911, 2320, 1449, -1590, -2974, -2003, -1321, -1504, -922, -1726, -4792, -5126, -1994, -635, -2849, -4931, -4168, -2776, -1822, -728, -750, 163, 1609, -1444, -5251, -3826, -467, 194, -379, -564, -857, 258, 2260, 1990, 629, 976, 1958, 534, -809, 1682, 3916, 2294, 463, 584, 379, -83, 593, 748, 95, 2138, 4489, 2928, 932, 1516, 1855, 589, -131, 607, 675, -893, -2427, -2957, -2407, -2482, -2758, -93, 2513, 1764, 604, 818, 1704, 1486, -245, 110, 709, -2622, -4389, -837, 2276, 1809, -35, -1357, -1045, 647, 1305, 563, 481, 474, -620, -2580, -2471, 518, 1175, -1493, -2944, -2641, -3381, -3763, -1656, -1457, -4696, -5326, -1444, 2536, 3774, 2815, 963, -131, 1211, 3401, 2063, -93, 1323, 1710, -152, 901, 4012, 3997, 1897, 1479, 1654, 1849, 1877, 763, -17, 14, 9, 1, -740, -1712, 376, 2710, 1644, 1139, 1008, -512, -302, 798, 1056, 2088, 2770, 305, -2068, -299, 2273, 2130, 304, -1221, -2040, -2321, -1174, 251, -504, -1845, -2050, -3059, -3407, -1448, -848, -1638, -1707, -2281, -3540, -4608, -4790, -3558, -2948, -3593, -4177, -5955, -7396, -5229, -2883, -3203, -4321, -5055, -4772, -4063, -3502, -2545, -1282, -360, -953, -4187, -6571, -3351, 1708, 2127, 27, -84, 385, -50, -535, -1096, -1485, -602, 326, -1926, -3701, -753, 958, -1028, -1628, -445, -378, -1626, -1505, -1494, -4499, -6170, -4009, -1801, -977, -284, 201, -110, -745, -117, 1119, -172, -2781, -3076, -3338, -5239, -3837, 543, 2643, 2433, 1689, 596, 162, 583, 48, -1315, -751, 1571, 963, -2201, -1190, 1704, 279, -1520, -245, 554, -927, -2145, -1125, 92, -1798, -5279, -4421, 92, 1420, -434, -5, 1571, 720, 618, 3512, 5130, 3544, 656, -1297, -380, 1481, 1109, -284, -1168, -1269, -453, -1239, -3294, -2693, -985, -1417, -2443, -2926, -3542, -3239, -1336, -355, -1478, -2197, -1473, -941, -1375, -1543, 138, 2064, -389, -4280, -4021, -2627, -3002, -5031, -8097, -7833, -4260, -3020, -3497, -2295, -1667, -3358, -2791, 1693, 4176, 1830, -1335, -1170, 243, -410, -434, 1784, 1417, -3037, -4113, -597, 132, -1148, 528, 1939, -249, -1901, -197, 1488, 1745, 1724, 597, -1691, -2375, 590, 2922, 641, -1550, -168, 916, -117, -964, -180, 1440, 2005, 478, -1532, -3252, -4633, -3184, -394, -355, -1435, -1760, -2672, -3319, -3038, -1558, -1051, -4518, -6462, -3067, -739, -1986, -2714, -2010, -1943, -3130, -3847, -3247, -3066, -3634, -5618, -8556, -7718, -4049, -3754, -6138, -6644, -5510, -5231, -5884, -6456, -6089, -4577, -3578, -4988, -6223, -3979, -2187, -2851, -2973, -3434, -4529, -4677, -4682, -4255, -2226, -1052, -2976, -2728, 1010, 1239, -1551, -2739, -2731, -2460, -2136, -2334, -1469, 1093, 338, -2774, -1357, 1865, 1817, 1497, 1888, -72, -1821, 32, 2374, 2502, 371, -2671, -2096, 2554, 3674, 182, -119, 2777, 2436, -253, -385, 1136, 1958, 1846, 696, -1175, -2998, -1204, 3035, 2519, -550, -422, 647, -226, -1137, -520, -967, -2799, -1453, 2102, 1797, -658, -1749, -2493, -3142, -4126, -4958, -4408, -3431, -3622, -3973, -3497, -3966, -3989, -440, 2702, 1673, -494, -1082, -537, -213, -803, -1199, 145, 1644, 443, -2750, -5758, -5911, -2659, -928, -2564, -3743, -2869, -1158, -468, -965, -643, 325, 656, 360, -2646, -6648, -6640, -4580, -4512, -5845, -6920, -6649, -5260, -5154, -5923, -5481, -5484, -6106, -5548, -5965, -7017, -3827, 1017, 1525, -417, -705, -183, 49, 884, 1640, 1277, -57, -2151, -4075, -2974, 568, 2112, 1635, 1121, 546, 187, 906, 1343, -339, -1175, 660, 1012, -1426, -3178, -3435, -3637, -4122, -4529, -4740, -3210, -1698, -4282, -7333, -5490, -1684, -337, -752, -546, 984, 1388, 552, 285, -926, -2467, -1643, 847, 655, -2813, -2840, 1180, 1648, -1004, -2059, -1393, 177, 396, -777, -318, 837, 964, -498, -4231, -5415, -1914, -550, -2790, -3782, -3575, -2804, -375, 945, 146, -588, -1408, -2956, -3969, -2019, 901, 1436, 217, -1234, -719, 929, 1559, 1748, 500, -1311, -111, 2362, 3020, 2551, 2441, 2803, 2757, 2130, 2870, 3392, 1435, -220, -157, -992, -4618, -6926, -4954, -3083, -3750, -4911, -5101, -4372, -3018, -2314, -2891, -2332, -1449, -3358, -5934, -4323, -491, -585, -2557, -1911, -1217, -2377, -3579, -3629, -2970, -2339, -1815, -2421, -3618, -2414, 950, 2421, 959, -641, 137, 1930, 1475, -61, -425, -927, -1303, -454, -1091, -4745, -6777, -2898, 1788, 1660, 435, 213, -661, -837, -307, -708, -1122, -202, 276, -1588, -2957, -1674, -1091, -1315, -1357, -2355, -1570, -24, -1673, -2247, -213, 496, 689, 1545, 1503, 2259, 3118, 740, -1841, 76, 3602, 3491, 1840, 2538, 3514, 1960, 141, 1215, 3386, 3251, 2310, 3616, 5048, 3368, 1627, 3125, 4551, 3701, 2328, 1136, 1181, 1288, 1215, 3017, 4145, 2763, 1647, 2339, 2669, 361, -1997, -551, 1860, 1439, -495, -1196, -1133, -1388, -1456, -1131, -1407, -2629, -3221, -2739, -3587, -6581, -8482, -6026, -2244, -1966, -4214, -5624, -5437, -3664, -2202, -3717, -6536, -7325, -5926, -4467, -4580, -6633, -6657, -1560, 2684, 1644, -434, -1291, -1962, -1279, -71, -1552, -2799, -921, 105, -503, 506, 1881, 1564, 1206, 1877, 1965, 1063, 325, 231, 924, 1568, 327, -1898, -1525, -917, -3768, -4409, -985, 190, -423, -519, -1180, -716, 165, -228, -699, -1504, -2254, -1821, -1670, -3434, -3621, 52, 1980, 646, -106, 39, 824, 1503, 466, -694, -596, 404, 1295, 215, -2670, -2608, 1285, 3225, 1399, -557, -861, -1262, -2489, -2856, -1431, -1832, -5263, -6640, -4050, -2840, -5011, -5838, -4604, -4268, -5053, -5899, -5708, -3573, -1807, -2575, -3999, -5774, -7362, -5357, -2837, -3776, -4594, -4375, -4322, -2625, -525, 112, -354, -2354, -3438, -604, 1840, 804, 88, 1351, 2524, 1866, 51, -342, 999, 2393, 2401, 136, -2411, -742, 3295, 3944, 3130, 3719, 2981, 1787, 1642, -463, -2028, -769, 36, -197, -1241, -1275, 1798, 4446, 3805, 1636, -346, -890, 96, 2372, 2531, -2406, -5451, -678, 4460, 2731, -1480, -2587, -1581, -1495, -2778, -4494, -5866, -6190, -4891, -2246, -1651, -4325, -4763, -979, -611, -5651, -8572, -7390, -6553, -7166, -5972, -2879, -938, 690, 3100, 1591, -3172, -3232, 182, 1817, 1854, 264, -890, 721, 2133, 912, 217, 1415, 1526, 917, 2486, 4155, 2897, 1574, 2637, 3760, 3778, 3347, 1892, 762, 1048, 824, -1691, -4188, -2370, 1804, 2463, -277, -1379, -870, -1332, -2708, -3831, -3175, -1393, -1916, -4880, -4286, 336, 1883, 986, 447, -1786, -3164, -2133, -954, 149, 648, 576, 562, -1198, -3766, -1850, 2894, 3309, 507, -19, 2051, 3466, 1797, -381, 413, 1023, -2027, -3939, -519, 3613, 3338, 343, -1463, -550, 970, 1477, 1467, 1383, 1619, 1489, 506, -1603, -3539, -1976, 1794, 2267, 72, -528, 1947, 5098, 5169, 3550, 3805, 5047, 5486, 4063, 1268, 2501, 7545, 8459, 5378, 3971, 4048, 4710, 5657, 5445, 5001, 4580, 4242, 5119, 4093, 1860, 3239, 5685, 5882, 4110, 1715, 641, 1583, 2469, 2068, 1619, 1139, 1381, 4601, 7820, 6540, 3388, 2400, 3448, 4133, 3093, 2492, 4721, 6981, 6365, 4556, 3499, 3484, 2863, 846, 796, 3960, 5774, 4498, 2842, 2581, 3239, 2857, 1961, 974, -1770, -3560, -2839, -2497, -698, 4152, 6088, 3763, 3787, 6678, 7559, 5237, 2619, 2872, 4637, 4410, 3417, 3368, 2932, 4355, 7964, 8830, 6586, 5319, 6553, 7573, 6632, 5286, 5087, 4600, 2234, 188, 1642, 4203, 3463, 1435, 938, 760, 508, 885, 1691, 1953, 1449, 1631, 1601, 133, 1194, 4629, 4678, 3443, 4561, 4452, 3108, 3238, 4089, 4870, 5267, 5604, 5036, 2462, 1433, 4192, 5315, 3789, 3963, 4787, 3703, 2092, 1241, 1319, 2251, 1285, -1567, -843, 3291, 4546, 2355, 1138, 1205, 751, 797, 1565, 1782, -354, -3807, -1881, 4012, 5271, 3557, 3486, 3375, 2776, 2950, 3251, 3194, 3249, 3810, 3855, 1975, -1126, -940, 3225, 4848, 2651, 734, 634, 1792, 3381, 4345, 3595, 3250, 4002, 3782, 3469, 2378, 2254, 6072, 8786, 7021, 4213, 3519, 4650, 5463, 4711, 4112, 4744, 5525, 5911, 6139, 6388, 5406, 3173, 3534, 6366, 7109, 4691, 2641, 2499, 3267, 4328, 5606, 7003, 7502, 7372, 6297, 4334, 3689, 3266, 29, -2847, -1677, 33, 85, 268, 86, -785, -418, 1042, 789, -1156, -2370, -1910, -1434, -4091, -7832, -5927, -256, 1965, 1183, 674, 186, -82, 618, 72, -1899, -1925, -657, -173, 1456, 3382, 1620, 684, 4654, 7170, 5002, 1889, 688, 954, 1366, 1167, 738, 233, 536, 2436, 2741, 119, -1397, 1230, 3921, 2712, 689, -136, 142, 1762, 2721, 2556, 2197, 2450, 3023, 1632, 38, 2172, 4923, 4116, 2861, 3795, 4556, 4496, 4519, 4808, 5034, 3821, 1935, 2730, 5095, 5672, 5577, 4931, 3645, 3784, 3731, 2992, 3484, 3875, 3102, 2895, 3019, 1007, -1790, -608, 2318, 1918, -43, -451, 450, 1298, 297, -1604, -1623, -1637, -3019, -2496, -637, -71, 787, 2455, 1826, -95, 287, 917, 94, 259, 170, -1864, -1225, 2616, 4318, 2786, 26, -1388, -522, -1853, -5343, -4649, -674, 1231, 1044, 765, 1314, 3005, 3100, 1978, 4340, 6260, 3174, 2352, 5428, 6220, 5443, 5684, 5658, 5450, 6100, 5843, 3771, 1993, 4345, 8851, 8961, 6941, 7843, 8243, 5421, 2837, 2592, 3036, 2611, 2196, 2303, 2205, 2356, 2759, 2644, 2392, 959, -1259, 162, 3309, 2071, -45, 54, -13, 242, 368, -412, 125, -327, -3571, -2096, 2895, 1730, -1723, -1274, -1544, -3663, -2949, -961, -1055, -1601, -1427, -2154, -2398, -1619, -3955, -5667, -2122, 1925, 3938, 4197, 2963, 4168, 5994, 4112, 2923, 5139, 5828, 3220, 1748, 2308, 1009, -690, 2060, 5443, 3708, 309, -61, 2398, 4081, 3140, 2905, 3522, 1770, 29, 1037, 205, -4630, -6257, -1999, 1394, 693, -683, -1816, -4028, -5526, -4973, -4411, -3452, -1138, -344, -787, -826, -2294, -3537, -689, 1764, 95, -636, 906, 2549, 4161, 3687, 1740, 2392, 5532, 7884, 6501, 2537, 3033, 8006, 9194, 5810, 3354, 3497, 4375, 4195, 3541, 3404, 2615, 1857, 2706, 2058, -590, -374, 2086, 2775, 3078, 3473, 1440, -69, 656, 367, -1061, -1115, -654, -1344, -1831, 312, 3426, 3904, 3420, 4241, 3118, -674, -1434, 530, -107, -607, 818, -1512, -4909, -2449, 2061, 2156, 263, 655, 2172, 2831, 2652, 901, -1555, -1527, 277, 371, -2020, -3974, -2608, 387, 1066, -284, -1228, -887, 180, 836, 1446, 1313, 477, 1025, 2048, -5, -3471, -3176, -35, 1043, -603, -1854, -2022, -1773, -585, 46, -473, 340, 1526, 396, -679, -1284, -2367, -511, 3564, 4233, 2003, 2457, 5234, 4990, 2543, 2633, 4467, 4720, 2892, 1638, 2200, 1889, -266, -2646, -4303, -3163, -410, 232, 255, 1522, 2242, 1801, 3301, 5347, 3814, 1024, 1207, 2977, 2553, 1897, 3040, 2509, 65, -860, 1202, 2444, 885, 44, -457, -2713, -3634, -1617, -443, -118, 258, -453, -915, -165, -801, -3926, -4474, -823, 947, -1123, -2738, -2869, -2036, 199, 1701, 621, -885, -1495, -1573, -1023, -1726, -4852, -6058, -656, 3691, 476, -2841, -2133, -804, -1218, -1475, -711, -1103, -1984, -813, 770, -110, -1295, -1924, -4235, -6095, -3148, 780, -687, -3489, -2873, -1253, 325, -318, -3836, -5266, -4856, -5421, -5892, -5866, -5580, -5528, -5390, -3479, -913, 71, -869, -2918, -3666, -3309, -3358, -2544, -1983, -3182, -3275, -886, -804, -5587, -7132, -922, 3295, 675, -2516, -2782, -1089, 218, -99, -1124, -2288, -3048, -2950, -1621, -127, -939, -2455, -2120, -3553, -7025, -5642, -414, 1271, -397, -1501, -2105, -2151, -2488, -3120, -2590, -3302, -5471, -5423, -3496, -2273, -3400, -8034, -9760, -4385, -1995, -4993, -4824, -3972, -5504, -5210, -3733, -3783, -4783, -4727, -4145, -4735, -4266, -3439, -6563, -9038, -5655, -2229, -2669, -3362, -3424, -3842, -3732, -3364, -2529, -1077, -1169, -3233, -3804, -2134, -2085, -3160, -1540, 476, -500, -2255, -1881, -1037, -2577, -3514, -762, 644, -2395, -3980, -2099, -1840, -2837, -2930, -3373, -5388, -6291, -3696, -1682, -1024, 1172, 2777, 1395, -104, 639, 965, 76, 769, 2066, 1279, 1046, 3538, 4382, 318, -2268, 1936, 6038, 4031, 1392, 1671, 1847, 1992, 3496, 3434, 854, -521, -37, -138, 433, 1712, -52, -2145, 1039, 5351, 4062, 483, -287, 134, 579, 1587, 1883, 998, 925, 2052, 2329, -1589, -915, -2382, -3208, -1668, -796, -1359, -1561, -1501, -2094, -2943, -1827, -7, -204, -1130, -1356, -1753, -2263, -1632, -1528, -2294, -2618, -3077, -2848, -1594, -1064, -1409, -1996, -1874, -1202, -590, 193, -333, -1341, -512, -570, -2277, -2394, -2343, -2673, -2238, -2316, -2713, -3077, -3107, -2149, -1472, -2091, -3024, -2330, -1142, -875, -484, 29, -417, -1143, -1053, -647, -491, -587, -492, -654, -1008, -1557, -1574, -698, -869, -1480, -959, -720, -2180, -3366, -2595, -1749, -2490, -3942, -4205, -3875, -4628, -4669, -3539, -3179, -3005, -2462, -2328, -2514, -2280, -2194, -2322, -1667, -1502, -2162, -1872, -908, -138, 104, -1030, -2216, -1581, -835, -1293, -1842, -1470, -1286, -2049, -2346, -2329, -2725, -2872, -2098, -925, -1529, -3454, -4152, -3914, -3779, -4005, -4098, -3544, -2952, -2979, -3274, -2590, -1531, -1675, -2044, -2356, -2710, -2255, -2244, -2617, -1962, -1477, -1608, -1354, -1228, -1836, -2846, -3000, -2032, -1786, -2515, -2534, -1591, -553, -542, -1039, -637, -111, -334, -683, -1361, -1782, -1302, -1060, -1540, -2140, -2193, -2835, -3621, -2685, -2826, -4907, -4730, -2579, -2513, -4292, -5029, -4206, -3854, -4680, -5140, -4932, -4918, -5216, -5330, -5363, -5112, -4065, -3735, -5100, -5872, -5021, -4590, -5133, -4805, -4017, -4298, -4186, -2906, -2603, -2631, -2039, -2189, -2028, -1603, -2168, -2759, -2469, -1652, -1189, -1411, -2033, -2147, -1654, -1548, -1633, -1949, -2138, -1951, -2377, -2484, -2411, -4050, -4994, -3390, -2409, -3264, -4310, -4483, -4033, -4065, -4976, -5159, -3686, -2515, -2635, -2156, -2302, -3696, -3215, -2108, -2650, -3147, -2849, -3217, -4198, -4074, -2902, -2032, -1580, -862, -832, -1909, -2528, -2238, -2096, -3067, -4204, -4258, -3817, -2966, -2552, -3600, -4527, -4477, -3375, -2714, -3656, -3433, -2047, -2061, -1964, -1275, -1232, -619, -69, -586, -685, -580, -645, -25, -166, -982, 8, 1458, 1498, 936, 1043, 1708, 1705, 1245, 574, -109, -84, -458, -1393, -1196, -527, -968, -2230, -3082, -3133, -2737, -2303, -2646, -3394, -2787, -2249, -3611, -4304, -3165, -2245, -2104, -2354, -2639, -1880, -563, -579, -1277, -1001, -814, -1474, -1436, -1144, -1411, -853, 211, 184, -873, -1354, -1156, -1003, -364, -116, -715, -1030, -568, -1063, -2307, -1829, -1450, -1832, -1460, -1428, -1914, -1308, -980, -1920, -1462, 111, 50, -446, 188, 379, -762, -1138, -90, 564, 531, 659, 448, -425, -621, 302, 219, -446, 176, 634, 622, 957, 769, 998, 2635, 2595, 1015, 802, 955, 508, 337, 730, 1425, 2222, 2137, 1572, 1691, 1787, 2046, 2433, 2018, 1451, 1027, 544, 549, 1205, 2091, 1997, 1998, 2840, 3099, 2583, 2190, 2446, 3442, 4186, 3563, 3110, 3981, 4149, 3643, 3629, 3418, 2760, 2152, 1716, 2096, 1992, 364, -166, 438, 932, 1515, 737, -143, 516, 1015, 966, 1007, 1235, 1366, 1276, 1849, 2468, 1788, 1308, 2384, 3284, 2342, 1219, 2435, 3596, 3107, 3056, 3560, 3767, 3419, 2739, 3125, 4271, 4516, 4310, 4669, 4660, 4136, 4137, 4009, 3774, 4132, 4601, 4302, 3388, 2391, 2065, 2823, 3399, 3178, 2916, 3027, 3294, 2893, 2994, 4291, 4994, 4638, 3437, 2382, 3179, 4709, 4642, 3880, 4039, 4597, 4484, 4713, 5232, 4504, 3732, 3813, 3998, 3692, 2916, 2662, 3330, 3428, 2802, 2832, 3390, 3099, 2664, 3679, 4190, 3941, 4401, 4107, 3163, 2862, 2841, 2932, 3190, 3411, 3640, 3863, 3989, 3736, 2746, 1783, 2850, 4213, 2850, 1489, 2640, 3280, 2182, 2238, 3113, 2358, 1348, 2219, 3856, 4454, 3975, 3467, 3338, 4006, 4225, 3967, 4382, 3926, 3173, 4103, 5001, 4232, 3391, 3526, 3340, 2018, 1358, 2598, 3788, 3076, 2349, 3345, 3941, 3510, 3826, 3594, 2941, 3886, 4600, 4140, 4108, 4303, 3787, 3572, 3765, 3007, 2355, 2491, 2968, 3927, 3353, 1352, 1262, 2614, 1956, 599, 1126, 1276, 449, 1164, 2471, 2547, 2519, 3268, 3824, 3803, 3429, 3314, 4714, 5666, 4301, 3749, 5093, 5015, 3544, 3439, 3921, 3892, 4616, 4437, 2947, 3006, 4170, 4747, 4934, 4574, 2880, 1244, 1390, 1691, 1036, 1254, 1746, 758, 905, 2297, 2799, 2271, 1785, 2287, 2701, 2456, 2481, 3592, 4726, 3839, 2855, 3557, 3499, 2898, 3819, 4887, 4347, 3905, 4143, 3884, 4317, 4834, 3259, 2076, 2787, 3915, 4526, 4200, 3841, 3336, 2491, 2966, 3693, 3385, 3788, 3636, 1379, 447, 1927, 2178, 1489, 1398, 1016, 1117, 1755, 2266, 2969, 2471, 742, 642, 1714, 1992, 1624, 1668, 2877, 4391, 3806, 2368, 2900, 3414, 2607, 2116, 2186, 2304, 2494, 2177, 2103, 3654, 4708, 3500, 2880, 3765, 4276, 4910, 5206, 4246, 3633, 3267, 2246, 1365, 822, 784, 1337, 923, 211, 1239, 1971, 1668, 2638, 3708, 2891, 1984, 2758, 4326, 4406, 2608, 2145, 3042, 1978, 491, 1316, 2457, 2717, 3352, 3178, 2424, 2627, 3034, 3058, 3061, 3519, 4278, 4796, 3849, 2918, 4039, 4564, 3273, 2580, 2867, 2745, 2437, 2495, 2248, 1145, 321, 259, 94, -210, 262, 572, 107, -139, -365, -525, -156, 398, 634, 381, 350, 869, 1665, 1960, 1909, 2443, 2611, 2496, 3265, 2959, 1810, 2205, 2657, 2755, 3356, 3467, 3051, 2328, 2033, 2584, 2198, 861, 397, 890, 1453, 1582, 1115, 618, -50, 242, 1827, 1913, 798, 527, 1073, 1721, 701, -546, 510, 1314, 878, 1481, 2185, 1045, 303, 1405, 1545, 774, 1239, 2130, 1444, 240, 254, 702, 259, 556, 1469, -340, -2541, -1819, -790, -1010, -1557, -2313, -1491, -407, -1076, -990, -548, -1489, -1289, 773, 1493, 604, -591, -953, -209, -189, 152, 1599, 582, -2385, -2214, -88, 392, 8, -403, -960, -843, -192, 48, -58, 246, 503, 717, 977, 625, 502, 741, 796, 1258, 1919, 1676, 400, 114, 1633, 1375, -889, -860, 807, 1445, 1165, 793, -38, -1305, -1498, -598, -501, -1194, -2202, -2881, -2139, -1311, -1490, -1617, -628, 694, 1102, 1116, 1063, 244, -603, 521, 2094, 2159, 2065, 1893, 865, -118, 448, 2122, 3193, 2675, 929, 616, 1277, 250, -309, 946, 1049, -220, -227, 641, 848, 669, 260, -322, -1175, -1615, -1243, -1215, -1875, -2655, -2116, -62, 779, -800, -2070, -1860, -1039, -518, -877, -1272, -891, -534, -496, 227, 838, 180, -348, 308, 1791, 1723, -343, -475, 1404, 1602, 1013, 1220, 765, 80, -133, -135, -1017, -2135, -1381, -1080, -1959, -1710, -684, 164, 770, 532, 230, 795, 1375, 1170, 725, 783, 1175, 1434, 1249, 328, -398, -87, 261, -120, 36, 442, -432, -1901, -1771, -463, -528, -691, 168, 147, -207, 560, 987, 498, 691, 481, -664, -828, -527, -478, -1151, -2092, -1120, -1193, -2538, -1241, 581, 58, -734, -301, -252, -820, -1483, -1561, -1086, -681, -314, -1055, -1194, 257, 578, 747, 1100, 775, 1463, 2198, 1589, 821, 190, -757, -1088, -132, 222, -369, 86, 518, -524, -933, -376, -781, -1670, -1831, -2306, -3539, -4009, -3450, -2884, -2062, -2233, -2585, -384, 880, -461, -654, -786, -2563, -2399, 126, 733, -961, -1422, -306, -137, 16, 610, 17, 134, 1646, 1734, 1792, 2652, 1142, -895, 97, 1618, 482, -708, -83, -160, -1752, -2853, -2131, -1109, -1372, -1722, -1121, -186, 452, 1216, 1670, 1405, 1294, 2250, 2982, 2022, 1235, 1416, 2208, 2502, 1780, 1602, 1518, 334, 219, 1384, 1031, 66, -265, -54, 428, 162, 216, 783, 176, -993, -724, -188, -1855, -2975, -1646, -2042, -3671, -2962, -2331, -2414, -1703, -2509, -4022, -3120, -1510, -1753, -2516, -2267, -2051, -2555, -2272, 236, 916, -1574, -1329, 982, 1384, 683, 684, 1348, 2057, 1827, 1292, 1485, 1216, 566, 647, 637, 406, 158, 42, 498, 465, 484, 1520, 1104, -398, 33, 780, -46, -810, -851, -1292, -2235, -2618, -2026, -1610, -1684, -1002, -129, -984, -2636, -1993, 64, 695, 875, 1180, 702, 263, 392, 466, 696, 1513, 1664, 1205, 1469, 2067, 2725, 2886, 2236, 1752, 1526, 1412, 804, -354, -109, 648, 642, 442, -296, -1092, -1221, -1518, -1194, -531, -1418, -2212, -2492, -2633, -1948, -1689, -2137, -1336, -12, -233, -861, -964, -583, -819, -2054, -1871, -1268, -1576, -1230, -616, -804, -375, -67, -900, -948, 12, 266, -53, 562, 1237, 691, 189, 656, 197, -960, -495, 258, -580, -612, 585, 898, 195, -1260, -2209, -1984, -1568, -923, -650, -1836, -3315, -3056, -1825, -1220, -710, -361, -344, -646, -200, 754, -132, -1186, -828, -998, -1823, -2042, -1682, -1832, -2130, -1326, -806, -894, -502, -1004, -1724, -338, 480, -426, -228, 733, 1563, 2168, 1125, 968, 2293, 1410, 705, 1591, 524, -654, 250, -93, -1073, -787, -1015, -1990, -2926, -3291, -2450, -1405, -839, 40, 664, 1030, 1294, 628, 329, 629, 578, 349, 693, 1537, 898, -349, -28, 1061, 1856, 2008, 2155, 2091, 1271, 1069, 1958, 2658, 2090, 831, 112, -115, -381, -538, -662, -1173, -1526, -1932, -1830, -938, -776, -1700, -1977, -1401, -1775, -2846, -2697, -1546, -1161, -1162, -957, -1517, -1749, -669, -1103, -2299, -1374, -784, -1585, -1201, -352, 47, 1376, 2798, 2348, 752, -663, -1963, -2039, -1412, -1542, -1849, -1755, -696, 605, -315, -1885, -1055, 383, 470, 296, 708, 1130, 1199, 627, -301, -29, 5, -1502, -643, 1668, 1276, 63, -317, -318, 369, 657, 342, 440, -56, -833, -440, 407, 570, 197, -129, -579, -1569, -1627, -322, -157, -1733, -2772, -1648, -1221, -3068, -4000, -2744, -2349, -3971, -4807, -3655, -2939, -3466, -3282, -2297, -1965, -2383, -2369, -1498, -156, 829, 665, 24, -358, -185, 251, 448, 513, 1172, 1668, 1252, 559, 870, 1328, 90, -615, 312, 795, 246, -137, -288, -1217, -2229, -2147, -2167, -2924, -2816, -3042, -4033, -4084, -3257, -3434, -4435, -3889, -2631, -1870, -884, -1330, -1873, -496, 459, -3, -301, 124, 621, 1556, 1911, 1017, 150, -224, -801, -1394, -1620, -1108, 93, 383, 294, 674, 517, 281, -75, -548, -124, -5, -1066, -1645, -1358, -1390, -1708, -1753, -1800, -2208, -2542, -2196, -2044, -2097, -1532, -1213, -2508, -3969, -4454, -4150, -2757, -2498, -3567, -3377, -2691, -2648, -2398, -2135, -1760, -1725, -1965, -1367, -968, -1261, -1234, -858, -328, 173, -624, -2760, -3421, -1993, -1081, -1616, -2331, -1918, -1192, -1762, -3007, -3284, -3058, -2784, -1560, -1818, -3489, -2775, -1669, -2259, -2388, -2110, -2684, -3042, -2471, -1668, -1243, -1248, -446, 944, 330, -1255, -1258, 177, 1230, 1009, 339, -30, 944, 1976, 245, -1439, -1222, -1473, -1710, -2266, -2679, -2091, -2637, -3784, -3376, -2749, -2773, -2793, -2249, -994, -574, -1311, -1980, -2573, -2155, -891, -659, -90, 1378, 1021, -164, -336, -262, -389, -1115, -881, 280, 796, 400, 12, -526, -1414, -1182, 104, 862, 688, 337, -472, -948, -445, -30, -247, -935, -1596, -1819, -2367, -3569, -3019, -1151, -1324, -2475, -2312, -2588, -3369, -2634, -2246, -2560, -2230, -2621, -3110, -2484, -1695, -1289, -1254, -1463, -2424, -3882, -4843, -4040, -2654, -2988, -3828, -3213, -1882, -875, -94, -133, -832, -1382, -1946, -2704, -3059, -3278, -2874, -1116, 314, -23, -500, 318, 976, 463, -473, -420, 978, 1491, 896, 997, 1332, 1650, 2491, 2279, 1659, 1941, 1701, 706, 87, 468, 936, 342, 180, 1137, 1658, 1065, 211, 70, 808, 1342, 1433, 1170, 704, 829, 1108, 395, -304, -415, -1202, -2054, -1292, -115, -272, -560, -283, 268, 918, 678, -703, -1566, -164, 1068, 352, 296, 750, -271, -1544, -1086, 255, -175, -1898, -1630, 300, 1277, 846, 737, 1663, 1776, 694, -775, -871, 640, 515, -1042, -741, 285, -470, -917, 156, 145, -980, -1096, 187, 1131, 832, 1186, 2219, 1495, 46, -45, -150, -1292, -852, 1138, 1391, 386, 97, 271, 761, 640, 150, 644, 1469, 1799, 1513, 1849, 2534, 1486, 402, 1614, 2547, 1643, 641, -362, -1289, -584, 1054, 818, -1389, -2603, -1357, -14, -753, -1169, -428, -682, -1204, -1272, -1225, -612, -254, -306, -223, -564, -234, 923, 617, -1005, -1812, -1159, -386, 543, 2359, 2217, 336, 584, 1792, 1284, 458, 787, 1497, 1510, 1449, 1818, 1340, 185, 526, 1629, 1567, 841, -399, -991, 190, 859, 213, -187, -55, 181, -418, -1687, -1973, -1608, -2074, -2369, -1908, -1294, -1060, -1600, -623, 1465, 1610, 360, -4, 673, 318, -616, -589, -259, 376, 545, -851, -477, 1118, 637, -433, -972, -1224, -1548, -2502, -2241, -775, -1688, -2962, -1906, -1280, -1938, -1356, -425, -1337, -1724, -409, -438, -1877, -1540, -24, 743, 1505, 1697, 856, 648, 1383, 2054, 2025, 918, 435, 1512, 1756, 1403, 1147, 456, 117, 463, 264, -14, 1477, 2534, 1658, 707, -230, -516, 265, 932, 66, -1221, -1537, -1428, -897, -332, -259, -483, -138, 468, 920, 1026, 954, 2360, 2921, 719, -517, 644, 1487, 1478, 933, -14, 713, 1929, 1602, 665, -871, -2352, -936, 861, 222, -252, 351, 589, 268, 60, -23, -420, -876, -899, -1123, -1477, -682, 167, -79, -206, -467, -1209, -1347, -1475, -1985, -1262, 61, 165, 17, 437, 662, 447, 369, 1211, 1059, -567, -1698, -1984, -1612, -986, -1927, -2762, -1514, -1004, -1412, -450, 0, -1483, -2193, -1446, -1607, -2626, -1834, -395, -449, -912, -1178, -1289, -1289, -2783, -4678, -4157, -3025, -2651, -3421, -4676, -4473, -3554, -2095, -558, -607, -1838, -1998, -1016, -1257, -2859, -2749, -1259, -1580, -1883, -1028, -900, -849, -99, -667, -1793, -695, 519, -75, -477, 419, 575, -460, -704, -388, 30, 1002, 546, -1058, -1133, -627, -646, -584, -1005, -1951, -2041, -1678, -1542, -1099, -680, 90, 946, 318, -457, -95, 505, 641, 446, 805, 314, -769, 417, 1876, 1209, 865, 1417, 1160, 1053, 2007, 2425, 1146, 236, 1231, 1952, 1943, 2026, 934, -914, -1214, 199, 786, -961, -1540, 47, 186, -748, -955, -413, -210, -601, -806, -1047, -1173, -395, 148, -193, -197, 489, 424, -214, 60, 199, -138, 99, 396, 455, -174, -1934, -2162, -254, 453, 87, 565, 410, -588, -853, -1121, -949, -39, -84, -846, -914, 67, 65, -1667, -2266, -1179, -635, -1254, -1699, -2128, -1994, -984, -1268, -1229, 1006, 1947, 747, 195, 860, 1463, 839, -186, -295, 341, 38, -1097, -644, 491, -226, -1003, -871, -1304, -1131, -444, -1074, -1299, -517, -211, 394, 345, -413, 494, 1439, 967, 734, 998, 99, -1528, -1656, -242, -14, -919, -619, -562, -1332, -1204, -827, -1139, -1432, -1885, -2073, -1030, -351, -1017, -1901, -1680, -340, -344, -1648, -1246, 467, 184, -782, 694, 1063, -1103, -645, 1902, 2053, 335, 100, 966, 682, 235, 243, 249, 1121, 932, -798, -748, 65, 665, 1057, 420, 74, 767, 1226, 1231, 1129, 695, 680, -158, -1034, 90, 1072, 959, 969, 276, 34, 1449, 2091, 1316, 1036, 1946, 2425, 1874, 2307, 3247, 2735, 1895, 1881, 1212, -199, 225, 1185, -96, -1277, -237, 445, -829, -1336, -52, -146, -1155, -684, -138, 21, -106, -329, -392, -207, -120, 32, 991, 1192, -51, -793, -831, -836, -1229, -1364, 297, 2116, 1106, -824, 190, 1145, -956, -1421, 579, 349, -857, -491, 799, 1526, 551, -1056, -916, 414, 645, 356, 470, 1030, 979, -236, 5, 1872, 2117, 1165, 1184, 1866, 2514, 2200, 1180, 688, 951, 1002, -133, -624, 332, 19, -1072, -412, 845, 1030, 311, 268, 856, 989, 432, 73, 1012, 1318, -152, -576, 797, 1365, 721, -268, -694, -857, -1456, -1951, -1666, -3, 1561, 1306, 1103, 751, -1608, -2065, 416, 599, -1320, -1228, -4, -467, -1106, 23, 439, -599, -353, -364, -1450, -568, 1294, 1009, -140, 809, 2526, 1530, 1048, 3223, 3027, 718, 792, 1594, 589, -221, 320, 579, 457, 633, 984, 1079, 817, 905, 781, 340, 147, 769, 2221, 3220, 2764, 1348, 833, 1344, 1861, 2550, 2637, 1727, 1115, 1871, 2893, 2553, 2097, 1805, 790, 357, 869, 1102, 1774, 2198, 1641, 1525, 1268, 342, 190, 639, 236, 96, 1351, 2451, 2312, 1132, 714, 1578, 1418, 1139, 1847, 2183, 1950, 2156, 2418, 1784, 973, 1638, 2974, 1859, 17, 749, 2691, 3089, 1714, 888, 1616, 2148, 1934, 983, 139, 1169, 1677, 136, -53, 1447, 1655, 1376, 841, 553, 1386, 979, 245, 525, 359, 642, 1653, 1650, 785, -434, -435, 1295, 1568, 13, -727, 78, 1325, 1263, 860, 1640, 2885, 3075, 2751, 3611, 3786, 1827, 316, 216, 0, -26, 529, 1236, 745, 23, 1039, 1686, 447, -763, -1586, -2360, -1488, 283, -51, -1482, -1172, 78, -307, -1591, -1529, -698, -404, -447, 160, 484, -1184, -2054, -340, 1284, 918, -1014, -1259, 618, 500, -673, -907, -1354, -1016, -363, -1130, -1639, -238, 1142, 777, -473, -870, 215, 1810, 2070, 927, 541, 763, 934, 1381, 1252, 1002, 1685, 1505, 319, 289, 979, 1012, 1071, 1849, 1854, 817, -357, -85, 1412, 1766, 2034, 2520, 1996, 1419, 1422, 2007, 2648, 2072, 1120, 1780, 2690, 2676, 2978, 3543, 2809, 1588, 2519, 2777, 1059, 1515, 3177, 3354, 3107, 2410, 1047, 980, 1641, 252, -1042, -322, -387, -1310, -764, 354, 195, -622, -785, -34, 713, 427, 390, 1310, 1171, -39, 245, 1337, 1002, 657, 1724, 2096, 1010, 134, 422, 1343, 925, -278, 28, 765, 918, 1128, -60, -2916, -3046, -692, 407, 87, 98, 204, -801, -1150, 94, 98, -1326, -1794, -1873, -1876, -830, 340, 431, -110, -815, -827, -412, -1671, -3284, -2006, 492, 348, -422, 681, 1795, 1536, 48, -1178, 196, 1279, -27, -414, -23, -1042, -1754, -916, -635, -2004, -2337, -772, -445, -2068, -2456, -1049, -898, -1297, -681, -299, -637, -602, -1030, -2230, -2215, -1404, -1236, -1455, -1577, -1669, -2290, -2079, -501, 514, 1303, 2431, 2422, 989, -521, -1388, -2338, -2736, -2700, -3899, -4295, -2217, -462, -1296, -2543, -1632, 235, -70, -2107, -2273, -2036, -1804, 696, 1946, 720, -208, 107, 1274, 1781, 1582, 1837, 1590, 464, -766, -1557, -1465, -973, 93, 913, 421, 543, 1179, 508, 323, 384, -1492, -2363, -1711, -1470, -755, -55, -140, 732, 2305, 2256, 1963, 2113, 1416, 323, -107, 1195, 2509, 992, -346, 360, 495, 87, -241, -891, -1497, -1817, -1422, -778, -1022, -447, 1388, 1235, -492, -982, -549, -10, 459, 773, 1950, 2634, 867, -607, 1167, 3042, 1401, -153, 1633, 3282, 3117, 2990, 2064, 1145, 2342, 3685, 2968, 1643, 1685, 2461, 1931, 544, 822, 1874, 1832, 1755, 1818, 979, 477, 1139, 890, -1699, -3255, -2182, -2057, -2370, -1441, -1314, -1532, -1159, -1280, -1283, -568, -748, -1345, -520, 564, 477, 136, 52, -204, 396, 2381, 2671, 551, 1002, 2933, 1802, 781, 1551, 1292, 783, 863, 249, -498, -509, -732, -1266, -1483, -1469, -2050, -3514, -3438, -1411, -1290, -1691, -787, -926, -457, 1299, 906, -1143, -937, 1078, 1199, -464, -979, -412, 1058, 2272, 1362, 397, 1043, 1077, -508, -2267, -2457, -489, 738, 362, 461, 479, 189, -9, -1123, -1722, -606, 345, 350, 387, 1174, 1305, 272, -549, -833, -905, -1657, -2366, -1712, -1226, -2640, -3976, -2697, -1136, -1226, -1043, 446, 1207, 778, -66, -985, -832, -385, -1146, -2109, -1871, -1171, -635, -246, -636, -599, 11, -975, -2102, -428, 1383, -129, -1590, -553, 87, 483, 1244, 584, -1026, -1361, -989, -1241, -1619, -1753, -1710, -1608, -1565, -2210, -2129, -156, 178, -1419, -1510, 41, 1316, 1020, -81, -413, 117, -50, -1945, -3092, -2116, -378, -55, -1083, -1112, -435, -92, -89, -416, -1065, -1208, -820, -794, -1276, -1423, -1236, -1701, -2499, -1960, -1201, -2053, -2984, -2964, -3066, -3205, -2490, -1225, -151, 5, 23, 834, 1404, 750, 329, 683, 532, 702, 1886, 1662, 9, 14, 1315, 932, -603, -319, 1257, 1684, 777, -61, -147, 103, 109, 46, -994, -1856, -1153, -1417, -2183, -1063, -533, -1609, -1423, -331, -169, -776, -925, -212, 444, 246, -645, -1304, 131, 2015, 933, -603, -37, 166, -2, 1110, 1713, 572, -8, 1970, 2890, 1480, 2044, 3917, 2928, 1241, 1668, 2560, 2441, 2078, 2221, 1902, 1714, 1888, 1317, 415, 177, 71, -376, -468, -74, 185, 72, -313, -946, -1604, -1239, -603, -683, -670, -527, -447, -633, -1271, -1583, -470, 1215, 815, 200, 1652, 1538, -351, -766, -411, -330, 143, 1088, 972, 633, 1968, 2513, 596, -348, 777, 549, -1250, -1513, -234, 897, 1053, 523, -452, -1775, -1549, -659, -937, -868, -190, -787, -1461, 283, 1785, 978, -280, -273, 390, 1142, 1007, 533, 516, 588, 513, 635, 664, -83, -1260, -1792, -1631, -1673, -2282, -2545, -1917, -598, -67, -1365, -2884, -3418, -2982, -2085, -1816, -2132, -2486, -2586, -2370, -1925, -1352, -782, -664, -1241, -1675, -1402, -812, -588, -473, -177, 163, 445, 631, 875, 1072, 1001, 711, 405, 86, -124, -333, -777, -1240, -1921, -2831, -3018, -2510, -1965, -1485, -997, -891, -1402, -1858, -1195, 335, 1445, 1455, 503, -411, -755, -475, -299, -567, -2, 1338, 2046, 2323, 2554, 2445, 2946, 3668, 3473, 3327, 3475, 2943, 2033, 1851, 1942, 1761, 1765, 1354, 1091, 1813, 2218, 1941, 1587, 750, -192, -610, -1070, -1303, -1399, -1671, -1468, -1055, -1181, -1362, -560, 702, 892, -28, -607, -310, -52, -149, -337, -738, -1329, -1676, -1629, -1557, -1539, -1240, -15, 1694, 2374, 2197, 2026, 1912, 1707, 1303, 1044, 1160, 1601, 1987, 1996, 2174, 2430, 2409, 2671, 2934, 2540, 2031, 1716, 1434, 1439, 1167, 367, 59, 175, -160, -332, 43, 416, 883, 1273, 1140, 1036, 1473, 2099, 2626, 2687, 2221, 2491, 3409, 3019, 2591, 4350, 5803, 5193, 4858, 5894, 6979, 7587, 8355, 9115, 9048, 8476, 8375, 8766, 9521, 10470, 11072, 11732, 12989, 13989, 14458, 14785, 15149, 15861, 16018, 15346, 15215, 15112, 13670, 12568, 13251, 13399, 12616, 12677, 12580, 11490, 11059, 11996, 12653, 12503, 12456, 12725, 12610, 11813, 10968, 10045, 8910, 8093, 7542, 6851, 6153, 5478, 4797, 4227, 4121, 3815, 2659, 1655, 947, -60, -1067, -1942, -2694, -3523, -4835, -6114, -6607, -7256, -8535, -8910, -8774, -9524, -10414, -10452, -9906, -9405, -9012, -8733, -8961, -9193, -8811, -9123, -9913, -9923, -9763, -9629, -9185, -8793, -8609, -7993, -7388, -7274, -6701, -5792, -5783, -6228, -6037, -5881, -5999, -6097, -6672, -7714, -8395, -8723, -9588, -10531, -10823, -11041, -11682, -12018, -12133, -12302, -11630, -10855, -10816, -10270, -8811, -7350, -6121, -5164, -4723, -4327, -3833, -3792, -3886, -3786, -3888, -4246, -5122, -6887, -8072, -7019, -5576, -6372, -7771, -7601, -6831, -6324, -6934, -8774, -10047, -10093, -10169, -10834, -11642, -12230, -12248, -11871, -11840, -12054, -12216, -12105, -11538, -11127, -11118, -11043, -10666, -9983, -9491, -9124, -8290, -7646, -7846, -8319, -8474, -8386, -7868, -6937, -6517, -6485, -6115, -5753, -5335, -4578, -4224, -4306, -4385, -4604, -4700, -5107, -5817, -5727, -5465, -5592, -5554, -5425, -5221, -4635, -4254, -4241, -4197, -4565, -4795, -3985, -3408, -3597, -3263, -2673, -2313, -1886, -1773, -1760, -1873, -2271, -2579, -3115, -3856, -4594, -5491, -6383, -6854, -6649, -5920, -4811, -3702, -3382, -3277, -2926, -2843, -2943, -3194, -3538, -3840, -4133, -3817, -3046, -2986, -3626, -3476, -2585, -2140, -1844, -1344, -966, -486, -38, 140, 191, -284, -862, -1161, -1832, -2402, -2239, -1920, -1951, -2289, -2511, -2553, -2873, -3141, -2845, -2948, -3176, -2401, -1968, -2917, -3679, -3689, -4312, -4293, -2723, -2497, -4065, -5051, -5174, -5436, -5617, -5651, -5977, -6079, -5190, -4652, -5450, -6060, -5767, -5374, -5289, -5559, -5900, -5787, -5427, -5552, -5865, -5744, -5236, -4899, -5098, -5115, -4574, -4053, -4057, -4675, -5256, -5120, -4459, -3802, -3596, -3947, -3965, -3040, -2553, -2987, -2897, -2529, -2721, -2548, -2297, -2892, -3277, -2925, -2644, -2839, -3235, -2980, -2489, -2937, -3606, -3518, -3669, -4233, -4384, -4210, -3829, -3407, -2879, -1789, -749, -479, -385, -345, -827, -1589, -2341, -2830, -2507, -1970, -1817, -1637, -1238, -809, -644, -536, -389, -597, -609, -26, 213, -169, -434, -644, -915, -944, -1278, -1629, -974, -139, -435, -1305, -2106, -2856, -3224, -3223, -3543, -3798, -3086, -2136, -1506, -545, 264, 38, -283, 3, -225, -989, -1669, -2157, -2092, -1664, -1751, -2018, -1515, -1146, -1033, -420, -101, -165, 562, 1643, 2072, 2118, 1851, 1580, 2042, 2549, 2124, 1578, 1738, 1755, 1223, 823, 769, 636, 92, -418, -533, -956, -1670, -1864, -1901, -2108, -1936, -1496, -1426, -1337, -963, -502, -76, 76, -130, -247, -20, -129, -854, -1145, -714, -738, -777, -278, -245, -466, 89, 354, -80, -116, 277, 536, 281, -155, -498, -349, 72, -268, -946, -1042, -1031, -1426, -1627, -1465, -1375, -1096, -1070, -1278, -1065, -1063, -1372, -1297, -986, -894, -1039, -914, -654, -88, 777, 1025, 850, 1107, 1451, 809, 168, 95, -386, -455, 297, 627, 439, 371, 283, 175, 285, 390, 405, 60, -382, -253, 465, 1036, 804, 429, 502, 433, 11, 31, 557, 608, -126, -244, 713, 1110, 646, 654, 924, 764, 471, 466, 670, 636, 630, 167, -724, -130, 1348, 1640, 1269, 1431, 1671, 1522, 1330, 1124, 926, 677, 423, 155, -408, -638, -201, 249, 588, 585, 320, 361, -91, -669, -335, -703, -1883, -1639, -657, -371, -150, 291, 610, 682, 626, 387, 275, 738, 1377, 1320, 1063, 1553, 2168, 2267, 1933, 1702, 2016, 2015, 1730, 1901, 2069, 1828, 1479, 1300, 1241, 1286, 1362, 1278, 918, 758, 1072, 1580, 1596, 1034, 1002, 1305, 1074, 709, 744, 1026, 1010, 650, 412, 306, 520, 671, 494, 841, 1309, 1048, 921, 1426, 1803, 1601, 1333, 1142, 639, 161, 319, 810, 829, 661, 1088, 1596, 1883, 2197, 2483, 2842, 3252, 3114, 2534, 2093, 1700, 1453, 1445, 1462, 1244, 1182, 1403, 1439, 1367, 959, 442, 806, 1687, 1902, 1749, 1991, 2221, 2387, 2606, 2772, 3009, 3118, 3060, 3123, 3397, 3269, 2899, 3162, 3216, 2702, 2543, 2709, 2482, 2033, 1627, 1405, 1674, 1993, 2166, 1775, 1177, 1123, 1292, 1263, 881, 795, 1253, 1181, 979, 1089, 777, 531, 1440, 2513, 2598, 2564, 2667, 2505, 2413, 2353, 1622, 939, 992, 1034, 1039, 714, 303, 606, 987, 946, 678, 373, 353, 540, 626, 410, 201, 568, 1192, 1452, 1544, 2197, 2893, 3101, 3608, 3783, 3106, 2644, 2805, 2733, 2351, 2440, 2688, 3055, 3543, 3320, 2381, 1579, 1182, 500, -307, -499, -934, -1726, -1789, -1342, -1203, -1296, -1606, -2167, -2009, -1190, -1124, -1677, -1077, 220, 357, -337, -426, 458, 1317, 1386, 1562, 2483, 3469, 3715, 3468, 3335, 3510, 3166, 2487, 2467, 2488, 1982, 1834, 2146, 1941, 1293, 1176, 1557, 1518, 874, 475, 744, 653, 261, 217, 42, 51, 479, 611, 264, -25, 45, 524, 1655, 2652, 2461, 1874, 1787, 2325, 3012, 2817, 2141, 2146, 2533, 2506, 2048, 1893, 2077, 2237, 2552, 2836, 2770, 2344, 1728, 1540, 1690, 1320, 475, 350, 1040, 1329, 1166, 1295, 1569, 1724, 1923, 2273, 2589, 2357, 1595, 1001, 497, 91, 359, 998, 1141, 704, 415, 569, 972, 1549, 1874, 2159, 2570, 2348, 2020, 2202, 2287, 2029, 2045, 2536, 2641, 2406, 2333, 1985, 1900, 2317, 1957, 899, -160, -980, -1008, -886, -1271, -1595, -1478, -1121, -1194, -1380, -732, 450, 1426, 2072, 2509, 2815, 3021, 3034, 2621, 2169, 2462, 3239, 3413, 3295, 3813, 4630, 5111, 5064, 4856, 4969, 5181, 4564, 3345, 2662, 2188, 1903, 2022, 1578, 964, 867, 826, 922, 1032, 624, 53, -55, 18, -456, -1329, -1945, -2218, -2458, -2434, -2423, -2461, -1694, -287, 622, 618, 514, 867, 1098, 841, 633, 1166, 2049, 2369, 2231, 1925, 1620, 1264, 795, 658, 495, -7, -229, -369, -976, -1388, -1352, -1527, -1510, -979, -504, -461, -803, -714, 47, 812, 962, 169, -731, -799, -588, -268, 303, 968, 1684, 2154, 2863, 3888, 4146, 4283, 4746, 4492, 4348, 4522, 4165, 4320, 5089, 5236, 5117, 5354, 5335, 4376, 2991, 1731, 715, 375, 177, -520, -1250, -1394, -1443, -1906, -2279, -2250, -1925, -1613, -1387, -1066, -788, -761, -550, 97, 696, 1167, 1354, 1167, 1104, 1287, 1789, 2627, 3286, 3798, 4038, 3664, 3202, 2741, 2408, 2483, 2473, 2011, 1197, 534, 394, 547, 447, 8, 145, 602, 373, 124, 63, -456, -1201, -1757, -1858, -1637, -1843, -2166, -1632, -1186, -1710, -1928, -1337, -927, -356, 752, 1548, 1847, 1959, 1985, 1862, 1450, 1387, 1820, 1728, 1749, 2502, 2326, 1250, 1093, 1693, 1717, 1251, 1160, 1166, 468, -298, -247, 239, 786, 1158, 1068, 855, 1278, 1620, 1042, 162, -577, -838, -672, -958, -1314, -391, 1281, 1869, 1603, 1376, 683, 20, 369, 840, 835, 1301, 1933, 1512, 708, 800, 1253, 1684, 2270, 2416, 2013, 1865, 2127, 2391, 2187, 2009, 2381, 2762, 2807, 3115, 3546, 3158, 2450, 2004, 1591, 801, -582, -1493, -1294, -1396, -2478, -3508, -3525, -2666, -1822, -1399, -959, 79, 1172, 1370, 630, -105, -451, -711, -1174, -1800, -1857, -1635, -1372, -835, -358, 19, 220, 352, 934, 1492, 1234, 977, 1130, 1245, 1337, 1189, 1072, 1381, 1485, 1010, 555, 435, 243, -102, -653, -1160, -882, -245, -262, -931, -1366, -1428, -1624, -1803, -2015, -2228, -2050, -2081, -2258, -2071, -1936, -1952, -2163, -2259, -1880, -1658, -1994, -2750, -3365, -2380, -688, -363, -840, -783, -44, 503, 505, 193, -73, 254, 676, 762, 1001, 1168, 1344, 1352, 961, 1126, 1943, 2377, 1876, 1607, 2347, 2679, 2896, 3691, 3774, 2578, 1295, 1014, 1070, 832, 806, 1241, 1467, 1414, 1435, 1174, 857, 962, 1208, 970, 711, 1326, 1987, 2280, 2682, 2519, 1779, 1391, 1283, 1083, 1167, 1292, 1086, 790, 1055, 1908, 1919, 1450, 1673, 1394, 479, 99, 278, 605, 672, 558, 400, 355, 654, 1217, 1395, 770, 420, 861, 1295, 1123, 429, -6, 454, 1102, 1275, 1263, 1094, 1459, 2226, 1964, 1218, 1015, 1012, 653, 217, 562, 953, 387, -29, 226, -224, -1058, -756, -103, -48, 79, 233, 302, 618, 820, 680, 348, 516, 1399, 2017, 1793, 1559, 1957, 2367, 2317, 2201, 2384, 1997, 1188, 1132, 1481, 1564, 1634, 1982, 2278, 2111, 1505, 1206, 1423, 1658, 1185, 53, -382, -406, -1069, -2003, -2339, -2350, -2405, -2511, -3018, -3019, -2170, -1630, -1235, -292, 460, 374, -41, -33, 423, 700, 691, 680, 597, 953, 1845, 2047, 1926, 2216, 2522, 2483, 1868, 1124, 1190, 2014, 2089, 1216, 955, 1388, 1400, 1313, 1200, 479, -44, 246, 108, -1099, -1683, -925, -595, -1167, -1310, -1381, -1847, -1538, -932, -1094, -1182, -508, 471, 843, 566, 393, 459, 996, 1586, 1360, 667, 398, 1042, 1784, 1674, 1497, 1554, 1490, 1819, 2167, 1697, 1158, 1012, 683, 327, 309, 470, 592, 819, 994, 792, 288, -75, 11, -428, -1293, -1442, -1250, -1232, -1271, -1457, -1326, -1018, -761, -447, -344, 80, 685, 759, 384, 344, 928, 1141, 1139, 1720, 2097, 1682, 1184, 1268, 1581, 1568, 1181, 1078, 1214, 672, -70, -129, -228, -728, -1012, -901, -751, -781, -387, 334, 317, -238, -169, 309, 183, 72, 689, 832, 609, 1085, 1233, 721, 707, 1412, 2101, 2395, 2291, 2325, 2520, 2407, 2358, 2526, 2426, 1875, 1515, 1487, 1396, 987, 240, -146, 248, 716, 683, 589, 665, 197, -814, -1285, -1177, -1019, -637, -170, -298, -347, 353, 1080, 1662, 2702, 3946, 4506, 4385, 3710, 2460, 1074, 668, 1098, 1256, 1325, 1558, 1666, 1471, 701, -360, -1020, -1156, -1054, -750, -204, 122, -202, -604, -332, -154, -598, -1078, -1125, -774, -754, -1111, -1093, -931, -1129, -1061, -747, -879, -1342, -1784, -2277, -3111, -3792, -3762, -3214, -2456, -1528, -648, -146, -112, -246, -9, 493, 875, 908, 767, 728, 845, 1267, 1993, 2380, 2085, 1386, 560, -143, -239, -219, -928, -1876, -2458, -2225, -1360, -777, -668, -438, 335, 797, 113, -422, 119, 565, 363, 96, -449, -1257, -1513, -1168, -707, -680, -1303, -1108, 129, 383, 122, 445, 234, -297, -1, 136, -409, -1087, -1564, -1617, -1936, -2480, -2426, -2509, -2805, -1786, -1006, -1891, -1784, -410, -196, -774, -576, 160, 282, -249, -440, -24, 95, -198, -177, -303, -1046, -1608, -1545, -1438, -1285, -709, -304, 19, 1110, 1420, 621, 414, 668, 1075, 1178, 868, 796, 339, -210, -498, -1076, -1605, -1534, -865, -625, -1081, -1308, -1605, -1928, -1664, -1223, -655, -191, -698, -1613, -1418, -653, -629, -1064, -1323, -1074, -809, -785, -715, -1025, -1485, -1255, -480, 178, 195, 60, 241, 290, 559, 1075, 1057, 781, 938, 1128, 942, 642, 582, 705, 961, 589, -558, -313, 870, 312, -1366, -2238, -2395, -2627, -2722, -2382, -2215, -2350, -1980, -1192, -825, -881, -935, -716, -154, -330, -1106, -982, -23, 1248, 1985, 2153, 2502, 2470, 2237, 2237, 1742, 1141, 969, 886, 768, 381, -410, -998, -1145, -1087, -1171, -2021, -2885, -2848, -3041, -3883, -4076, -3710, -3743, -3981, -4102, -4154, -4723, -5367, -4569, -3439, -3694, -3897, -2892, -2228, -2387, -2366, -2245, -1878, -814, -62, -317, -1067, -1206, -634, -162, 327, 762, 589, 16, 65, 424, -263, -1503, -1426, -478, -757, -1812, -2152, -1778, -1290, -1374, -1949, -1915, -1059, -438, -443, -585, -545, -746, -1132, -1232, -871, -281, -241, -920, -1809, -2468, -2380, -1730, -1095, -518, -528, -571, 483, 1552, 1447, 1177, 1582, 1755, 1413, 1147, 1335, 1767, 1784, 1857, 2540, 2783, 2331, 2129, 1952, 1476, 905, 598, 631, 704, 930, 1434, 1577, 1310, 1349, 1603, 1331, 510, 222, 875, 1324, 1348, 1572, 1405, 1455, 2784, 3698, 3292, 2986, 3031, 2666, 2464, 2658, 2343, 1604, 1906, 3047, 3583, 3892, 4266, 4084, 3591, 3057, 2376, 1633, 1078, 843, 1089, 1177, 747, 485, 360, 606, 1212, 1075, 164, -424, -413, -651, -1180, -1044, -515, -199, -139, -333, -329, 200, 332, -120, 170, 841, 744, 330, 92, -195, -91, 553, 868, 944, 1182, 1084, 1008, 1225, 963, 479, 370, -72, -502, -532, -1596, -3246, -3058, -1933, -2273, -3083, -3148, -3002, -2768, -2594, -2720, -2544, -1736, -918, -679, -959, -887, -42, 214, 266, 934, 911, 377, 906, 1542, 905, 313, 614, 1029, 1182, 916, 365, -21, 73, 394, 457, 590, 690, 972, 1259, 621, -182, 143, 782, 710, 500, 1, -912, -1596, -1643, -1307, -1074, -1186, -1448, -1413, -1261, -1421, -1395, -976, -471, -98, -62, -272, -131, 728, 1032, 384, 33, 188, 349, 268, 63, -24, 574, 1709, 2328, 2627, 2981, 3069, 3075, 3113, 2622, 1800, 1205, 864, 1337, 2102, 1762, 1311, 1826, 2254, 2049, 1666, 1045, 395, 212, 80, -364, -377, 97, 217, 182, 555, 1166, 983, 461, 925, 1663, 1760, 2034, 2873, 3245, 2940, 2669, 2509, 2291, 2203, 2224, 2101, 1618, 1021, 759, 547, 226, 127, 596, 1347, 1002, -554, -1276, -1014, -1365, -2340, -2670, -1814, -931, -840, -853, -649, -525, -186, -229, -620, -591, -605, -933, -859, -458, -191, 268, 848, 1208, 1527, 1508, 982, 809, 902, 732, 335, -419, -786, -592, -1266, -2438, -2420, -1828, -1973, -1977, -1928, -3068, -3771, -2608, -1920, -2331, -1984, -1395, -1766, -1921, -1239, -774, -398, 223, 849, 1314, 934, 209, 344, 530, -463, -1226, -390, 220, 257, 762, 319, -651, 170, 1456, 1177, 641, 624, 267, -134, -194, -203, -258, -103, -241, -726, -659, -641, -961, -892, -788, -595, -185, -21, -217, -237, -126, -663, -1412, -1367, -1013, -712, -120, 178, 67, 274, 659, 730, 411, -64, -284, -91, -40, -380, -188, 472, 696, 447, 518, 733, 395, -282, -892, -1132, -807, -662, -1007, -1009, -644, -565, -256, 249, 118, 97, 613, 548, -240, -651, -596, -289, 276, 637, 780, 729, 724, 927, 715, 347, 790, 1253, 1267, 1689, 1844, 952, 221, 156, 19, -156, -521, -1139, -971, -521, -580, -633, -842, -853, -307, -198, -863, -1414, -1544, -1671, -2075, -2644, -2375, -1456, -938, -411, 40, -184, -417, 265, 1135, 908, 327, -238, -1173, -1497, -1335, -1017, -495, -606, -597, 397, 590, -503, -818, -277, -611, -1284, -1355, -1728, -2277, -2335, -2581, -3129, -3055, -2667, -2822, -2722, -2573, -3246, -3207, -2432, -2282, -2165, -1905, -1655, -1182, -868, -589, -489, -743, -607, -599, -647, 39, 298, -279, -792, -847, -972, -1265, -871, -571, -841, -751, -790, -1732, -2522, -2113, -1589, -2107, -2691, -2832, -3236, -3338, -3193, -3711, -3612, -2737, -2831, -3202, -2378, -1578, -1653, -1441, -1005, -1020, -921, -810, -703, -250, 169, 310, 302, 386, 337, -434, -1130, -852, -371, -281, 13, 562, 516, 7, -626, -1308, -1295, -541, -465, -1064, -340, 1158, 1384, 992, 985, 1277, 1748, 1258, -320, -1306, -1516, -1589, -1550, -1415, -882, 58, 1204, 2138, 2278, 1592, 1076, 1253, 1132, 495, -137, 70, 1160, 1737, 1380, 999, 1398, 1914, 1694, 1500, 1879, 2156, 1857, 1555, 1877, 2401, 2683, 3027, 3537, 3784, 3638, 3590, 3221, 2190, 1242, 424, -144, -468, -517, 39, 0, -1129, -1472, -699, -688, -1465, -1714, -1858, -2388, -2169, -1203, -935, -1350, -1257, -425, 139, -151, -344, 117, 398, 48, -309, -179, 338, 1017, 1234, 765, 174, -668, -1640, -2127, -2120, -1937, -2174, -2890, -3014, -2373, -2415, -3468, -4010, -3252, -2556, -3095, -3845, -3690, -3670, -3830, -3179, -2852, -2921, -2162, -1283, -668, 16, 424, 680, 463, -626, -1011, -474, -785, -1492, -1278, -606, -748, -1454, -1758, -1225, -618, -834, -1166, -1228, -1527, -1789, -1703, -1739, -2092, -2149, -1789, -1658, -1609, -1334, -1841, -2295, -1260, -348, -499, -753, -352, -184, -641, -431, -272, -862, -1251, -1301, -1112, -600, 32, 309, 204, 11, -380, -666, -431, 45, 430, 889, 1357, 1416, 1359, 1783, 1616, 361, 143, 1348, 2182, 1795, 421, -2, 1011, 1368, 1097, 1297, 1297, 975, 1034, 1149, 505, -565, -152, 1560, 2017, 1470, 1820, 2707, 3180, 3337, 3237, 2639, 1600, 1397, 2152, 2213, 1912, 1761, 1179, 1034, 1746, 2194, 2162, 2354, 2547, 2993, 3998, 3831, 3425, 4403, 4894, 3900, 2873, 2488, 1948, 1384, 778, -320, -891, -493, -561, -772, 46, 681, 102, -220, 299, 23, -441, -395, -798, -783, 173, 1047, 1032, 968, 1475, 1483, 1049, 192, -976, -471, 971, 554, -746, -655, 132, 202, 141, 661, 914, 604, 1061, 1877, 1410, 190, -637, -1041, -1830, -2370, -1428, -497, -775, -1344, -1859, -2175, -2821, -3996, -4739, -4890, -4867, -4281, -2979, -2526, -2373, -1109, -413, -341, 85, -111, -711, -255, 222, -403, -828, -84, 976, 1052, 534, 618, 1325, 1371, 642, 291, 419, -193, -1295, -1758, -2592, -3837, -3715, -3102, -3802, -5168, -5814, -5483, -5028, -5227, -4720, -3492, -3461, -3981, -3680, -3189, -2959, -2773, -3011, -2701, -1421, -926, -1446, -1628, -868, -340, -1008, -1724, -1317, -267, -54, -399, -521, -425, 435, 1242, 315, -985, -349, 77, -779, -512, -9, -761, -1546, -1654, -1646, -2249, -2994, -3197, -3273, -3519, -3987, -4680, -4741, -3628, -3259, -3849, -3612, -3043, -2534, -1751, -2127, -3041, -2019, -348, -350, -977, -617, -16, 101, 493, 625, -171, -241, 623, 501, 334, 669, 495, 915, 1721, 1541, 1308, 1447, 1903, 2565, 2502, 1635, 1076, 835, 97, -899, -1460, -1335, -1220, -1212, -1022, -1005, -493, 229, 131, 101, 706, 1239, 1262, 1156, 1096, 686, 418, 779, 808, 60, -27, 784, 955, 1143, 1896, 1353, 51, -3, 273, -182, -296, 201, -364, -1158, -714, -539, -946, -729, 83, 864, 1413, 1403, 1611, 1890, 1176, 316, 62, 137, 192, -311, -698, -89, 327, 735, 1438, 1020, 256, 167, -36, -742, -1383, -1025, -346, -134, -18, -161, -516, -28, 644, 14, -394, 181, -33, -806, -1567, -3309, -4759, -4722, -4544, -4427, -3554, -2727, -2488, -2159, -1859, -1898, -2007, -1824, -1756, -2549, -2774, -1674, -1267, -1305, -853, -447, -417, -967, -1218, -842, -1466, -2066, -581, 532, 57, 33, 900, 1649, 1302, 293, 482, 977, 252, -189, -56, -526, -1584, -2244, -2315, -2689, -3422, -3823, -3459, -3277, -3686, -3776, -3597, -3357, -3490, -4143, -4603, -3926, -2437, -1673, -1684, -1173, -440, -659, -693, -103, -523, -1795, -2275, -1727, -1543, -1633, -1529, -1689, -1394, -742, -1117, -1794, -1515, -1271, -1447, -1474, -1259, -541, 213, -61, -1545, -2295, -1234, -583, -1381, -1308, -518, -1315, -2207, -1735, -1742, -2513, -2027, -991, -990, -1510, -1568, -883, -465, -723, -830, -732, -1029, -1150, -1335, -2019, -2090, -1653, -1217, -818, -914, -1763, -2390, -1049, 392, -39, -776, -718, -400, -48, 351, -221, -664, 622, 1504, 1014, 773, 1104, 1433, 1771, 1901, 975, -587, -815, -376, -994, -1788, -2018, -1622, -765, -890, -2327, -2730, -1996, -2192, -2992, -3168, -2414, -1289, -788, -1100, -1225, -646, -157, -533, -1348, -1066, -332, -751, -935, 5285, 5350, 4537, 3644, 3654, 3779, 3009, 1750, 1061, 774, -344, -1786, -2146, -1516, -657, -239, -600, -1040, -761, -878, -1144, -441, -701, -1439, 423, 2962, 3377, 3213, 4111, 5403, 5692, 4839, 3943, 3222, 2708, 3350, 4314, 4177, 3889, 3440, 2763, 4003, 5275, 3867, 2523, 2299, 1387, 426, 542, 263, -855, -1445, -1693, -1973, -2047, -1719, -1220, -1486, -1803, -1242, -1071, -1237, -912, -705, -232, 233, 413, 356, -190, 751, 2913, 3656, 3968, 4830, 4655, 4326, 5111, 5314, 4285, 3563, 3699, 3395, 2657, 2578, 2764, 3125, 3974, 4328, 3731, 3340, 3188, 2728, 2662, 2032, -336, -1803, -301, 786, -273, -1555, -2540, -2821, -2069, -1285, -788, -256, 9, 354, 426, -1243, -2602, -1458, 219, 824, 403, -195, -79, 331, 841, 1358, 1414, 1586, 2029, 1890, 1347, 824, 372, 412, 703, 781, 921, 1891, 3466, 4234, 3952, 3510, 2982, 2550, 2123, 1334, 739, 219, -427, -873, -1281, -468, 1473, 2060, 1389, 869, 180, -489, -413, -623, -1582, -2185, -2249, -1777, -776, -191, -250, 36, 1545, 3927, 5088, 4587, 3840, 3265, 3353, 4613, 5962, 5736, 4506, 4368, 4460, 3326, 2720, 2969, 2651, 3103, 5140, 6347, 6134, 5930, 6055, 6835, 8270, 9338, 9578, 9249, 8383, 7491, 6643, 5758, 6225, 7379, 6964, 5930, 5683, 6415, 8446, 10004, 10194, 9967, 9778, 10577, 11452, 9975, 7955, 7318, 6609, 5919, 4994, 2975, 2901, 4614, 3805, 1713, 945, 950, 875, 726, 283, -650, -1201, -1013, -1489, -3298, -3762, -1781, -942, -1958, -1990, -1359, -2105, -3398, -3650, -3351, -3150, -2861, -2709, -2493, -1750, -1224, -1101, -969, -1630, -2302, -995, 642, 746, 403, 24, -529, -953, -1103, -1033, -1302, -1735, -1667, -1177, -1004, -2023, -2648, -1620, -1657, -3222, -4205, -4354, -3783, -2726, -2319, -2416, -2076, -1719, -1817, -1627, -1299, -1477, -1975, -2844, -2323, -43, 177, -1417, -1620, -884, -619, -563, -348, -298, -600, -796, -651, -757, -1042, -1147, -1581, -2378, -2969, -3376, -2822, -1779, -2531, -4288, -4688, -4383, -4657, -5006, -5056, -5089, -4862, -4305, -3950, -4016, -4031, -3383, -3485, -5083, -5178, -3866, -4117, -4866, -4373, -3761, -4387, -4973, -4434, -4213, -4552, -4531, -4026, -3170, -2619, -2638, -2351, -2493, -4044, -5272, -4712, -4214, -5048, -5572, -5652, -5982, -5712, -5121, -4778, -4368, -4243, -4359, -4024, -2729, -1562, -2511, -3752, -1626, 933, 218, -1397, -1810, -2202, -2642, -2250, -1977, -2190, -2026, -1580, -1272, -1065, -1218, -2725, -4650, -3890, -2119, -2740, -3865, -3738, -3539, -3326, -2430, -1473, -718, 81, 429, -145, -1158, -1970, -2187, -2129, -2311, -2001, -1015, -772, 26, 2652, 3467, 1595, 497, 463, -183, -1283, -2348, -2521, -1773, -1783, -2125, -1610, -1207, -1105, -965, -1445, -2245, -2458, -1763, -1457, -2241, -2930, -2871, -1810, -196, -128, -816, 101, 907, 513, -399, -1832, -1629, 629, 1597, 493, -613, -1025, -568, 800, 1087, -61, -316, -182, -599, -153, -139, -1439, -987, 724, 710, -336, -1359, -2155, -2554, -2817, -2866, -3066, -3366, -3103, -2876, -3040, -3005, -2336, -1601, -2413, -3708, -2807, -1393, -1594, -2179, -2524, -3262, -4084, -4034, -3311, -3079, -3556, -3646, -2655, -1497, -1713, -3208, -3345, -1651, -1643, -3649, -4585, -4178, -3223, -2055, -1808, -2579, -3095, -2671, -2002, -2040, -2458, -2635, -2801, -2982, -2741, -1605, -700, -907, -797, -469, -884, -957, -129, 436, 201, -568, -1144, -1595, -2728, -3120, -1065, 822, 1058, 1295, 1080, 10, -817, -1128, -1386, -1665, -2379, -3139, -2950, -2163, -1683, -2190, -2119, -527, 741, 769, -392, -1468, -1420, -797, -53, 373, 168, -664, -1075, -260, 343, -943, -1779, 325, 1842, 941, 416, 997, 1470, 1445, 1153, 989, 467, -422, -524, 177, 168, -1871, -3951, -3235, -2278, -3218, -4323, -4870, -4907, -4616, -4180, -3647, -3087, -3263, -4265, -3501, -1411, -1321, -2060, -1512, -629, -689, -1339, -1286, -251, -172, -1858, -2501, -624, 763, 477, 241, 114, -381, -748, -974, -2147, -3551, -2493, -395, -413, -1048, -1504, -2644, -3441, -3179, -2611, -2431, -2295, -2653, -3578, -2976, -1756, -2421, -3633, -3956, -3975, -4071, -3993, -3701, -3638, -3300, -2030, -1566, -1955, -1813, -1516, -1309, -1620, -2314, -1543, -25, -224, -647, 108, 665, 76, -846, -1375, -1780, -2004, -2177, -2455, -2470, -2556, -1874, -278, -139, -1140, -1238, -656, -558, -854, -1353, -2410, -3334, -4030, -4005, -2760, -2622, -3637, -3796, -3096, -2686, -2705, -2034, -1361, -2265, -3044, -1686, -563, -1037, -1115, -633, -1045, -1737, -2087, -3636, -4821, -2907, -1024, -1059, -854, -713, -1396, -2225, -2524, -2708, -3444, -3185, -1660, -1556, -2582, -2828, -2669, -2598, -2714, -3047, -3139, -3557, -5018, -5890, -4431, -2734, -2991, -4114, -4377, -3713, -3489, -3792, -3523, -3084, -4000, -4307, -2158, -1257, -2711, -3223, -2721, -2956, -3124, -2345, -1479, -1192, -1979, -3368, -3533, -3161, -3976, -5075, -5868, -6019, -5402, -5004, -5011, -4998, -5249, -6259, -6003, -3988, -3072, -2929, -2018, -996, -899, -1359, -1410, -1287, -1230, -693, -515, -742, 419, 1951, 1861, 512, -586, -832, -1158, -1728, -2123, -2910, -3196, -1441, 146, 42, -480, -923, -1306, -1875, -2865, -3627, -3559, -3442, -4318, -4518, -2777, -1690, -1688, -1124, -649, -600, -595, -969, -1212, -1113, -2445, -4640, -4072, -1885, -1425, -1717, -1862, -2105, -1913, -1759, -1889, -1504, -1599, -3203, -3613, -2331, -2746, -4073, -4135, -3624, -3675, -4335, -4802, -4447, -3882, -4438, -5633, -4870, -2422, -1526, -1925, -1932, -1738, -1319, -748, -175, 127, -8, -905, -2675, -3159, -2067, -2216, -2976, -2574, -1874, -1769, -1583, -875, -304, -468, -1910, -3030, -2102, -1527, -2699, -3822, -4249, -4108, -3148, -2353, -2311, -1910, -1001, -820, -1407, -761, 735, 640, 303, 763, 566, -380, -576, 531, 1302, 715, -238, 348, 2116, 2336, 1169, 114, -749, -1245, -1432, -2375, -4422, -5357, -3671, -2040, -2315, -3110, -3024, -2625, -2642, -2606, -2345, -2083, -1885, -1919, -2813, -3269, -1702, -1020, -2403, -2547, -1487, -1710, -2173, -1318, 87, 828, -105, -630, 1368, 2521, 1376, 257, -496, -1022, -1143, -1370, -1606, -2411, -3776, -2909, -602, -1051, -3158, -3788, -3475, -3861, -4470, -4727, -5636, -6185, -4656, -3449, -4080, -4358, -3482, -2650, -2357, -2136, -1164, -458, -1834, -2545, -349, 1381, 1430, 1723, 2081, 2150, 2497, 2628, 1557, 548, 632, 382, 24, 714, 1289, 848, 643, 1148, 1026, 419, -592, -2889, -3960, -1957, -590, -1298, -1766, -1343, -624, -479, -1139, -1652, -1788, -1883, -428, 2223, 2730, 1610, 1501, 1872, 1967, 2335, 2929, 3594, 3598, 2751, 2468, 1913, 267, 38, 1127, 867, 52, 337, 1052, 1224, 420, -889, -1396, -1668, -2843, -2976, -1541, -1200, -1751, -1446, -909, -1331, -1776, -1229, -825, -1008, -1563, -2750, -2406, 102, 1160, 261, -108, 625, 1217, 1103, 811, 886, 1671, 2171, 1823, 2503, 3685, 3586, 3190, 2704, 1329, -465, -1357, -1150, -1098, -1319, -1867, -1836, 114, 555, -1415, -2442, -2249, -2222, -2369, -2123, -2412, -3268, -2195, -181, -350, -816, 731, 2663, 2877, 2075, 1866, 2633, 3497, 2850, 1927, 3253, 4604, 3786, 2455, 1701, 1426, 1289, 1331, 1627, 634, -1697, -1579, 156, -732, -2184, -1875, -1115, -213, 1044, 1885, 1666, 997, -163, -1831, -1810, -324, -477, -1193, -375, 580, 1003, 1528, 2422, 3386, 2753, 1041, 1714, 3731, 3620, 2186, 1086, 568, 709, 1227, 2039, 2428, 1933, 1963, 1629, -91, -451, 433, -6, -716, -932, -1587, -2607, -2997, -1835, 236, 640, -528, 686, 2991, 2524, 811, -155, -226, 548, 736, -702, -827, 1070, 1597, 1235, 1829, 2403, 2697, 3368, 4087, 4477, 4676, 4708, 3777, 2202, 2632, 4198, 3018, 466, -340, 22, 166, -357, -744, -622, -1541, -2625, -1642, -485, -942, -1299, -695, -352, -194, 470, 320, -382, -239, -485, -1091, -161, 959, 530, 189, 455, 166, -480, -1049, -1656, -2398, -1876, 413, 1482, 1271, 2171, 3009, 2850, 2748, 2534, 2363, 2947, 3127, 2077, 551, -339, 780, 2518, 2284, 1102, 567, 657, 1310, 1900, 1444, 750, 1114, 1392, -48, -1478, -122, 2237, 2524, 2180, 3024, 3889, 3657, 3165, 2777, 2015, 1085, 773, 1366, 1474, 1070, 2091, 2732, 1629, 955, 704, 214, 489, 2172, 3590, 3254, 2390, 2939, 4493, 4763, 3476, 2466, 2801, 3796, 3980, 3008, 2481, 2820, 1819, -23, 639, 2598, 2600, 1130, -279, -1004, -1511, -2111, -1847, -1214, -1529, -1398, -340, -176, -371, -373, -490, -62, 597, 1471, 2656, 3260, 3163, 2462, 1029, 691, 1723, 1848, 1864, 2652, 3044, 3485, 3752, 2756, 1905, 2306, 1963, -71, -1209, 584, 2591, 2251, 1269, 1275, 1448, 804, -38, -1109, -2564, -2088, 332, 919, -317, -239, 749, 933, 1150, 1447, 1311, 1148, 1040, 1253, 1194, 84, -69, 1486, 2200, 1710, 1245, 848, 586, 788, 928, 596, -509, -2353, -2619, -405, 434, -748, -662, 296, 417, 273, 400, 537, 943, 1486, 908, -870, -1159, 458, 985, 282, 5, 376, 880, 1157, 1604, 1570, 378, 324, 2687, 3890, 2579, 1760, 1850, 1898, 1779, 1460, 1339, 1635, 2337, 2765, 1570, 488, 2021, 3117, 1493, 10, -10, 185, 97, 8, 484, 1285, 1975, 2344, 1688, 1057, 2870, 4544, 3612, 2908, 2731, 1461, 811, 1532, 2132, 2553, 3027, 2804, 2085, 2709, 3450, 2470, 1669, 2147, 2877, 2998, 2754, 2465, 1638, 873, 1151, 673, -369, 804, 2004, 1227, 498, 413, 768, 1627, 2173, 2277, 2252, 1604, 232, -1418, -3294, -3677, -1873, -549, -244, -127, 183, 1096, 2101, 2759, 3295, 3683, 3564, 2468, 1977, 3267, 3755, 3065, 2878, 2395, 1788, 1853, 2154, 2578, 2731, 3117, 3992, 3552, 2156, 2404, 2666, 1114, 473, 1198, 1411, 1269, 1183, 434, -739, -558, 641, 707, 344, 852, 1523, 2033, 1775, 1031, 1640, 2312, 1359, 1036, 1599, 729, 595, 3079, 4468, 3663, 3170, 3385, 3238, 2783, 2610, 2697, 3412, 4632, 4742, 3361, 2754, 3840, 4375, 3864, 3417, 2967, 2770, 2752, 2135, 1661, 1949, 1042, 78, 2208, 3920, 2582, 1722, 2316, 2508, 2137, 2246, 2749, 3116, 2934, 1622, 993, 2929, 4260, 3427, 2444, 1194, 227, 354, 25, -897, -1268, -1463, -1775, -2136, -2680, -2046, 130, 1238, 942, 814, 842, 453, 209, 692, 789, -20, -1319, -2487, -1852, -743, -1490, -2591, -3001, -2742, -1770, -1365, -1279, -203, 51, -1301, -1181, 818, 1897, 1868, 1325, 732, 850, 1371, 1672, 1876, 2406, 2210, 2041, 3582, 4197, 3080, 2494, 2075, 1771, 2003, 1481, -25, -1192, -1287, -652, -1092, -2385, -657, 2511, 2622, 1988, 2824, 3277, 2837, 2691, 2683, 1874, 827, 925, 1925, 1971, 232, -165, 2355, 3398, 2267, 1665, 1182, 1113, 1797, 2107, 1783, 499, -558, 1013, 2641, 1571, 6, -485, -363, -345, -944, -1776, -1755, -1052, -1120, -2655, -3820, -2592, -979, -1202, -2045, -2325, -1890, -1150, -830, -704, -320, 411, 467, -154, 1147, 2902, 2547, 2421, 2925, 2254, 1505, 1234, 961, 1299, 1643, 812, 910, 3152, 3634, 1680, 409, -245, -841, -454, -31, -623, -289, 809, 100, -251, 1377, 1744, 702, 761, 1474, 1554, 1160, 928, 1520, 1818, 287, -394, 1692, 2839, 2084, 1858, 2306, 2421, 1721, 1475, 2212, 2148, 1290, 1629, 2251, 1621, 1980, 3925, 4094, 2774, 2588, 3059, 2996, 2863, 3143, 2719, 1253, 1346, 3441, 3932, 2254, 554, -311, -877, -1419, -1291, -740, -355, -126, -61, 460, 1178, 1417, 2276, 3095, 2870, 2844, 2771, 2501, 2897, 3204, 3186, 3247, 2684, 2149, 2410, 1490, -317, 240, 1612, 943, -14, -269, -404, -43, 529, 573, 360, 287, 71, -984, -3320, -4643, -3294, -2338, -3108, -3815, -3439, -2561, -2175, -1981, -1575, -1568, -1870, -1818, -1669, -1130, 931, 3002, 3242, 2940, 2881, 2644, 2569, 2772, 2678, 2553, 2736, 1921, 137, 392, 2345, 2628, 1754, 1813, 2136, 1819, 1656, 1708, 405, -918, 226, 1443, 616, -159, -120, -113, -470, -1078, -1519, -1016, 97, -475, -2223, -1156, 1494, 2049, 1784, 1888, 1519, 1213, 1577, 1913, 1663, 851, -77, 96, 1139, 753, -245, 563, 1585, 1555, 1505, 1635, 1558, 1208, 977, 812, 29, -531, -480, -1452, -2053, -178, 1288, 704, 947, 2469, 2574, 1945, 2278, 2380, 1925, 1442, 310, -1094, -345, 1840, 2366, 1636, 1174, 1539, 2516, 2862, 2297, 1216, 108, 734, 2460, 2637, 2199, 2431, 2896, 3311, 3121, 2302, 2146, 2396, 1676, 371, -549, -1895, -3236, -2230, -882, -1647, -2718, -2649, -2277, -2843, -3556, -3575, -3576, -3727, -4734, -6753, -6577, -3959, -3074, -3672, -3674, -3426, -3257, -2787, -2242, -2320, -2557, -2511, -2467, -2354, -1748, -1115, -984, -571, -258, -775, -1355, -1526, -1814, -1956, -1814, -1889, -1792, -1461, -2286, -4489, -4995, -3299, -2671, -3194, -3210, -3202, -3641, -3385, -2201, -1562, -1947, -2282, -2066, -1603, -1650, -3085, -4106, -2513, -1204, -2450, -3261, -2619, -2286, -1986, -1190, -707, -594, -655, -163, 933, 491, -840, 323, 2363, 2256, 1510, 1116, 1005, 1303, 1366, 1272, 1838, 2420, 2179, 2028, 1813, 203, -1379, -607, 745, 274, -877, -1593, -1694, -412, 839, 448, 215, 967, 1396, 1196, 434, -1173, -2404, -807, 1395, 467, -1274, -500, 1297, 1505, 875, 864, 914, 731, 284, -258, -435, -1120, -2163, -1699, -219, -591, -2800, -4036, -3870, -4207, -4825, -4656, -4852, -5382, -4799, -3486, -2907, -3821, -4038, -2069, -615, -762, -817, -233, -8, -509, -995, -1221, -729, 320, 69, -1196, -320, 1620, 1152, -240, -600, -718, -355, 523, 412, -450, -1064, -1233, -978, -1128, -2488, -4195, -4099, -1969, -1439, -3001, -3368, -2633, -2238, -2009, -2304, -3034, -3188, -2776, -2430, -3068, -4576, -4597, -2549, -1706, -2491, -2352, -1778, -1688, -1129, -877, -1470, -1647, -1405, -1163, -1450, -3297, -4287, -2117, -439, -1209, -2113, -2215, -2120, -2319, -2727, -3016, -3364, -4547, -5241, -3845, -3059, -3888, -4066, -3342, -2866, -3403, -4186, -4454, -4378, -4371, -4376, -4318, -5129, -6695, -6066, -3186, -2113, -3216, -3572, -2831, -2584, -2867, -2157, -560, -285, -1348, -928, 1162, 2349, 2532, 2071, 1187, 1106, 1359, 1169, 636, 252, 556, 601, -339, -412, 991, 1305, 651, 563, -127, -1364, -1446, -1357, -1673, -1135, -265, -26, -317, 180, 1811, 1807, 281, -34, 302, -454, -1026, 429, 2121, 1324, -293, 1169, 3213, 2785, 1965, 1252, 452, 334, 237, -241, -257, -50, 178, 636, 579, -924, -2522, -2444, -2745, -4441, -5518, -5569, -5682, -5603, -4094, -2278, -2051, -2418, -2034, -1807, -2648, -2551, -899, -256, -436, 92, 583, 106, -148, 696, 1567, 1767, 1006, -604, -233, 2260, 2398, 207, -535, 116, -43, -490, -550, -1333, -2209, -1863, -2047, -3848, -4424, -2962, -2168, -2630, -3560, -4073, -3962, -3596, -3245, -3385, -3921, -4650, -5637, -4801, -1983, -1079, -1997, -2014, -1761, -2205, -2713, -3254, -3225, -1917, -983, -1574, -3376, -5354, -4369, -1175, -700, -2347, -2695, -2081, -2128, -2423, -2213, -1766, -1778, -2465, -3300, -2842, -1639, -1744, -2607, -2986, -2524, -1489, -1067, -1388, -1808, -2200, -2512, -2354, -2782, -4763, -4978, -2487, -1431, -1892, -1474, -1178, -1349, -1107, -517, -108, 276, 1194, 1745, 816, 407, 1569, 1889, 1384, 1622, 2160, 2070, 1631, 1560, 1868, 1723, 1203, 775, -34, -247, 1180, 1199, -602, -1127, -396, 100, 22, 188, 1508, 2699, 1924, 1281, 2603, 3300, 2390, 1764, 1788, 1726, 1657, 1769, 2003, 2702, 3570, 3714, 3114, 2373, 2043, 1530, -391, -1196, 972, 2480, 1909, 1130, 1080, 1601, 1244, -395, -1827, -2633, -3147, -3626, -4318, -3512, -1122, 270, 525, 829, 1400, 1447, 1013, 990, 1348, 1616, 1535, 1764, 2217, 1705, 1295, 2795, 4243, 4058, 3820, 3751, 2990, 2351, 2150, 1760, 1465, 513, -891, -187, 1056, 89, -1399, -1909, -1808, -2041, -2848, -2874, -2342, -2140, -1798, -2018, -3241, -3282, -1210, -75, -679, -1058, -1337, -1707, -1136, -468, -737, -915, -305, 687, 759, -519, -592, 1291, 1627, 33, -808, -868, -1072, -1103, -892, -915, -1829, -3587, -3958, -2129, -1458, -2396, -2917, -3151, -3215, -3345, -3851, -3869, -3616, -4654, -4935, -2823, -1959, -2643, -2121, -1004, -688, -679, -292, -225, -968, -1627, -1341, -1192, -2433, -2691, -628, 165, -1091, -1633, -1274, -1423, -2106, -2181, -1160, -294, -810, -1329, -375, 203, -348, 828, 2532, 1966, 924, 952, 1407, 1337, 1177, 1813, 2545, 2319, 1636, 1501, 1681, 1190, -712, -2380, -1236, 476, 211, -167, 275, 801, 2336, 4610, 5400, 4543, 3888, 3747, 3428, 2811, 2049, 1008, 330, 1584, 2876, 2312, 2096, 2771, 2980, 2773, 2747, 3030, 2707, 1770, 1454, 1515, 238, -1710, -757, 1665, 1306, -437, -1028, -810, -797, -1391, -2121, -2403, -1984, -977, -314, 223, 1296, 1366, 1182, 2795, 3564, 2452, 1931, 2360, 2748, 2352, 1607, 1774, 2610, 3216, 3453, 2914, 1282, -58, 685, 1491, 288, -984, -1452, -1318, -580, -529, -805, -401, -265, -286, -755, -2074, -1590, 191, 229, -599, -483, 327, 687, 180, -329, 493, 1196, -13, -372, 1773, 2738, 1558, 647, 280, 117, 218, 347, 710, 772, 68, -315, -549, -1741, -3710, -3743, -1614, -995, -1892, -2411, -2729, -2681, -2192, -1981, -2336, -2891, -3519, -3857, -2856, -1506, -1400, -2259, -2456, -731, 221, -1274, -1970, -538, 499, -1354, -2569, 113, 1604, 623, 526, -1, -1749, -2291, -2061, -2662, -2722, -1836, -1487, -799, 836, 1406, 397, -345, 807, 2675, 2804, 1742, 1374, 1960, 2901, 3019, 2304, 1918, 2131, 2971, 2849, 904, 427, 2726, 4343, 3964, 3145, 2689, 2183, 1977, 2544, 2336, 1295, 1092, 1560, 2177, 2628, 2780, 3075, 3440, 3430, 2716, 2213, 2322, 2138, 1671, 1919, 2557, 2285, 1695, 2189, 3120, 2734, 1201, 819, 2762, 4835, 4038, 1573, 817, 1525, 1569, 650, 75, -461, -1399, -1514, -1160, -1930, -2719, -1433, 1381, 2713, 2449, 2865, 3939, 4966, 4882, 3298, 1969, 1986, 2919, 3780, 3867, 3499, 2808, 1708, 1931, 4250, 5717, 4080, 1633, 1324, 2125, 1834, 1257, 1545, 1310, -336, -1721, -1403, -1836, -3779, -3348, -1543, -1722, -2376, -1882, -1580, -2828, -3622, -2049, -531, -866, -1912, -1187, 889, 228, -1805, -51, 2361, 1451, 1790, 4117, 4205, 3308, 4030, 4643, 4126, 4393, 4354, 2890, 2038, 2851, 3576, 2875, 2354, 1988, 583, -1113, -1616, -1427, -1378, -1239, -1195, -1117, -1214, -2177, -2091, -1069, -2160, -3207, -2281, -1876, -2428, -2840, -2392, -1764, -1055, 365, 477, -146, 1797, 4090, 3742, 2722, 1340, 1, 77, -560, -2130, -3026, -3336, -2745, -2284, -4099, -5295, -2659, -17, 55, -273, -464, -949, -748, 455, -226, -2177, -1416, 51, -1128, -2782, -943, 2245, 1696, -531, -674, -261, -554, -396, 49, 232, 113, -731, -434, 681, -1022, -3009, -852, 1431, 783, 190, -717, -2258, -1877, -548, -105, -74, -349, 109, 2205, 3796, 1975, 816, 4183, 6144, 4848, 4216, 4180, 4231, 4942, 5005, 4155, 3953, 4359, 4053, 2951, 1671, 156, -971, -731, 752, 1179, 436, 1140, 2051, 1982, 2752, 3829, 4349, 5467, 5696, 4724, 5402, 6217, 5309, 5172, 5899, 4166, 2464, 4631, 5900, 4043, 3493, 3727, 2120, 1374, 3216, 4093, 2995, 2892, 3095, 1304, 125, 145, -1254, -1495, 1729, 3549, 1963, 1546, 3635, 4925, 3700, 2801, 3765, 3787, 3107, 3355, 3895, 5227, 5399, 3323, 4037, 6870, 6376, 4374, 3276, 1792, 133, 32, 1565, 2359, 1618, 234, -14, 1257, 1826, 943, -1201, -2599, -1707, -1711, -3129, -3415, -3320, -3634, -3341, -2117, -875, -323, -704, -702, 704, 1861, 1910, 1117, 323, 1410, 3752, 4270, 2246, 793, 1850, 3015, 2957, 3114, 3776, 3606, 2669, 2837, 3765, 2630, -814, -1773, -242, 142, -30, 181, 1118, 2146, 1206, -92, 733, 1637, 458, -1877, -2791, -1920, -1345, -1290, -1730, -3646, -4220, -1597, -551, -2426, -2692, -942, -184, -228, 926, 1537, 457, 324, 2017, 2797, 1865, 1220, -107, -1848, -1143, -1, -1584, -3224, -2481, -2442, -3339, -2196, -1067, -1719, -2013, -1711, -2161, -2176, -1474, -2541, -4525, -2788, 641, 566, -130, 332, -215, -335, 409, -220, -1064, -297, -61, -1088, -982, -1004, -2304, -1429, 352, 259, -566, -1667, -2463, -2758, -3039, -3058, -2749, -2883, -3438, -3197, -2250, -2465, -3449, -3881, -4870, -4985, -2544, -1394, -868, 1398, 2542, 2785, 3630, 4085, 4179, 4912, 5474, 4602, 3191, 2059, 2140, 2902, 1946, 1340, 2986, 3977, 3302, 1430, -225, 191, 428, -892, -935, 324, 731, 791, 134, -780, 85, 284, -1999, -1900, 1812, 3684, 3013, 2779, 2830, 2920, 3798, 4615, 4060, 2825, 2893, 3766, 677, 146, -1534, -2163, -1144, -1090, -2032, -2136, -1300, -701, -1016, -927, 89, 891, 1308, 1226, 249, -1041, -1942, -2363, -2091, -1683, -1694, -958, 680, 1301, 838, 549, 1220, 2952, 4260, 4000, 3196, 2242, 1061, 1146, 1842, 1136, 0, -66, 175, -312, -1059, -1459, -1337, -509, -63, -1055, -1891, -1648, -1651, -1671, -1609, -2050, -2126, -1520, -1338, -2131, -2631, -2226, -2162, -2072, -1680, -1884, -1827, -1439, -1086, -357, -317, -932, -646, 347, 1304, 1982, 1488, 594, 716, 222, -1763, -2944, -2259, -1605, -1833, -2107, -2311, -2055, -1283, -622, -37, 866, 1816, 2487, 2825, 2333, 1478, 1092, 645, 693, 1321, 915, -286, -645, -319, -863, -2347, -3107, -2821, -3090, -3946, -4086, -3869, -4491, -4540, -3446, -3011, -2845, -1957, -1028, -530, -672, -1197, -1467, -1336, -1257, -2015, -3276, -3802, -3269, -2991, -3757, -4114, -2962, -1315, -101, 407, 148, 117, 759, 1244, 1323, 893, -145, -795, -445, -300, -1249, -1911, -1326, -565, -316, -368, -282, -8, -639, -2136, -3331, -4065, -3961, -2989, -2105, -1300, -264, 73, 269, 1034, 728, -756, -1539, -1218, -839, -1203, -2481, -3183, -2329, -1900, -2571, -2397, -1101, 353, 1156, 952, 999, 1632, 1876, 1792, 1800, 1495, 1216, 1847, 2632, 1876, 648, 616, 813, 1027, 1196, 481, -623, -572, 432, 731, 534, 937, 1950, 2953, 3593, 3661, 2750, 1829, 1773, 1740, 1094, 152, -436, -535, -928, -1906, -3001, -3691, -3491, -3328, -4270, -5816, -6350, -5166, -4116, -4470, -4917, -4403, -3447, -3003, -3415, -3860, -3796, -3640, -3404, -3102, -3198, -3059, -2121, -1468, -1444, -1276, -1053, -902, -523, -216, -540, -1354, -1323, -444, -267, -993, -1600, -2017, -2067, -1505, -1861, -2796, -2116, -793, -532, -740, -819, -918, -965, -1223, -1892, -2241, -1922, -1191, -688, -745, -832, -431, 388, 1350, 1503, 644, 448, 1496, 2217, 1389, 114, -429, -614, -894, -1190, -1475, -1979, -2508, -2667, -2772, -3218, -3648, -3596, -3438, -3708, -4022, -3355, -2220, -1662, -1280, -1454, -2409, -2564, -1333, -89, 150, 3, 211, 655, 1365, 1774, 732, -334, 377, 1118, 743, -105, -1200, -1180, -193, -256, -1219, -2000, -2047, -1785, -2094, -2557, -2590, -2088, -1341, -1084, -1307, -1698, -2164, -2349, -2881, -4066, -4571, -4098, -3604, -3524, -3519, -3374, -3088, -2135, -1236, -1392, -1449, -364, 876, 1018, 510, 234, 289, 523, 377, -154, -109, -251, -637, -140, -167, -1206, -1356, 44, 1679, 2051, 1503, 1157, 1257, 1033, 1, -952, -1138, -797, -435, -155, -154, -661, -634, 558, 1853, 2047, 1307, 1076, 1853, 2254, 1689, 1131, 1357, 2155, 2547, 2227, 1884, 1491, 1075, 1102, 662, -798, -1716, -964, 90, -189, -749, -227, 514, 1119, 1450, 599, -324, -40, 605, 417, -717, -1451, -1128, -474, 446, 1502, 1641, 830, 1157, 2596, 2248, 558, 458, 1461, 1775, 1413, 806, 739, 1743, 2379, 1293, 274, 839, 1113, 453, 425, 1079, 1820, 2041, 1550, 1127, 627, 74, 160, -19, -1251, -2145, -2087, -1773, -1358, -1313, -2037, -2292, -985, 535, 1132, 973, -140, -1087, -732, -390, -649, -788, -717, -522, -325, -475, -745, -96, 1135, 1102, 323, 281, 76, -662, -717, -548, -654, -451, 203, 672, 293, -710, -1138, -285, 516, -53, -1130, -1832, -1835, -471, 731, 123, -381, 518, 1153, 923, 994, 1522, 2141, 3024, 3221, 1766, 75, -556, 116, 1523, 1484, 217, 263, 1523, 2268, 2302, 2364, 2791, 3621, 4203, 3711, 3079, 3396, 3993, 4221, 3878, 3022, 2282, 2269, 2457, 2151, 1307, 332, 601, 2280, 3143, 2443, 1717, 1965, 2423, 2331, 2011, 1725, 1810, 2681, 3332, 3096, 2835, 2631, 2687, 3222, 3129, 2066, 1530, 2315, 3067, 2721, 2325, 2269, 1553, 508, -179, -849, -1269, -1292, -1161, -671, -338, -373, -152, 275, 425, -93, -559, 121, 1550, 2413, 2431, 2403, 2419, 1695, 445, 290, 1032, 1393, 1607, 1828, 2156, 2791, 3342, 3647, 3510, 2766, 2130, 1688, 1171, 1172, 1080, -6, -695, -28, 691, 1084, 1616, 2280, 2747, 2990, 2624, 1821, 1984, 2425, 2062, 1812, 1789, 1473, 1587, 2108, 2251, 2029, 2093, 2842, 3516, 3506, 3055, 2757, 2760, 2739, 2971, 3455, 3821, 4258, 4468, 4037, 3345, 2665, 2140, 2160, 2309, 2106, 2251, 3194, 3780, 3550, 3437, 2961, 2474, 3208, 3898, 3477, 2321, 1260, 1401, 2118, 1725, 248, -724, -190, 1039, 1720, 1660, 1487, 1511, 1566, 1675, 1499, 766, 524, 1132, 1477, 1217, 1134, 1540, 1962, 2120, 2248, 2196, 1986, 2203, 2556, 2263, 1296, 349, 249, 961, 1533, 1495, 1597, 1906, 2069, 2837, 3338, 3032, 2978, 2568, 1655, 982, 971, 1540, 1772, 1814, 1447, 206, -286, 649, 1306, 550, -549, 116, 1952, 2388, 1245, 420, 727, 1683, 2473, 1943, 732, 781, 1655, 1550, 669, 177, -60, -338, -526, -589, -405, -258, -168, 332, 596, 131, 235, 1215, 1694, 1336, 1477, 2692, 4142, 5195, 5073, 4120, 3747, 4075, 4177, 3849, 3952, 4582, 4810, 4764, 4513, 3497, 2776, 3090, 3374, 3015, 2630, 2519, 2612, 2841, 2902, 2609, 2240, 2089, 1849, 1232, 712, 646, 711, 968, 1606, 1816, 628, -533, -117, 870, 1117, 658, 552, 988, 1281, 845, 15, -138, 219, 706, 846, 122, -545, -434, 312, 1024, 1273, 1253, 1390, 1727, 1520, 378, -352, 36, -181, -1135, -1631, -1790, -1767, -1241, -695, -826, -956, -595, 155, 795, 776, 649, 761, 1216, 1892, 2297, 1993, 1331, 1604, 2250, 1304, -266, -657, -135, 500, 474, -659, -1900, -1551, -163, 188, -85, 295, 757, 969, 1165, 1299, 1093, 935, 1705, 2300, 1831, 1468, 1798, 2772, 3609, 3606, 3733, 4413, 5461, 6052, 5032, 3154, 2469, 2861, 2521, 1482, 550, -733, -1638, -1524, -1801, -2542, -2560, -1975, -1604, -1577, -1663, -1951, -2083, -1677, -1794, -2321, -1800, -467, 341, 333, 232, 533, 685, 337, -2, -16, 160, 471, 545, 560, 951, 1235, 1322, 1645, 2331, 3125, 3185, 2780, 2851, 2698, 1733, 674, 260, 119, -484, -1538, -2188, -2171, -1755, -1283, -1862, -3027, -3050, -1849, -908, -1168, -1592, -1397, -950, -583, -863, -1485, -1775, -1140, 341, 911, 503, 879, 2055, 2609, 2131, 1404, 884, 948, 1596, 1398, 189, -337, -216, 18, 894, 1565, 856, 451, 1251, 1317, 292, -391, -186, 235, 366, 495, 422, 167, 446, 854, 949, 463, -463, -523, 509, 737, -822, -2211, -1437, 431, 1146, 497, 219, 740, 1598, 2491, 2687, 2793, 3311, 3688, 3227, 2056, 1278, 973, 777, 250, -1334, -2760, -2605, -1425, -1007, -1688, -2197, -2091, -1779, -2001, -2623, -2914, -2635, -1521, -338, -186, -254, -135, 105, 1049, 1658, 1212, 828, 679, 593, 149, -748, -1178, -1085, -1092, -1126, -1036, -803, -252, 716, 2052, 2742, 2303, 2085, 2423, 2134, 652, -1276, -2405, -2481, -2786, -3988, -4366, -3194, -1846, -1156, -1418, -2455, -3267, -3218, -2958, -3513, -4101, -3756, -2702, -1505, -994, -850, 63, 1898, 3358, 3849, 3958, 3691, 2993, 2408, 2077, 1484, 577, 317, 882, 777, -19, -274, -94, 65, 306, 231, -55, 141, 449, 722, 869, 464, 502, 1654, 2506, 2011, 887, 547, 1363, 2339, 2294, 1287, 790, 1352, 2104, 2037, 1910, 2377, 2836, 3457, 3707, 3214, 2306, 894, -342, -1078, -1734, -2267, -2438, -2576, -2774, -2878, -2953, -2727, -2317, -1826, -1866, -2633, -2770, -2316, -2311, -2844, -3336, -2977, -1669, -172, 683, 501, 461, 1692, 2723, 2223, 1028, 604, 947, 1125, 971, 423, -187, 82, 664, 349, -418, -471, -118, 533, 1473, 1213, 458, 859, 1293, 778, -137, -779, -749, -156, 82, -373, -789, -1199, -1557, -1557, -1987, -3334, -3570, -2249, -1708, -1817, -1656, -1678, -1662, -1450, -1328, -1400, -1102, -21, 608, 438, 385, 449, 610, 748, 638, 66, -812, -1079, -855, -1367, -2848, -3463, -1991, -926, -1357, -1522, -1415, -1070, -198, -246, -1646, -2337, -1542, -964, -1416, -2064, -2524, -2459, -1751, -793, -130, -383, -694, -259, -304, -1093, -1650, -2086, -2232, -1697, -1299, -1582, -1645, -1179, -1069, -1439, -2354, -3461, -3393, -2091, -944, -643, -1232, -1915, -1841, -1967, -2930, -3920, -3909, -3031, -2500, -2315, -1572, -752, -443, -219, -353, -738, -474, -99, -942, -2096, -2038, -2008, -2340, -1252, -8, -288, -553, -26, 442, 432, -291, -1325, -1612, -1525, -2025, -3165, -4436, -4543, -3517, -3332, -4243, -4585, -3598, -1984, -497, 385, 333, -296, -578, -753, -1974, -3575, -3253, -1437, -859, -1081, -587, -220, 325, 1153, 729, 105, 538, 556, 12, -321, -800, -1169, -858, -477, -630, -572, 195, 933, 1023, 742, 100, -340, -239, -432, -1347, -2616, -3331, -2949, -2542, -3096, -3276, -2164, -1431, -1503, -745, 443, 623, 135, 31, 153, -405, -1365, -2313, -2575, -2047, -2161, -2959, -3115, -2236, -1496, -1702, -1962, -1997, -1910, -1221, -1031, -1773, -1978, -1499, -1458, -1854, -2369, -2530, -1997, -1468, -1171, -1043, -1551, -1313, 823, 2449, 2171, 1423, 1173, 1111, 682, 45, -112, -83, -34, 503, 787, 791, 1173, 1208, 846, 289, -383, -145, 1197, 2394, 2239, 1387, 1254, 2267, 3378, 3320, 2074, 1344, 1777, 2135, 2254, 1797, 760, 654, 1270, 1564, 1596, 2026, 3110, 3462, 2009, 276, -428, -819, -913, -877, -1438, -1608, -660, 59, -128, -269, -223, -162, -57, -415, -959, -1267, -1795, -2274, -1797, -1216, -1298, -1292, -854, -744, -1294, -1503, -1322, -1155, -172, 697, -50, -485, 684, 1452, 851, 196, -39, -369, -378, 111, -298, -813, 496, 1897, 1432, 89, -897, -1077, -653, -745, -1432, -1887, -1789, -1422, -1829, -2700, -2867, -2463, -1969, -1633, -1638, -1880, -2117, -1744, -1199, -1799, -2306, -1632, -700, 69, 665, 500, 254, 1013, 1208, -189, -1381, -1726, -1760, -1093, -204, 245, 285, 309, 822, 901, -218, -1337, -1266, -349, 378, 326, -295, -1027, -1220, -1027, -1465, -2007, -1921, -1551, -981, -484, -610, -876, -750, -555, -441, -670, -1314, -761, 738, 871, 183, 555, 1271, 1091, 415, 54, -134, -689, -1105, -1197, -1710, -2763, -3030, -2272, -1978, -2858, -4038, -4240, -3984, -4167, -3968, -3873, -4491, -4246, -3512, -3911, -4517, -4047, -3007, -2462, -2549, -2671, -2709, -2606, -3011, -4528, -5741, -6323, -6796, -6290, -5220, -5250, -5277, -3849, -2585, -2283, -1854, -1355, -93, 1748, 1492, -258, -1126, -720, 269, 122, -926, -951, -430, -1021, -2400, -3112, -2940, -2891, -2978, -2522, -2412, -2905, -2593, -1760, -1533, -1568, -1672, -1530, -839, -437, -411, -274, -411, -684, -503, -259, -1011, -2083, -2122, -1820, -2046, -2520, -2596, -2581, -2616, -2405, -3058, -4522, -4610, -3549, -3158, -3324, -3382, -2960, -2430, -2383, -2720, -3312, -3506, -3107, -3400, -4610, -5252, -4767, -4008, -4064, -4772, -5242, -5659, -5404, -4660, -4911, -5296, -4566, -3574, -3258, -2967, -2623, -2762, -2740, -2294, -2498, -3704, -4084, -2688, -1575, -1956, -2491, -2366, -1491, -195, 441, -304, -1627, -1858, -1336, -1718, -2806, -3366, -2970, -1629, -370, 37, 530, 1162, 1474, 1101, 147, -125, 101, 169, -141, -952, -1472, -1063, -142, 577, 302, -832, -736, 802, 1490, 1228, 933, 1067, 1558, 1636, 1111, 680, 587, 973, 1690, 1556, 280, -1011, -1379, -917, -696, -1056, -1275, -1032, -579, -19, 269, -310, -787, -466, -212, -781, -1703, -2560, -3617, -4327, -4143, -3359, -2486, -1843, -1327, -480, 763, 1457, 1176, 905, 858, 491, 210, 376, 384, -172, -947, -1186, -1020, -1425, -2232, -2539, -2888, -3613, -3667, -3337, -3329, -2867, -1611, -357, 613, 1540, 1740, 885, 52, -296, -1215, -2659, -3138, -2986, -3669, -4190, -3784, -3505, -2965, -1860, -1658, -2393, -2345, -1022, 261, 505, 792, 1839, 2973, 3913, 3766, 2450, 1719, 1990, 2273, 1822, 438, -744, -410, 593, 1179, 1418, 1737, 1958, 2288, 2906, 2342, 927, 637, 772, 287, -307, -537, -448, -233, -262, -826, -1641, -1549, -827, -1256, -2019, -1654, -587, 888, 1941, 1772, 1560, 1964, 2030, 1633, 1337, 1006, 322, -212, 261, 1071, 622, -639, -787, 110, 812, 1120, 984, 592, 991, 2029, 1810, 682, 661, 1266, 1117, 250, -123, 343, 1168, 2335, 2592, 1797, 1513, 1713, 1544, 480, -265, 107, 701, 1480, 1912, 1160, 689, 1668, 2598, 1912, 519, 774, 2186, 2187, 972, 441, 712, 1441, 2409, 2900, 2429, 1835, 2259, 2709, 2365, 1504, 156, -455, 291, 615, -187, -507, 33, 742, 1222, 1225, 1048, 1095, 1590, 1989, 1795, 1500, 1267, 1013, 948, 1136, 985, 446, 245, 40, -406, -576, -778, -1064, -57, 1860, 2147, 986, 909, 1992, 2214, 1682, 1715, 2077, 2248, 2091, 1287, 611, 1007, 1537, 1419, 958, 648, 981, 1641, 1904, 1711, 1651, 2125, 2652, 2732, 2404, 1761, 1417, 1784, 2076, 1475, 894, 1370, 1423, 541, 392, 904, 874, 1065, 2266, 2875, 2379, 2632, 3957, 4818, 4137, 2910, 2758, 3145, 3274, 3412, 3203, 2443, 2426, 3427, 4048, 3571, 3219, 3865, 4732, 5566, 5983, 5553, 5120, 4783, 4117, 3151, 1936, 1164, 1527, 2240, 2137, 1775, 2618, 4005, 4377, 3680, 2282, 1315, 1598, 1862, 1087, -108, -539, 829, 2302, 2149, 1452, 1195, 1246, 1236, 801, 240, -61, -116, 579, 977, 242, -176, -174, -151, -415, -1191, -1607, -1546, -1807, -2165, -2241, -1964, -1039, 110, 955, 1298, 1536, 2070, 2676, 2931, 2610, 2004, 1562, 1634, 2459, 3479, 3851, 3750, 3274, 2592, 2100, 1292, 628, 829, 1301, 1186, 532, 578, 1274, 1432, 1108, 781, 445, 577, 1116, 1335, 1362, 1223, 1076, 1604, 2521, 2514, 1444, 849, 1014, 1052, 589, 3, 76, 634, 913, 864, 924, 1390, 1958, 2505, 2824, 1957, 850, 721, 1090, 959, 140, -223, 401, 918, 916, 535, 23, 44, -78, -605, -647, -897, -1538, -1352, -1072, -1646, -2224, -1995, -1107, -554, -910, -1151, -817, -782, -998, -1374, -1867, -1991, -1883, -1707, -1692, -2109, -2274, -1495, -545, -520, -1056, -863, 308, 1490, 2327, 2581, 2202, 2455, 3589, 4032, 3360, 2973, 3612, 3886, 2834, 1381, 934, 1283, 1682, 2347, 2770, 2804, 3393, 4313, 4816, 3973, 2090, 1332, 1427, 1523, 1883, 2056, 2479, 4034, 5260, 4729, 3674, 3276, 2951, 2411, 1558, 723, 1282, 2543, 2770, 2379, 2028, 1334, 903, 1106, 844, 39, -533, -916, -1100, -1037, -1334, -1044, 536, 1738, 2091, 1538, -1, -1059, -1567, -2726, -3952, -4129, -3308, -1528, 457, 1056, 1065, 1976, 3143, 3052, 1578, 306, 703, 1906, 2698, 2680, 1421, 409, 1064, 2227, 2424, 2033, 2179, 2644, 2773, 2500, 1887, 1756, 2460, 3252, 3877, 3759, 2705, 2123, 2519, 2604, 1656, 704, 1070, 2251, 2174, 699, -184, -330, -414, -405, -764, -1445, -1553, -1118, -749, -675, -953, -1008, -488, -319, -673, -785, -443, 197, 874, 932, 49, -857, -542, 673, 1288, 740, -184, 260, 1826, 1861, 396, -284, -240, -166, 166, -147, -1247, -843, 811, 943, 42, 233, 1076, 1573, 1753, 904, -351, -708, -481, -565, -995, -1184, -995, -293, 284, -106, -424, 421, 1649, 2422, 2682, 2438, 2240, 3248, 4545, 4015, 2461, 2176, 3350, 4219, 3671, 3050, 3436, 4008, 4491, 4614, 3930, 3762, 4700, 4957, 4108, 2948, 1830, 1180, 1326, 2000, 2092, 1504, 1931, 3047, 3170, 2801, 2247, 1627, 1868, 2391, 2211, 1639, 1666, 2216, 2456, 2608, 2590, 2077, 1865, 1650, 719, 162, 775, 1824, 2192, 1965, 1790, 1703, 2108, 2544, 1742, 470, -428, -1660, -2121, -771, 472, 252, 185, 1436, 2234, 1981, 2085, 2278, 2045, 1945, 1961, 1851, 1739, 2049, 2615, 2516, 1927, 1758, 2511, 3569, 3771, 3328, 3104, 3493, 4094, 4119, 3558, 2742, 2021, 1232, 184, -351, -284, -245, -61, 352, 35, -776, -664, 129, 214, -373, -327, 270, 450, 176, -541, -939, -341, 425, 1187, 1746, 1412, 1389, 2485, 3073, 2394, 1878, 1722, 1198, 790, 198, -824, -1199, -604, -92, -101, -273, -344, 479, 1254, 314, -1132, -1520, -1274, -1186, -1127, -1386, -1979, -1922, -1135, -335, 37, -148, -349, 204, 829, 614, 150, 412, 1276, 1672, 1114, 259, 24, 779, 989, -181, -894, -502, -272, -621, -895, -887, -807, -627, 113, 1244, 1260, 602, 1246, 2555, 3079, 2883, 2370, 2269, 2281, 1878, 1283, 650, 584, 960, 703, 108, 305, 1520, 2678, 2432, 1405, 727, 277, 132, -250, -689, -152, 857, 2053, 3404, 4054, 3583, 3089, 3059, 2662, 1311, -474, -1102, -366, -269, -1103, -1288, -957, -1005, -1244, -1513, -1957, -1948, -1242, -866, -1417, -1968, -1636, -1193, -1374, -1555, -1367, -1095, -514, 267, 650, 191, -1160, -2183, -1911, -1393, -1431, -1279, -15, 1906, 2733, 2057, 1479, 1515, 894, -366, -1285, -1541, -1489, -1392, -1011, -664, -840, -963, -326, 178, -72, -529, -705, -245, 287, 424, 572, 572, 689, 1379, 1802, 1701, 1691, 1759, 1431, 553, -60, 126, 797, 1607, 2134, 1879, 1342, 1427, 1772, 2180, 2263, 957, 206, 1510, 2086, 1104, 770, 1497, 2343, 2643, 1885, 700, 371, 561, 628, 215, -672, -1317, -1063, -835, -1565, -2279, -2223, -1927, -1789, -1928, -2460, -2272, -917, -457, -1047, -1231, -1711, -1990, -740, 120, -955, -2031, -1214, 302, 390, -118, -85, 213, 735, 704, -993, -3182, -3596, -2731, -2446, -2514, -2128, -1805, -1525, -868, -157, 377, 1232, 1934, 1406, -437, -1846, -1112, 280, 933, 1347, 1240, 708, 1057, 1972, 1662, 931, 1699, 2755, 2974, 3159, 3261, 2132, 102, -286, 417, -390, -1519, -1485, -887, -329, -382, -994, -1359, -984, -155, -99, -1463, -2622, -2347, -1772, -1509, -1662, -2248, -2392, -1663, -1242, -1521, -1440, -1300, -1342, -679, -482, -1593, -2751, -2935, -2491, -2631, -2909, -2437, -1909, -1939, -2498, -3255, -3636, -3483, -3494, -3357, -1801, 224, 1214, 1767, 1648, 804, 469, 249, 17, 96, -660, -1938, -1848, -808, -681, -1541, -1908, -1434, -1172, -943, 104, 1047, 1597, 1645, 163, -1437, -1839, -2054, -2299, -2207, -2722, -3658, -3853, -3497, -3713, -5089, -5646, -4610, -3762, -3253, -2132, -1045, -1176, -2053, -2042, -1483, -1995, -2594, -2074, -1144, -646, -702, -573, 383, 1680, 2121, 1326, 520, 898, 1739, 1611, 909, 932, 1353, 1301, 655, -648, -1672, -1339, -631, -666, -1040, -1313, -1093, -48, -93, -1988, -2587, -1646, -1862, -2461, -2445, -2730, -2765, -2312, -2285, -2349, -1335, 119, 604, 770, 1322, 1479, 888, 101, -96, -120, -253, -645, -1195, -1029, -663, -611, -536, -976, -1339, -590, -345, -937, -797, -187, -349, -1530, -1875, -1072, -654, -510, -733, -2001, -2846, -2089, -1200, -1744, -2530, -1633, -127, 346, -445, -1094, -247, 644, 192, -117, 185, -564, -1580, -1439, -1479, -2944, -4538, -4362, -2887, -1833, -1682, -1746, -1437, -938, -314, 589, 389, -595, 279, 1316, 383, -478, 49, 1252, 1780, 1218, 1100, 1585, 1668, 1141, -51, -1101, -1626, -1896, -2225, -3101, -3329, -1776, 265, 1238, 826, 90, -11, 387, 956, 1361, 1126, 789, 1400, 2426, 2608, 1985, 1165, 265, -490, -1298, -2479, -3173, -2676, -1746, -1712, -2111, -1519, -378, 112, -410, -1287, -2243, -2661, -2071, -1960, -2342, -1603, -496, -632, -794, -393, -39, 109, -327, -708, -1042, -1914, -2235, -1003, 421, -443, -2958, -3726, -2604, -1945, -2582, -3646, -3298, -1723, -1438, -1968, -1419, -945, -1874, -2664, -3272, -4477, -5181, -5238, -4963, -4247, -3816, -3046, -916, 63, -1638, -3055, -3054, -3323, -3449, -2753, -2625, -3177, -2961, -1571, -917, -2650, -3877, -2761, -1480, -854, -404, -363, -363, 461, 1419, 789, -837, -1213, -696, -775, -1737, -3052, -2890, -1729, -1455, -1222, -974, -1444, -998, -402, -1841, -3323, -3153, -2287, -1813, -2170, -2773, -2521, -1163, -703, -1901, -2596, -2360, -1979, -1521, -997, -719, -1199, -1539, -1025, -640, -1534, -2638, -2414, -1491, -1217, -2117, -3214, -3512, -3470, -3612, -3516, -3360, -3378, -3460, -3136, -2768, -2908, -2798, -2344, -1943, -1849, -1769, -1274, -1619, -2909, -3133, -2450, -1561, -575, 210, 644, 414, -97, 88, 856, 474, -1203, -1465, -736, -1003, -1373, -1422, -1922, -2498, -1672, -692, -1628, -2513, -1465, -607, -873, -1170, -1571, -2144, -2757, -3410, -4159, -4997, -5092, -3819, -1697, -66, 490, 601, 1375, 2927, 3267, 2022, 968, 969, 1790, 2021, 388, -348, 876, 1096, 1015, 2202, 2937, 2724, 2692, 2491, 1689, 1033, 393, -531, -920, -1082, -1336, -859, 282, 1248, 1641, 1287, 619, 517, 628, 299, -174, -321, 113, 460, 356, 339, 35, -612, -4499, -2450, -3462, -4808, -3545, -2996, -3860, -3901, -3620, -4605, -6346, -4243, 183, 150, -3211, -4884, -4445, -3511, -1903, -2151, -3854, -3895, -3540, -2618, -1369, -2185, -3515, -3427, -2424, -1990, -1859, -1224, -2407, -4230, -3290, -3794, -7197, -7572, -6314, -5792, -5180, -5937, -6791, -6469, -5648, -4427, -3584, -3759, -4617, -4612, -4229, -4175, -3417, -2317, -2837, -4650, -5158, -4000, -3017, -3255, -3806, -4405, -4161, -3334, -2825, -2468, -3512, -4904, -4112, -2683, -4047, -6208, -5152, -2377, -1075, -1584, -2091, -2255, -2446, -484, 1484, -393, -2413, -2100, -1935, -2592, -3294, -4161, -4276, -3048, -2833, -3432, -2914, -2482, -1927, -1165, -3334, -6701, -6588, -4564, -4000, -4619, -4274, -3852, -4671, -4562, -4294, -5202, -5367, -3547, -1104, -1271, -3216, -3648, -2199, 74, 489, -942, -589, 1343, 2365, 2374, 2900, 3081, 1951, 1323, 289, -1617, -2298, -2586, -2805, -2125, -2685, -4506, -4658, -3442, -3165, -4828, -5947, -3731, -1583, -2761, -4406, -4212, -2954, -2515, -3192, -3561, -3322, -2901, -2011, -1597, -2278, -3039, -3301, -2850, -1408, 174, -739, -2155, 347, 1779, -1634, -2552, 889, 1910, -668, -2473, -2547, -3339, -4453, -3875, -2931, -3789, -5345, -5534, -4813, -3886, -3011, -3990, -6642, -7269, -5987, -6615, -8808, -8706, -7029, -7193, -7865, -6744, -5771, -4610, -2820, -2754, -2689, -1746, -1297, -908, -247, 389, 189, -515, -725, -338, -253, -1448, -2077, -1045, 262, 901, 276, 239, 980, -471, -2272, -1261, 264, 218, -969, -2045, -1985, -2006, -3184, -3218, -1397, -565, -889, 231, 487, -2229, -3577, -2731, -2393, -2412, -2455, -2701, -2799, -1745, 465, 1640, 1199, 1884, 3008, 2010, 70, -891, -414, -699, -2660, -3889, -3807, -2766, -1539, -2064, -3282, -3287, -1931, -1128, -1887, -2027, -2656, -5128, -5565, -4447, -5378, -6168, -5918, -5631, -4059, -2608, -2492, -2002, -1795, -2110, -1073, -347, -1027, -1613, -1323, -672, -974, -1948, -2987, -3050, -1522, -1163, -3052, -3748, -2233, -1033, -1771, -3523, -4357, -3621, -2686, -3021, -3687, -2664, -1817, -3647, -5309, -5760, -6747, -6978, -6188, -5875, -5190, -3600, -3286, -3859, -3077, -2760, -4050, -4085, -3114, -2938, -2409, -1383, -743, -1231, -1769, -1341, -1542, -1574, -956, -886, -1423, -1809, -2256, -3138, -2972, -2911, -3631, -3709, -3712, -4532, -4491, -4393, -5980, -5548, -3199, -3429, -4520, -3048, -916, -871, -831, 498, 981, 1275, 2804, 3138, 1218, -169, 849, 1734, 342, -1137, -1888, -1304, 229, -470, -1864, -605, -23, -1140, -1074, -594, -792, -1304, -1231, -92, 977, 180, -1027, -335, 592, 1019, 1240, 720, 68, -62, 482, 1168, 1499, 2666, 3788, 4340, 4731, 4413, 4048, 3980, 3833, 3683, 2882, 1099, 308, 1168, 941, -839, -2072, -1950, -1053, -896, -1995, -1397, 749, 780, 567, 1759, 3258, 5234, 4907, 2901, 2561, 2541, 2755, 4013, 4516, 3241, 2364, 4374, 6125, 4537, 3475, 5030, 6277, 5962, 5021, 4650, 4302, 4094, 4599, 4269, 3373, 2402, 1409, 2352, 3734, 3017, 2441, 3328, 3675, 2807, 1411, -192, 159, 2670, 4148, 3056, 1328, 885, 1561, 2517, 2836, 1866, 923, 1705, 2651, 1130, -292, 1288, 3510, 3848, 1920, -386, 288, 3308, 3986, 2603, 2299, 2382, 2153, 3550, 5101, 3445, 1480, 2263, 4140, 4633, 3261, 2002, 2766, 3989, 3931, 3171, 1640, -132, 225, 3035, 3735, 2133, 2192, 2783, 2529, 2906, 3901, 3668, 2940, 3788, 4958, 4803, 4820, 5011, 3745, 2249, 3121, 4422, 3080, 2428, 4397, 4988, 3077, 2475, 3907, 3669, 1419, 822, 2205, 2610, 1083, -504, -1118, -417, 440, 712, 787, -134, -393, 1836, 3566, 2616, 1488, 2078, 2829, 2458, 2416, 3442, 4634, 4816, 4524, 5788, 6366, 5261, 6263, 7032, 5023, 3830, 3821, 3597, 3915, 4303, 3169, 1973, 2561, 2622, 1851, 1551, 1645, 3181, 4001, 2134, 1200, 3049, 3070, 851, 917, 1246, 185, 1191, 3288, 3290, 2693, 3595, 4504, 4702, 4767, 4668, 5642, 6384, 4969, 4690, 6103, 4737, 1751, 2142, 4061, 4139, 4237, 3569, 1731, 2137, 4174, 4999, 5266, 6450, 6684, 4846, 3895, 4062, 3567, 4525, 5856, 3675, 2374, 4127, 5101, 4326, 2964, 2019, 1371, 1444, 2247, 3131, 3796, 3129, 2608, 3648, 2997, 1245, 2343, 4379, 4079, 3464, 3259, 2359, 2943, 4468, 2624, -305, -20, 2452, 3830, 3081, 2350, 1808, 1534, 3462, 4969, 3949, 3847, 4051, 1276, -889, 355, 1130, 1326, 1900, 1424, 1602, 2543, 2908, 3776, 3710, 1062, -170, 1125, 1496, 686, 394, 1227, 3065, 3170, 2010, 2345, 1582, 399, 1261, 1791, 1394, 1318, 1045, 1880, 5039, 6498, 4579, 4519, 6333, 5492, 4167, 4091, 3135, 2369, 2467, 2201, 1419, 79, -225, 1128, 845, -336, 1737, 4003, 3807, 4509, 5578, 4433, 2528, 2731, 5415, 6138, 3000, 1738, 3876, 3966, 2069, 2303, 3999, 5207, 6412, 6011, 3769, 2889, 3929, 4756, 4079, 3368, 3696, 4529, 4593, 3913, 3946, 3654, 2531, 2577, 3414, 2986, 2480, 3635, 4901, 3703, 891, -868, -994, -253, 1338, 2306, 1790, 1351, 1931, 3170, 3827, 3615, 3607, 3901, 4431, 5138, 5909, 6068, 5692, 5701, 4692, 3543, 4756, 5391, 4475, 4588, 4587, 4203, 4548, 4927, 4445, 2314, 671, 1856, 2931, 1875, 304, -442, 458, 2054, 2103, 1027, -62, 491, 2484, 2718, 1492, 759, 1438, 3328, 2884, 937, 1678, 2575, 2770, 5129, 6546, 4386, 2780, 4095, 4826, 4005, 3799, 3868, 2602, 1153, 853, 985, 642, 1598, 3838, 2860, 407, 1416, 4060, 5793, 6034, 4047, 3766, 6010, 6644, 6443, 5359, 2205, 875, 3146, 4206, 2854, 1848, 2432, 3936, 4251, 4610, 6458, 5646, 2164, 2713, 5630, 5485, 4094, 3489, 2422, 963, -40, -732, -1434, -1689, -1972, -1999, -1382, -534, 1106, 1870, 785, 590, 2566, 3985, 2582, 1905, 4523, 5403, 3490, 3481, 4402, 4008, 3872, 4949, 4810, 1869, -111, 1342, 2607, 1839, 213, -728, 568, 2070, 1690, 643, 925, 2159, 2353, 1766, 1269, -342, -2360, -1040, 1783, 1810, 640, 481, 430, -393, 107, 2591, 4748, 5406, 4055, 3348, 4378, 3663, 2920, 4546, 4975, 3714, 3821, 4621, 5200, 5428, 3997, 2708, 2901, 3490, 3929, 3612, 2689, 1968, 2828, 5188, 6239, 3776, 899, 773, 2334, 2642, 865, -140, 1136, 2443, 2559, 2421, 1959, 1371, 1499, 1912, 3096, 3650, 2423, 3278, 6116, 6400, 6122, 7698, 7863, 6308, 4584, 3309, 2652, 2235, 2563, 2212, 1187, 1337, 2246, 3065, 2843, 1075, 376, 1538, 1960, 723, -798, -1000, 474, 1957, 1952, 208, -1221, -418, 525, -128, -663, -858, -1675, -2098, -560, 1944, 2000, 1194, 2237, 2332, 1651, 3181, 4157, 2885, 2550, 1641, -247, 986, 2648, 1558, -394, -1496, 454, 1289, -1096, -823, 509, -989, -1661, 282, 705, -621, -1048, -210, -152, -1042, -307, 331, 1345, 3758, 3591, 2496, 2103, 1665, 2793, 3312, 1704, 645, 736, 135, -725, -326, 3, 233, 1706, 1834, -198, -400, 1181, 1370, 747, 681, 275, -394, 126, 1473, 2135, 2194, 767, -452, 1475, 1699, -1909, -2826, -1809, -3103, -2767, 876, 2386, 781, 854, 2813, 2072, 854, 2433, 2878, 1738, 1355, 405, 658, 2648, 1010, -2614, -1675, 1852, 1916, 683, 1945, 3109, 2475, 1221, 700, 522, -757, -1444, -221, 748, 62, 116, 645, -535, -1947, -1574, -985, -2383, -2707, -702, 1428, 2044, 1330, 1893, 3042, 1768, 454, 1457, 2279, 2254, 1651, 1183, 1793, 2225, 2265, 2389, 1325, -485, 246, 2091, 596, -1402, -658, -1241, -2987, -2709, -3297, -4069, -2923, -3885, -6354, -5584, -3329, -3145, -3229, -2041, -1408, -1939, -1059, 3540, 5132, 12, -1819, 1389, 3691, 3618, 1765, 700, 2188, 2590, 1193, 1621, 2396, 2390, 3141, 2901, 1267, -248, -784, -158, 120, 796, 2387, 1308, -1115, -641, 355, -736, -1767, -1413, -804, -968, -1823, -1729, -1025, -854, 249, 1302, -768, -3956, -3501, -1172, -1055, -1153, -248, -194, -271, 116, -460, -508, 2393, 4738, 3199, 1426, 2164, 3629, 3698, 2823, 2238, 1463, 1730, 2574, 914, -923, -759, 68, 635, -239, -2123, -3515, -3757, -1359, 1083, -382, -1852, -1299, -747, 92, -143, -2138, -1978, 683, 1160, -1116, -2686, -1356, -194, -1753, -2530, -2524, -2635, -1331, -471, -1737, -2682, -3045, -3714, -2943, -1071, -841, -1795, -227, 2452, 2424, 1671, 2585, 2612, 1275, 1274, 1409, -91, -225, 1059, 1299, 101, -2548, -3726, -2054, -994, -1251, -1266, -1684, -3012, -3540, -2968, -3190, -3964, -4699, -5414, -6722, -7006, -5123, -4224, -3919, -2471, -1604, -1844, -2302, -2209, -2164, -2808, -2187, -925, -491, 42, -588, -2183, -1048, 132, -1526, -1815, -777, 50, 1680, 1138, -125, 634, -38, -902, -196, -1115, -2389, -1269, -1013, -1647, -1186, -1102, -1354, -1887, -2872, -2930, -2186, -1143, 725, 1729, 1408, 820, 65, 471, 1020, 354, -649, -193, 2166, 2475, 195, -1064, -670, 963, 1997, 1175, -240, -1714, -2562, -1509, 518, 1372, 733, -199, -216, 486, 872, 50, -1431, -1196, -505, -990, -1343, -1100, -1185, -1179, -488, -985, -2780, -2164, 373, 721, -5, 264, -1, -387, 361, -1039, -3197, -1887, -1372, -3604, -4557, -4739, -4331, -1487, 1255, 1118, -131, -200, -45, -479, -1360, -2100, -2187, -1162, 815, 1780, 83, -1839, -1243, -835, -1907, -2961, -3580, -3739, -3924, -5353, -7196, -6555, -5496, -6879, -6334, -3783, -3364, -3517, -2829, -1841, -497, 493, 1354, 2259, 1143, -1135, -1596, -145, 1344, 1194, -266, -1638, -2601, -1806, 17, -139, -1551, -2366, -1182, -368, -2934, -5097, -3060, -1269, -3031, -4700, -4205, -3828, -4669, -5168, -4777, -4946, -5420, -4150, -2436, -2065, -1717, -1558, -1841, -1511, -931, -1067, -1087, -364, 531, 785, 356, -485, 174, 1786, -57, -2505, -1137, 890, 588, -493, -1301, -2514, -2735, -826, -424, -2632, -3131, -2900, -3590, -3766, -3372, -3619, -4723, -4410, -3204, -2995, -2989, -4119, -4853, -3381, -2247, -2599, -3196, -3044, -1988, -60, 533, -536, -884, -499, -562, -711, -743, 236, 2335, 2559, 1265, 1003, 1534, 2294, 1504, -607, -711, -37, -710, -1098, -1193, -1773, -1056, 812, 931, -896, -2234, -1898, -1555, -1572, -969, -358, -1546, -3189, -3464, -2893, -1404, -802, -1213, -392, 550, 154, -268, 215, 938, -269, -1758, -591, 236, -215, 399, 603, 249, 1551, 1814, -1366, -3298, -949, 1782, 1185, -1030, -1516, -886, -994, -1284, -973, -1444, -2135, -62, 1487, 60, -544, -1312, -2761, -1544, -106, -1334, -1822, -304, 850, 1267, 1093, 1562, 3306, 2924, 995, 833, 1482, 1395, 1142, 587, -748, -626, 966, -196, -2610, -2872, -2946, -2234, -910, 71, 1049, -239, -2594, -1932, -358, -528, -1497, -2240, -1814, -1375, -2370, -3946, -5300, -5021, -3374, -2971, -2769, -1421, -1119, -418, 1391, 1033, -1164, -2526, -791, 1536, 1211, -565, -1103, -751, -1365, -1903, -1078, 123, 462, 490, -669, -2736, -3262, -2216, -926, -413, -1281, -2170, -1829, -1580, -1393, -1268, -2477, -2883, -1403, -1826, -3951, -3689, -2296, -1559, -1219, -2319, -3392, -2388, -121, 1369, 1335, 1113, 234, -1378, -2118, -1397, -1333, -3189, -4831, -4572, -3128, -2128, -1390, -349, 992, 1666, 640, -774, -1008, -970, -546, 644, 1019, 479, 502, 575, -417, -1617, -2269, -2072, -580, -419, -2194, -2274, -907, -520, -705, -1785, -1957, 124, 759, -1301, -3034, -1957, 640, 716, -608, 99, 1616, 1845, 916, -769, -1876, -1847, -1142, -621, -884, -1325, -1826, -2694, -2817, -2312, -2803, -3316, -1794, 47, -783, -2749, -3614, -3061, -2329, -3151, -4979, -5071, -2293, -465, -1077, -1151, -749, -1413, -2113, -1803, -986, -1598, -3970, -4576, -2633, -1309, -1926, -1745, 1139, 3104, 1237, -2503, -2728, 1130, 1928, -1324, -2352, -885, -862, -979, 4, -638, -2194, -2261, -1223, -1203, -3157, -3572, -1486, -1656, -3600, -3616, -2984, -2977, -1245, 1127, 378, -2181, -3506, -2929, -1036, -608, -1759, -1715, -582, 8, -906, -1188, 313, 872, 728, 2285, 3062, 1228, -62, -370, -1398, -1585, 457, 1773, -171, -2214, -1221, 227, -789, -813, 553, -1122, -3409, -3086, -2195, -1676, -1519, -1518, -866, -450, -192, 222, -25, -1137, -2631, -2620, -1565, -790, 1362, 2500, 518, 2, 1356, 675, -299, 346, 1040, 462, -348, 426, 534, -1694, -2732, -1837, -761, -85, -1828, -3495, -1617, 165, -505, -1761, -2408, -2131, -2120, -3119, -3992, -4175, -4226, -3124, -1077, -319, -1135, -2698, -1864, 1708, 3288, 1887, 1096, 2101, 1873, 301, -542, -1204, -539, 898, -314, -262, 1379, 461, -190, 94, -638, -1767, -2662, -1239, 1713, -77, -3597, -2936, -1655, -2339, -2688, -2986, -5425, -6665, -4128, -3243, -5961, -6190, -2809, -329, 493, 536, -15, 268, 1790, 2494, 1608, -158, -617, 1322, 2074, 1074, -118, -1045, -794, 54, -283, -913, 1016, 2903, 2353, 1305, -383, -1026, 923, 2624, 1490, -665, -1848, -2162, -1067, 63, -763, -2346, -1176, 1561, 2118, 1018, 790, 2890, 3837, 1274, -602, 137, 1160, 1999, 1698, -376, -502, 1515, 2755, 2413, -950, -4649, -2101, 1515, 50, -986, 140, 293, 66, 292, 97, -156, -177, -313, -1048, -2062, -1514, -535, -890, -772, -1307, -3677, -4521, -3508, -3436, -3899, -3533, -2932, -2846, -2776, -2254, -2936, -4359, -3236, -1989, -2806, -3623, -4226, -3542, -530, -186, -2646, -2609, -1580, -1127, 482, 781, -1873, -3105, -1271, -623, -2885, -4207, -3098, -1853, -1394, -1948, -2956, -2920, -3349, -5239, -5681, -4927, -4140, -3871, -4344, -4500, -4611, -3624, -1094, -57, -2306, -4529, -4059, -3252, -4154, -4041, -1925, -1689, -1964, -326, 584, -172, -917, -1751, -1866, 672, 2269, -84, -2198, -378, 1514, -4, -1808, -1794, -358, 2472, 2959, 124, -1247, -477, 578, 1403, 1085, -345, -881, -529, -1031, -2266, -3576, -2925, -357, -207, -1980, -1920, -690, -121, -147, 137, -512, -1483, 941, 3959, 3299, 2195, 2684, 2823, 2439, 2594, 2589, 918, -304, 1234, 2067, 1491, 2041, 1971, 184, -308, 1517, 2422, 409, -283, 1644, 1800, 807, 654, 1219, 1035, 318, 304, -391, -1525, -1302, -873, -1177, -1048, -276, -703, -2162, -1394, 944, 1618, 938, 869, 1944, 2072, -407, -1145, 1464, 2249, 1085, 2128, 3502, 2923, 2082, 1127, 1646, 2993, 1547, -1185, -1923, -98, 1019, -1090, -2813, -1401, 653, 659, -833, -2788, -3339, -2039, -2327, -3266, -1974, -1457, -3011, -3206, -2180, -2728, -4119, -4419, -3990, -2773, -2174, -3311, -2885, -567, -25, -726, -1226, -1205, 877, 2954, 1452, -437, 206, 1000, 1950, 1655, -830, -1422, -188, -438, -1466, -1666, -2404, -4090, -4309, -2341, -1203, -1714, -1433, -1148, -2464, -3996, -4066, -2735, -1531, -2270, -3172, -1774, 15, 701, 715, 41, 93, 293, -353, 744, 3165, 2481, 553, 2031, 2635, -625, -1580, 738, 1744, 753, -196, -1014, -2147, -1712, -460, -659, -321, -437, -2426, -2228, -675, -33, 110, -97, 352, 1563, 1749, 1137, 1803, 2595, 2475, 418, -1142, 958, 3088, 3446, 3904, 2591, 1159, 3007, 4712, 3238, 914, 1030, 2119, 2025, 2300, 2530, 1272, 620, 1587, 1359, -587, -688, 740, 92, -1275, -21, 1541, -29, -1223, 508, 476, -975, 324, 1885, 1823, 1019, 531, 642, 1106, 1178, 1115, 2122, 3028, 2839, 2366, 1210, 6, -59, 226, 1054, 1812, 103, -2276, -175, 3032, 1243, -476, 1695, 2116, 454, 183, 1271, 1905, 1051, -527, -1662, -1753, -1485, -1017, -855, -692, -857, -2390, -1976, 822, 1091, -1049, -2580, -1834, 1302, 2307, 126, -1447, -372, 1371, 238, -1274, 327, 1352, 464, 1454, 2686, 1402, -493, -197, 780, 48, -791, -138, 1072, 573, -1832, -3091, -1946, -667, -241, -1064, -2014, -1733, -1111, -867, -697, 464, 1541, 974, 765, -96, -3004, -2025, 2299, 2306, 131, 751, 1978, 1674, 1870, 3607, 3664, 1505, 1561, 2036, -144, -828, 1379, 2340, 1546, 1333, 1347, -1023, -2155, 993, 1975, -645, -1362, 13, 506, 246, 201, -193, -254, 341, 725, 630, 184, 520, 1369, 1567, 647, -125, 1332, 3720, 4023, 2309, 1010, 1234, 2932, 4785, 4412, 2838, 1678, 1695, 3390, 4247, 3288, 1289, -203, 580, 1721, 1364, 2143, 3553, 3904, 4015, 3041, 1507, 1467, 2010, 1609, 1865, 2976, 3427, 3523, 2839, 2297, 2700, 1848, 1991, 4256, 4855, 3195, 2714, 3759, 3163, 1706, 2896, 5051, 3527, 778, 1183, 3036, 3480, 2483, 2111, 2972, 2911, 1966, 1055, 275, 1236, 2064, 248, -529, 1656, 3202, 3687, 2768, 1462, 2352, 2529, 1265, 490, 650, 1768, 2348, 1303, -796, -2854, -2375, 616, 1617, -269, -1557, -405, 1424, 711, -1111, -907, 919, 1742, 795, 843, 1171, -479, -1913, -1963, -2360, -1908, 243, 2336, 2186, 853, 1349, 2348, 1489, -327, -2303, -3743, -2253, 967, 1227, -851, -990, 902, 1426, -293, -2152, -2841, -2635, -2431, -2058, -2174, -4406, -5076, -1595, 1894, 1675, -1531, -2574, -21, 591, -786, -898, -646, 215, 1627, 1414, 190, 1334, 3914, 4323, 2175, -37, 169, 2010, 2584, 1422, 268, -1125, -1461, 422, 1279, 841, 1209, 548, -1116, -1298, -857, -854, -269, 1121, 1645, 1146, -274, -824, 711, 1938, 2978, 3083, 1792, 1833, 2640, 2795, 2716, 2154, 1782, 2956, 3759, 2980, 2938, 3885, 3236, 1017, 869, 983, -375, 368, 1585, 1277, 1725, 1901, 1008, 1640, 2583, 1055, 643, 2848, 3217, 1365, 539, 1674, 2924, 2607, 1071, 646, 1887, 2366, 2665, 3630, 2156, -726, 412, 3882, 3801, 1261, 1128, 2225, 1980, 1083, 905, 2472, 3336, 1696, 943, 1337, 675, 688, 776, -2249, -3608, -811, 1183, 729, 534, 978, 329, 683, 3348, 4191, 1718, -779, -1265, 610, 2524, 2178, 731, -454, -1256, -418, 751, -1235, -3431, -1208, 2337, 1172, -1780, -1145, 608, 187, -1698, -3410, -2350, -460, -884, -888, 257, -127, -302, 1556, 1959, -568, -2084, -243, 1318, -427, -1690, 110, 347, -732, 193, 539, -1214, -1568, -1235, -2692, -3026, -2075, -2887, -3814, -2918, -2377, -3545, -3615, -1427, -54, -357, -294, -72, -803, -1554, -1769, -2312, -2123, -753, -909, -1752, -393, 1970, 1973, 374, 1138, 4050, 3988, 250, -1000, -640, -856, 1941, 4342, 2863, 495, -715, -202, 1254, 1726, 810, -753, -1796, -2489, -3082, -2650, -2163, -1375, 113, 209, -404, -219, -540, -672, -115, -858, -1219, -1202, -1568, -46, 1778, 1532, 1456, 3187, 3999, 4064, 4085, 2797, 1128, 529, 2369, 4671, 2874, 708, 2135, 3233, 3342, 3789, 3017, 1914, 1868, 2135, 1421, -442, -45, 3139, 3697, 1197, 35, -1, 139, 1212, 2243, 3396, 4090, 2676, 1725, 4413, 7258, 5176, 2549, 4502, 6216, 5040, 3930, 2366, 1823, 3868, 4407, 2197, 786, 2065, 4405, 3640, 174, -254, 1687, 2254, 2668, 3190, 2453, 2494, 3377, 1978, -1515, -2440, 257, 2037, 2840, 4203, 3670, 2789, 3681, 3803, 2849, 3064, 2986, 1633, 1239, 1600, 1228, 1307, 2286, 2027, 1731, 3921, 4696, 2168, 2155, 3148, 413, -672, 1126, 587, -701, -552, -514, -183, 1330, 2613, 2736, 2194, 1781, 1372, 9, -340, 1617, 1996, 1104, 1097, -314, -1215, 1227, 2845, 575, -1101, 912, 2604, 790, -1817, -3074, -1846, -151, -1912, -4320, -4139, -4250, -5550, -6081, -5629, -3848, -2294, -1702, 139, 1368, 456, -95, -470, -1569, -1555, -300, 294, 275, 1685, 2630, 1084, -808, -1237, -440, -1138, -3119, -2461, -788, -1731, -2414, -394, 559, -656, -724, 1083, 1256, -1439, -4185, -4450, -2310, -1287, -2950, -3924, -2230, -420, 548, 1681, 1919, 2392, 3723, 2375, -26, 1895, 5235, 3882, 807, -22, -328, 1090, 3720, 3334, -44, -2186, -2061, -1294, -968, -1910, -2641, -1532, 557, 910, 524, 2300, 2556, 387, 431, 1754, 1543, -29, -1491, -1823, -1375, -1470, -3088, -3894, -1949, 1519, 3194, 1375, -348, 639, 1904, 1377, 421, -378, -787, -424, -709, -2015, -1956, -525, -146, -1112, -708, 1240, 2014, 1032, -922, -2334, -1740, -225, 734, 1171, 79, -1353, -550, 1121, 752, -696, -1286, -1514, -931, 958, 931, -897, 272, 3427, 3634, 1230, 1293, 3651, 4103, 2449, 824, 89, 196, 508, 733, -719, -2286, -614, 684, 8, 1369, 2882, 1648, 1675, 3266, 2550, 363, -181, 1229, 2710, 2256, 45, -1082, 1783, 5042, 2727, -1107, -665, 568, -147, -217, 88, -1191, -1568, 1643, 3397, 1396, 1786, 5047, 5206, 2798, 1696, 1885, 1614, 993, 1358, 1068, 562, 1716, 2419, 1215, 177, 108, -38, -50, 435, 332, -207, -91, -223, -1121, -670, -51, -647, -418, -597, -1819, -2776, -4286, -5426, -3869, -1655, -2593, -3215, -266, 456, -2527, -4029, -3521, -2602, -1633, -433, -715, -2031, -513, 1754, -319, -3109, -2237, -1340, -2341, -1862, 187, 2296, 4617, 5288, 2802, -431, -658, 668, 846, 1018, 673, -1727, -2970, 2, 2422, 613, 1824, 1868, 2196, 2514, 1619, 222, -443, -581, -307, -550, -1458, -2249, -2542, -2155, -2160, -2892, -3419, -3489, -3910, -4839, -5136, -4624, -4074, -3284, -2745, -3015, -2986, -2585, -2010, -1008, -399, -267, 297, 804, 578, -142, -834, -1283, -1664, -1830, -1674, -1789, -2191, -2136, -1931, -2126, -2507, -2938, -3172, -2798, -2859, -3474, -3377, -3301, -3931, -4310, -4348, -4644, -4665, -4175, -3475, -2818, -2738, -3072, -2492, -1206, -1015, -1973, -2497, -2236, -1860, -1465, -781, 169, 775, 801, 687, 47, -859, -849, -488, -923, -1533, -1446, -781, -290, -624, -1078, -1136, -710, -241, -600, -1396, -2089, -2311, -2056, -2183, -3107, -4126, -4159, -3329, -2803, -2912, -3118, -3203, -2906, -2712, -3322, -4063, -4278, -3865, -3545, -3879, -4025, -3465, -2496, -1495, -968, -766, -51, 732, 744, 327, -264, -412, 224, 894, 1077, 426, -252, -52, 347, 316, -329, -1402, -1383, -339, -362, -1320, -1689, -1550, -1609, -1688, -1736, -1826, -1458, -1169, -1097, -507, -80, -473, -588, 583, 1136, -83, -458, 426, 1047, 1674, 1952, 1450, 1400, 2592, 3362, 2811, 2362, 2894, 3419, 2673, 1447, 1300, 2440, 3250, 3017, 2831, 2607, 2533, 3389, 4249, 3982, 3229, 2956, 3745, 4786, 4490, 4197, 5862, 8546, 10552, 11105, 10693, 11124, 12366, 12995, 13462, 14449, 14782, 14066, 13931, 14425, 13997, 13853, 15182, 15884, 14801, 13657, 13646, 13639, 12989, 12238, 11379, 10594, 10320, 9467, 7476, 5739, 4835, 4648, 4678, 4118, 2587, 387, -804, -625, -1010, -2338, -3256, -3551, -4039, -4920, -6402, -8232, -8789, -8416, -8916, -10232, -11419, -11606, -10734, -9822, -10087, -11069, -10943, -9935, -9642, -9933, -10157, -10216, -10131, -9912, -9618, -9104, -8701, -8959, -8912, -8289, -8435, -9071, -9118, -9209, -9592, -10018, -10867, -11421, -11000, -11016, -11765, -11875, -11491, -11145, -10796, -10670, -10563, -9997, -8842, -7837, -7675, -7513, -6605, -5471, -4783, -4916, -5289, -5191, -4763, -4598, -5124, -5704, -5499, -5162, -5352, -5465, -5385, -5736, -6354, -6413, -6329, -6919, -8115, -9218, -9334, -9394, -10823, -12788, -13337, -12307, -11809, -12665, -13587, -13503, -12370, -11486, -11734, -11856, -11254, -10626, -10038, -10067, -10838, -11155, -10784, -10408, -9808, -9539, -10164, -10047, -8964, -8860, -9603, -9418, -8501, -8329, -8611, -8526, -8363, -8305, -8522, -9171, -10059, -10735, -10513, -9751, -9381, -9153, -8736, -8052, -7142, -6466, -6130, -5587, -4969, -4488, -4052, -4057, -4342, -4399, -4342, -4395, -4195, -3882, -3687, -3042, -2074, -1954, -2560, -2765, -2026, -1189, -1348, -1747, -2077, -2920, -3634, -4149, -4887, -5424, -5603, -5669, -5731, -5855, -5921, -5502, -4641, -4262, -4462, -4220, -3413, -2584, -1991, -1556, -1413, -1495, -1292, -724, -135, 36, 95, 592, 810, 344, -369, -980, -1255, -1297, -1608, -2288, -2601, -2392, -2318, -2370, -2767, -3669, -3968, -3327, -2538, -2087, -2145, -2137, -1721, -1578, -1695, -1727, -1375, -224, 1090, 1397, 695, -159, -185, 432, 332, -822, -1773, -1484, -651, -395, -492, -457, -279, -294, -736, -977, -820, -681, -958, -1822, -2684, -2652, -2426, -2902, -3021, -2271, -1690, -1674, -1561, -1078, -1126, -1680, -1264, 11, 492, 202, 170, 476, 551, 441, 542, 474, 169, 307, 396, -429, -1015, -461, -141, -389, -441, -649, -694, -50, 159, -632, -1233, -812, -47, 233, 17, -332, -628, -485, 34, -116, -1034, -1053, 30, 748, 527, -30, 563, 2126, 2942, 2672, 2007, 1449, 1754, 2729, 2580, 1326, 921, 1731, 2341, 2232, 1891, 1682, 1892, 2675, 3346, 3086, 2524, 2618, 3010, 2892, 1930, 517, -149, -44, 42, 200, 270, 255, 805, 1505, 1212, 274, 215, 1343, 2509, 2567, 1702, 1564, 2690, 3584, 3460, 2834, 2511, 2877, 3525, 3481, 2712, 2822, 3683, 3745, 3281, 2794, 2466, 2679, 2996, 2987, 2600, 1886, 1221, 650, -166, -907, -1518, -1860, -1403, -994, -1180, -1251, -1082, -645, 312, 742, 123, 469, 2112, 2946, 2899, 3151, 3616, 4176, 4801, 4915, 4142, 3188, 2788, 2682, 2484, 2260, 2215, 2277, 2568, 2919, 2733, 2595, 2822, 2941, 2975, 2901, 2756, 2667, 2949, 3290, 2563, 1442, 1820, 3351, 4046, 3515, 2959, 3035, 3257, 3158, 3116, 2989, 2964, 3285, 3085, 2517, 2416, 2693, 3050, 3367, 3528, 3406, 3075, 2905, 2974, 2935, 2533, 2132, 2210, 3062, 3455, 2466, 1980, 2855, 3582, 3317, 2735, 2435, 2439, 2992, 3430, 2892, 2212, 2079, 2509, 3118, 2777, 1884, 1755, 2675, 3461, 2537, 1368, 1632, 2061, 1999, 1877, 1728, 1836, 2407, 2687, 2206, 1617, 1168, 1237, 1950, 2324, 2406, 3015, 3424, 3504, 3761, 3478, 2813, 2679, 2826, 3114, 3428, 3192, 2609, 2172, 2094, 2156, 2158, 2272, 2538, 2723, 2386, 1675, 1800, 2775, 3152, 2658, 1817, 1047, 1254, 2066, 2288, 1979, 1722, 2116, 2487, 1957, 1563, 1821, 2142, 2659, 3336, 3319, 2754, 2673, 3058, 3411, 3308, 2769, 2841, 3653, 3532, 2573, 2613, 3188, 3217, 2958, 2050, 706, 232, 566, 648, 206, -275, -375, -241, -295, -471, -600, -406, 700, 2168, 2726, 2624, 3243, 4542, 4702, 3514, 2782, 3183, 3710, 4199, 4645, 4170, 3348, 3633, 4705, 4765, 4025, 3920, 4328, 4703, 4558, 3992, 3750, 3877, 3904, 3454, 2406, 1402, 1217, 1399, 1448, 1214, 456, 448, 1989, 2917, 2347, 2355, 3005, 2986, 2753, 2605, 2060, 1644, 2266, 3066, 3226, 3346, 3720, 3875, 3975, 4008, 3241, 2433, 2797, 3255, 2464, 1601, 1800, 1962, 1785, 1426, 833, 766, 1039, 1518, 2181, 2133, 1218, 662, 1040, 1706, 1998, 1796, 1528, 1423, 1521, 1534, 1558, 2000, 2451, 2674, 2644, 2165, 1942, 2446, 2780, 2526, 2081, 1830, 2028, 2273, 1841, 1359, 1660, 1832, 1487, 1260, 1004, 800, 1072, 1795, 2742, 2873, 2031, 1486, 2098, 3417, 3351, 2536, 3055, 3618, 3264, 3156, 3552, 3943, 4156, 4026, 3430, 2587, 1940, 1869, 1916, 1214, 480, 578, 1308, 2048, 1896, 994, 529, 971, 1198, -25, -1492, -1591, -736, -121, -211, 24, 968, 1658, 1844, 2202, 2969, 3351, 3432, 3889, 3951, 3197, 2742, 3120, 3501, 3203, 2927, 3535, 4284, 4772, 4751, 3504, 2498, 3172, 4037, 3887, 3080, 2174, 1988, 2335, 2249, 1757, 1546, 2002, 2456, 2179, 1526, 705, 534, 1247, 1615, 1511, 1132, 515, 718, 1701, 2087, 1793, 1748, 2516, 3724, 3954, 3148, 3236, 4322, 4792, 4497, 4228, 3929, 3970, 4337, 4180, 3692, 3232, 2878, 3171, 3910, 3754, 2494, 2215, 3662, 4362, 3186, 2396, 2744, 2784, 2400, 1914, 1369, 1000, 1178, 1746, 1443, 494, 555, 1403, 1958, 1717, 1255, 1826, 2964, 3703, 4038, 3875, 3740, 4398, 5238, 5364, 4799, 3968, 3612, 3702, 3309, 2740, 2528, 2293, 2093, 1898, 1526, 968, 205, -43, 455, 610, -281, -857, 33, 775, 411, 205, 697, 1484, 2553, 3525, 3445, 3090, 3427, 3665, 3869, 4429, 4690, 4754, 4743, 4368, 3741, 3540, 3966, 4020, 3486, 3256, 3150, 2995, 3267, 3290, 2481, 1639, 1355, 1261, 1494, 1590, 927, 655, 1313, 1330, 82, -1090, -1279, -980, -1153, -1859, -2058, -1532, -1329, -1840, -1979, -950, 674, 1957, 2301, 2102, 1907, 1757, 1813, 2356, 2813, 2505, 1929, 1763, 2518, 3411, 2852, 1633, 1746, 2225, 1396, 327, 298, 745, 912, 833, 605, 73, -331, 47, 623, 454, -160, 60, 1054, 1281, 287, -546, -129, 647, 995, 1446, 1879, 1929, 1875, 2319, 3078, 3196, 3240, 4047, 4618, 4223, 3543, 3106, 3308, 4129, 4051, 2854, 1872, 1483, 1392, 895, 85, -249, -399, -1307, -2360, -2578, -2478, -2380, -2086, -1815, -1643, -1260, -715, -58, 251, -163, -495, -20, 852, 1355, 1137, 836, 1372, 2342, 2738, 3098, 3452, 2949, 2609, 3023, 3403, 3281, 2809, 2655, 3090, 3538, 3475, 3044, 2217, 1301, 1015, 949, 690, 449, 537, 972, 610, -690, -1164, -501, -327, -849, -1126, -780, 107, 442, -681, -1589, -698, 796, 1569, 1453, 1180, 1584, 2533, 3153, 2915, 2764, 3462, 3830, 3465, 2940, 2189, 1963, 2920, 3652, 3241, 3077, 3521, 3212, 2491, 2174, 1774, 1211, 947, 1022, 948, 482, -157, -411, -139, -172, 26, 473, 40, -365, -338, -919, -1939, -2182, -1494, -891, -476, 54, 380, 830, 1452, 1180, 29, -419, 27, 191, -51, -246, -109, 749, 1677, 1409, 107, -613, -66, 765, 1073, 822, 310, -73, -103, 317, 502, -72, -141, 470, 230, -1178, -2389, -2200, -1716, -2009, -2499, -3130, -3332, -2456, -2017, -2869, -3663, -3653, -3409, -2988, -2501, -2754, -3302, -3210, -2985, -3091, -2994, -2278, -1148, -305, 122, 543, 945, 1400, 1735, 1798, 1962, 1675, 1031, 852, 712, 127, -479, -511, -206, -477, -1185, -1429, -1246, -948, -621, -661, -886, -624, 88, 458, -191, -1208, -1222, -223, 342, 18, -286, -243, -343, -380, 363, 1300, 1333, 1091, 1625, 1921, 1492, 1509, 1726, 1586, 1433, 1035, 691, 1206, 1817, 1729, 1592, 1609, 1294, 610, -36, -550, -746, -599, -308, 115, 76, -587, -880, -514, -544, -1253, -1058, 516, 1465, 1411, 1019, 429, 414, 540, -43, -522, -696, -1159, -1532, -1209, -1240, -1669, -847, 894, 2062, 2245, 1703, 1224, 1401, 1171, 96, -271, -38, 206, 1049, 1777, 1458, 625, 218, 196, -25, -557, -868, -469, 345, 601, 52, -466, -585, -459, -488, -776, -930, -359, 646, 751, 70, -485, -570, -189, 235, 421, 668, 953, 1254, 1577, 1336, 922, 1103, 1487, 1748, 1654, 1061, 930, 1255, 1130, 723, 189, -430, -910, -1026, -1073, -2043, -3532, -3910, -3492, -3478, -3910, -4348, -4459, -4435, -4152, -3598, -3807, -4286, -3360, -1670, -646, -439, -489, -243, 403, 472, -306, -594, -82, 355, 680, 842, 294, -69, 191, 301, -105, -523, -638, -844, -1098, -1697, -2343, -2157, -1891, -2092, -2046, -2060, -2721, -3096, -2700, -2565, -3441, -4191, -3597, -2673, -2391, -2293, -1977, -1363, -837, -1055, -1473, -1008, -146, 318, -4, -510, -25, 885, 1382, 1442, 1079, 906, 1578, 2221, 2156, 1390, 565, 561, 754, 428, 98, 17, -140, -271, -339, -681, -1482, -1832, -1206, -1124, -1820, -1990, -1840, -1809, -1793, -1839, -2017, -2018, -1190, -56, 186, -455, -265, 1041, 1695, 1302, 824, 979, 1676, 1945, 1120, 254, 452, 718, 125, -300, -252, -607, -974, -1081, -1366, -1800, -2258, -2600, -2565, -2393, -2587, -2852, -2687, -2219, -2202, -3287, -4689, -5173, -4785, -4220, -3898, -3370, -2466, -1981, -1782, -895, -167, -293, -109, 680, 1056, 514, 448, 1465, 1864, 1086, 192, -138, 184, 555, -76, -1633, -2535, -2071, -1220, -900, -1273, -2139, -2434, -2102, -2206, -2722, -3021, -2849, -2559, -2457, -2482, -2497, -2647, -2641, -1876, -1413, -1912, -2055, -1622, -1280, -939, -1045, -1542, -1067, 10, -149, -988, -773, 1, 139, -486, -1153, -1204, -769, -608, -1034, -1482, -1824, -2208, -2405, -2612, -3307, -3742, -3002, -2236, -2610, -3290, -3436, -3109, -2476, -1789, -2013, -3403, -4064, -3356, -2796, -2700, -2176, -1447, -1064, -1056, -1103, -999, -1068, -1204, -1225, -2396, -4714, -6020, -5068, -3230, -2781, -2997, -2240, -1343, -1510, -2684, -4420, -5406, -4367, -3055, -3118, -3491, -3156, -2492, -2243, -2533, -3081, -3301, -3083, -2950, -3207, -4054, -4563, -3616, -2499, -2819, -3606, -3691, -3468, -3117, -2947, -3674, -4231, -3750, -2963, -2227, -2024, -2114, -1526, -227, 440, -44, -474, -111, 247, -124, -861, -1522, -1811, -1613, -1239, -1190, -1661, -2072, -1755, -898, -695, -1868, -3280, -3817, -4099, -4684, -5242, -5651, -5594, -4616, -3395, -3284, -4032, -4112, -3382, -2875, -3598, -4676, -4188, -2944, -2607, -2894, -2707, -2037, -1461, -1126, -1065, -831, -414, -565, -1387, -1909, -1891, -1914, -1706, -1272, -1610, -2261, -2305, -1527, -218, 43, -1632, -3191, -3148, -2668, -3138, -4208, -4322, -3294, -2506, -2235, -2023, -2102, -2258, -1920, -1754, -2301, -2368, -1773, -1187, -426, 120, -107, -215, 535, 1056, 183, -1445, -2352, -2273, -1914, -1794, -2012, -2078, -1323, -492, -989, -1804, -1658, -1863, -2445, -2714, -3447, -4413, -4255, -3261, -2727, -2668, -2314, -1305, -156, -238, -1520, -2041, -1431, -1251, -1592, -1462, -1099, -977, -607, -19, -31, -370, -134, 621, 835, -458, -1851, -1963, -1631, -1424, -1518, -2025, -2330, -2015, -1397, -1204, -1853, -2097, -1214, -995, -2168, -2933, -2787, -2484, -2063, -1767, -1676, -1218, -554, 69, 517, 60, -512, -71, 201, -210, -492, -787, -987, -662, -241, 139, 167, -91, 597, 2180, 2227, 610, 314, 1208, 1228, 293, -665, -1156, -1092, -842, -1345, -2385, -2381, -1291, -802, -1752, -3227, -3778, -3535, -3443, -3364, -3391, -3827, -3658, -2697, -2422, -3137, -3256, -2745, -2733, -2555, -2139, -2034, -1966, -2013, -2119, -1869, -1920, -2196, -1959, -1494, -1402, -1696, -1712, -1317, -759, -84, 61, -556, -806, -576, -837, -1056, -695, -568, -1030, -1325, -1242, -1309, -1222, -723, -518, -1221, -2283, -2366, -1323, -393, -569, -980, -840, -669, -648, -786, -747, -255, -5, -331, -664, -721, -1144, -1434, -704, -42, -224, -454, 18, 612, 230, -800, -1171, -392, 604, 495, -281, -156, 462, 310, -256, -661, -906, -390, 826, 1358, 1064, 530, 261, 315, 316, 153, -413, -1112, -1057, -751, -1004, -1100, -114, 843, 492, 49, -312, -965, -877, -391, 164, 569, 353, 776, 1898, 1981, 1194, 981, 1115, 1053, 926, 736, 298, 277, 1246, 1300, -432, -1961, -2041, -1502, -1728, -2521, -2722, -2558, -2892, -3508, -3356, -3291, -4437, -5015, -4234, -3580, -3277, -2637, -1769, -871, -286, -410, -304, 372, 506, 376, 673, 1071, 1379, 1668, 1929, 1939, 1792, 1820, 1896, 1571, 1140, 988, 812, 935, 1090, 292, -935, -926, -85, -560, -2069, -2643, -2341, -1791, -1498, -1925, -2474, -2724, -2609, -2124, -1600, -1595, -2147, -2001, -1062, -875, -1037, -220, 889, 1315, 1392, 1691, 2194, 2223, 1816, 1360, 729, 630, 1515, 2550, 2706, 2143, 1955, 2084, 1814, 1460, 1094, 468, 352, 445, -160, -1215, -1799, -1502, -874, -763, -1345, -1860, -1989, -1891, -1569, -1545, -1884, -1609, -783, -579, -1371, -2013, -1601, -1203, -957, -451, -360, 126, 1377, 1853, 1388, 1000, 916, 1657, 2735, 2755, 2156, 2004, 2372, 2401, 1621, 753, 428, 767, 1340, 928, -437, -1058, -525, 312, 214, -988, -1640, -1194, -566, -590, -1463, -1923, -1220, -644, -920, -1428, -1531, -1515, -1573, -1014, -240, -95, -275, -434, -171, 497, 644, 399, 746, 1243, 735, -100, 210, 921, 771, -129, -1125, -1347, -880, -344, 98, -598, -2111, -2390, -2088, -3171, -4934, -5716, -5436, -4898, -4556, -4340, -4102, -3471, -2187, -939, -917, -1503, -1079, -48, 380, 567, 1137, 1667, 1896, 2021, 2380, 2565, 1866, 1405, 2011, 2080, 1179, 965, 1249, 1217, 1277, 1027, 255, 84, 608, 522, -395, -1079, -796, -234, -85, -353, -720, -376, 593, 1170, 1061, 902, 1238, 2098, 2730, 2667, 2512, 2558, 2812, 3450, 3527, 2511, 1979, 2344, 2560, 2232, 1648, 1745, 2168, 1443, 537, 955, 1231, 1018, 1521, 1415, 373, 536, 1402, 1197, 278, -299, -321, 60, 622, 579, -382, -1043, -463, 180, 184, -49, -160, 427, 985, 591, 63, -251, -539, -79, 1133, 1519, 1109, 1410, 2328, 2894, 2820, 2683, 2960, 3450, 3693, 3414, 3190, 3588, 4175, 3949, 2995, 2266, 2065, 2527, 2850, 2528, 2059, 1450, 1330, 2054, 2346, 1454, 244, 254, 952, 1026, 779, 580, 765, 1516, 1967, 1961, 2340, 2931, 3325, 3429, 2865, 1918, 2041, 3270, 3622, 3267, 3525, 3700, 3275, 3018, 2905, 2484, 1908, 1654, 1723, 1574, 951, 552, 1472, 2770, 2569, 1265, 281, -206, -769, -1220, -1531, -2078, -2172, -1219, -33, 303, 83, 351, 1069, 1469, 1432, 1588, 1793, 1785, 1819, 1665, 1311, 1560, 2515, 3249, 3373, 3132, 2926, 3217, 3718, 3463, 2677, 2354, 2496, 2263, 1999, 1956, 1623, 1235, 802, 131, -499, -742, -306, 458, 928, 679, 188, 725, 1854, 2127, 1206, 179, 633, 1639, 1376, 1124, 1725, 2339, 3008, 3287, 2717, 2416, 2763, 2514, 1411, 782, 1307, 1944, 2035, 1813, 1505, 1159, 1016, 1616, 2223, 1466, 101, -260, 244, 377, 103, -152, -435, -72, 846, 1025, 387, 74, 595, 1113, 1021, 787, 878, 1545, 2674, 3217, 2482, 1291, 998, 1541, 1740, 1586, 1647, 1940, 1990, 1670, 1762, 2096, 1691, 1403, 2271, 3037, 2972, 2590, 2419, 2785, 3000, 2507, 2007, 2288, 2686, 2327, 1695, 1616, 1968, 1989, 1210, 408, 960, 1973, 2115, 1981, 1852, 1799, 1927, 1604, 877, 702, 840, 563, 752, 1474, 1396, 1083, 1787, 2994, 3606, 3431, 2593, 1702, 2648, 4455, 3995, 2247, 1784, 2425, 2956, 2962, 2494, 2076, 2272, 2386, 1814, 1205, 491, -215, -383, -690, -1496, -1667, -609, 546, 662, -213, -858, -758, -687, -1061, -1420, -1616, -1487, -390, 948, 1467, 1567, 1875, 2323, 2507, 2155, 1845, 2099, 2171, 1705, 1342, 1205, 1372, 1983, 2259, 1893, 1533, 1538, 1689, 1620, 914, -111, -279, 78, 251, 90, -362, 51, 1086, 1118, 522, 755, 1224, 1053, 1086, 1142, 1139, 2012, 2998, 3238, 3246, 3745, 4361, 4249, 4056, 4121, 3767, 3665, 4399, 4807, 4461, 4268, 4252, 4060, 3868, 3607, 3216, 2643, 2075, 2264, 2606, 2259, 1512, 926, 1170, 1473, 816, -273, -376, 747, 1342, 623, 161, 777, 1399, 1532, 1577, 1788, 2017, 2042, 2002, 2070, 2014, 1779, 2079, 3057, 3782, 3505, 2735, 2623, 2586, 1374, 253, 646, 1079, 948, 1074, 1152, 1089, 1509, 2056, 1528, 412, -282, -427, 248, 696, 139, -73, 558, 993, 1422, 1997, 1227, -35, 363, 1638, 2071, 1541, 1243, 1689, 2127, 1942, 1086, 279, 18, 456, 1319, 1693, 2006, 2857, 3429, 3291, 2941, 2550, 2000, 1544, 1659, 1612, 1236, 1786, 2411, 2277, 2163, 1470, 311, 269, 1024, 965, 68, -186, 271, 680, 1009, 1305, 1279, 801, 424, -156, -1213, -1560, -1377, -1232, -1068, -1260, -1353, -987, -640, -357, 64, 409, 928, 2256, 2756, 1271, 367, 1062, 1614, 1624, 1571, 1549, 1982, 3009, 3638, 3150, 2939, 3814, 4240, 3760, 3246, 2508, 1901, 1932, 1895, 1506, 1006, 709, 422, 40, -300, -1071, -2150, -2474, -2294, -2645, -3036, -2646, -1478, -255, 65, -330, -165, 543, 839, 708, -12, -763, 133, 1888, 2154, 1490, 1575, 1803, 1264, 959, 1039, 639, 479, 862, 865, 370, -210, -454, -420, -479, -622, -801, -513, 451, 1409, 1784, 1873, 2427, 3053, 2856, 2466, 2168, 1547, 1467, 2115, 2468, 2519, 2945, 3872, 4148, 3439, 3037, 2959, 2579, 2836, 3655, 3170, 1812, 1581, 1972, 1769, 1072, 180, -45, 454, 225, -581, -659, -253, 281, 1122, 953, -324, -342, 1029, 1759, 1285, 441, 67, 404, 818, 593, 273, 678, 1482, 2066, 2113, 1904, 2171, 2977, 3877, 4004, 2824, 1424, 719, 592, 766, 566, 457, 922, 801, 231, 7, -400, -579, -146, 146, -146, -665, -88, 1495, 2108, 1236, 726, 1404, 1716, 1544, 1868, 1936, 1718, 1886, 2072, 2079, 1853, 1303, 609, 4, -453, -974, -1392, -1559, -1349, -670, -432, -598, -226, 824, 1933, 2101, 1520, 1432, 2024, 2847, 3345, 3702, 4855, 6182, 6438, 5289, 3423, 2026, 1197, 340, -271, -1140, -2596, -3169, -2343, -2210, -3575, -4000, -3246, -3191, -3587, -4205, -4980, -5036, -4467, -4213, -3897, -2721, -1297, -126, 666, 1131, 1494, 2222, 3187, 3116, 2468, 2928, 3362, 2585, 2103, 1533, 125, -274, 281, -383, -2174, -3074, -3086, -2882, -2180, -1887, -2610, -2922, -2028, -918, -433, -470, -839, -1051, -860, -909, -1284, -1431, -935, -529, -854, -921, -362, 447, 1672, 2540, 2198, 1653, 2188, 3049, 2638, 1365, 492, 595, 1292, 1426, 320, -552, 368, 1297, 752, -52, -143, 142, 21, -287, -190, -322, -1086, -1356, -845, -1053, -2075, -2095, -901, 7, 458, 499, 375, 1107, 1610, 389, -1119, -1163, -302, 417, 909, 1240, 1490, 2269, 2921, 2171, 671, -11, 565, 1344, 1351, 472, -92, 674, 1022, 114, -581, -617, -249, 543, 1303, 1159, 415, -50, 35, 24, -834, -1720, -1352, -436, -257, -608, -1479, -2423, -2120, -1023, -510, -581, -676, -711, -387, 309, 273, -342, -185, 765, 743, -584, -996, -127, 524, 381, -650, -1773, -1487, -587, -672, -1765, -2930, -3090, -2619, -2403, -2286, -2111, -1913, -1704, -1824, -2061, -2193, -2256, -2194, -2161, -1974, -1608, -1212, -781, -552, -604, -460, 50, 382, 539, 449, -79, -478, -374, -321, -1098, -2604, -3315, -2687, -2270, -2831, -3578, -3736, -3052, -1780, -1140, -1687, -1961, -1315, -681, -712, -947, -1190, -1312, -421, 897, 1001, 495, 453, 481, 792, 3612, 4426, 5464, 4859, 4171, 4415, 3892, 2620, 2696, 3331, 2491, 1662, 1435, 765, 1129, 1819, 1258, 776, 708, 106, -131, 658, 1321, 1717, 2274, 2572, 2744, 2824, 3231, 4519, 4765, 3222, 2259, 2302, 2215, 1963, 2064, 2350, 2496, 2579, 1666, 861, 1790, 2674, 2278, 1937, 2556, 2599, 1979, 1492, 1027, 826, -142, -1760, -1707, -121, 435, -419, -353, 1156, 1732, 1407, 1628, 2408, 2959, 2260, 1878, 2782, 2745, 1842, 2006, 2602, 2298, 2061, 2826, 3209, 2892, 3064, 2849, 1901, 1766, 1942, 1366, 1238, 1564, 1595, 1781, 1795, 1263, 666, 227, 465, 2166, 3870, 3804, 3541, 3680, 3569, 3460, 3148, 2108, 1487, 1884, 1993, 1380, 852, 1081, 1709, 1615, 1092, 773, 435, 350, 1242, 2534, 2343, 1306, 1819, 3077, 3454, 2993, 2395, 2445, 2577, 2287, 2165, 1880, 1123, 1033, 1755, 2257, 2342, 2583, 2605, 1792, 1115, 1236, 1373, 767, 221, 404, 1048, 1624, 1793, 1098, 13, 270, 1042, 1172, 1200, 492, -345, -39, 212, 202, 793, 952, 935, 1697, 2092, 2239, 2829, 3345, 3126, 2173, 1474, 752, 464, 1869, 3276, 3010, 1781, 666, 777, 2066, 3506, 4116, 2836, 1101, 1309, 2610, 2791, 1804, 991, 1367, 2691, 4024, 4620, 3992, 3263, 3622, 4577, 5331, 5754, 5890, 5419, 4371, 4524, 5840, 6343, 6332, 6465, 5961, 4881, 4870, 5617, 5317, 4692, 4737, 4561, 3977, 3547, 3407, 3257, 2413, 977, 348, 459, 65, -492, -784, -918, -1321, -1741, -1323, -441, -468, -1717, -2455, -1630, -634, -1170, -2551, -2648, -2221, -2808, -3064, -2248, -1787, -1768, -1354, -1390, -1038, 184, -65, -1180, -1706, -1953, -2106, -2397, -2213, -2050, -2978, -3341, -3107, -3199, -2962, -2995, -4033, -5410, -5668, -4336, -3316, -3735, -4501, -4774, -4055, -3465, -3631, -3396, -3183, -3558, -3932, -3854, -3534, -2801, -2204, -3087, -3699, -2853, -2542, -2251, -1736, -2066, -1917, -1729, -2243, -1990, -948, -1110, -2293, -2608, -2284, -2772, -3922, -4362, -4677, -6124, -7373, -7229, -6349, -5305, -4528, -4572, -5247, -5194, -4878, -4989, -4919, -3872, -2196, -2157, -4166, -5525, -4945, -4134, -4383, -5342, -6109, -5705, -5243, -5665, -5890, -5313, -4313, -4033, -5158, -6717, -6649, -5302, -4486, -4248, -4683, -5306, -4991, -4310, -4338, -4658, -4858, -5231, -5990, -6102, -5160, -4490, -4544, -4838, -4770, -4389, -3612, -2391, -2605, -3544, -2725, -1992, -3017, -3922, -3517, -2476, -2103, -2929, -3224, -1929, -1169, -1639, -2475, -3918, -4380, -2890, -2176, -2781, -3189, -3629, -3926, -3826, -3843, -4487, -5905, -6985, -6491, -5448, -5145, -5279, -4481, -2707, -1801, -2612, -3681, -3780, -3136, -2431, -2020, -1501, -685, 23, -235, -1034, -1118, -695, -603, -587, -821, -2281, -3770, -4026, -3704, -3561, -4015, -4074, -3204, -2880, -3308, -3478, -2421, -1290, -1564, -2044, -1874, -2343, -2843, -2358, -1951, -1742, -1345, -1583, -1959, -1463, -1860, -3176, -3266, -2887, -2905, -3090, -4227, -5772, -5773, -4106, -3686, -5829, -8189, -7945, -5659, -5198, -6115, -5841, -5896, -6527, -5481, -4739, -6121, -6706, -6074, -5897, -5771, -5684, -5487, -5409, -6205, -5994, -4649, -4020, -4075, -5142, -6323, -5914, -5350, -5416, -5394, -5581, -5289, -4525, -4793, -4962, -3974, -4036, -5539, -5237, -3528, -3608, -4678, -4684, -4578, -5273, -5092, -4288, -4554, -4862, -4840, -5029, -4634, -4281, -4769, -5060, -4416, -4203, -4873, -4401, -3291, -3648, -4107, -3881, -4006, -3763, -3192, -3891, -4297, -3238, -3604, -5155, -4111, -2590, -3989, -5484, -4695, -3625, -3681, -3255, -2157, -2561, -3774, -3119, -2359, -3209, -3719, -3745, -4317, -4202, -3070, -2933, -4242, -5128, -5011, -4688, -4673, -4688, -4313, -3590, -3077, -2774, -2694, -3479, -3986, -3354, -3097, -3275, -3348, -4053, -4189, -3205, -3082, -4216, -4641, -4017, -3422, -2731, -2464, -2900, -3533, -3856, -3004, -2188, -2693, -3379, -4003, -4728, -4652, -4472, -5026, -4684, -3689, -3717, -3955, -3921, -4253, -4019, -3113, -3201, -3707, -2688, -1646, -2173, -2543, -2220, -2040, -1425, -1404, -3012, -4153, -4185, -4454, -4453, -3535, -3026, -3029, -2476, -1806, -1342, -1920, -3501, -3799, -2676, -2347, -3129, -3871, -4089, -3945, -3778, -2761, -1280, -1168, -1647, -2272, -3417, -3704, -2558, -1982, -3009, -3660, -2879, -1846, -2178, -3551, -3866, -3638, -3671, -2820, -1632, -1448, -1651, -1122, -784, -1858, -2883, -2038, -625, -333, -603, -1224, -2248, -3200, -3487, -2601, -2143, -2482, -2366, -2352, -2418, -2229, -1979, -1654, -1464, -1631, -2293, -2463, -1368, -698, -1979, -3409, -3752, -3890, -3878, -3493, -3156, -3017, -3831, -4505, -2794, -1296, -2526, -3658, -2851, -1697, -1580, -1814, -1729, -1676, -1443, -249, 517, -953, -2967, -2878, -1272, -1007, -2223, -3124, -3599, -4001, -3978, -3474, -3728, -4456, -3944, -2542, -2237, -2330, -1785, -2393, -3392, -2859, -2447, -2674, -1623, -587, -1189, -1637, -1415, -776, 189, -76, -1064, -1173, -734, -131, -330, -1565, -1650, -1046, -570, 769, 1174, -283, -953, -346, 86, -351, -1290, -1558, -1345, -2515, -4186, -3458, -2052, -2057, -2091, -1788, -1883, -1882, -882, -381, -1611, -2220, -1111, -403, -551, -350, 75, 268, 740, 1539, 1720, 1869, 2147, 1625, 708, 591, 635, 23, -19, 616, 593, 201, 147, 450, 958, 0, -2253, -2981, -2239, -2649, -3198, -2569, -2352, -2874, -2727, -1994, -2361, -2365, -521, -862, -3620, -4028, -2582, -1315, -821, -1060, -581, -272, -897, -879, 98, 317, -577, -947, -743, -238, 353, 39, -862, -833, -34, 306, 232, -613, -1669, -1064, -571, -2518, -4121, -2931, -1475, -1305, -2151, -3288, -2303, -381, -539, -1684, -1598, -341, 597, 350, 222, 788, 709, -9, -599, -1090, -1527, -1436, -1672, -2362, -1926, -1316, -1608, -1646, -1416, -2155, -3142, -3006, -2736, -2585, -1877, -1190, -641, 513, 1487, 1169, 502, 1465, 3189, 3271, 2158, 2101, 2494, 1932, 1347, 408, -1463, -2976, -2297, -646, -731, -1287, -1164, -1404, -1916, -2880, -3895, -3880, -2877, -2797, -3427, -1842, -597, -2249, -3197, -2257, -1546, -1604, -1661, -1129, -543, -307, 349, 1175, 1665, 1289, -5, -900, -550, 85, 286, -5, -817, -758, 73, 15, -611, -1057, -1559, -1438, -504, -605, -1530, -1261, 286, 889, -812, -2649, -1800, -242, -1045, -2021, -2057, -1966, -867, 485, 283, -808, -774, -320, -1296, -2145, -2234, -2792, -3002, -2512, -2177, -2041, -1411, -53, 540, -346, -514, 304, 767, 821, 1084, 1316, 432, -626, -789, -967, -1118, -733, -634, -672, 41, 1328, 1521, 212, -335, 290, -21, -1552, -1781, -610, -605, -1182, -118, 166, -1567, -2250, -1494, -1107, -1358, -1433, -732, -620, -1702, -452, 2113, 1357, -859, -1274, -118, 1168, 1358, 778, 117, 136, 1302, 1309, -466, -1832, -1722, -1446, -1775, -1390, -1092, -1704, -2059, -1718, -890, -182, -38, -740, -844, 322, 580, 126, 594, 344, -931, -902, 50, 375, -127, -676, -886, -790, -631, -1052, -1385, -785, -440, -1114, -1789, -1816, -1466, -984, -334, 81, -38, -252, -297, 251, -84, -1006, -41, 217, -1090, -831, 56, -548, -656, 243, -435, -2146, -1662, -524, -1438, -2349, -2240, -2331, -1457, -189, -607, -998, 250, 1764, 1412, 239, 82, -44, -39, 674, 826, 589, 10, -288, 921, 1796, 513, -1179, -828, 192, -523, -824, 219, 281, -928, -1440, -524, -60, -428, -965, -1940, -1236, 541, 560, 203, 1026, 1257, 689, 1038, 1423, 1163, 1528, 2075, 1702, 1502, 1734, 1019, 169, 548, 451, -587, -1176, -1486, -1710, -1332, -557, -781, -1504, -1462, -1156, -1311, -1516, -870, -162, 294, 247, -437, -854, -602, -138, -14, 262, 518, 650, 865, 768, 500, 186, -234, -408, -57, 314, 1094, 2188, 1584, 323, 776, 1887, 2062, 1651, 1626, 1228, -327, -1043, 692, 1949, 1244, 978, 1035, 964, 1329, 1400, 458, -830, -1235, -1462, -1587, -918, -847, -1429, -575, 1042, 1264, 623, 220, 268, -324, -1875, -2674, -2351, -1651, -935, 5, 809, 807, 494, 1293, 1888, 309, -1022, -201, 883, 546, -558, -684, 487, 569, -419, -230, 579, 1501, 2086, 935, -671, -1080, -566, -124, -725, -1008, 332, 1418, 416, -431, 507, 1481, 1637, 779, -55, 570, 1294, 1332, 1105, 647, 787, 1135, 427, -306, 283, 302, -176, 590, 1323, 1289, 1343, 1373, 778, -255, -323, 875, 1489, 612, 142, 1033, 2443, 3529, 3843, 3656, 3359, 2266, 1314, 2695, 3675, 2123, 932, 1534, 1995, 1238, 1080, 1707, 1020, 122, 1081, 1955, 649, -964, -1176, -670, -65, 200, -288, -1081, -741, 547, 633, 62, 659, 2098, 2706, 2073, 2183, 2705, 2311, 1513, 854, 866, 1213, 1452, 1741, 1826, 2154, 2603, 2002, 1166, 1052, 1365, 1290, 674, 890, 1286, 288, -698, 262, 1771, 1727, 764, 365, 1218, 2605, 2752, 1555, 642, 582, 514, 49, -18, 210, -11, -260, -503, -1076, -1498, -1087, -463, -299, 208, 752, 685, 413, -247, -544, -31, -255, -1707, -2433, -1149, -354, -1383, -1699, -1156, -1230, -870, 541, 629, -634, 190, 2269, 2173, 1787, 2805, 3805, 4218, 4045, 3760, 3660, 3183, 2607, 2213, 1318, 180, 189, 1274, 1844, 1740, 1366, 1226, 2337, 3887, 4296, 3402, 2644, 2512, 2325, 2304, 2550, 2655, 2279, 1990, 2882, 3922, 4002, 3948, 3769, 3445, 3118, 2800, 2375, 1768, 2161, 3109, 3129, 3312, 4391, 4849, 4872, 5389, 4713, 3300, 3472, 4059, 3862, 3778, 3626, 3120, 2319, 1631, 2087, 2179, 986, 957, 994, 112, 397, 663, 0, -168, -77, -387, -655, -687, -1027, -2068, -2264, -900, -77, -343, -497, -10, 706, 465, -76, 302, 1149, 1884, 2274, 2351, 2684, 3371, 3637, 3081, 2277, 1678, 1563, 2144, 2448, 2231, 3019, 3376, 2147, 2366, 3725, 3359, 2671, 2945, 2518, 1726, 2182, 2673, 1423, -228, -61, 864, 606, 312, 761, 747, 637, 1215, 1103, 667, 1840, 2509, 1182, 465, 1256, 1416, 1067, 1550, 1901, 1600, 1021, 1207, 2378, 2768, 1565, 1131, 2725, 3629, 3215, 3538, 3523, 2775, 3054, 3617, 3069, 2799, 3479, 3495, 2798, 2701, 3147, 3092, 3260, 4009, 4229, 3654, 3326, 3379, 3051, 2697, 2492, 1531, 230, 141, 640, 851, 1281, 1780, 1845, 2139, 3411, 3199, 894, 692, 2638, 3994, 3839, 2896, 2759, 3283, 3426, 2843, 2385, 2780, 2187, 526, 400, 1438, 2149, 2725, 2891, 2709, 3150, 3029, 1622, 1295, 2866, 3664, 2564, 1537, 1766, 2490, 2393, 1511, 1456, 2625, 2607, 1321, 1497, 2469, 2072, 1543, 2606, 3726, 3274, 2177, 2247, 3360, 3326, 1926, 1447, 2602, 3572, 3326, 2829, 2790, 2730, 2114, 1533, 2104, 3350, 3253, 1833, 892, 1097, 1106, 683, 870, 1438, 1579, 1209, 1730, 3386, 4176, 3483, 2654, 2553, 2561, 2137, 1456, 1404, 2171, 2296, 2629, 3768, 4649, 4910, 4167, 3088, 3037, 3358, 2880, 1642, 931, 1586, 2242, 2515, 3367, 3474, 2117, 1312, 1576, 1540, 1391, 1332, 755, 1010, 2143, 2482, 1732, 1123, 1281, 1084, 248, -18, 371, 858, 1270, 1033, 841, 1576, 2487, 3326, 3416, 2294, 1848, 1916, 594, 108, 1765, 2506, 2185, 2496, 2882, 3589, 4784, 5024, 4147, 3397, 2276, 987, 1023, 2148, 2962, 2631, 2388, 2926, 2867, 3518, 4755, 3493, 1465, 1473, 2211, 2137, 2051, 1896, 2066, 3624, 4456, 3430, 2518, 2809, 3215, 1918, 295, 466, 1276, 1919, 1874, 854, 793, 2445, 3644, 3718, 3728, 3979, 4468, 5050, 4816, 3595, 2507, 2273, 2529, 2216, 1731, 1915, 2000, 2343, 3325, 2631, 750, 169, 503, 1060, 1292, 651, 626, 2125, 3309, 2833, 2134, 2731, 3207, 2363, 1274, 1151, 1988, 2424, 2592, 3647, 3965, 3164, 3286, 3718, 3298, 2615, 2141, 1787, 1851, 2046, 1578, 508, -294, 86, 1368, 2151, 1330, -263, -527, 252, 800, 1127, 432, -58, 1229, 2845, 3178, 2564, 2785, 3815, 3374, 1659, 1188, 2081, 2716, 2276, 1939, 2872, 3541, 3687, 4154, 4030, 3459, 2793, 2295, 3525, 4371, 2705, 1692, 2444, 2815, 2144, 1798, 2212, 2867, 3100, 2550, 1879, 1284, 122, -337, 824, 1190, 34, 71, 1649, 1733, 1001, 1252, 1669, 1663, 1021, 462, 693, 1618, 1923, 1224, 1713, 2804, 2550, 2001, 1870, 2031, 2462, 2107, 1200, 700, 123, -259, 510, 1287, 1553, 2184, 2606, 2456, 1971, 1738, 2006, 1835, 1870, 2022, 1167, 1076, 1330, -62, -348, 1582, 1551, -272, 538, 2921, 3233, 1487, -277, -123, 1222, 1650, 1773, 1602, 636, 430, 699, 332, 134, 761, 1391, 1336, 1345, 1761, 1559, 1275, 2169, 2447, 1447, 1607, 2276, 1706, 1298, 1998, 1976, 59, -1209, -519, 23, 351, 747, 665, 340, -277, -267, 723, 807, -57, 35, 337, 114, 344, 817, 753, 648, 1831, 2910, 1723, 684, 1607, 1239, -317, 226, 1780, 1507, 595, 1378, 1892, 734, 279, 1163, 1494, 1108, 1344, 873, -618, 7, 1471, 756, -131, 719, 1417, 942, 434, 378, 915, 2067, 2123, 582, 8, 1130, 2260, 2405, 2070, 1516, 807, 1022, 1327, -466, -1956, 167, 2128, 709, -543, 153, 948, 987, 687, 654, 1271, 1800, 1477, 1069, 1461, 2384, 2686, 2131, 1315, 612, 1120, 1903, 1450, 1500, 2162, 2248, 2355, 2898, 2843, 1400, 610, 1329, 1211, 237, 115, -26, -1335, -2096, -1053, 149, 342, 477, 419, -525, -1274, -881, -119, 83, -124, -144, 638, 1940, 2654, 2830, 2692, 2000, 1037, 697, 65, -1800, -2428, -1461, -982, -502, 394, 208, -1075, -858, 277, -829, -1982, -1783, -2487, -2967, -1493, 25, -45, -475, -119, 445, -11, -100, 1146, 1316, 19, -509, 224, 747, 312, -720, -1138, -348, 509, -105, -1227, -883, 520, 1075, -49, -1229, -918, -72, -582, -1588, -1243, -1204, -1918, -1239, 29, 291, -470, -1215, -1025, -609, -867, -982, -783, -1288, -2080, -1688, -414, 393, 743, 854, 383, -49, 696, 1397, 801, 1385, 2612, 1723, 1188, 1535, 157, -689, 318, 626, -736, -2025, -1369, -691, -1390, -1002, -3, -865, -2729, -3309, -1797, -169, -550, -1712, -1688, -1085, -1209, -1059, -102, -180, -999, -1885, -2600, -1627, -655, -1373, -1394, -586, -1335, -2479, -2349, -1828, -1724, -1805, -684, 811, 1365, 2089, 2157, 1265, 1103, 946, 277, 395, 660, 976, 1859, 1822, 557, 44, 863, 1182, 346, 412, 1254, 742, -462, -1122, -1126, -157, 302, -247, -340, -685, -1055, 423, 2190, 1888, 411, -830, -1336, -1176, -1410, -1536, -800, -218, 47, -49, -218, 309, 1021, 1365, 809, -1322, -3040, -2260, -632, 14, -512, -669, -171, -287, -58, 65, -1434, -2194, -1276, -1779, -3281, -3106, -2481, -3349, -3564, -1976, -1410, -2311, -2578, -1837, -1388, -1886, -1617, 668, 1531, -798, -2002, -437, 1011, 1261, 672, -124, -411, -713, -1007, -819, -802, -1425, -1763, -845, 36, -770, -1946, -1935, -1178, -965, -1698, -2034, -1819, -2613, -2984, -2111, -2346, -2996, -2335, -2070, -2969, -3634, -3546, -3140, -2256, -1629, -2075, -1716, -1216, -2087, -1824, -686, -532, -18, 191, -1006, -1124, -151, -861, -2016, -1379, -1323, -3483, -4625, -3956, -3701, -3972, -3978, -3955, -4419, -4943, -5055, -4664, -4071, -3975, -4046, -3855, -3482, -3024, -2765, -2477, -2099, -2591, -3172, -3064, -3723, -4090, -3393, -3747, -5110, -5104, -3996, -3694, -3432, -2220, -1785, -2705, -2251, -671, -970, -2126, -2804, -3425, -3616, -3039, -2458, -2932, -3394, -2796, -2126, -2230, -2346, -1965, -2224, -2159, -850, -986, -2549, -3415, -3597, -3718, -3662, -2972, -2338, -2721, -2757, -2023, -1947, -1762, -752, -1355, -2960, -2385, -1332, -1705, -1293, -722, -1750, -2024, -1245, -1570, -2361, -1895, -1117, -2317, -3757, -2875, -2014, -2513, -2709, -2702, -2212, -657, -772, -2685, -3261, -3674, -4647, -4182, -3038, -2638, -2721, -2666, -2201, -2100, -1833, -814, -372, -928, -975, -545, -855, -873, -834, -1985, -2458, -1100, -710, -1329, -1725, -1983, -849, -504, -2167, -2628, -2152, -1759, -1070, -1042, -1406, -1200, -1604, -2831, -3759, -4100, -3492, -2919, -3567, -3814, -2889, -3058, -4105, -3993, -2585, -1564, -2426, -3250, -2954, -3297, -3245, -2095, -1811, -1674, -1011, -1468, -2160, -1880, -1594, -890, -1483, -4427, -5097, -2762, -1907, -2779, -3304, -3383, -3362, -3262, -2381, -1507, -2070, -2961, -3570, -3933, -3559, -3971, -5335, -5014, -3682, -3598, -3552, -2488, -2063, -2638, -3355, -3367, -2376, -1771, -2291, -3224, -3665, -3004, -1601, -1097, -2120, -2785, -2682, -2813, -2942, -3495, -4169, -3853, -3143, -2284, -2115, -3030, -3054, -2394, -2601, -3186, -3510, -3104, -2012, -1996, -2864, -3025, -3144, -3241, -2205, -1584, -2748, -3212, -1649, -865, -1708, -2618, -2744, -2027, -1545, -2434, -3768, -3613, -2530, -2264, -2639, -2535, -1820, -1185, -435, -53, -506, -718, -1011, -1641, -1886, -2194, -2496, -2238, -1599, -1362, -2101, -2751, -2719, -2570, -2074, -2424, -3843, -4088, -3446, -3117, -2941, -2891, -2763, -1563, 3, -489, -2559, -3981, -4133, -4334, -4933, -4377, -3119, -2302, -1321, -174, 151, 306, 589, -353, -1515, -1847, -2361, -2309, -1784, -1995, -1767, -856, -1097, -1890, -1795, -1732, -1732, -1590, -1989, -2465, -2608, -2693, -2569, -1857, -1533, -1458, -863, -713, -1138, -1066, -1157, -2116, -2140, -1372, -1387, -1612, -1709, -1446, -691, -292, -1245, -2487, -1713, -185, -474, -1024, -341, -38, -807, -1440, -1529, -1331, -1387, -2013, -2761, -3459, -3475, -2077, -1198, -2234, -2869, -1727, -1433, -2743, -3522, -3152, -3008, -3808, -3573, -2555, -2345, -2177, -1773, -1887, -2695, -2839, -1656, -1021, -2883, -4697, -3434, -1633, -1412, -966, 361, 670, -341, -1623, -2437, -2066, -1281, -1174, -1599, -1880, -1614, -858, -255, -386, -1249, -2190, -2091, -749, 183, -919, -2476, -1945, 18, 532, -749, -1537, -1558, -1482, -1047, -545, -70, 708, 697, -452, -1460, -1872, -2266, -2629, -2433, -2550, -2863, -2233, -1508, -1155, -518, 425, 564, 94, 235, 118, -882, -1361, -925, -535, -644, -724, -986, -1632, -1964, -1865, -730, 483, -544, -1793, -982, -619, -1634, -1502, -1394, -2582, -2370, -1169, -1663, -1713, -216, -1376, -4404, -4808, -3488, -2005, -591, -158, 236, 1528, 2379, 1697, 572, -11, -297, -67, 853, 850, -49, -160, -101, -71, 1023, 2014, 2371, 2599, 2036, 1228, 977, 214, -561, 444, 1384, 238, -1416, -946, 773, 651, -471, -782, -973, -1431, -1253, -1038, -1401, -2078, -3309, -3809, -2794, -2412, -3252, -4066, -4252, -3325, -2559, -2716, -2418, -1171, -1089, -2069, -1724, -742, -518, -332, 135, 333, 594, 799, 117, -671, -676, -808, -1046, -1503, -2150, -2494, -2325, -1443, -806, -1395, -1973, -1482, -995, -1410, -2020, -1344, -783, -1796, -2345, -2025, -2417, -2770, -2356, -2364, -2777, -1705, 32, -13, -991, -1341, -1593, -1805, -1548, -1724, -2339, -2893, -3162, -2764, -2513, -2684, -2347, -1157, -744, -2096, -2807, -2317, -2049, -1241, 119, 155, -247, 626, 1556, 1339, 1102, 1016, 585, 193, -535, -1423, -1264, -389, -329, -507, -315, -1185, -2553, -2389, -2095, -2210, -1813, -2342, -3351, -3169, -2794, -3432, -3806, -2945, -2047, -1082, -133, -294, -675, -595, -428, -50, -126, -549, 50, 682, 571, 760, 1280, 1527, 857, -102, 372, 1013, 312, -70, 804, 969, -618, -1609, -1477, -2327, -3009, -2129, -1485, -756, 1243, 2005, 607, -120, 657, 1674, 1894, 1844, 2424, 3305, 3743, 3635, 3288, 2840, 2053, 881, 587, 1517, 1395, -565, -2316, -2725, -2479, -2913, -3667, -3413, -3432, -3659, -2690, -2458, -2977, -2521, -1623, -294, 1414, 1955, 1291, 722, 754, 1340, 1800, 1766, 1627, 2175, 3075, 2934, 1954, 1117, 1093, 896, -322, -1264, -2219, -3120, -2680, -2144, -2763, -3377, -2875, -1837, -787, -409, -1091, -1358, -105, 1249, 1412, 1002, 1085, 1187, 572, 327, 515, 570, 366, 480, 1695, 2798, 2638, 2219, 3129, 4041, 2990, 1139, -176, -525, 76, 288, -358, -615, -915, -1798, -2148, -2209, -1783, -692, -660, -1605, -2538, -2939, -2419, -3051, -4091, -2832, -1493, -1181, -415, -327, -1283, -1606, -1464, -1445, -385, 911, 449, -1170, -2341, -2748, -3023, -3022, -2618, -2037, -1823, -2286, -2728, -2482, -2000, -1945, -1833, -1922, -2894, -3639, -3482, -3208, -3471, -4334, -4252, -2593, -2181, -3050, -2533, -1206, -369, 403, 835, -168, -1566, -1502, -1071, -1711, -1797, -556, -636, -2054, -1802, -1305, -2395, -2076, -1306, -2679, -2905, -690, 485, 198, 344, 508, 23, 631, 2478, 2586, 574, -820, -502, 877, 1759, 527, -1247, -1793, -1126, -269, -1338, -2639, -2758, -3238, -4273, -4945, -4376, -3439, -3429, -3336, -2340, -1568, -1700, -1807, -885, -162, 56, 1455, 2656, 2031, 2308, 3348, 1826, -271, 894, 2804, 1980, 195, -149, 353, -53, -1233, -2040, -2353, -2176, -2093, -2697, -2939, -1784, -268, -469, -1522, -768, 873, 362, -547, 144, 17, -1342, -702, 967, 1042, 1112, 1948, 445, -990, -2855, -2167, -384, -1682, -3608, -3462, -3255, -2836, -1943, -1916, -312, 2929, 2584, -436, -1730, -1414, -664, 533, 957, 238, -506, -616, 567, 1370, -1, -179, 1087, 508, -500, 1366, 4036, 2716, -275, 227, 1088, -613, -1669, -894, 631, 960, 200, 211, 1436, 2642, 2220, 1958, 2114, -68, -2284, -2298, -1285, 675, 1112, -1676, -2551, 240, 808, -1540, -1832, -1004, -2123, -3832, -2899, 27, 952, -409, -688, 1060, 926, -682, 456, 1516, 499, 172, -21, -152, 1826, 4287, 3782, 1669, 795, 83, -397, 629, 1345, 666, 852, 1377, 1630, 3813, 4139, 672, -1516, -1090, 524, 1195, 382, -374, -643, -951, -752, -506, -257, 705, 445, -1568, -2097, -410, 1168, 1685, 2025, 1693, 179, -120, 759, 312, -1006, -1547, -1066, -125, -55, -405, -628, -1204, -1361, -589, 102, -437, -1208, -832, -293, 954, 3355, 2796, -813, -2241, -656, 1128, 1626, 718, -672, -2189, -2530, -1018, 129, -145, -1505, -2488, -632, 2016, 1528, -407, -1303, -1689, -505, 2315, 1865, -1248, -1586, -952, -1889, -1709, -197, 1272, 2396, 356, -3242, -2282, 1044, 1559, 1929, 3906, 3367, 924, 2221, 6368, 6993, 4164, 2878, 3404, 2800, 1071, 27, 115, -39, -897, -904, -135, 512, 1028, 961, 705, 981, 676, -165, 235, 1705, 1508, 1095, 2193, 2292, 1850, 2525, 3189, 2892, 1432, 955, 3090, 4640, 3044, -166, -1505, 560, 2864, 2358, 335, -293, 536, 449, 121, 460, 178, 596, 1659, 619, -482, 55, 505, 1068, 1495, 557, -515, -459, 118, -124, -182, 1926, 4388, 4852, 5430, 6095, 4599, 3249, 3041, 2328, 555, -678, -629, -1162, -1129, 922, 1873, 978, -475, -1641, -1410, -498, 871, 1066, -1319, -2482, -941, 1376, 3127, 2034, -52, 222, 1427, 2130, 1913, 1079, 836, 1045, 216, -878, -327, 183, -129, -101, -1465, -3140, -2871, -2726, -2458, -1414, -1753, -2587, -1043, 946, 108, -1871, -1659, -234, -76, -718, -1287, -1238, 1330, 3284, 768, -1605, -333, 1576, 948, -819, -1670, -1682, -1232, -1847, -2778, -1305, 956, 1015, -576, -1484, -465, 1509, 1865, 938, 1273, 1518, 390, -454, -581, 240, 2534, 2635, -433, -2090, -857, 861, 904, 703, 503, -197, -562, -392, 1088, 2349, 1359, 56, 32, 567, 902, 1050, 1733, 1769, 54, -555, 953, 1153, 833, 1887, 2085, 1291, 797, -175, 87, 1452, -290, -2700, -1780, 252, 2072, 2305, -423, -2386, -2542, -2544, -1234, 578, 305, -1538, -2149, -677, 904, 834, -586, -1167, 939, 2832, 1340, -245, 1294, 2990, 2868, 1682, -350, -2213, -2295, -1197, -518, 118, 45, -390, 345, 1545, 490, -2123, -1650, 1011, 1765, 509, -224, 1612, 3823, 3255, 1451, 1542, 2992, 2192, 381, 369, 225, 353, 2040, 2057, 377, 469, 2078, 1470, -63, 140, 338, 143, -531, -777, 1230, 1826, 684, 1717, 2274, 305, -1632, -2361, -1985, 131, 1475, -281, -1495, -645, 123, 406, -141, -1885, -1919, 1038, 1587, -1527, -3843, -4300, -3329, -2641, -3826, -4212, -3738, -4660, -5938, -5698, -4084, -3280, -3793, -3334, -2681, -3223, -2283, -371, -508, -988, -1017, -2682, -2432, 1139, 1044, -2408, -2657, -1256, -1785, -1554, 28, -833, -2479, -1404, 420, 260, -927, -1768, -1541, -653, -170, -778, -1778, -1671, -1876, -981, 2334, 2391, -163, -525, -1116, -2781, -628, 2022, 347, 88, 1883, -324, -3396, -1932, -405, -1227, -465, 1324, 844, -991, -1067, 16, -509, -1609, -1402, -473, -4, 232, 675, 352, -531, 126, 2108, 1949, -327, -1016, -593, -1230, -2278, -2122, -680, 1546, 3377, 2823, 1123, 1155, 1638, 549, -682, -831, 9, 2268, 3582, 2819, 3223, 3774, 1809, 306, 620, 1578, 2771, 1818, -197, 218, 1261, 2074, 3928, 4200, 2482, 1808, 1307, 312, 579, 1359, 1490, 755, -417, -341, 116, 7, 47, 4, 767, 2298, 2368, 915, -1655, -2920, -400, 2651, 3005, 1897, 770, -473, -878, -223, 135, -99, -757, 173, 2658, 3113, 1629, 952, 1441, 1378, 410, 510, 1892, 1679, -625, -1420, -440, 464, 1169, 881, -441, -698, 722, 653, -1351, -2276, -1953, -1332, -997, -449, 1039, 756, -1358, -1422, 507, 1458, 1475, 2959, 5294, 4849, 1886, 1015, 2357, 2797, 2352, 2104, 1665, 203, -783, -74, 1086, 1260, 162, 411, 1810, 1241, 606, 1487, 2077, 1611, -473, -2995, -1947, 241, -981, -2579, -2102, -1395, -1150, -963, 809, 3438, 1389, -2427, -825, 1961, 1104, -512, -284, 589, 1649, 2297, 1285, -214, -1127, -454, 2153, 3048, 995, 245, 1321, 1344, 853, 122, -1158, -1540, -186, 1541, 1894, 1209, 965, 1089, 947, 839, 1037, 1413, 1647, 984, -842, -1889, -922, -262, -325, -564, -1132, -27, 2252, 2657, 958, -66, 1256, 3229, 3297, 2365, 2188, 2133, 2909, 4148, 3531, 2490, 1434, 480, 514, -325, -1023, 1833, 4170, 1840, -383, -298, -155, 634, 2152, 1393, -1467, -1240, 3450, 6097, 3576, 1054, 1763, 2313, 1073, 1556, 3291, 3237, 2758, 2841, 2420, 1892, 2572, 3009, 2538, 1829, 640, -161, 501, 1266, 1361, 810, -1127, -1338, 2233, 3742, 261, -1457, -673, -1272, -858, 473, 328, 424, 1668, 1067, -1463, -723, 2865, 3722, 2032, -1, -569, 318, -106, -880, -267, 55, -1325, -1609, 679, 1466, 196, -210, 230, 633, 1484, 3547, 3992, 1417, -757, -552, 724, 310, -770, 1296, 2871, 331, -2110, -2271, -1058, 1163, 451, -3497, -3849, -204, 1517, -190, -723, 1353, 2437, 1982, 1939, 2202, 2113, 1521, 887, -346, -2078, -2439, -2247, -2728, -2844, -2735, -4163, -5296, -3521, -1553, -1366, -1403, -480, 725, 662, -581, -642, 1650, 4873, 4504, 485, -740, 1956, 3448, 2819, 2492, 2106, 1706, 2055, 2873, 1456, -1410, -1394, 164, 589, 696, 1442, 2272, 2395, 1740, -364, -622, 1287, -478, -3306, -2236, -357, -741, -2751, -3396, -1864, -900, -1346, -1470, -836, -363, -1278, -2215, 84, 3261, 2709, -58, -1939, -1809, -403, 494, 1805, 1937, -63, -373, 835, 816, 672, 1870, 2738, 1863, 79, 67, 2352, 3483, 1853, 650, 1895, 2192, 400, -407, -1266, -3028, -2030, -163, -1491, -2838, -1685, -1514, -2486, -2123, -1825, -2303, -1508, 19, -161, -633, 834, 2119, 914, 214, 2003, 3163, 1537, -1072, -1948, -1343, -585, 340, 508, -421, -1098, -793, 489, 645, -889, -741, 1332, 2215, 1216, 531, 311, -816, -1286, -1440, -2788, -3233, -1903, -75, 875, -205, -1368, -619, 734, 2767, 4177, 1653, -527, 1639, 3614, 3101, 2083, 933, -484, -828, 709, 936, -1505, -1527, 239, -857, -3098, -3030, -1046, -619, -1777, -860, 2468, 2444, -2111, -3653, -1416, 142, 883, 1529, 1135, -302, -1476, -1850, -1478, -818, -1643, -3270, -2559, -540, -463, -2261, -3156, -2362, -1726, -1847, -1754, -1104, 85, 1610, 2362, 2385, 2378, 2129, 2168, 3376, 3927, 2267, 2226, 1849, -2127, -2916, -341, -885, -2121, -946, -692, -1861, -1215, 1476, 1368, -1528, -1337, 1351, 3295, 3752, 1353, -1133, -692, 705, 354, -1343, -864, 1345, 1446, -170, -929, -311, 369, -568, -1350, -613, -788, -2339, -1562, 1488, 1713, -378, -697, -649, -1243, -1242, -1221, -1398, -2075, -2436, -1631, -532, 179, -368, -1468, -2069, -1918, -253, 1934, 1873, -232, -1120, 525, 2147, 1317, 153, 477, 493, -194, -774, -1972, -3171, -3357, -3304, -2837, -1326, -765, -2488, -3435, -2153, -1187, -1148, -265, -18, -1075, -922, -602, -947, -397, 636, 773, 720, 2064, 3089, 1618, -216, -58, 887, 707, -312, -125, 894, -577, -2685, -2965, -2867, -2484, -1556, -1282, -1506, -1194, -717, -706, 229, 3123, 5175, 2858, -405, -582, 343, 1175, 1627, 333, -1846, -1705, 506, 237, -2098, -3708, -4070, -1679, 754, -995, -2994, -2409, -2905, -3718, -2622, -1350, -1154, -1042, -312, 348, 594, 207, -267, 90, 679, -574, -2357, -732, 1071, -638, -2529, -2323, -1546, -1209, -1447, -1506, -1092, -239, 224, -1318, -3031, -2868, -1904, -1577, -1834, -1963, -1145, -561, -644, -130, 80, -716, -2448, -4380, -4829, -3695, -2669, -3167, -3387, -2408, -2611, -3275, -2606, -1976, -2077, -2888, -4423, -3790, -1847, -1765, -1019, 145, -399, -617, -388, 40, 525, -423, -724, 1934, 2893, -171, -2173, -983, 1259, 1519, -377, -233, 868, -698, -1432, 1215, 2449, 151, -489, 1012, -531, -2792, -1649, -494, -2550, -5094, -4220, -1813, -1634, -2824, -3826, -4730, -4664, -2056, -103, -2596, -4649, -3362, -2833, -4098, -4027, -1348, 89, -1118, -1950, -1722, -1880, -936, 607, 284, 466, 1620, 891, -665, 45, 2294, 2529, 210, -1516, -1314, -1753, -2704, -1350, -52, -1944, -4042, -3153, -745, 656, -18, -1497, -1207, 515, 552, -230, -81, -1245, -2942, -2814, -2346, -3649, -4543, -3190, -1884, -2048, -1959, -858, -5, -72, -865, -1814, -1507, -1364, -2813, -3407, -1872, -1055, -3441, -5915, -5151, -4006, -4511, -4739, -4410, -3810, -1141, 1716, 247, -3115, -2953, -1403, -2257, -3338, -2877, -2099, -1667, -1268, -1193, -1057, 149, 1662, 1067, 497, 1901, 2382, 1387, 993, 1542, 1984, 568, -1866, -1064, 837, -192, -2444, -3342, -1939, -1079, -1168, -312, -1505, -3709, -3696, -2720, -2007, -2367, -3168, -3312, -2833, -1545, -834, -85, 2000, 1310, -1356, -1537, -1790, -3443, -2466, 222, 789, 1196, 2387, 1700, -484, -1072, 425, 1191, -598, -2393, -2362, -2388, -1658, -420, -1364, -2847, -2798, -3053, -4111, -4680, -4466, -3659, -2831, -1933, -1487, -2209, -2513, -2094, -2240, -3088, -3238, -2047, -1291, -1230, -394, 1380, 2284, 1624, 772, 265, 168, 875, 2257, 2417, 1240, 488, 586, 1055, 1344, 2362, 3531, 2494, 860, 877, -103, -1787, -1416, -1139, -2665, -3725, -2409, -1643, -3209, -3541, -2052, -2192, -3319, -2643, -2588, -4403, -4471, -3388, -4229, -4306, -2040, -505, -583, -706, -483, 295, 1032, -716, -3086, -2776, -2208, -1971, 707, 2539, 756, -885, -1085, -1643, -1196, -195, -886, -2032, -1492, -474, -610, 475, 2691, 1831, -133, 947, 2132, 1151, -183, -369, -279, -861, -925, -134, -130, -651, -1323, -2481, -2761, -2613, -2487, -1358, -445, -1649, -3272, -2743, -435, 674, -304, -2303, -3656, -2981, -1804, -1683, -1940, -1592, -2003, -3464, -3472, -2390, -2373, -2191, -1562, -1799, -1787, -948, -526, 7, 1356, 1399, -480, -816, 170, -703, -2031, -2735, -3530, -3683, -3882, -4382, -3697, -2862, -3352, -3792, -3497, -3134, -2977, -2309, -504, 694, 345, -1459, -2684, -1183, 255, 10, -1220, -2783, -3150, -2789, -1212, 791, -194, -2725, -4436, -4839, -3304, -1752, -1968, -2789, -2387, -1367, -2292, -2776, -490, 275, -2383, -3836, -1922, -1131, -2574, -2526, -580, 1237, 465, -2053, -1568, -829, -2267, -2224, -739, 270, 698, 647, 682, 1425, 2723, 3033, 1666, -58, -1257, -2990, -4113, -2197, -52, -1205, -2728, -2975, -2878, -1317, -813, -2564, -2925, -2231, -3492, -5539, -5290, -2159, -369, -2163, -4004, -3656, -2121, -1295, -1635, -1265, -876, -2109, -2311, -907, 298, 1867, 1402, -975, -1948, -2039, -469, 1997, 888, -957, 467, 425, -1712, -988, -66, -807, -1217, -1652, -2018, -1675, -1005, -887, -2102, -3131, -1781, -27, -527, -1532, -611, -347, -300, 1225, 336, -1242, -397, -380, -1790, -1725, 452, 2015, 1338, -855, -2839, -3338, -2553, -2286, -2816, -2503, -2799, -3920, -3656, -2986, -2796, -2193, -1487, -849, -1011, -2162, -2030, -558, -18, -280, -1853, -4875, -5359, -3242, -2228, -2878, -3472, -2935, -2309, -2818, -3999, -3814, -1368, 805, 515, -444, 1451, 4016, 2735, 763, 1098, 550, -629, 594, 1382, -347, -1617, -2684, -4102, -4178, -3642, -4318, -5345, -4944, -3869, -3633, -3168, -2410, -2630, -2376, -1572, -2488, -3853, -3786, -3350, -2239, -1103, -1877, -3678, -4419, -2941, -2526, -4892, -5267, -2792, -1165, -1461, -2271, -1408, 360, 1547, 2168, 1541, 1162, 2364, 2905, 2745, 3517, 2451, -302, -538, 249, -697, -1562, -544, 633, 431, -66, -361, -1034, -1039, -463, 347, 1301, 553, -573, -22, -213, -1429, -1067, -983, -1541, -687, 28, -760, -1358, -227, 514, -647, -1445, -1227, -918, -301, -59, -487, -1108, -2048, -1774, 528, 2429, 2609, 2124, 1944, 2892, 2901, 1603, 1263, 973, 971, 1939, 1565, -472, -2212, -2415, -1075, -697, -989, 726, 1082, -1687, -1421, 2557, 2524, -1355, -2375, -190, 1587, 1910, 1625, 1525, 1478, 1701, 2148, 1551, 801, 1423, 2119, 589, -2183, -2373, -171, 417, -39, 1022, 1833, 2442, 4682, 5790, 3999, 2828, 3376, 2787, 1210, 569, -62, -683, 154, 386, -362, -615, -766, -236, 859, -203, -2138, -728, 563, -752, -605, 724, 378, -539, 233, 743, -232, -524, 404, 393, 272, 1641, 2396, 1527, 1601, 2948, 2308, 750, 1721, 3831, 4065, 3450, 2983, 751, -867, 342, 717, -1109, -2138, -1022, 281, 230, -369, 866, 3324, 2975, 1194, 2179, 4028, 3507, 2489, 1931, 287, -384, 865, 1108, 43, 116, 1973, 1771, -1578, -2325, 118, 954, -406, -1007, 27, 1268, 2314, 2928, 3246, 4210, 4540, 3213, 1409, 315, 623, 1820, 2364, 1651, 2191, 3345, 2073, 503, 187, 906, 1713, 1950, 2271, 1806, 511, 168, 546, 660, 1046, 2620, 2578, 314, -230, 800, 1307, 1118, 806, 1290, 1130, -171, -397, 218, 577, 1164, 1777, 1466, 1022, 1088, 564, -413, 135, 757, -315, -1204, -1159, -625, -1010, -3077, -3247, -1149, -1718, -2823, 379, 2118, -259, -179, 2595, 1782, -939, -200, 2218, 3045, 2605, 1478, -560, -1967, -1477, 422, 2052, 1978, 1113, 1436, 3085, 3707, 1698, -213, 412, 1415, 904, -284, -1336, -982, 442, -33, -1469, -1240, -635, -1046, -1578, -1049, -544, -652, -400, 188, 772, 1006, 892, 1357, 1487, 784, 528, 1558, 2161, 384, -1095, -576, 97, 1575, 3651, 3566, 2713, 2928, 976, -532, 979, 1169, 1322, 2906, 1497, -1554, -1283, 1148, 1833, 917, 1433, 2438, 739, -1380, -717, 1267, 2222, 1590, 43, -693, 352, 922, 305, 1141, 3239, 2646, 133, -441, 1257, 1581, -1813, -3501, -1171, -628, -3124, -2363, 503, 756, -34, -493, -280, 569, 1528, 1850, 1302, 1191, 1660, 840, 194, 1639, 2031, 1128, 710, 239, 1460, 3931, 3873, 2531, 2551, 2804, 1704, 74, 691, 2780, 3280, 2047, 189, -345, 1279, 2403, 2308, 2758, 2940, 1881, 615, 1736, 4651, 4083, 1169, 1175, 2961, 4925, 6182, 4594, 2883, 3701, 4089, 2440, 777, 2, 1381, 4022, 3452, 1595, 1876, 2239, 2316, 3180, 3441, 2953, 4092, 6451, 4508, -640, -1545, 615, 521, -481, 688, 1310, -127, 13, 1906, 1577, -455, -135, 2434, 3666, 2370, 2004, 4092, 4961, 3582, 2405, 1520, 1137, 2298, 2975, 1687, 323, -349, -654, 513, 962, -1235, -2036, 356, 2428, 2793, 2868, 2803, 2880, 3394, 4136, 4684, 3963, 2288, 505, -662, -1648, -2844, -2263, -688, -1114, -2265, -2662, -2276, -340, 1159, 866, 450, -121, -273, 1700, 2778, 1949, 2992, 4212, 3290, 2514, 2040, 1035, 1224, 2467, 1134, -1703, -2496, -2443, -1968, -197, 702, 1291, 3285, 3171, 871, 1006, 3439, 4621, 3394, 2844, 3251, 2810, 2373, 2676, 2672, 1991, 1861, 1482, 322, 19, -145, -646, -738, -334, 105, 477, 1696, 3375, 3284, 1214, 205, 1692, 3074, 2164, 259, -683, 145, 2850, 3886, 1322, -175, 804, 814, 377, 2041, 2532, -615, -1761, 1279, 2695, 716, -41, 1162, 1167, 54, 61, 888, 1351, 1411, 587, -890, 49, 1933, 598, -741, 740, 1375, 218, 160, 1092, 1974, 2155, 2063, 1268, -873, -1437, 120, 300, -296, 1491, 4258, 4822, 3010, 223, -690, 326, 109, -237, 362, 677, 1326, 1516, 686, 899, 2430, 4167, 4342, 2813, 2317, 2997, 2768, 2239, 2432, 2263, 1811, 2304, 2126, 201, 476, 2210, 1741, 739, -181, -49, 806, 1212, 2272, 1571, -1169, -1337, 547, 243, -994, 208, 1817, 1832, 1138, 85, -698, -465, -91, -333, -753, -844, -1156, -1038, 728, 2162, 2178, 2090, 1919, 1156, 562, 465, 889, 1854, 2419, 2959, 3816, 2724, 1757, 3799, 4162, 1550, 52, 233, 559, 634, 933, 1821, 2246, 1702, 1122, 1174, 1530, 1712, 1645, 1942, 1864, -190, -1912, -472, 962, -235, -962, 107, 1304, 1390, 664, 315, 292, 1639, 4163, 4678, 2884, 1054, 457, 398, 731, 1585, 1834, 1882, 1843, 1021, -563, -2509, -2096, 921, 1400, -234, 5, 936, 1827, 2153, 1066, 344, 779, 1446, 1860, 1536, 886, 1481, 2440, 2631, 2245, 1578, 880, 586, 474, -264, -520, 311, 682, 24, 32, 1453, 3473, 5527, 6137, 4416, 2964, 2922, 2918, 2665, 1728, 80, -478, 118, 350, 124, -265, 88, 1788, 2276, 266, -1354, -1412, -605, 717, 1662, 1782, 1109, 2210, 4885, 4812, 2268, 851, 1404, 1550, 1153, 1370, 1307, 736, 426, 1229, 2063, 903, 62, 1837, 2969, 1948, 1707, 2275, 1583, 994, 1484, 2581, 2441, 639, -214, 572, 1300, 1250, 2198, 2223, -6, -926, 22, 824, 1114, 2088, 2423, 1044, -39, -349, -8, 1648, 2036, -196, -69, 2164, 1809, 862, 1244, 454, -694, -160, 71, 724, 2677, 2099, -178, 226, 1058, -532, -1792, -156, 1932, 1648, 526, 346, 390, -146, -479, -328, -729, -1278, -66, 816, -1529, -2385, 6, 351, -1161, -894, 173, -510, -1406, -1058, -806, -933, -384, 978, 847, -1184, -2345, 259, 3510, 2517, -91, -317, 543, 672, 426, -284, -587, -773, -1803, -1670, -836, -726, -418, -438, -1148, -1129, 458, 2379, 3359, 4270, 4155, 1826, 459, 1842, 3682, 2322, -352, 351, 2947, 4045, 2951, 1425, 1617, 2817, 2902, 3073, 4168, 3603, 1611, 827, 317, -1014, 112, 3364, 3663, 2520, 3402, 3793, 2352, 1212, 1093, 639, -433, -569, -78, -671, -697, 741, 190, -1004, 62, 972, 2115, 2529, -411, -1551, 926, 1815, 822, 325, -29, 1068, 2263, 952, 325, 1370, -155, -3457, -2401, 1482, 1232, -1228, -1730, -1429, -142, 2093, 3088, 2962, 2866, 1892, 659, 1976, 3352, 491, -2079, -1417, -504, 1298, 3601, 1601, -2053, -2559, -1231, -433, -1557, -2774, -2225, -2949, -6044, -8143, -7704, -5445, -4674, -5934, -6344, -5981, -5761, -5483, -5222, -5435, -5569, -4679, -2349, -392, -1374, -4020, -4309, -1748, 1051, 859, -1410, -1543, -298, 796, 1845, 2497, 2776, 2584, 2273, 2921, 4367, 4053, 1783, 566, 1128, 1713, 2087, 2529, 1754, 930, 2390, 3491, 2552, 1338, 657, -228, -1215, -2413, -3769, -3672, -3369, -3824, -3741, -3385, -3815, -4456, -4692, -4458, -4231, -4494, -3917, -3020, -3065, -1955, -193, 557, 1796, 2514, 1165, -312, -789, -750, 236, 514, -815, -1313, -1365, -1690, -2021, -1830, 312, 2008, 2337, 2935, 2812, 2009, 1230, 1124, 1569, 1108, 969, 444, -1311, -1510, -1207, -2604, -3435, -3021, -3215, -3048, -2549, -3077, -2630, -1160, -2040, -3459, -3332, -2798, -925, 920, -62, -1396, -557, 341, 112, 279, 411, -203, -517, -348, 270, 1475, 996, -824, -622, 781, 927, 1342, 3807, 4672, 2595, 2197, 3835, 3227, 910, -621, -1826, -3627, -3893, -2018, -2282, -4227, -4736, -4416, -3681, -2193, -876, -698, 487, 2946, 3372, 2159, 1941, 3351, 4712, 3854, 1703, 775, 299, -1202, -2120, -1754, -1036, -1811, -4453, -5392, -4252, -3072, -1241, 554, 1172, 1325, 1341, 1855, 2350, 1162, 433, 1848, 3333, 3875, 3324, 3122, 3193, 2076, 2019, 2787, 1437, -367, -311, -896, -2749, -2256, -81, 169, 19, 913, 217, -1351, -216, 2670, 2881, 121, -1210, -256, 545, -436, -2542, -3431, -1884, -693, -2212, -4273, -5285, -5279, -3697, -1693, -719, -1041, -3111, -4874, -5243, -4410, -4376, -7028, -8327, -6546, -5104, -5300, -5457, -4260, -1947, 194, 874, -702, -2217, -2057, -2242, -2469, -1430, -651, -1335, -1948, -2057, -1434, 470, 1350, 431, -667, -358, 817, 1000, 1127, 1620, 1176, 1044, 2012, 1695, 644, 626, 224, -2163, -4302, -2912, -523, -176, -922, -1567, -1643, -1518, -983, -1054, -2675, -3667, -3210, -2000, -1613, -3523, -4368, -3218, -2594, -3303, -5005, -4626, -2921, -3148, -3693, -3107, -2267, -1703, -1404, -1412, -1636, -1877, -1218, -379, -1399, -2272, -1182, -782, -1642, -1084, -532, -924, -392, -1222, -2262, 531, 4042, 3649, 1158, 410, 1421, 2255, 3144, 3385, 1124, -139, 1155, 1315, -130, -943, -1251, -1611, -1327, -663, -1549, -2678, -285, 1237, -1905, -5150, -5372, -3575, -2983, -3349, -1673, 804, 875, 241, 2099, 3991, 2722, 1056, 1578, 2398, 2554, 2397, 66, -2167, -406, 1970, 1426, 229, -655, -1387, -636, 376, -253, -1047, -639, -484, -907, -1299, -1970, -2379, -1846, -1203, -708, -124, -265, -770, -587, -978, -1162, 851, 2182, -606, -3224, -2107, -339, -92, -3769, -3994, -5438, -4990, -3269, -2710, -2730, -2543, -2245, -2330, -3214, -2908, -1893, -2332, -2691, -1876, -1383, -1826, -1626, -1104, -1271, -1934, -2828, -2638, -1736, -1796, -1622, -848, -428, -381, 175, 48, -2779, -4849, -3734, -3128, -3949, -3786, -3183, -2858, -2764, -2947, -3127, -3594, -3875, -3346, -2721, -3003, -3557, -2137, -353, -385, -886, -783, -620, -850, -1212, -1864, -1829, -1005, -1845, -3363, -2929, -2214, -2514, -2560, -2375, -2194, -2352, -3018, -3101, -2802, -2543, -2127, -2601, -2745, -1413, -1079, -2627, -3644, -2256, -815, -806, -690, -576, -892, -782, -564, -470, 277, -6, -1917, -1885, 58, 631, -273, -1335, -1309, -839, -1254, -1799, -1990, -1925, -2132, -3041, -3119, -2350, -2482, -2809, -2399, -1918, -2138, -2883, -3417, -3254, -2594, -2426, -2809, -2524, -2381, -2594, -2221, -2011, -2797, -3781, -3943, -3709, -3611, -4011, -4890, -4683, -2886, -1592, -1991, -2966, -2196, 341, 1698, 1237, 856, 1024, 380, -907, -782, 70, -99, -463, -363, -641, -1028, -1107, -1764, -2765, -3573, -3974, -4335, -5130, -6018, -6180, -4841, -2926, -1891, -1827, -1273, -301, -389, -1433, -1632, -417, 22, -1179, -2773, -3572, -3527, -3134, -2784, -2928, -3415, -2466, -357, 432, 1053, 2527, 3227, 2559, 1959, 1923, 1599, 1283, 1228, 169, -1061, -1245, -2032, -3014, -3692, -4374, -4564, -4806, -4263, -3195, -3411, -3869, -3225, -2245, -1826, -1893, -1738, -1025, -495, -932, -1186, -904, -1381, -1389, -291, -9, -463, -706, -1116, -715, -1, -811, -1494, -1166, -1238, -1567, -1759, -1536, -866, -782, -977, -493, -141, -396, -889, -746, -385, -800, -1821, -2388, -1571, -512, -215, 324, 800, 244, 84, 495, -163, -967, -1048, -1825, -2933, -2975, -1847, -360, 80, -426, 154, 1548, 2166, 2033, 1879, 1315, 624, 942, 1372, 1054, 335, 269, 1009, 835, 331, 622, 270, -430, -718, -1485, -2993, -3551, -1702, -637, -1697, -1811, -1203, -1465, -1002, 94, -181, -1063, -981, -193, 694, 1290, 956, 366, 589, 892, 227, -200, 978, 2643, 3284, 2762, 2740, 3544, 3665, 3178, 2653, 2453, 2282, 1712, 1131, 450, 727, 2283, 2892, 1836, 930, 1433, 1700, 690, 766, 1886, 1994, 1430, 788, 380, 619, 854, 256, -515, -600, -644, 83, 1388, 1394, 706, 698, 1575, 2514, 2627, 2359, 2412, 2129, 1731, 1686, 1089, 639, 1693, 2471, 2336, 1847, 1071, 1386, 2866, 3325, 1924, 42, -686, -348, 97, 283, -898, -2615, -2485, -277, 2338, 3692, 3643, 2624, 1517, 2029, 3216, 2975, 2003, 1648, 1323, 1577, 2627, 2290, 1490, 2925, 4909, 4436, 2949, 2666, 2951, 2400, 1390, 648, 528, 605, 193, 848, 2023, 1070, -1183, -1173, 491, 373, -186, 904, 1964, 2215, 1918, 1379, 1768, 3181, 3995, 3536, 2763, 2584, 2487, 1753, 712, 77, 286, 1099, 1682, 2062, 3021, 2781, 1312, 1531, 2497, 2291, 1727, 1536, 1673, 1655, 1207, 1145, 1741, 1761, 909, 1067, 1667, 1061, 712, 1215, 1094, 705, 1544, 2557, 2538, 1956, 1168, 943, 455, -583, 0, 459, -1064, -1783, -1112, -956, -755, -247, -226, -246, 177, 448, -343, -1354, -1116, -600, -1186, -1766, -1176, 289, 1901, 2098, 1640, 2309, 3152, 3177, 3120, 3125, 1937, 616, 1524, 2560, 1627, 766, 1141, 871, 181, 465, 892, 962, 1164, 1503, 1685, 2195, 2478, 1534, 974, 1484, 1706, 1806, 2427, 1956, 705, 1478, 3965, 5207, 3759, 2165, 1679, 1612, 1823, 1826, 1763, 1702, 1496, 1705, 2190, 2154, 2057, 1842, 1276, 2084, 3460, 3733, 3614, 3093, 2144, 1509, 2020, 3136, 3584, 3917, 3946, 2956, 2835, 4033, 4173, 3211, 2680, 2705, 2335, 1801, 1938, 2298, 2590, 2134, 275, -12, 1611, 1688, 878, 1616, 2780, 2456, 1763, 1855, 3132, 4850, 4393, 3046, 3438, 3759, 3436, 3648, 3719, 3037, 2430, 2893, 3600, 3533, 2979, 2420, 1892, 1441, 432, -579, 489, 1406, -251, -883, 541, 684, -489, -703, -264, 306, 1611, 2255, 2184, 2856, 3369, 3059, 2602, 2521, 1848, 661, 1117, 2317, 1922, 1204, 1516, 1541, 1767, 2363, 2022, 1734, 1573, 771, 96, 495, 1737, 2053, 505, -1080, -655, 552, 631, 367, 1240, 2623, 2190, 661, 623, 1181, 1198, 786, -1106, -2523, -667, 1559, 2099, 2832, 3583, 2898, 1802, 2080, 2559, 1906, 1724, 2049, 843, -541, 785, 3005, 2646, 831, 642, 1939, 2471, 2057, 1426, 1026, 1471, 1553, 1127, 1606, 2031, 1703, 1683, 2797, 3512, 2460, 1340, 1967, 3271, 3267, 2709, 2377, 1810, 1209, 1303, 1687, 1299, 508, -58, 668, 2638, 3575, 3259, 2691, 2220, 1959, 1773, 1051, 118, 139, 900, 695, -1167, -1708, -19, 1201, 1764, 2488, 2584, 1964, 1546, 1790, 2137, 1585, 794, 636, 19, -896, -161, 861, 163, -336, 419, 575, 37, 644, 1240, 388, -37, 408, 336, -466, -501, 899, 1185, -168, -652, 487, 1503, 1146, 43, 286, 1093, 383, -106, 483, 292, -181, 392, 1541, 2073, 1081, 823, 2745, 4272, 3217, 1612, 1906, 2522, 2538, 2413, 2112, 2088, 2043, 1979, 1975, 1231, 662, 894, 773, 638, 849, 145, -1467, -2090, -1079, -169, -1112, -1662, 160, 1206, 1147, 1910, 1960, 1619, 2138, 2898, 2696, 1420, 1311, 2040, 1483, 1070, 1139, 1052, 1285, 1414, 1547, 1694, 1754, 1453, 1033, 1090, 741, 617, 1459, 1431, 526, 417, 240, -1612, -2600, -858, 967, 677, -518, -389, 565, 1118, 1123, 934, 1996, 3030, 2119, 1201, 1721, 2062, 1675, 1530, 1390, 1222, 158, -797, -464, -692, -1286, -1216, -2079, -3560, -2829, -450, 1051, 1279, 1304, 1882, 2670, 3173, 3683, 3334, 2134, 1686, 1792, 1497, 765, -215, -1414, -2431, -2529, -1944, -2182, -2877, -2044, -404, -236, -805, -208, 1099, 1747, 1576, 1168, 751, 712, 1502, 2172, 1666, 977, 705, 158, 174, 867, 573, 287, 930, 1509, 1977, 2637, 3020, 1957, -2, 524, 2026, 1202, -351, -1993, -3780, -4751, -4444, -3198, -2871, -4139, -5236, -4472, -2996, -2176, -1593, -455, 178, -1028, -720, 1512, 2180, 2066, 2216, 1989, 1283, 477, 418, 568, -292, -1056, -303, 394, 152, -68, -367, -1015, -1538, -1155, -961, -2108, -2355, -1259, -1262, -1671, -454, 761, 234, -197, 1009, 974, -790, -188, 1404, 419, -961, -401, 628, 617, 257, 313, 735, 1546, 2154, 1466, 158, 516, 1755, 2135, 1444, -657, -1758, -395, 285, -1089, -2156, -1344, -318, -529, -234, 484, 436, 229, 640, 1099, 859, 30, -763, -928, -173, 1018, 1137, 826, 776, -1108, -3106, -1803, -271, -933, -1123, -291, -589, -1343, -1248, -1297, -2513, -3121, -779, 1196, 788, 1067, 1570, 1091, 596, -571, -769, 886, 768, -232, 56, 143, -756, -1367, -30, 1105, 437, 96, -443, -1311, -893, -1352, -3283, -3454, -1919, -1465, -1407, -487, -139, -85, 818, 1078, 267, 333, 1051, 1298, 1512, 2044, 1584, 476, 253, -66, 531, 2029, 933, -576, 851, 2105, 1661, 1538, 1107, -530, -969, 776, 2027, 1807, 1664, 1368, 582, 1053, 1752, 1173, 891, 1393, 1150, 745, 561, -949, -1885, -986, -398, -433, -136, 385, 167, -164, 110, -312, -658, 178, 250, -312, 328, 667, 657, 1535, 1505, 919, 1600, 2222, 1409, 517, 392, 1028, 1744, 1778, 1079, 190, 172, 339, -144, -307, 226, 1030, 1538, 284, -1404, -1244, -851, -1593, -2454, -2092, -967, -1207, -1894, -989, 309, 1149, 1862, 1905, 1664, 1188, 1146, 1958, 2119, 1739, 1757, 1524, 973, 1659, 2738, 1716, 1195, 3191, 3693, 2272, 1504, 1271, 1056, 254, -699, -36, 185, -1073, -1013, -77, -235, -322, -180, -626, -526, 213, 119, -704, -1040, -209, 943, 1461, 1386, 802, -73, -151, 793, 1147, 280, -97, 597, 1272, 1369, 1041, 920, 965, 602, 788, 1762, 1514, 443, 309, 308, -389, -1207, -1855, -2188, -1949, -1951, -2332, -2405, -2218, -1883, -2012, -2245, -1290, 215, 602, 296, 448, 128, -1053, -1448, -1125, -1044, -1158, -1742, -1932, -1031, -514, -910, -549, 92, -41, -520, -1078, -1037, -57, 1554, 3084, 3445, 2567, 1945, 1861, 1211, 351, -289, -829, -1350, -1642, -1914, -1543, -726, -1387, -2001, -797, -410, -996, -136, 813, 492, -38, -266, -836, -2092, -3697, -3621, -1293, 459, 560, 118, -253, -874, -1550, -936, 413, 385, -1043, -1468, -168, 356, 222, 1827, 3972, 4157, 2726, 1730, 2041, 1420, -1010, -1603, -296, -540, -1628, -1659, -2260, -3402, -2085, -148, -406, -811, -118, -279, -1694, -2022, -1567, -2575, -3660, -3448, -4195, -4716, -3231, -1935, -1378, -596, 750, 1225, 473, 711, 1777, 1654, 1439, 2264, 2544, 1389, 118, -124, 401, 401, -591, -1595, -1780, -771, 140, -254, -29, 971, 504, -510, -715, -783, -1296, -1780, -2435, -3071, -2639, -2016, -2101, -2796, -3593, -3492, -2891, -2409, -2207, -2494, -2866, -2220, -1179, -763, -20, 886, 937, 1122, 2368, 3226, 3031, 2081, 86, -1322, -247, 785, -452, -1747, -1427, -938, -1494, -2450, -2009, -715, -795, -573, 906, 1026, 1482, 3107, 2598, 885, 561, 889, -64, -1830, -1823, -378, -214, -580, 51, 794, 638, 62, 865, 1089, -470, 85, 2230, 3114, 2465, 829, 115, 966, 1506, 1084, 458, -257, -700, -331, 853, 1264, -124, -1038, -100, 938, 1312, 1583, 1692, 1053, -388, -992, -621, -1144, -2147, -1443, -303, -794, -741, 479, 120, -1079, -285, 1299, 1804, 2189, 2544, 2611, 2532, 1666, 705, 1775, 3422, 3383, 3110, 3163, 2342, 694, 131, 1611, 3181, 2732, 667, -90, 1528, 2754, 1870, 1161, 2129, 2310, 1413, 1498, 2008, 2463, 2746, 1874, 451, 160, 1176, 1114, 526, 1480, 1572, 606, 1524, 2609, 2064, 1372, 1130, 1191, 1149, 855, 388, -48, 14, 347, 625, 858, 270, -516, -348, -177, -798, -1035, -683, -631, -668, -791, -143, 1047, 743, 46, 1064, 1717, 1228, 1547, 2001, 2236, 2154, 694, -660, -365, 929, 2425, 2290, 518, -570, -657, -344, 59, 72, -594, -1506, -1660, -650, 236, 243, 70, 165, 934, 1771, 1676, 1453, 1595, 1590, 1203, 155, -969, -306, 651, -170, -1337, -2142, -2623, -2096, -1617, -2372, -2469, -2065, -2715, -3135, -2786, -3164, -3926, -3762, -2462, -1505, -1339, -973, -465, -377, -532, -135, 33, -448, -269, -776, -2196, -1560, -548, -934, -369, 69, -1131, -1399, -760, -1279, -1230, -377, -666, -1186, -1470, -2152, -2352, -1441, -1314, -1772, -1731, -1704, -796, -212, -612, -323, 128, 211, -664, -1545, 508, 2465, 1640, 1096, 1413, 881, 523, 1402, 1414, 352, 648, 1664, 949, -696, -213, 1532, 1487, 1241, 2041, 2014, 1154, 346, 380, 699, -595, -1006, 89, -221, -1497, -1846, -2225, -3760, -4035, -2248, -825, -700, -1117, -664, 753, 1965, 2188, 1070, 232, 1248, 1880, 687, -932, -1429, -416, -654, -3027, -3502, -1644, -561, -489, -1159, -1420, -384, -323, -1500, -1787, -869, 206, -325, -1815, -1128, 220, 230, 1264, 3101, 4256, 4477, 4380, 4158, 2365, 116, -326, -543, -918, 605, 1963, 1133, -192, -705, -270, 108, 263, 877, 933, 693, 848, 656, 639, 1489, 1603, 483, -680, -951, -553, -350, -432, -665, -93, 1893, 2844, 1904, 1409, 1734, 1465, 1533, 1964, 1357, 213, -720, -1725, -2596, -2281, -1211, -1189, -2029, -2396, -2078, -1404, -744, 280, 789, 115, 98, 1573, 2310, 1958, 2047, 2231, 1883, 714, -1060, -1827, -755, 575, 1284, 1493, 1325, 1051, 1178, 2181, 2893, 1274, -710, -25, 889, 106, -730, -1577, -2465, -2211, -2034, -3164, -3139, -1479, -758, -1097, -801, 285, 384, 548, 2549, 3507, 2428, 2170, 2484, 1463, -162, -686, -749, -1714, -3095, -3617, -2880, -1751, -1033, -706, -243, 172, -355, -1082, -891, -723, -166, 1019, 1545, 665, -95, 772, 778, -1273, -2230, -855, -383, -947, -292, -99, -395, 1597, 3759, 3248, 1606, 1124, 2530, 3694, 3041, 2711, 2969, 2498, 1400, 429, 363, 870, 1181, 406, -1038, -1627, -1269, -1204, -2320, -3062, -1846, -289, 171, 931, 2829, 3465, 1901, 680, 585, 379, -99, -836, -1351, -980, -703, -554, -336, -654, -876, 489, 2282, 2062, 511, 293, 1607, 1817, 1266, 1725, 2106, 1759, 1839, 1966, 1305, 1483, 2272, 2102, 1542, 1157, 651, -458, -1336, -826, -273, -387, -190, 714, 1067, 885, 1976, 2847, 1776, 270, 82, 1221, 1490, 321, 22, 635, 314, 441, 1551, 1608, 1458, 1833, 1962, 1657, 136, -1397, -728, 474, 62, -668, -53, 542, 217, -111, 111, 975, 2280, 3190, 2298, 920, 1337, 1854, 793, -559, -632, -641, -1528, -1946, -2022, -2333, -1933, -1301, -1979, -2457, -718, 537, -271, -536, -123, -589, -606, 158, -386, -1119, -491, -299, -412, 491, 1436, 842, -834, -1427, -54, 1177, 612, 103, 345, -1274, -3403, -1817, 701, 293, -832, -536, 33, -252, -593, -286, -696, -1855, -592, 1295, -85, -1652, -1539, -1028, -541, 206, 570, 102, 308, 831, -91, -355, 1706, 3131, 2600, 1714, 971, 629, 1038, 485, 271, 1606, 2111, 2538, 2937, 1551, 5, 156, 634, 388, -39, -217, 286, 1061, 1039, 1811, 3342, 3484, 3024, 2471, 1865, 2041, 1616, 494, 28, -192, -776, -1048, -866, -867, -697, -537, -990, -1177, -942, -2110, -2548, -572, 783, 1847, 2921, 2414, 1657, 1290, 931, 858, 365, -1221, -1629, -320, -5, -686, 533, 2221, 1447, 626, 1138, 961, 1131, 2232, 1714, 356, 87, 4, -378, -284, 316, 401, -370, -608, -753, -1388, -446, 407, -831, -1590, -1083, -162, 682, 643, 648, 1425, 1219, 944, 1623, 2001, 1697, 907, 367, 293, 334, 342, 108, 100, -22, -1017, -1959, -1146, 83, -196, -161, 360, -455, -1205, -817, -661, -1245, -1676, -1712, -1406, -546, -602, -1979, -2661, -1707, -432, -374, -1441, -1797, -1304, -1737, -1717, -362, 125, -753, -1745, -2046, -1334, -559, -1014, -1208, -182, 87, -1224, -1804, -1313, -1463, -2184, -2342, -1685, -1966, -3205, -3099, -1393, -317, -302, -742, -1341, -1374, -1052, -1036, -1142, -1023, -590, -91, -125, -169, -133, -1051, -1705, -1318, -1070, -994, -1403, -2078, -1622, -703, 247, 1511, 2242, 2404, 2770, 2980, 1716, 317, 1149, 1924, 981, 381, 991, 1742, 1290, 1094, 3038, 3611, 1212, 459, 1469, 862, 69, 202, -773, -1931, -767, 959, 1066, 788, 898, 1152, 858, -24, -142, 0, -338, -911, -1467, -909, 9, -567, -2142, -3364, -2654, -826, -57, 190, 945, 1728, 2680, 3502, 3301, 2740, 2149, 1450, 1187, 513, -850, -859, 325, 241, -963, -1619, -2215, -3081, -2643, -1180, -1229, -2237, -1328, 327, 401, -60, 234, 1265, 2333, 2301, 1316, 578, 155, 67, -274, -1418, -2280, -2276, -1878, -1789, -1639, -452, 86, -1281, -2054, -1649, -1424, -1417, -1699, -1896, -1253, -1209, -1792, -1515, -1362, -905, -522, -1607, -1771, -659, -1447, -3471, -4148, -3797, -3167, -2178, -1664, -2134, -1542, 808, 1720, 729, 161, -26, -160, -279, -1308, -1506, 429, 1008, -1030, -2340, -1074, -39, -118, -341, -1106, -2155, -2846, -2622, -2482, -2976, -2567, -881, 487, -1242, -4201, -3307, -1070, -1847, -2449, -1465, -1969, -1882, 427, 917, -907, -1563, -623, 412, 531, -882, -821, 1615, 2866, 2355, 1786, 1712, 1675, 916, 469, 1088, 569, -602, -477, -204, -704, -516, 1329, 2943, 2213, 556, 323, 937, 1052, 149, -625, -313, -351, -1244, -1433, -694, 346, 976, 57, -1145, -1639, -1737, -411, 1433, 1209, 565, 1277, 435, -2624, -2922, -214, 735, 140, 211, -274, -1063, 403, 2293, 1832, 1500, 2664, 2575, 861, -125, -542, -1570, -2192, -1343, -540, -714, -128, 611, 382, 998, 2478, 2598, 431, -1038, 372, 1017, -223, -347, 742, 433, -1063, -673, 196, -972, -1854, -698, 159, -546, -692, -1067, -1982, -1268, -258, -778, -1347, -1050, -1113, -864, -351, -738, -1191, -1880, -2531, -2059, -1378, -640, 453, 997, 354, -1079, -1686, -1072, -643, -237, -165, -334, -133, -763, -1059, -247, -203, -879, -921, -253, 149, -556, -1276, -1102, -859, -1195, -1617, -1694, -1141, -428, -240, -984, -2393, -2525, -537, 533, -940, -1530, -461, 128, 673, 338, -1468, -1949, -1060, -1254, -1634, -435, 871, 87, -2152, -2526, -855, -483, -844, -162, 959, 693, -289, 525, 1480, 1110, 923, 1053, 937, 98, -1135, -455, 1374, 1741, 1168, 388, 623, 1675, 1374, 592, 601, 477, -132, -58, 1024, 1361, 969, 1460, 2024, 2622, 3386, 2402, 1077, 1449, 961, -439, -720, -1064, -2121, -2966, -2854, -1133, 724, 571, -769, -1196, -490, 94, 666, 1346, 1568, 1313, 1294, 1848, 1841, 1517, 1286, 440, -40, 104, -1166, -1957, -358, 216, -335, 565, 1779, 2425, 2443, 1651, 1174, 1089, 430, -540, -2028, -3875, -3996, -2311, -1157, -1779, -3278, -2895, -299, 959, -170, -1233, -1636, -2631, -2824, -1052, 185, -396, -767, -214, -672, -1445, -977, -289, 126, -366, -1203, -854, -278, -994, -1420, 69, 1048, -367, -1507, -1184, -1428, -1625, -1543, -2403, -2881, -2458, -1975, -2061, -2329, -1684, -1267, -1323, -899, -1291, -2055, -1263, -540, -1577, -2320, -1471, -633, -1488, -2430, -1160, -279, -1018, -1051, -854, -1281, -1682, -1412, -611, -712, -1718, -1580, -1021, -1490, -1250, -349, -859, -2236, -2419, -1454, -470, 82, -602, -2268, -3113, -2747, -2996, -4503, -5332, -4126, -2461, -1819, -1670, -1571, -1399, -1020, -460, 171, 494, 324, 248, 251, 1118, 2216, 1270, 773, 2066, 1728, 709, 978, 511, -158, 664, 1675, 1378, 964, 1900, 3323, 2911, 567, 3, 1682, 862, -1517, -1050, 172, -361, -695, 3, 425, -118, -345, 120, 301, 145, -103, -561, -1248, -805, 562, 254, -710, -535, -201, 91, 559, 1113, 1527, 1359, 1115, 699, -651, -846, 580, 1161, 830, 982, 1337, 720, -584, -960, 81, 1560, 2028, 1046, 199, 254, 408, 154, -239, -709, -1210, -646, 894, 993, -474, -987, -839, -1751, -2315, -2255, -2841, -3772, -3950, -2691, -1790, -1788, -1250, -1258, -1542, -793, -526, -484, 0, 418, 935, 702, -144, -185, 87, 152, 837, 787, 152, 1296, 2183, 949, -472, -1596, -2384, -1743, -424, 51, -504, -1063, -362, 385, 67, 147, 443, -496, -876, -139, -473, -1011, -113, 1249, 1755, 1923, 2372, 2273, 1485, 1085, 1199, 816, 551, 981, 1085, 524, -959, -2555, -2935, -2324, -2159, -2998, -3581, -2990, -2304, -1897, -1247, -2149, -3290, -2016, -1162, -1804, -1896, -1972, -2369, -2906, -3018, -2120, -1656, -2056, -1537, -408, 10, 578, 1063, 1092, 1417, 1145, 376, 387, 952, 1491, 1434, 977, -127, -1218, -380, 208, -634, -294, 672, 719, 375, -243, -1098, -1421, -817, -48, -701, -2211, -2270, -1419, -1727, -2022, -1353, -1362, -1792, -1373, -1239, -1983, -1883, -676, 417, 1430, 2015, 1878, 1869, 2860, 4232, 3728, 2747, 2979, 2645, 1824, 1130, 292, 370, 1527, 2224, 1246, 384, 1140, 1611, 1344, 1287, -26, -1446, -453, 132, -626, -364, 744, 1149, 285, 75, 783, 728, 885, 1081, 481, -109, -1285, -2027, -972, -372, -1103, -1162, -637, -536, -411, 541, 1667, 2066, 3149, 4743, 4704, 4226, 5361, 6536, 6039, 4820, 4082, 3957, 4048, 3610, 2620, 2854, 4090, 3401, 2047, 2228, 2229, 1742, 1201, 16, -905, -455, -119, -1172, -1302, 21, -190, -1797, -2095, -1050, -807, -2249, -2666, -481, 1504, 1415, 1279, 2599, 2973, 1744, 776, 682, 526, 269, 617, 76, -1816, -2815, -2413, -2402, -3060, -2829, -1882, -2312, -3007, -2546, -2819, -3339, -2927, -3112, -3627, -3857, -4716, -5272, -4317, -2207, -426, 186, 1122, 2678, 2649, 1401, 1240, 1152, 293, -91, -993, -2122, -888, 1159, 1826, 1837, 1871, 2114, 2241, 1755, 1538, 1128, 11, -906, -2018, -4102, -4925, -3439, -2343, -2430, -2469, -2101, -2054, -2573, -3333, -3520, -2190, -865, -793, -1008, -1090, -308, 1608, 2219, 829, -276, -48, 430, -95, -1061, -1292, -482, -24, -922, -2160, -2770, -2952, -2590, -979, 288, 149, 361, 1793, 2415, 1437, 1168, 1644, 1479, 1329, 1541, 2021, 1762, 441, -515, -1435, -2028, -1842, -2189, -3154, -4518, -4889, -2834, -1591, -2618, -3177, -2241, -1275, -682, -179, -337, -506, 315, 745, -280, -650, 1036, 2410, 1399, -848, -1075, 1430, 3629, 3674, 3473, 3706, 3482, 3147, 2235, 953, 117, -734, -2251, -3261, -2281, -1095, -2058, -3163, -2611, -1276, 554, 2013, 1344, 491, 1599, 2371, 1754, 1906, 2375, 1418, 556, 1019, 1519, 1501, 1240, 1420, 1752, 906, 742, 1975, 1631, -113, -598, -203, -603, -802, -846, -2307, -1110, -1226, -32, 1256, 921, -365, -1064, -966, -260, 46, -637, -1874, -3012, -3277, -3114, -3399, -3903, -3893, -3484, -3177, -2841, -2317, -1804, -1419, -1508, -2135, -2484, -2401, -2366, -2060, -1491, -1295, -1168, -460, 785, 1516, 1262, 750, 473, 531, 536, -34, -760, -1378, -2039, -2665, -3250, -3824, -3976, -3249, -2595, -2543, -2353, -2032, -2124, -2815, -3658, -4235, -4350, -3909, -3225, -2731, -2921, -3655, -3260, -1592, -714, -1145, -1652, -1407, -807, -539, -430, -129, 22, -207, -796, -1485, -1693, -1563, -1407, -1060, -635, -379, -137, 180, 13, -593, -835, -567, -460, -777, -1236, -1774, -2197, -1997, -1501, -1969, -3257, -3683, -3322, -3330, -3286, -2753, -2180, -1617, -1518, -2302, -3200, -3517, -3236, -3123, -3715, -4108, -3746, -3289, -3050, -2778, -2594, -2537, -2454, -2269, -2309, -2976, -3227, -2197, -972, -639, -1044, -1380, -1355, -1181, -1039, -1527, -2591, -2579, -1480, -1152, -1896, -2460, -2205, -1704, -1581, -1996, -2318, -1713, -730, -3, 415, 338, 52, 338, 1129, 677, -761, -894, -190, 240, 399, -294, -1450, -1697, -773, 166, 717, 1506, 2033, 1536, 1341, 2743, 4014, 4163, 3956, 3810, 3739, 3299, 3365, 4262, 4395, 3602, 3405, 4290, 5413, 5894, 5393, 4993, 6095, 8034, 9161, 9301, 9680, 11037, 12044, 11978, 12321, 12754, 11942, 11467, 12077, 11680, 10349, 10120, 10560, 10373, 10250, 10707, 10822, 10208, 10045, 10644, 10463, 9222, 8283, 7745, 6972, 6033, 5355, 5053, 4723, 4104, 2840, 1149, 11, -711, -1479, -2099, -2855, -3962, -4887, -5221, -5984, -7796, -8909, -8524, -8276, -9397, -10964, -11283, -10583, -10242, -10877, -11928, -12088, -11514, -11180, -11122, -11190, -10842, -9919, -9357, -9440, -9526, -9545, -9527, -9102, -8828, -9144, -8990, -8030, -7357, -7282, -7573, -8109, -8105, -7436, -7322, -7908, -8349, -8606, -8715, -8650, -8839, -9097, -8614, -7608, -7223, -7554, -7444, -6574, -5743, -5253, -5094, -5190, -5033, -4492, -4104, -4288, -4641, -4494, -4260, -4497, -4830, -5051, -5398, -5558, -5174, -5430, -7256, -8665, -7435, -5744, -6657, -8683, -9847, -10279, -10104, -10421, -11769, -12651, -12159, -11213, -11290, -12383, -12976, -12714, -12288, -11913, -12044, -12625, -12603, -12075, -11939, -11777, -11353, -11164, -10841, -10251, -10247, -10702, -10430, -9284, -8248, -7865, -7775, -7291, -6288, -5895, -6517, -7217, -7449, -7003, -6370, -6474, -6902, -6900, -6593, -6065, -5554, -5389, -5198, -4954, -4605, -4269, -4724, -5554, -5665, -5104, -4673, -4533, -4450, -3959, -2762, -1634, -1272, -1433, -1524, -961, -317, -586, -1327, -2145, -3025, -3397, -3408, -3810, -4449, -4544, -4198, -4128, -4458, -4586, -3981, -3300, -3537, -3982, -3748, -3302, -2895, -2419, -1997, -1752, -1473, -911, -278, 243, 453, 392, 546, 760, 472, -188, -392, -35, 66, -435, -1250, -1741, -1626, -1450, -1523, -1989, -2588, -2614, -2139, -1761, -1848, -2002, -1573, -776, -371, -544, -703, -229, 550, 825, 583, -192, -1254, -792, 756, 558, -1105, -2055, -2029, -1675, -1464, -1908, -2447, -2024, -1256, -1316, -1899, -2104, -1749, -1556, -2090, -2759, -2705, -2296, -2397, -2970, -3428, -3192, -2391, -1840, -1849, -2259, -2379, -1542, -595, -558, -996, -1051, -475, 127, 152, -306, -649, -435, -53, -309, -1156, -1528, -1112, -810, -1068, -1645, -2234, -2162, -1392, -1148, -1945, -2638, -2374, -1742, -1562, -1858, -2147, -1965, -1414, -1061, -1184, -1492, -1158, -307, 2, -335, -598, -154, 735, 1355, 1349, 861, 405, 573, 1256, 1372, 952, 1130, 1923, 2386, 2072, 1541, 1521, 2048, 2719, 3022, 2605, 2054, 2239, 2437, 1705, 658, -243, -775, -574, -217, -375, -1075, -1421, -719, -116, -613, -1300, -1031, 69, 1049, 999, 155, 38, 1054, 1899, 2095, 2142, 2226, 2475, 2956, 2968, 2273, 2161, 2960, 3517, 3407, 2942, 2552, 2599, 3065, 3346, 3057, 2496, 2169, 2100, 1603, 646, -93, -316, -34, 184, -108, -350, -200, 77, 369, 422, 148, 277, 1251, 2169, 2109, 1733, 1913, 2400, 2654, 2522, 2121, 1949, 2313, 2743, 2819, 2758, 2804, 2761, 2778, 2639, 1821, 1217, 1197, 1139, 1128, 1087, 981, 1280, 1890, 2069, 1536, 945, 1207, 2069, 2255, 1734, 1396, 1607, 2010, 2112, 2032, 1843, 1868, 2576, 3220, 3028, 2783, 3117, 3618, 3924, 3757, 3167, 2989, 3500, 3867, 3514, 2899, 2675, 2964, 3886, 4673, 4358, 3761, 3964, 4167, 3393, 2636, 2513, 2454, 2641, 2802, 2188, 1479, 1314, 1285, 1213, 975, 699, 671, 1125, 1772, 1541, 982, 1406, 2117, 2202, 1816, 1518, 1687, 1970, 2045, 1960, 1718, 1459, 1771, 2674, 3065, 2772, 2639, 2826, 3333, 3750, 3348, 2762, 3008, 3664, 4055, 3920, 3519, 3532, 3702, 3498, 3074, 2792, 2954, 3550, 3710, 2735, 1568, 1436, 1983, 1900, 848, -155, -370, 24, 406, 230, -324, -557, -114, 376, 505, 599, 809, 1282, 1910, 2021, 1697, 1811, 2349, 2601, 2506, 2430, 2616, 3260, 3848, 3584, 3044, 2970, 2973, 2831, 2548, 1891, 1201, 1140, 1721, 2128, 1707, 978, 803, 1104, 986, 161, -484, -345, 417, 1207, 1281, 827, 753, 1268, 1540, 1028, 505, 827, 1554, 2430, 3281, 3149, 2513, 2906, 3800, 3456, 2311, 1915, 2414, 3033, 2908, 2245, 2287, 3014, 3318, 3049, 2547, 1929, 1808, 2322, 2671, 2371, 1701, 1555, 2143, 2380, 1721, 1194, 1370, 1637, 1717, 1565, 1252, 1162, 1467, 1771, 1657, 1460, 1620, 1785, 1774, 1639, 1344, 1437, 2383, 3249, 2924, 2196, 2093, 1980, 1406, 523, -405, -891, -1146, -1227, -906, -820, -994, -494, 731, 1630, 1535, 1121, 1203, 1601, 1540, 735, 232, 768, 1428, 1559, 1285, 681, 512, 1245, 1702, 1247, 717, 726, 1052, 1235, 945, 475, 664, 1378, 1908, 2127, 2142, 2243, 2674, 3136, 3158, 2638, 2138, 1950, 1882, 1826, 1163, 712, 1440, 1946, 1651, 1688, 2303, 2913, 3543, 4154, 4205, 3802, 3633, 3762, 3433, 2199, 815, 500, 1301, 1876, 1516, 931, 1007, 1552, 1795, 1361, 506, 175, 853, 1628, 1543, 830, 540, 1170, 1511, 1088, 937, 1067, 1480, 2260, 2254, 1455, 1352, 2212, 2874, 2566, 1988, 2281, 3089, 3485, 3155, 2262, 1591, 1797, 2457, 2804, 2479, 1850, 1759, 1977, 1757, 1339, 1073, 1026, 1387, 1726, 1459, 763, 381, 632, 820, 696, 515, 366, 884, 1815, 1716, 758, 419, 959, 1555, 1550, 870, 482, 1159, 2062, 2186, 1855, 1777, 2341, 3139, 3147, 2444, 2079, 2364, 2883, 3171, 2707, 1751, 1641, 2857, 3972, 3825, 3266, 3105, 3239, 3270, 2712, 1998, 1760, 1823, 2112, 2156, 1519, 1086, 1383, 1897, 1901, 1369, 1206, 1928, 2822, 2965, 2492, 2410, 3350, 4360, 4426, 3999, 3829, 4214, 4703, 4402, 3520, 3027, 3267, 3930, 4157, 3631, 3016, 2718, 2677, 2579, 2228, 1748, 1690, 2406, 3026, 2653, 1782, 1486, 1832, 2078, 2017, 1765, 1669, 1933, 1835, 1409, 1607, 2372, 3262, 3720, 3410, 2884, 2832, 3122, 3278, 3596, 4007, 3844, 3415, 3214, 2899, 2315, 1775, 1484, 1420, 1608, 1578, 1070, 1042, 1872, 2205, 1194, 176, 294, 701, 470, -281, -739, -255, 304, -152, -806, -624, 213, 973, 1015, 690, 604, 949, 1627, 2365, 2704, 2465, 2294, 2504, 2897, 2880, 2148, 1759, 2202, 2295, 1864, 1791, 1776, 1444, 1433, 1713, 1523, 1125, 1337, 1809, 1632, 903, 206, -89, 288, 813, 689, 313, 290, 415, 581, 543, 257, 414, 965, 1101, 749, 264, 157, 861, 1731, 2061, 2119, 2416, 3202, 4007, 3854, 3060, 2907, 3274, 3316, 2881, 2263, 1923, 1934, 1643, 1093, 880, 746, 631, 687, 415, -305, -732, -706, -611, -498, -510, -639, -544, 85, 872, 719, -141, -307, 388, 959, 1258, 1506, 1631, 2017, 2606, 3054, 3113, 2700, 2445, 2626, 2740, 2472, 2031, 1783, 1881, 2004, 1705, 1128, 720, 867, 1293, 895, -98, -22, 883, 885, 157, -262, -121, 649, 1230, 760, 348, 1094, 2024, 2003, 1286, 824, 666, 780, 1334, 1254, 550, 850, 1914, 2314, 2028, 1762, 1957, 2622, 3199, 2977, 2191, 1784, 1932, 2224, 2197, 1984, 1942, 1787, 1533, 1272, 773, 79, -59, 446, 320, -270, -448, -575, -749, -1020, -1920, -2883, -2753, -1942, -1548, -1550, -1574, -1412, -783, -177, -335, -825, -642, 19, 352, 317, 99, 93, 824, 1442, 1019, 266, 172, 649, 1151, 1405, 1314, 1410, 2110, 2714, 2630, 2022, 1322, 1139, 1696, 2015, 1296, 176, -86, 513, 837, 519, -107, -476, -210, -119, -897, -1960, -2753, -3128, -3163, -3530, -4362, -4693, -4303, -3902, -3627, -3374, -3065, -2284, -1065, -22, 395, 554, 1199, 1821, 1715, 1329, 1114, 1209, 1488, 1338, 619, 390, 886, 1216, 945, 249, -128, 155, 537, 555, 221, -232, -533, -487, -334, -564, -1044, -1097, -579, -375, -997, -1644, -1857, -1911, -1972, -2172, -2434, -2332, -1501, -546, -346, -488, -165, 384, 682, 603, 42, -446, -61, 460, 87, -711, -1069, -1002, -975, -1232, -1825, -2558, -2991, -2410, -1472, -1810, -2743, -2547, -1797, -2065, -2910, -2868, -2006, -1270, -873, -889, -1275, -1253, -695, -584, -904, -911, -517, 87, 611, 673, 310, 96, 536, 1086, 747, -168, -360, 398, 914, 636, 179, -361, -539, -3, 94, -400, -443, 77, 669, 943, 639, 136, 253, 768, 795, 262, -284, -498, -179, 214, 105, -214, -86, 457, 688, 555, 316, 344, 771, 807, 137, -276, -47, 373, 633, 264, -324, -95, 789, 1352, 1098, 302, -311, -520, -557, -783, -1444, -2039, -2214, -2208, -2433, -3080, -3642, -3622, -3399, -3283, -3327, -3650, -3868, -3769, -3619, -3739, -4305, -4575, -3629, -2228, -1599, -1379, -667, 308, 968, 951, 431, 268, 735, 1302, 1388, 1122, 1030, 1340, 1691, 1604, 1145, 782, 827, 999, 738, -25, -499, -367, -465, -916, -1134, -1364, -1648, -1510, -1347, -1904, -2797, -2858, -1925, -1584, -2181, -2385, -2166, -1892, -1624, -1878, -2232, -1963, -1581, -1306, -1210, -1633, -1820, -916, 111, 209, -96, 6, 621, 1137, 1237, 1095, 1071, 1218, 1242, 1235, 1150, 941, 890, 1029, 883, -74, -1370, -1607, -956, -1011, -1805, -2305, -2348, -2116, -2126, -2851, -3509, -3163, -2450, -2500, -3042, -3172, -2390, -1245, -668, -737, -916, -602, 95, 591, 413, -75, 148, 827, 981, 733, 454, 160, 131, 210, -134, -696, -984, -993, -1079, -1343, -1762, -2439, -2765, -2357, -2252, -2849, -3462, -3786, -3571, -3015, -2874, -2931, -2508, -1923, -1635, -1404, -1420, -1752, -1506, -887, -834, -786, 87, 1255, 1704, 1268, 529, 136, 170, 109, -344, -1142, -1870, -1952, -1368, -1064, -1544, -1911, -1518, -1027, -1191, -1778, -1806, -1229, -924, -949, -1158, -1712, -2135, -1855, -1325, -1425, -1894, -1828, -1604, -1639, -1439, -1198, -1265, -1000, -183, -11, -627, -484, 490, 1043, 787, 185, -151, 13, 21, -370, -691, -1140, -1492, -1220, -1076, -1646, -2005, -1545, -1110, -1429, -2292, -2992, -2965, -2550, -2571, -2812, -2553, -1916, -1353, -1233, -1508, -1569, -1394, -1285, -1349, -1896, -2585, -2682, -2287, -2057, -2602, -3356, -3101, -1809, -732, -1024, -2067, -2352, -1982, -1982, -2495, -3350, -4004, -3759, -3270, -3067, -2747, -2208, -1573, -1033, -1077, -1785, -2167, -1636, -1043, -1273, -2152, -2663, -2166, -1312, -1131, -1687, -2316, -2624, -2619, -2809, -3341, -3254, -2564, -1937, -1540, -1897, -2632, -2599, -1715, -904, -744, -771, -222, 535, 581, 286, 210, 87, 114, 417, 99, -797, -955, -237, 460, 755, 532, -38, -267, -239, -765, -1826, -2700, -2932, -2560, -1936, -1795, -2185, -2033, -1028, -132, -233, -787, -411, 647, 871, 54, -602, -563, -322, -290, -176, 167, 294, 409, 601, 459, -2, -563, -744, -371, -229, -774, -1325, -917, -42, -336, -1943, -2994, -2752, -2565, -3006, -3368, -3245, -2417, -1220, -453, -222, -153, 148, 674, 740, 402, 209, -176, -333, 261, 655, 163, -437, -215, -5, -974, -2086, -1919, -1210, -1062, -1189, -1356, -1542, -1190, -587, -841, -1545, -1647, -1677, -1918, -1899, -2030, -2390, -2144, -1571, -1289, -1250, -1223, -650, 164, 342, -298, -964, -722, 18, 205, -330, -781, -476, 19, 32, -320, -546, -437, -305, -422, -905, -1278, -1229, -1098, -964, -1074, -1443, -1389, -833, -523, -866, -1378, -1460, -1318, -1046, -683, -651, -882, -947, -853, -1006, -1397, -1407, -753, 259, 827, 229, -631, -533, -78, -3, -325, -989, -1271, -708, 93, 345, -10, -55, 768, 1524, 1147, 387, 548, 1246, 1360, 860, 349, -12, -134, -263, -836, -1504, -1700, -1381, -1091, -1602, -2547, -2694, -2110, -1672, -1841, -2792, -3670, -3239, -2292, -2418, -3276, -3727, -3751, -3462, -2824, -2671, -3211, -3363, -2710, -2156, -2159, -2247, -2069, -1967, -1898, -1624, -1534, -1614, -1398, -852, -663, -1164, -1472, -1019, -671, -1161, -1614, -1328, -988, -1012, -1101, -1262, -1446, -1197, -738, -830, -1533, -2248, -2316, -1869, -1591, -1454, -872, -376, -696, -1199, -1450, -1454, -1115, -806, -873, -1295, -1848, -1950, -1374, -815, -900, -1330, -1421, -1058, -1095, -1643, -1636, -879, -55, 470, 499, 152, 318, 1237, 1792, 1562, 1172, 906, 1275, 2315, 2702, 2074, 1561, 1974, 2459, 2169, 1671, 1381, 1403, 1878, 2114, 1615, 1229, 1608, 1919, 1592, 1429, 1457, 1367, 1609, 1859, 1911, 2050, 2186, 2440, 2734, 2887, 2873, 2666, 2494, 2269, 1803, 1258, 539, 45, 280, 452, 25, -472, -353, 271, 325, -439, -917, -591, -373, -890, -1517, -1826, -2040, -2071, -1981, -2073, -1919, -1338, -771, -251, -23, -169, 209, 1133, 1361, 917, 781, 1204, 1702, 1827, 1751, 1661, 1509, 1621, 2181, 2409, 1919, 1483, 1586, 1877, 1488, 454, -95, 275, 503, -73, -340, -12, -36, -138, -221, -838, -1473, -1575, -1434, -1457, -1786, -2223, -2153, -1322, -754, -1276, -1781, -1070, 111, 871, 1206, 1248, 1445, 1913, 2362, 2440, 1757, 1052, 1442, 2438, 2573, 1940, 1752, 1883, 1495, 900, 490, 152, 340, 628, 295, -167, -224, 115, 631, 808, 175, -466, -163, 407, 476, 151, -317, -503, -51, 359, -420, -1620, -1462, -532, -402, -829, -914, -586, 2, 611, 459, 143, 774, 1720, 1853, 1372, 1377, 1705, 1632, 1330, 1111, 905, 867, 1390, 2135, 2256, 1927, 1954, 2296, 2405, 2083, 1499, 1054, 1103, 1438, 1124, 94, -537, -282, 358, 602, 260, 30, 157, 150, 69, 29, -172, -88, 562, 1079, 1070, 929, 1097, 1724, 2359, 2161, 1505, 1812, 2814, 3265, 2850, 2054, 1643, 1531, 1355, 1238, 816, 305, 340, 89, -1006, -2060, -2361, -2003, -1648, -1970, -2693, -2984, -2466, -1706, -1529, -1829, -1777, -992, -227, -68, 156, 714, 1200, 1716, 2112, 2119, 1824, 1469, 1737, 2623, 2825, 2288, 2462, 3130, 3109, 2428, 1632, 1174, 1029, 856, 562, -33, -632, -506, -79, -252, -897, -1331, -1096, -469, -192, -570, -902, -661, -470, -644, -600, -194, 69, 377, 782, 704, 504, 1018, 1845, 1940, 1329, 1062, 1502, 1581, 425, -369, 534, 1141, 769, 691, 130, -800, -300, 1045, 1393, 408, -762, -1152, -892, -647, -847, -1380, -1943, -2179, -1785, -1139, -1331, -2018, -1971, -1657, -1783, -1898, -1677, -1391, -982, -421, -340, -633, -340, 593, 1239, 970, 420, 715, 1604, 1889, 1483, 1005, 841, 1018, 758, 231, 524, 1185, 1742, 2210, 2151, 1647, 1342, 1472, 1293, 456, -285, -473, -239, -75, -122, -351, -940, -1130, -299, 252, -168, -278, 295, 796, 1001, 989, 862, 1218, 2102, 2525, 2188, 2091, 2606, 2996, 3135, 3240, 3058, 2988, 3423, 3432, 2406, 1095, 551, 1115, 1546, 692, -540, -854, -401, -297, -839, -1401, -1467, -823, 235, 800, 263, -341, 132, 635, -25, -920, -1000, -452, 374, 1099, 1328, 1230, 1487, 2364, 3143, 3161, 2654, 2138, 2037, 2222, 1955, 1306, 1026, 1238, 1582, 1717, 1270, 781, 935, 832, 152, -503, -1071, -961, -202, 146, -111, -184, 311, 901, 1184, 701, -178, 116, 1245, 1405, 991, 1067, 1521, 1740, 1453, 988, 503, 247, 208, -20, -179, 301, 1010, 1252, 1121, 815, 238, -243, 14, 340, 16, -301, -203, 83, 87, -320, -788, -1103, -898, -496, -559, -826, -829, -343, 385, 383, -497, -928, -198, 709, 734, 213, -137, -99, 411, 840, 461, -104, 195, 844, 883, 518, 265, 113, 283, 954, 1282, 1005, 1034, 1474, 1813, 1854, 1403, 903, 1271, 2198, 2432, 1917, 1956, 2734, 3073, 2663, 2095, 1771, 1957, 2621, 2826, 2027, 1481, 1813, 1908, 1382, 834, 496, 598, 1364, 1990, 1555, 728, 816, 1826, 2523, 2188, 1361, 878, 1441, 2358, 2352, 1804, 1668, 1972, 2306, 2410, 1988, 1649, 2348, 3130, 2862, 2024, 1273, 1180, 1746, 1855, 1050, 428, 960, 1906, 1579, 94, -845, -752, -536, -940, -1570, -1543, -699, 246, 386, -254, -675, -177, 823, 1389, 1157, 975, 1602, 2357, 2476, 2063, 1571, 1597, 2195, 2546, 2376, 2239, 2168, 1898, 1510, 812, -71, -221, 377, 641, -121, -1011, -809, -400, -509, -518, -509, -625, -238, 584, 720, 170, 91, 711, 1209, 1140, 1055, 1377, 1913, 2520, 2882, 2609, 2268, 2569, 2979, 2770, 2226, 1699, 1440, 1585, 1402, 525, -262, -215, 295, 199, -307, -626, -719, -79, 674, 329, -666, -1086, -549, 117, 29, -414, -383, 5, 148, -160, -516, -334, 256, 463, 326, 10, -581, -724, -165, 367, 191, -619, -1126, -1067, -1409, -2002, -1614, -513, 274, 419, 149, -81, 119, 615, 816, 703, 395, 385, 1403, 2255, 1820, 1234, 1478, 2033, 2355, 2124, 1336, 1082, 1761, 2348, 2195, 1465, 1031, 1435, 1799, 1365, 912, 805, 591, 879, 1559, 1679, 1712, 2192, 2701, 2846, 2424, 1496, 1008, 1671, 2726, 2883, 2451, 2776, 3639, 3941, 3503, 2940, 2909, 3169, 3330, 3269, 2717, 2226, 2191, 2151, 1573, 800, 601, 828, 1091, 706, -258, -464, 17, 322, 373, -43, -586, -122, 991, 1400, 1188, 1361, 1811, 2032, 2327, 2595, 2545, 2370, 2313, 2340, 2046, 1509, 1305, 1465, 1554, 1405, 1262, 1467, 2072, 2717, 2812, 2093, 1331, 1269, 1245, 459, -561, -928, -802, -604, -426, -444, -569, -555, -592, -832, -1282, -1505, -729, 461, 947, 499, -192, 19, 773, 786, -38, -480, 278, 1139, 929, 155, -94, 383, 629, 3, -1111, -1911, -1954, -1666, -1618, -1861, -2047, -2012, -2017, -1918, -1489, -1091, -818, -208, 770, 1404, 1665, 2265, 2780, 2490, 1738, 939, 509, 850, 1671, 2234, 2318, 2432, 2844, 3107, 3018, 2939, 2728, 2296, 2247, 2389, 1883, 965, 716, 831, 316, -566, -1486, -1882, -1417, -1394, -2144, -2680, -2886, -2740, -2408, -2868, -3530, -3182, -2467, -1732, -1138, -1523, -1847, -896, 91, 124, 43, 351, 585, 592, 419, -39, -233, 474, 1138, 580, -495, -737, -419, -349, -418, -835, -1229, -1013, -837, -960, -1294, -1594, -1298, -907, -837, -947, -1087, -958, -730, -391, 195, 452, 456, 861, 1623, 2254, 2470, 2514, 2623, 2738, 2518, 1849, 1268, 1090, 974, 543, -195, -620, -218, 711, 1290, 1090, 928, 1203, 1758, 2246, 1890, 1347, 1734, 2332, 2312, 1748, 1294, 1569, 1997, 2062, 1622, 966, 712, 509, 71, -258, -728, -1349, -1824, -1939, -1844, -2308, -2622, -1817, -1086, -1421, -2124, -2541, -2475, -1818, -1157, -1091, -1155, -843, -295, -130, -548, -1089, -1143, -644, -453, -760, -620, -183, -150, 154, 662, 479, 77, 103, -17, -766, -1464, -1349, -598, -181, -473, -828, -874, -804, -631, -411, -476, -950, -1243, -1109, -1437, -2111, -2040, -1430, -1397, -1769, -1692, -1533, -1476, -894, -280, -373, -687, -548, -266, -525, -1202, -1605, -1331, -882, -841, -1286, -1889, -1993, -1543, -1176, -1323, -1564, -1458, -1237, -1141, -1195, -1327, -1348, -804, 280, 769, 396, 343, 876, 1078, 867, 486, 111, 151, 208, -325, -1105, -1354, -1200, -1626, -2581, -2994, -2857, -2740, -2563, -2514, -3038, -3518, -3176, -2451, -2146, -2377, -2279, -1437, -765, -762, -1009, -1703, -2766, -2909, -2281, -2294, -2698, -2687, -2319, -1983, -2052, -2448, -2270, -1271, -679, -1102, -1784, -1951, -1554, -831, -256, -167, -37, 285, 464, 488, -175, -1344, -1924, -1879, -2068, -2447, -1811, -511, 205, 236, -435, -1472, -1893, -1713, -1897, -2929, -3847, -3571, -2746, -2194, -2059, -2181, -2006, -1512, -1171, -999, -1046, -871, -122, 163, 53, 540, 1178, 1557, 1903, 1995, 1830, 1805, 2075, 2478, 2404, 1593, 735, 347, -57, -974, -2131, -2848, -2680, -1975, -1682, -2192, -2767, -3021, -3084, -2906, -2996, -3360, -2953, -1973, -1634, -2061, -2593, -2151, -417, 751, 556, 535, 1038, 1371, 1627, 3852, 3422, 2350, 1930, 2724, 3098, 2542, 2045, 1935, 1946, 1859, 1798, 1658, 1210, 959, 758, 202, -144, -195, -613, -1279, -1399, -964, -171, 869, 1462, 1867, 2649, 3468, 4168, 4373, 4072, 3754, 2911, 1562, 832, 797, 737, 852, 1659, 2196, 1802, 1450, 1459, 1556, 1782, 1824, 1403, 1281, 1467, 908, -11, -282, -131, -113, -28, 110, 60, 266, 610, 433, 236, 421, 1072, 2185, 2743, 2537, 2500, 2350, 1878, 1775, 2015, 2224, 2437, 2305, 1927, 1799, 1586, 969, 551, 1194, 2189, 2123, 1404, 1180, 1370, 1238, 780, 428, 37, -476, -438, 408, 1231, 1273, 1284, 1902, 2104, 1553, 1083, 722, 549, 641, 352, -30, 291, 539, -8, -95, 676, 826, 270, 95, 387, 765, 849, 601, 553, 650, 534, 541, 892, 1123, 964, 799, 1239, 1779, 1632, 1297, 1286, 1437, 1605, 1832, 2274, 2428, 1792, 1023, 810, 1000, 1152, 1003, 754, 888, 1435, 1621, 1171, 1014, 1242, 865, 303, 263, 233, 23, -34, 151, 274, 251, 450, 669, 525, 637, 1424, 1836, 1176, 625, 1178, 1768, 1547, 1579, 2631, 3376, 2828, 2043, 2235, 3106, 3542, 3367, 2996, 2473, 1932, 1751, 1753, 1286, 571, 539, 1386, 2414, 3272, 4035, 4464, 4631, 5202, 5952, 6176, 6058, 5451, 4211, 3692, 4072, 4129, 4314, 4908, 4721, 4064, 4334, 5078, 4924, 4229, 4288, 4579, 4322, 4118, 3629, 2610, 2051, 1573, 625, -119, -430, -442, -409, -503, -672, -811, -649, -381, -332, -351, -281, -20, 200, -276, -1340, -2113, -2540, -3065, -3277, -2642, -1668, -961, -384, 84, 487, 759, 693, 367, -413, -1341, -1794, -1940, -1981, -1795, -1609, -1582, -1519, -1377, -1293, -1540, -2347, -3008, -2744, -2157, -2142, -2322, -1989, -1469, -1263, -1597, -2151, -2340, -2394, -2765, -3098, -2807, -2244, -2050, -1763, -1000, -501, -477, -277, 300, 523, 94, -402, -567, -385, -47, 152, -18, -240, -196, -353, -1002, -1754, -2320, -3013, -3955, -4339, -3706, -3264, -3698, -3449, -2463, -2483, -3041, -3498, -4146, -4404, -3883, -3302, -3125, -3083, -3143, -3132, -2601, -2107, -2385, -3067, -3525, -3686, -3672, -3665, -3514, -3127, -2927, -2803, -2658, -2581, -2349, -2166, -2253, -2397, -2338, -1981, -1637, -1954, -2845, -3398, -3378, -3467, -3560, -3273, -3104, -3276, -3441, -3385, -2949, -2529, -2589, -2653, -2032, -1061, -683, -931, -1198, -1076, -757, -603, -432, 57, 208, -292, -369, -293, -1285, -2339, -2316, -2048, -2062, -1984, -1859, -1864, -2145, -2796, -3539, -4127, -4765, -5161, -4833, -4216, -3633, -2860, -2051, -1733, -2002, -2240, -2182, -2029, -1796, -1787, -1898, -1599, -1073, -750, -617, -494, -306, -58, 27, -288, -810, -1289, -1499, -1397, -1604, -1977, -1837, -1496, -1626, -2141, -2347, -2129, -1917, -1558, -1115, -1176, -1684, -1896, -1575, -1247, -1118, -1104, -1434, -1930, -1623, -1169, -1877, -2335, -1723, -1537, -2103, -2704, -3189, -3299, -2967, -3025, -3339, -3139, -2690, -2275, -2131, -2415, -2559, -2453, -2565, -2690, -2825, -3118, -3301, -3507, -3823, -4061, -4383, -4815, -5045, -4958, -4502, -4050, -3953, -3777, -3521, -3599, -3952, -4274, -4314, -4185, -4123, -3819, -3312, -3146, -3099, -2820, -2769, -2919, -2568, -2097, -2325, -2887, -3307, -3603, -3763, -3850, -3964, -3550, -2460, -1970, -2429, -2589, -2307, -2313, -2436, -2490, -2576, -2619, -2409, -1913, -1453, -1329, -1547, -1773, -1764, -1723, -2005, -2252, -1826, -1214, -1380, -2211, -3120, -3640, -3614, -3323, -2772, -2081, -1505, -1115, -1038, -1268, -1417, -1339, -1212, -971, -709, -611, -674, -880, -1177, -1657, -2367, -2743, -2551, -2392, -2486, -2555, -2308, -1571, -724, -288, -362, -836, -1344, -1685, -1978, -2314, -2700, -2861, -2527, -1806, -1216, -1022, -831, -630, -602, -599, -651, -748, -735, -516, -620, -1369, -1817, -1789, -2184, -2748, -2914, -2960, -3112, -3076, -2537, -2034, -2114, -2103, -1609, -1258, -1260, -1359, -1220, -826, -524, -559, -873, -1190, -1656, -2302, -2854, -3302, -3517, -3508, -3219, -2518, -1897, -1420, -833, -571, -873, -1429, -1761, -1739, -1484, -1512, -2244, -2960, -3025, -2739, -2546, -2269, -1745, -1237, -948, -1330, -2175, -2357, -1866, -1641, -1736, -1722, -1783, -2082, -2515, -2667, -2351, -2302, -2357, -1751, -967, -625, -636, -805, -693, -127, 272, 663, 1304, 1528, 1077, 263, -584, -1261, -1681, -1970, -2236, -2007, -1381, -1088, -1000, -841, -642, -522, -691, -1352, -2085, -2210, -2084, -2024, -1770, -1737, -2158, -2607, -2856, -2700, -2186, -1838, -1951, -2176, -1960, -1372, -1159, -1478, -1578, -1013, -245, 277, 413, 159, -389, -1365, -2314, -2355, -2037, -1948, -1717, -1651, -2023, -2472, -2688, -2670, -2671, -2793, -2654, -2301, -2095, -1865, -1915, -2172, -2001, -1799, -2012, -2299, -2200, -1958, -1961, -1754, -1049, -486, -343, -84, 125, -320, -735, -520, -385, -697, -760, -410, -321, -440, -203, 295, 521, 561, 681, 246, -767, -1645, -2412, -3375, -4113, -4134, -3921, -3670, -3220, -2616, -1785, -1120, -1165, -1747, -2198, -2172, -1982, -2128, -2193, -1887, -1915, -1898, -1135, -341, 115, 640, 1069, 1189, 1261, 1466, 1466, 1096, 656, 227, 16, 88, 19, -146, -276, -510, -737, -1020, -1411, -1685, -1927, -2374, -2590, -2456, -2466, -2331, -1862, -1576, -1627, -1659, -1596, -1713, -1757, -1600, -1631, -1495, -1163, -993, -679, -234, 96, 207, 183, 299, 185, -230, -217, 314, 671, 548, 275, 223, 402, 260, -149, -387, -830, -1631, -2392, -2945, -3217, -2987, -2605, -2656, -3150, -3520, -3252, -2392, -1229, -538, -307, 430, 1327, 1616, 1406, 875, -71, -1439, -2565, -2767, -2790, -3313, -3575, -3180, -2618, -2182, -1697, -1199, -1202, -1478, -1238, -917, -980, -851, -547, -445, -52, 945, 1742, 1922, 1770, 1541, 1395, 1379, 1465, 1490, 1232, 571, -15, -402, -1139, -1861, -1863, -1529, -1300, -1172, -1062, -824, -737, -1240, -2107, -2829, -3125, -3071, -3018, -3113, -3137, -2687, -1972, -1634, -1489, -1262, -1081, -832, -687, -651, -480, -517, -590, -233, -4, -250, -364, -207, -248, -616, -1083, -1248, -1222, -1219, -891, -490, -411, -358, -140, 97, 119, 0, -186, -448, -514, -561, -627, -339, -27, -166, -579, -1066, -1541, -1567, -1109, -897, -1137, -1357, -1474, -1695, -2161, -2781, -3225, -3286, -3179, -2861, -2010, -1018, -587, -744, -560, 216, 896, 1037, 462, -543, -1363, -1530, -1367, -1410, -1444, -1418, -1395, -851, 139, 716, 612, 479, 510, 192, -188, -449, -740, -685, -415, -480, -794, -903, -727, -617, -675, -799, -967, -743, -151, 98, -41, -142, -286, -247, 129, 295, 394, 795, 1247, 1407, 1188, 705, 156, -460, -883, -904, -1203, -1790, -1740, -1373, -1454, -1577, -1610, -1764, -1667, -1072, -225, 311, 729, 1170, 840, -87, -745, -1057, -1107, -1261, -1708, -1551, -782, -433, -713, -899, -1003, -1414, -1517, -1227, -1128, -1228, -1159, -708, -257, -79, 29, 170, 307, 318, 176, -91, -620, -892, -546, -357, -299, 163, 490, 280, 151, 71, -516, -1157, -1442, -1645, -1590, -1167, -1109, -1274, -777, -335, -502, -147, 639, 611, 63, 64, 167, -167, -273, 86, 266, 188, 52, -162, -388, -819, -1117, -815, -321, -261, -507, -329, -25, -240, -683, -818, -763, -764, -358, 328, 563, 639, 866, 967, 1037, 1349, 1515, 1172, 762, 735, 736, 542, 712, 1254, 1336, 710, 69, -95, -14, -232, -832, -1201, -928, -371, -203, -315, -545, -870, -885, -788, -1002, -1084, -681, -303, -235, -173, 247, 601, 621, 633, 344, -45, -23, -54, -274, -315, -489, -915, -763, -28, 475, 742, 959, 985, 858, 764, 843, 1207, 1522, 1288, 651, 305, 349, 338, 564, 1001, 1091, 898, 647, 528, 583, 265, -292, -487, -662, -1174, -1520, -1160, -392, 145, 612, 1236, 1570, 1408, 953, 699, 632, 95, -527, -303, 358, 582, 632, 812, 738, 387, 263, 188, -216, -609, -565, -212, -39, 98, 504, 901, 1019, 1227, 1505, 1278, 699, 384, 359, 112, -520, -1054, -1151, -1346, -1694, -1262, -334, 19, -73, 9, 444, 845, 872, 839, 984, 1220, 1739, 2260, 2007, 1162, 686, 864, 971, 690, 473, 645, 1131, 1446, 1429, 1306, 1071, 502, -233, -439, -300, -267, 188, 1152, 1940, 2463, 2870, 3114, 3191, 2990, 2469, 1859, 1531, 1435, 1121, 663, 681, 971, 827, 547, 628, 711, 543, 241, -209, -681, -836, -635, -259, -102, -505, -1087, -1377, -1157, -609, -296, -203, 71, 709, 1654, 2481, 2743, 2561, 2088, 1364, 835, 755, 817, 917, 1166, 1435, 1491, 1254, 1204, 1413, 1322, 1127, 1082, 942, 897, 979, 600, 59, 92, 287, 82, 31, 296, 364, 397, 476, 399, 447, 697, 695, 551, 803, 851, 55, -585, -499, -440, -605, -464, -22, 337, 651, 901, 828, 544, 72, -552, -945, -1047, -1488, -2140, -2061, -1508, -1320, -1371, -1064, -492, -56, 477, 930, 698, 628, 1285, 1735, 1856, 2170, 2593, 2694, 2453, 2113, 1602, 1381, 1804, 2030, 1766, 1583, 1683, 1797, 1634, 1398, 1372, 1409, 1377, 1329, 1219, 1130, 1064, 811, 502, 403, 594, 949, 937, 596, 864, 1732, 2439, 2611, 2529, 2782, 2985, 2957, 3151, 3380, 3763, 4534, 4946, 4812, 4650, 4276, 3423, 2702, 2518, 2206, 1699, 1870, 2538, 2700, 2337, 2178, 2142, 1960, 1850, 1472, 1018, 1087, 738, -373, -1067, -1208, -1364, -1564, -1694, -1710, -1578, -1597, -1981, -2116, -1483, -910, -928, -1121, -1420, -1681, -1608, -1504, -1236, -514, 222, 1021, 1951, 2504, 2600, 2469, 2387, 2369, 2118, 1910, 2105, 2276, 1968, 1701, 2196, 2829, 2593, 1957, 1733, 1754, 1830, 1900, 1911, 1997, 1932, 1477, 1238, 1263, 972, 747, 808, 691, 310, -230, -618, -517, -198, -56, -130, -108, 179, 508, 798, 866, 819, 905, 712, 196, -326, -674, -545, 229, 994, 1487, 1997, 2115, 2037, 2231, 2122, 1879, 2354, 3060, 3435, 3813, 3927, 3342, 2538, 1958, 1806, 2024, 2456, 2779, 2390, 1409, 621, 184, -52, 183, 745, 835, 214, -166, 176, 569, 657, 775, 1050, 1103, 767, 287, -9, 352, 1275, 1978, 2143, 2024, 1862, 1850, 1989, 1770, 1069, 532, 188, -315, -519, -209, 46, 180, 719, 1314, 1342, 1152, 1214, 1307, 1128, 962, 852, 587, 284, 161, 95, -26, -117, -136, -187, -300, -226, 38, 140, 126, 156, 402, 1062, 1439, 929, 434, 794, 1318, 1400, 1406, 1624, 1840, 1859, 1753, 1412, 934, 722, 655, 573, 680, 835, 639, 280, 105, -56, -303, -231, 228, 587, 867, 1144, 1103, 961, 952, 857, 531, 229, 385, 864, 1204, 1348, 1628, 2074, 2407, 2880, 3501, 3437, 2816, 2487, 2283, 1894, 1556, 1328, 1300, 1511, 1503, 1107, 827, 638, 322, -58, -700, -1409, -1830, -1777, -1373, -1007, -794, -642, -539, -427, -294, -413, -665, -670, -524, -396, -226, 32, 295, 410, 465, 716, 1069, 1181, 1065, 1064, 1262, 1196, 1093, 1514, 1861, 2023, 2408, 2496, 1951, 1405, 872, 212, 16, 191, 283, 173, 216, 557, 450, 112, 180, 335, 417, 377, 110, -73, 333, 989, 1353, 1704, 2033, 1950, 1489, 945, 639, 279, -484, -1052, -991, -723, -920, -1454, -1384, -529, 380, 1001, 1443, 1671, 1652, 1613, 1560, 1312, 983, 794, 599, 214, 35, 223, 258, -18, -217, -297, -505, -916, -1307, -1458, -1443, -1310, -948, -501, -137, 313, 799, 819, 506, 653, 900, 709, 647, 993, 1470, 1894, 2107, 2142, 1970, 1508, 724, -431, -1269, -1122, -766, -853, -963, -925, -902, -768, -447, -224, -373, -840, -1223, -1615, -2058, -1988, -1725, -1578, -1134, -588, -382, -352, -232, -66, -7, -216, -492, -421, 225, 1113, 1828, 2236, 2270, 2134, 1987, 1881, 1778, 1644, 1526, 1449, 1164, 961, 1354, 1685, 1306, 704, 701, 1187, 1510, 1424, 906, 169, -213, -80, -171, -480, -528, -464, -230, -100, -400, -680, -479, -127, -383, -941, -700, -91, 17, 26, 367, 887, 1234, 1320, 1197, 1021, 1027, 980, 605, 276, 196, 37, -56, 284, 701, 848, 848, 872, 1048, 1029, 666, 543, 657, 294, -382, -449, 29, 160, -111, 104, 701, 586, 56, 6, -22, -300, -260, -280, -735, -768, -307, -53, -132, -420, -384, 14, 161, 130, 55, -223, -311, 55, 460, 813, 1266, 1833, 1958, 1528, 1462, 1660, 1423, 986, 558, -16, -277, -175, -398, -859, -910, -786, -812, -775, -918, -1354, -1477, -1286, -1556, -1794, -1438, -1342, -1538, -1360, -897, -468, -39, 271, 299, 326, 405, 270, 373, 884, 1154, 1046, 901, 1079, 1329, 1129, 886, 847, 599, 300, 118, -313, -665, -489, -485, -1184, -1897, -1882, -1501, -1382, -1346, -939, -455, -591, -957, -788, -510, -497, -404, -280, -376, -573, -740, -754, -597, -668, -848, -755, -767, -837, -770, -868, -945, -689, -329, 43, 643, 1230, 1280, 1258, 1762, 1966, 1485, 1203, 1148, 741, 499, 808, 1283, 1773, 2235, 2616, 2743, 2458, 2442, 2754, 2365, 1450, 679, 225, 334, 615, 490, 313, 629, 946, 681, 310, 292, 160, -141, -128, -116, -337, -95, 661, 1153, 1433, 1699, 1404, 615, 159, 143, 41, -346, -913, -1287, -1264, -1129, -1172, -1332, -1388, -1489, -1656, -1481, -1153, -926, -768, -967, -1298, -1136, -734, -552, -468, -399, -283, 71, 659, 940, 700, 484, 538, 613, 543, 516, 526, 491, 616, 637, 217, -211, -258, -158, -249, -470, -534, -642, -1051, -1588, -1868, -1761, -1402, -1094, -1065, -1138, -1331, -1451, -1049, -601, -584, -821, -1005, -1110, -1313, -1665, -1853, -1595, -1275, -931, -263, 420, 657, 691, 875, 1082, 1300, 1204, 555, 206, 426, 548, 409, 128, -85, -150, -399, -444, -144, -303, -640, -472, -451, -1050, -1359, -755, -229, -456, -450, 236, 703, 522, 152, 64, -203, -784, -1179, -1437, -1561, -1613, -1728, -1762, -1709, -1494, -1174, -1105, -1160, -1049, -754, -237, 533, 1168, 1249, 1189, 1615, 1904, 1583, 1476, 1797, 1876, 1652, 1518, 1428, 1367, 1435, 1613, 1817, 1963, 2076, 1995, 1968, 2213, 2054, 1569, 1484, 1588, 1659, 1646, 1452, 1381, 1471, 1579, 1890, 1929, 1118, 348, 192, -85, -424, -180, 212, 506, 856, 1015, 1202, 1688, 1872, 1421, 932, 735, 704, 767, 684, 370, 338, 725, 874, 567, 159, -378, -965, -1301, -1454, -1435, -1356, -1307, -1141, -854, -767, -999, -1068, -721, -456, -563, -529, 179, 1132, 1317, 1034, 1369, 1811, 1736, 1839, 2028, 1532, 882, 981, 1507, 1562, 1153, 904, 765, 440, 154, -104, -579, -871, -584, -302, -436, -694, -805, -890, -1017, -1250, -1645, -1737, -1761, -2168, -2215, -1563, -854, -523, -199, 240, 318, 439, 746, 563, 289, 544, 994, 1261, 1128, 867, 1050, 1136, 301, -508, -271, -214, -952, -1161, -777, -847, -1470, -1945, -1658, -1195, -1266, -1522, -1515, -1405, -1306, -1011, -711, -625, -684, -613, -318, -317, -815, -937, -367, -434, -1275, -1626, -1241, -886, -977, -924, -474, -89, 199, 473, 673, 1004, 1230, 1043, 832, 593, 291, 333, 755, 1181, 1074, 637, 463, 490, 372, 24, -263, -279, -34, 330, 465, 226, -311, -794, -1011, -869, -285, 321, 614, 794, 981, 1018, 768, 291, -116, 117, 753, 904, 949, 1492, 1848, 1665, 1741, 1991, 1704, 1234, 1166, 1377, 1123, 302, -153, 303, 1006, 1023, 971, 1384, 1399, 706, -322, -1269, -1810, -1842, -1543, -1364, -1234, -459, 484, 690, 438, 109, 6, 302, 526, 552, 602, 620, 712, 837, 862, 814, 979, 1331, 1447, 1217, 713, 243, 183, 469, 641, 355, 336, 845, 983, 498, -293, -920, -982, -1083, -1612, -1731, -1410, -1643, -2207, -2128, -1723, -1660, -1455, -973, -1005, -1514, -1622, -1315, -1139, -906, -316, 332, 986, 1667, 1859, 1691, 1713, 1402, 475, -443, -935, -1027, -884, -673, -664, -962, -1006, -733, -887, -1116, -944, -1178, -1879, -2105, -1837, -1793, -2224, -2826, -3046, -2823, -2457, -2184, -2027, -1768, -1533, -1390, -1097, -710, -483, -487, -516, -478, -267, 239, 670, 771, 685, 328, -206, -464, -625, -1098, -1258, -793, -584, -956, -1096, -810, -547, -290, -175, -313, -398, -238, -38, -25, 42, 69, -470, -1064, -704, 196, 662, 685, 527, 374, 345, 360, 511, 635, 317, -108, -255, -230, 403, 1612, 2178, 1976, 1927, 1986, 1691, 1315, 1129, 839, 455, 120, -303, -498, -398, -207, 327, 866, 766, 284, -124, -43, 271, 70, -548, -1044, -1078, -812, -633, -381, 56, 366, 456, 118, -793, -1537, -1779, -1722, -1374, -757, 151, 1005, 1544, 1850, 1745, 1102, 283, 161, 544, 193, -306, -28, 488, 1046, 1504, 1386, 959, 485, -66, -224, -212, -409, -375, -322, -750, -1119, -693, -124, -192, -459, -743, -1042, -1023, -1047, -1354, -1457, -1251, -772, -155, 85, 13, 164, 706, 1168, 1085, 827, 735, 634, 354, 58, 250, 821, 969, 524, -191, -751, -877, -1239, -1902, -1976, -1460, -981, -868, -1037, -1343, -1718, -1923, -2064, -2316, -2560, -2744, -2650, -2497, -2418, -2001, -1541, -1631, -1886, -1484, -894, -1028, -1456, -1438, -1119, -705, -41, 644, 1046, 968, 547, 104, -399, -973, -1075, -676, -474, -437, -458, -455, -160, 90, -86, -409, -450, -256, -246, -710, -1210, -1147, -678, -98, 445, 664, 624, 558, 532, 529, 642, 996, 1384, 1437, 1224, 1033, 820, 323, -319, -509, -170, 180, 368, 600, 912, 1233, 1606, 1702, 1257, 355, -612, -1123, -1286, -1170, -924, -1050, -1237, -770, -31, 9, -286, -216, -266, -445, -409, -509, -704, -614, -415, -278, -51, -4, -503, -929, -991, -1359, -1989, -2247, -1965, -1182, -279, 272, 775, 1369, 1550, 1093, 375, -201, -533, -713, -833, -977, -875, -572, -653, -753, 98, 1290, 1784, 1861, 1986, 1981, 1385, 481, -234, -881, -1531, -1933, -1977, -1615, -1187, -1475, -2264, -2686, -2848, -3410, -4070, -4136, -3798, -3753, -4012, -4149, -4442, -4949, -4690, -4052, -4081, -3829, -2974, -2246, -1478, -502, 18, -107, -90, 149, 23, -498, -856, -900, -919, -527, 404, 1236, 1597, 1388, 963, 791, 622, 23, -548, -606, -741, -1318, -1633, -1773, -2387, -2962, -3052, -2932, -2984, -3365, -3830, -4018, -3942, -3741, -3529, -3455, -3051, -1836, -877, -865, -734, -381, -616, -898, -721, -932, -1571, -1931, -2179, -2331, -2027, -1468, -1296, -1370, -859, -114, 3, -141, -94, -168, -315, -284, -263, -152, 254, 387, 85, -91, 226, 571, 3, -950, -1226, -1090, -1142, -1232, -1381, -1520, -1353, -1046, -1156, -1846, -2382, -2104, -1503, -1456, -1687, -1718, -1582, -1453, -1344, -973, -714, -713, -250, 402, 638, 717, 833, 1215, 1891, 2032, 1733, 1934, 2522, 2893, 3030, 2758, 2055, 1394, 1004, 842, 675, 343, 313, 594, 406, -320, -813, -525, 106, 493, 1053, 1749, 1849, 1876, 2351, 2631, 2710, 3464, 4435, 4692, 4926, 5290, 5017, 4395, 3526, 2201, 1290, 1207, 1048, 359, -155, -144, -207, -528, -679, -482, -103, 74, 108, 404, 954, 1538, 2060, 2726, 3506, 3697, 3212, 2905, 2815, 2353, 1972, 2090, 2160, 2142, 2343, 2512, 2481, 2394, 2254, 1566, 380, -466, -1028, -1684, -2042, -1811, -1584, -1620, -1299, -669, -255, -368, -782, -1036, -1022, -1147, -1683, -1793, -1587, -1998, -2642, -2767, -2334, -1400, -277, 348, 586, 992, 1421, 1219, 656, 627, 774, 118, -1158, -1860, -1609, -1399, -1753, -1927, -1528, -1370, -1700, -1620, -1159, -1181, -1426, -1077, -705, -1066, -1412, -1334, -1402, -1238, -502, 37, 292, 298, -330, -1101, -1296, -1059, -932, -1205, -1473, -1314, -1428, -2041, -2725, -3411, -3653, -3321, -3113, -3206, -3326, -3364, -3024, -2380, -1925, -1764, -1502, -1244, -1559, -2312, -3085, -3895, -4526, -4397, -3516, -2530, -1928, -1652, -1242, -867, -1174, -1786, -2067, -1874, -1486, -1451, -1332, -622, -346, -863, -1110, -1288, -1972, -2406, -2413, -2316, -1840, -1121, -756, -788, -604, -118, 177, 284, 479, 651, 396, -231, -519, -455, -679, -1130, -1605, -2196, -2588, -2569, -2680, -3129, -3597, -4082, -4658, -4955, -4614, -4068, -3207, -1734, -581, -18, 601, 1142, 1272, 1325, 1749, 2413, 2893, 3067, 3116, 3159, 2805, 2022, 1696, 1971, 1912, 1355, 808, 489, 132, -630, -1747, -2445, -2276, -2013, -2383, -2768, -2345, -1719, -1671, -1339, -451, -48, -49, 151, 108, -212, -193, -92, -124, 151, 722, 1205, 1771, 1059, -71, -560, -70, 269, -211, -1173, -1702, -1434, -1065, -468, 546, 1270, 1935, 2408, 1750, 638, 53, -375, -743, -895, -1440, -2042, -1742, -1268, -1023, -93, 1276, 2085, 2379, 2626, 2234, 967, 239, 760, 1294, 942, 378, 296, 513, 678, 685, 703, 1101, 1715, 1962, 1613, 818, -43, -752, -1373, -1858, -1809, -1464, -1299, -1003, -651, -578, -608, -721, -928, -1268, -1778, -1675, -972, -377, -89, -496, -1187, -1205, -672, -314, -598, -1125, -935, -399, -221, -294, -525, -353, 280, 378, -95, -343, 125, 869, 1042, 951, 915, 675, 765, 1165, 1018, 268, -144, 498, 1380, 1296, 609, 170, 131, 323, 208, -95, 17, 136, -116, -289, 29, 597, 922, 1063, 1119, 810, 206, -83, 275, 687, 556, 157, -80, -125, -362, -1140, -1850, -1792, -1220, -730, -707, -469, 494, 1519, 2095, 1873, 1046, 378, -110, -471, -421, -334, -601, -865, -931, -993, -1048, -802, -451, -680, -1146, -1041, -707, -716, -946, -1259, -1828, -2206, -1734, -1284, -1532, -1523, -787, -171, 61, 16, -413, -801, -1147, -1404, -1096, -818, -1234, -1248, -110, 894, 1084, 1461, 2040, 2203, 2209, 2207, 2033, 1318, 495, 382, 935, 1504, 1704, 1839, 1925, 1320, 393, -4, 13, 236, 317, -6, -68, 427, 957, 1637, 2268, 2206, 2026, 2546, 3002, 2383, 1234, 695, 758, 841, 540, -688, -1918, -1753, -1245, -1605, -1957, -1683, -1112, -506, -170, -321, -612, -588, -540, -1089, -1919, -2123, -1644, -996, -733, -1220, -1713, -1615, -1253, -823, -215, 611, 943, 877, 1452, 2227, 2459, 2546, 2372, 1367, 0, -895, -1162, -995, -784, -859, -1080, -1609, -2210, -2225, -2196, -2485, -2137, -1483, -1359, -1438, -1276, -670, 102, 419, 50, -443, -655, -647, -668, -1024, -1315, -1206, -1115, -1067, -1111, -1549, -2070, -2071, -1578, -1601, -2228, -2477, -2316, -2198, -2071, -1881, -1546, -1138, -1122, -1387, -1485, -1711, -2246, -2683, -2921, -3158, -3166, -3016, -2889, -2208, -1277, -880, -554, -268, -577, -1031, -960, -823, -963, -657, -289, -661, -1081, -1097, -819, -526, -587, -834, -647, -365, -493, -577, -781, -1099, -941, -1112, -2086, -2675, -2455, -2094, -1897, -2051, -2407, -2429, -2344, -2380, -2138, -1772, -1372, -544, 45, -204, -658, -808, -760, -1051, -1880, -2335, -1860, -1014, -719, -1121, -1285, -591, 154, 43, -406, -709, -1229, -1621, -1278, -1108, -1967, -2928, -3086, -2382, -1769, -2108, -2436, -1923, -1135, -1072, -1855, -2404, -2316, -2065, -1675, -1339, -1283, -902, -40, 558, 232, -479, -557, -605, -1417, -2111, -1944, -1341, -771, -356, 83, 535, 590, 322, 57, -321, -807, -975, -808, -536, -508, -793, -630, 86, 491, 360, 246, 101, -231, -437, -611, -671, -936, -1761, -1901, -811, 307, 382, -319, -766, -510, -50, -449, -1151, -800, -149, -62, -325, -887, -1045, -509, -810, -1965, -2222, -1618, -1125, -861, -666, -286, 127, 108, -216, -859, -1598, -1749, -1955, -2682, -3179, -3500, -3800, -3784, -3588, -3597, -3879, -3947, -3448, -3004, -3343, -3910, -3939, -3529, -3047, -2659, -2700, -3037, -2647, -1721, -1581, -1968, -1278, 35, 389, -174, -1044, -1757, -1951, -1736, -1547, -1800, -2058, -1674, -1351, -1854, -2610, -2807, -2453, -2089, -2038, -2301, -2594, -2458, -1898, -1441, -1454, -1914, -2499, -2770, -2753, -2590, -2238, -1785, -956, -340, -1283, -2930, -3457, -3008, -2414, -1842, -1565, -1553, -1429, -1449, -1613, -1496, -1505, -1776, -1411, -564, -145, 132, 718, 1127, 812, 109, -157, 12, -96, -503, -948, -1304, -1146, -455, 35, -198, -1003, -1852, -2211, -2398, -3050, -3321, -2373, -1081, -368, -158, -54, 13, -173, -473, -767, -1181, -1329, -886, -38, 318, -139, -376, 229, 929, 990, 493, 3, -87, -247, -475, -454, -455, -722, -1233, -1658, -2152, -2931, -2858, -1233, 430, 910, 888, 1095, 995, 440, 217, 198, 91, 67, -228, -620, -746, -758, -673, -481, -269, -187, 18, 634, 1089, 899, 516, 24, -704, -696, -100, -128, -357, 106, 964, 1205, 865, 753, 531, -132, -597, -776, -916, -976, -1210, -1326, -1082, -1077, -1035, -412, 126, -144, -835, -1223, -891, 163, 741, 233, -261, -77, 5, -716, -1521, -1817, -1737, -1491, -1427, -1293, -689, 233, 1046, 1327, 1445, 1898, 2252, 1975, 1441, 1066, 623, -46, -505, -907, -1723, -2430, -2490, -2051, -1116, -79, 382, 646, 1059, 986, 491, 15, -500, -539, 69, 465, 166, -354, -959, -1630, -1764, -1342, -538, 726, 1694, 1451, 498, -449, -1440, -2199, -2228, -1850, -1411, -878, -388, -8, 86, 246, 844, 1051, 709, 476, 155, -163, -124, -43, -219, -615, -947, -947, -893, -1072, -900, -251, 184, 453, 767, 968, 1345, 1878, 2183, 2154, 1811, 1639, 2039, 2157, 1420, 682, 626, 842, 843, 589, 46, -398, -226, 285, 484, 224, 34, 127, 562, 1579, 2622, 3157, 3668, 4164, 3935, 3526, 3606, 3898, 4298, 4453, 4055, 3682, 3585, 3473, 3084, 2236, 1384, 1043, 1248, 1750, 2169, 2105, 1738, 1741, 1847, 1584, 1258, 1099, 1011, 845, 611, 451, 669, 1145, 1428, 1776, 1844, 1338, 1260, 1673, 1615, 1055, 592, 665, 728, 390, -58, -584, -700, -455, -672, -799, -145, 604, 1042, 1348, 1364, 876, 256, 65, 211, 139, -223, -174, 610, 1263, 951, 361, 113, 0, -32, -471, -1444, -1805, -1196, -915, -1153, -822, -288, -249, -302, -166, -121, -206, 3, 300, 24, -844, -1677, -1980, -2012, -1997, -1627, -1134, -892, -495, -204, -860, -1487, -1027, -343, -135, -218, -353, -168, 420, 1163, 1929, 2621, 2981, 3212, 3619, 3677, 3290, 2979, 2761, 2234, 1090, -386, -1346, -1556, -1617, -1792, -1555, -919, -477, -258, -47, -65, -512, -678, -180, 161, -93, -577, -799, -922, -1454, -1919, -1790, -1381, -1008, -994, -1234, -1256, -829, 98, 1193, 1596, 1072, 391, -88, -630, -1171, -1319, -920, -166, 553, 840, 805, 806, 984, 1184, 1118, 804, 540, 525, 796, 1103, 899, 529, 852, 1312, 987, 11, -843, -1190, -1462, -1580, -1410, -1552, -2008, -2085, -1698, -1513, -1606, -1308, -352, 538, 920, 1213, 1582, 1639, 1025, 356, 495, 1160, 1699, 1857, 1463, 643, 336, 858, 1243, 1188, 1062, 1019, 1323, 1798, 1831, 1403, 1090, 1329, 1677, 1155, -30, -765, -689, -343, -216, -132, 66, 204, 598, 1199, 1218, 778, 912, 2038, 3291, 3796, 3429, 2717, 2501, 2705, 2520, 1988, 1763, 1549, 676, -350, -802, -974, -1175, -1041, -561, -559, -869, -444, 127, 146, 276, 425, 250, 118, 245, 605, 1006, 1308, 1464, 1319, 1238, 1151, 879, 1011, 1135, 453, -276, -264, -24, -20, -127, -433, -599, -61, 730, 1021, 836, 780, 1120, 1379, 1516, 2033, 2740, 3369, 3685, 3167, 2091, 1056, 90, -823, -1420, -1235, -868, -703, -31, 617, 275, -481, -507, 43, 269, 314, 600, 816, 970, 1288, 1281, 1075, 1766, 3072, 3359, 2412, 1541, 1172, 968, 907, 852, 555, 208, 217, 331, 115, -364, -547, -38, 643, 508, -22, 194, 637, 606, 448, 204, 13, 572, 1767, 2314, 1864, 1303, 888, 566, 760, 1609, 2409, 2593, 2433, 2355, 2461, 2718, 2928, 3065, 3133, 2694, 1767, 681, -673, -2054, -2643, -2555, -2412, -1969, -1285, -930, -758, -323, 371, 815, 631, 493, 1010, 1489, 1203, 442, -206, -318, 311, 1154, 1515, 1948, 2742, 3008, 2634, 2030, 1295, 778, 647, 552, 181, -293, -522, -275, 109, 204, 212, 166, 317, 974, 1510, 1482, 1473, 1833, 2274, 2613, 2500, 2063, 1831, 1519, 1038, 627, 409, 378, 8, -532, -657, -716, -645, -204, 155, 253, 126, -274, -640, -667, -740, -1297, -1529, -765, 34, 361, 572, 498, 424, 727, 714, -63, -605, -473, -457, -663, -1104, -1686, -1731, -1307, -787, -137, 489, 706, 420, -167, -856, -1420, -1646, -1340, -817, -687, -814, -474, 93, -139, -776, -850, -332, 392, 776, 992, 1093, 774, 681, 847, 802, 709, 396, -29, -127, -377, -1082, -1453, -1095, -755, -798, -844, -934, -1145, -1191, -1075, -1156, -1512, -1503, -744, 0, 105, -40, 156, 673, 802, 397, 197, 426, 818, 1412, 1922, 1972, 1966, 2212, 2525, 2785, 2725, 2621, 2626, 2245, 1749, 1282, 589, 211, 197, -269, -998, -1028, -484, -288, -329, -264, -315, -341, 24, 612, 740, 257, -228, -238, -216, -422, -397, 143, 1083, 1680, 1679, 1454, 1251, 1482, 2054, 2149, 1409, 701, 791, 1135, 895, 309, 158, 507, 839, 962, 910, 660, 845, 1396, 1290, 633, 295, 300, 131, -316, -923, -1542, -1824, -1633, -1286, -987, -782, -423, 337, 1163, 1352, 646, 19, 49, -341, -1347, -1729, -1522, -1453, -1413, -1230, -989, -751, -566, -406, -205, -99, -23, 308, 938, 1223, 457, -479, -625, -394, -479, -1167, -1654, -1209, -474, 270, 827, 832, 1219, 2707, 4107, 4296, 3579, 2855, 2673, 2617, 2051, 1415, 1533, 1764, 1233, 543, 180, 228, 1028, 1683, 1094, 169, -71, 43, -75, -387, -162, 349, 505, 548, 573, 517, 857, 1585, 2155, 2203, 1525, 683, 516, 919, 1493, 1998, 2386, 2724, 2705, 2306, 1717, 908, 501, 796, 586, -208, -397, -259, -404, -458, -325, -69, 479, 1108, 1276, 973, 661, 247, -239, 28, 629, 557, 331, 342, 247, 153, 276, 898, 2038, 2993, 3523, 3974, 4098, 3875, 3858, 4048, 3777, 2888, 2303, 2375, 2451, 2292, 2322, 2893, 3344, 2760, 1743, 1012, 585, 300, -181, -729, -1112, -1373, -1377, -1232, -1508, -2047, -1753, -697, -413, -776, -748, -716, -735, -387, -96, -347, -560, 47, 801, 872, 616, 462, 706, 1171, 1113, 703, 581, 799, 1381, 1943, 1717, 905, 211, 76, 203, -75, -534, -724, -613, -280, -336, -718, -448, 596, 1216, 839, 430, 451, 498, 545, 733, 586, 276, 665, 1418, 1646, 1157, 212, -173, 411, 867, 575, 170, 258, 605, 501, -189, -592, -437, -591, -1441, -2504, -3259, -3413, -2890, -2188, -2173, -2896, -3713, -4302, -4793, -5057, -4606, -3600, -2626, -1665, -972, -953, -1059, -526, 405, 720, 266, -421, -749, -848, -1448, -2327, -2929, -3050, -2653, -2555, -3079, -3180, -2531, -1994, -1595, -949, -349, 264, 842, 635, -367, -1075, -747, 138, 747, 1013, 969, 691, 529, 460, 156, -211, -336, -123, 252, 289, -245, -534, -183, 123, 217, 300, 623, 1233, 1713, 1871, 1864, 1717, 1699, 1790, 1630, 1148, 413, -312, -756, -944, -950, -720, -450, -382, -366, -514, -885, -896, -478, -53, 17, -330, -418, 11, 254, -167, -716, -655, -376, -576, -1298, -2344, -2692, -1877, -1426, -1822, -2076, -1905, -1419, -1034, -1294, -1971, -2436, -2629, -2707, -2593, -2221, -1603, -708, 82, 203, -230, -406, 192, 808, 601, -43, -467, -366, 307, 1001, 1055, 787, 920, 919, 203, -727, -1537, -1775, -1250, -864, -1099, -1236, -987, -497, -90, -274, -697, -455, 258, 344, -107, -77, 253, 463, 773, 935, 947, 1108, 888, 439, 408, 232, -536, -1118, -1192, -1373, -1537, -1384, -1163, -983, -855, -939, -1276, -1515, -1458, -1326, -1268, -1339, -1246, -896, -769, -776, -655, -486, -518, -1154, -2243, -2885, -3267, -3985, -4150, -3472, -3198, -3365, -2868, -2009, -1713, -1673, -1323, -1126, -952, -444, -188, -168, 102, 359, 240, -22, -544, -1637, -2743, -3546, -4351, -5007, -5055, -4619, -4359, -4542, -4566, -3910, -2563, -1160, -748, -1261, -1652, -1692, -1788, -1928, -1997, -1949, -1836, -1864, -2395, -3270, -3512, -3162, -3145, -3614, -3904, -3919, -3839, -3067, -1631, -317, 532, 1130, 1575, 1793, 1644, 1033, 735, 1111, 1045, -174, -1698, -2270, -2036, -1976, -2078, -1796, -1104, -61, 731, 676, 462, 616, 756, 306, -485, -780, -790, -931, -1125, -1401, -1815, -2062, -2052, -2266, -2539, -2156, -1171, -330, -44, -43, -237, -520, -575, -626, -1051, -1886, -2557, -2290, -1490, -921, -729, -688, -431, 21, 332, 314, -6, -232, 261, 954, 901, 455, 92, -274, -309, 132, 194, -132, 22, 598, 868, 778, 441, 97, -171, -650, -1075, -1061, -720, -310, 85, 16, -344, -32, 242, -491, -1278, -1552, -1724, -1416, -585, -42, 260, 556, 860, 1145, 1167, 1025, 946, 1146, 1431, 1003, 104, -277, -210, -22, 184, 390, 665, 766, 715, 450, 34, -36, 197, 301, 96, 91, 497, 576, 292, 346, 390, 220, 221, 17, -210, -175, -439, -693, -251, 280, 266, 189, 355, 738, 1079, 1289, 1495, 1479, 1259, 941, 280, -115, 379, 755, 223, -478, -402, 204, 662, 1006, 1358, 1266, 936, 1247, 1908, 2062, 1640, 1421, 1696, 2022, 1779, 930, 495, 565, 282, -192, -388, -670, -841, -479, -177, -170, 280, 1236, 1793, 1649, 1573, 1743, 1933, 2213, 1936, 860, -174, -413, -31, 185, -166, -116, 622, 1070, 1444, 1871, 1469, 596, 442, 352, -335, -970, -1463, -1522, -1206, -1179, -1019, -478, -35, -66, -526, -990, -1285, -1471, -1439, -1415, -1755, -1935, -1244, -397, -123, -229, -724, -1423, -1795, -1911, -2106, -2379, -2527, -2233, -1464, -995, -1405, -2022, -2082, -1868, -1901, -2376, -2881, -2491, -1949, -2250, -2351, -1864, -1614, -1447, -1275, -1294, -1062, -531, -350, -1074, -2149, -2398, -1658, -887, -626, -582, -750, -960, -888, -980, -1554, -2164, -2408, -2447, -2696, -3141, -3177, -2827, -2678, -2650, -2271, -1930, -1825, -1248, -387, -31, -38, -66, 152, 391, 190, -319, -829, -891, -602, -932, -1697, -1667, -1024, -631, -521, -91, 676, 973, 880, 826, 440, -142, -420, -346, -596, -1411, -2054, -2023, -1481, -1148, -1357, -1304, -803, -548, -597, -911, -1451, -1568, -1430, -1698, -2349, -2873, -2854, -2175, -1062, -392, -410, -468, -681, -1225, -1869, -2685, -3541, -3898, -3878, -3873, -3844, -3663, -3269, -2989, -2849, -2638, -2345, -1701, -716, -6, 81, -106, 43, 327, 106, -129, 135, 508, 637, 520, 196, -173, -364, -217, -166, -397, -387, -390, -226, 446, 406, -338, -249, 296, 638, 994, 1014, 819, 996, 1355, 1269, 809, 168, -399, -512, -504, -530, -260, 35, 118, 149, 65, -70, -182, -355, -659, -1119, -1419, -1305, -932, -546, -453, -290, 469, 1106, 1022, 456, -499, -1477, -1677, -1635, -2010, -2259, -1913, -1032, -335, -142, -72, -56, -267, -495, -637, -905, -594, 635, 1102, 202, -261, -184, -384, -262, 12, -429, -1230, -1234, -767, -1152, -1922, -1910, -1467, -1105, -534, 94, 576, 1151, 1707, 1716, 1001, 161, 137, 563, 430, -40, -396, -626, -1075, -1782, -2168, -2101, -2022, -2185, -2296, -2118, -1912, -1566, -1061, -673, -156, 240, 329, 638, 1027, 1118, 751, -15, -594, -605, -357, -512, -1167, -1550, -1388, -1533, -2171, -2457, -2056, -1543, -1550, -1899, -1672, -781, -196, -188, -127, 274, 626, 837, 1151, 1064, 365, -203, -389, -683, -1319, -1896, -1681, -1063, -1353, -2104, -1951, -1142, -500, -30, 216, 119, 30, 562, 1126, 750, 15, -123, 508, 1024, 596, 387, 827, 973, 1119, 1276, 1074, 1074, 1339, 1503, 1403, 814, -143, -909, -1098, -771, -86, 538, 751, 866, 1104, 1112, 797, 408, -146, -784, -987, -1150, -1557, -1363, -728, -517, -386, -189, -542, -1174, -1617, -1972, -2185, -1965, -1387, -882, -532, -224, 532, 1435, 1077, -309, -1413, -2067, -2439, -2329, -2170, -2254, -2158, -1636, -1112, -814, -487, -233, 42, 764, 1536, 1669, 1061, 338, -96, -500, -624, -337, -70, 252, 808, 1229, 1492, 1974, 2286, 1869, 1227, 700, 247, 146, 523, 1069, 1085, 576, 433, 602, 152, -551, -825, -1048, -1501, -2044, -2154, -1734, -1491, -1644, -1728, -1629, -1594, -1359, -971, -849, -613, 65, 884, 1498, 1561, 1159, 1075, 1590, 1885, 1209, 367, 205, 254, 284, 270, 47, -130, 231, 989, 1073, 239, -502, -639, -477, -428, -795, -1369, -1505, -1378, -1604, -1902, -1871, -1426, -643, -264, -441, -514, -350, 43, 454, 459, 117, -155, -79, -7, -236, -419, -267, -117, -270, -599, -1327, -2284, -2575, -2003, -1324, -1076, -776, -276, -102, -221, -136, 81, 200, 119, -244, -439, -445, -698, -927, -674, 0, 771, 1094, 991, 710, -37, -785, -819, -275, 76, -55, -211, 2, 815, 1635, 1845, 1922, 2061, 1926, 1668, 1342, 840, 196, -543, -1095, -1055, -589, -444, -619, -530, -440, -1054, -1700, -1403, -760, -564, -372, 72, 179, 278, 821, 990, 661, 642, 820, 735, 120, -844, -1242, -895, -658, -572, -71, 539, 938, 1572, 2224, 2046, 1340, 816, 821, 976, 696, 335, 199, 291, 602, 655, 417, 382, 471, 455, 420, 618, 1362, 1964, 1643, 1215, 1259, 1349, 1411, 1563, 1668, 1504, 1453, 1804, 1607, 868, 460, 622, 1236, 1551, 1122, 611, 609, 975, 1264, 1117, 876, 931, 1226, 1339, 1129, 1015, 1360, 1991, 2137, 1749, 1227, 602, 72, -243, -560, -705, -557, -496, -468, -438, -739, -1131, -1126, -934, -885, -769, -541, -421, -266, -53, -27, 18, 304, 683, 848, 585, 328, 532, 767, 884, 1282, 1818, 1901, 1309, 627, 0, -808, -1140, -527, 113, 117, -228, -714, -821, -307, 364, 797, 1228, 2132, 2822, 2294, 1079, 381, 579, 1303, 1663, 1551, 1952, 2680, 2782, 2197, 1625, 1798, 2512, 3128, 3405, 3078, 2276, 1515, 1377, 1677, 1816, 2006, 2334, 2553, 2545, 2077, 1334, 1049, 1342, 1653, 1519, 1230, 949, 262, -344, -556, -818, -819, -342, 270, 699, 770, 729, 841, 1248, 1718, 1584, 830, 469, 878, 1211, 1063, 983, 1060, 1213, 1230, 672, 98, -21, 300, 1100, 1520, 1091, 986, 1842, 2598, 2029, 771, 181, 433, 993, 896, -134, -631, 9, 441, 482, 951, 1369, 1418, 1509, 1526, 1450, 1045, 326, -213, -874, -1797, -2149, -1630, -1070, -714, -337, -329, -612, -661, -724, -1076, -1375, -1195, -912, -992, -1080, -1324, -1834, -1887, -1707, -1967, -2109, -1662, -941, 19, 1120, 1425, 1075, 1640, 2753, 2816, 2065, 1630, 1645, 1787, 2032, 2459, 3057, 3551, 3609, 3464, 3469, 3373, 2957, 2507, 2209, 1855, 1167, 148, -1052, -1945, -2314, -2538, -2408, -2114, -2281, -2762, -3295, -3477, -3170, -2753, -2106, -1382, -829, -175, 390, 602, 565, 82, -663, -931, -1031, -1356, -1281, -748, -99, 416, 351, 179, 647, 1279, 1629, 1930, 2206, 2645, 3500, 3947, 3454, 3094, 3205, 2934, 2142, 1133, 329, 117, 152, -445, -1504, -1844, -1192, -179, 492, 478, 469, 1038, 1433, 1181, 766, 479, 364, 520, 731, 550, -55, -350, 20, 755, 1457, 1597, 1375, 1738, 2623, 3161, 2925, 2711, 2980, 3104, 3017, 3141, 3449, 3605, 3334, 2680, 1994, 1451, 784, -4, -726, -1318, -1508, -1093, -706, -985, -1644, -1908, -1589, -1153, -501, 553, 1334, 1813, 2879, 4188, 4687, 4343, 4270, 5156, 6025, 6076, 5592, 4997, 4522, 4120, 3698, 3129, 2284, 1369, 863, 879, 1205, 1978, 2892, 3445, 3633, 3191, 2522, 2628, 3368, 3898, 4039, 4291, 4633, 4664, 4471, 4220, 3788, 3216, 2532, 1725, 934, 353, 617, 1825, 3022, 3310, 2713, 1812, 941, 440, 146, -880, -1975, -1791, -1421, -2172, -3196, -3595, -3712, -3675, -3629, -3751, -3506, -2823, -2373, -2194, -1523, -473, 333, 762, 513, -47, -495, -1018, -1237, -1091, -1240, -1667, -1719, -1408, -1283, -1355, -1324, -978, -65, 1003, 1466, 1150, 985, 1418, 1544, 974, 387, 173, 120, 257, 427, 58, -439, -234, 111, -19, -264, -275, 115, 761, 1076, 546, -339, -536, -618, -1433, -2129, -2009, -1346, -867, -1046, -1692, -2242, -1938, -874, -81, 292, 752, 1170, 1124, 710, 486, 94, -604, -865, -906, -1664, -2988, -3620, -3428, -3218, -2916, -2442, -2038, -1497, -690, -362, -937, -1244, -832, -879, -1654, -2238, -2031, -1257, -625, -591, -820, -728, -514, -310, 9, 362, 664, 633, 444, 405, 220, -171, -172, 653, 1506, 1124, -121, -974, -1145, -987, -1115, -1517, -1440, -941, -580, -616, -897, -1310, -1922, -2708, -3650, -4206, -3589, -2129, -1049, -559, -105, 225, 455, 935, 1154, 657, 250, 434, 612, 195, -695, -1489, -2041, -2321, -1978, -1246, -707, -233, 221, 319, -45, -533, -739, -691, -668, -971, -1513, -1547, -962, -708, -1179, -1283, -642, -204, -66, -55, -613, -1413, -1547, -1203, -1510, -2152, -1916, -1343, -2400, -1945, -2878, -2410, -1437, -2757, -4156, -3872, -3083, -2944, -4280, -4866, -2504, 3, -918, -3154, -3323, -2553, -1866, -1137, -716, -1048, -1878, -1187, 742, 1073, -224, -943, -499, -555, -1220, -1033, -1005, -2445, -3801, -4188, -4983, -5762, -5725, -5490, -5387, -5361, -4702, -3629, -2710, -1725, -988, -576, -759, -1684, -2029, -1403, -1196, -1195, -1444, -2815, -3125, -1862, -1376, -1658, -1908, -2355, -2394, -2347, -2196, -1657, -2005, -3059, -2993, -1634, -1791, -3150, -2049, -89, 297, 654, 1541, 2000, 2207, 3232, 3370, 464, -2042, -1742, -891, -633, -401, -409, -35, 1225, 1872, 2212, 2685, 2038, 1263, 980, -211, -1166, -714, -647, -1235, -1607, -1385, -1571, -2814, -3158, -2692, -3236, -3769, -3183, -2028, -1631, -1829, -1904, -1835, -633, 677, 303, 36, 919, 1818, 2250, 2017, 1485, 1033, 50, -1310, -1772, -1971, -3023, -3298, -1948, -1298, -1603, -931, 74, 503, 921, 1395, 2247, 3041, 2088, -85, -1422, -1497, -973, -712, -1349, -2080, -1893, -995, -547, -1128, -2328, -3287, -3240, -2112, -676, -727, -743, 1513, 2445, 1330, 2101, 3125, 2448, 1609, 671, -633, -1815, -2395, -2749, -2477, -1762, -2609, -3671, -2251, -119, 805, 1353, 1786, 2129, 2858, 3116, 2129, 1647, 1755, 858, -112, -228, -634, -963, -579, -744, -1296, -1670, -1532, -829, 92, 1245, 1929, 1804, 2077, 2927, 2820, 1849, 1832, 2354, 2628, 3412, 3436, 2117, 1431, 1400, 1791, 2928, 3156, 2004, 1134, 496, -387, -887, -1492, -1546, -185, 662, -395, -1278, -683, -26, 31, -77, 193, 628, 439, -96, -290, -281, 245, 1236, 1407, 1790, 2974, 2928, 1807, 1110, 945, 653, 188, -642, -1544, -1225, -568, -1170, -1784, -1394, -736, -669, -1213, -1090, -1134, -2418, -2942, -2515, -2714, -3348, -4091, -4123, -2645, -1067, 113, 965, 640, 54, 351, 236, -801, -2090, -2982, -3155, -3376, -3963, -4535, -4657, -3846, -3000, -3375, -3689, -2717, -1672, -1885, -2797, -2942, -1588, -196, -154, -230, 392, 328, -581, -573, 292, 27, -822, -602, -113, 226, 833, 1077, 1048, 1378, 1238, 630, 1115, 1774, 1360, 1496, 2267, 2618, 2652, 2940, 3159, 2318, 1666, 1823, 1882, 1703, 1592, 1158, 331, -97, -220, -589, -1517, -1971, -1694, -1390, -1290, -1607, -1214, -334, -676, -1565, -1290, 79, 835, 1128, 1829, 2086, 2383, 3508, 3891, 3057, 2759, 3207, 3300, 3072, 2527, 544, -1394, -1534, -1826, -2297, -2171, -2845, -2449, -357, 939, 1445, 1780, 2070, 2161, 1721, 1047, 626, 757, 894, 1177, 1290, 653, 536, 1347, 2262, 2925, 3556, 4416, 4866, 4805, 4560, 3272, 1394, 672, 1205, 1509, 804, -23, 177, 482, -455, -1482, -2024, -2527, -1900, -413, -468, -496, 1426, 2830, 2359, 2040, 3231, 4069, 3209, 2636, 2511, 1423, 896, 1833, 2212, 1388, 1108, 2186, 2722, 2113, 2455, 3353, 2887, 2006, 1778, 2078, 2055, 1699, 2009, 2269, 1641, 569, 113, 547, 716, -136, -1246, -1564, -1302, -1099, -1021, -1386, -1845, -963, 671, 370, -1733, -2659, -1327, 45, -299, -1417, -1850, -1889, -1857, -1697, -1722, -1748, -1260, -444, -390, -1318, -1652, -557, 278, -90, -458, -142, 159, 1019, 2107, 1328, 129, 996, 2586, 3062, 2666, 2185, 2400, 3119, 2972, 2255, 1759, 1012, 315, 686, 1331, 1324, 955, 504, 691, 1532, 2879, 3681, 2759, 2292, 3034, 2785, 2076, 3076, 4100, 3671, 3829, 4031, 2608, 2036, 2809, 2504, 1988, 2511, 2898, 2307, 1215, 1045, 1785, 1817, 1506, 1406, 738, 369, 758, 1278, 1318, 253, 219, 2423, 3384, 2281, 2209, 3200, 3153, 1973, 1811, 3328, 4823, 5195, 4993, 5357, 5656, 5234, 4788, 3987, 3373, 3058, 2076, 1390, 1588, 1940, 1908, 1622, 1903, 2089, 1817, 2032, 2045, 2157, 2478, 1672, 1300, 2658, 3317, 2535, 2089, 1680, 1305, 1867, 2611, 2949, 2250, 1146, 1329, 1961, 1883, 1635, 1697, 1513, 855, 1025, 1657, 657, -931, -242, 1813, 2491, 2160, 1523, 725, 1110, 2086, 2506, 2661, 2942, 3344, 3363, 3383, 3479, 2915, 2632, 3019, 2812, 2795, 3621, 3952, 3214, 1905, 447, -23, 985, 1765, 1435, 681, 112, -67, -269, -566, -550, -15, 769, 913, 865, 494, -729, -817, 519, 365, -827, 31, 2413, 3259, 2226, 1595, 1678, 2048, 3180, 3958, 3428, 2886, 2709, 1572, 601, 1176, 1406, 1075, 624, 76, 1425, 3506, 3670, 2802, 2195, 1537, 899, 990, 981, 543, 866, 1606, 2002, 1598, 1443, 2446, 1709, -168, 292, 1941, 1986, 412, -844, -287, 1625, 2286, 1709, 2603, 4187, 4599, 4500, 3710, 1945, 1330, 1659, 1384, 1030, 191, -730, -151, -165, -1888, -1624, 628, 2120, 3240, 4058, 3589, 2885, 3340, 4266, 4229, 3263, 2418, 2071, 1452, 765, 981, 1651, 2465, 3348, 3423, 2314, 1705, 2505, 2670, 1469, 748, 924, 942, 864, 967, 703, 454, 341, 654, 1884, 2563, 2205, 2410, 3238, 2388, -85, -1632, -1716, -1143, -127, 241, 194, 929, 2219, 3954, 4695, 4091, 4208, 4438, 3857, 3951, 4642, 4372, 3821, 4082, 3533, 1921, 1726, 2335, 2521, 2380, 1438, 967, 1759, 1567, 248, -410, -612, -609, -115, 271, -496, -1513, -1272, -517, -378, -818, -984, -117, 679, 289, 197, 1120, 2031, 2945, 2977, 1600, 1369, 2083, 2078, 2159, 2487, 2447, 2182, 2396, 2892, 2963, 2456, 1217, 70, 78, 336, 352, 147, 173, 797, 452, -339, 463, 2324, 4666, 5724, 4410, 4001, 4796, 4661, 4711, 4394, 1954, 344, 1326, 1726, 490, -193, 782, 2141, 2432, 2544, 3474, 3459, 1911, 2198, 4138, 4167, 3019, 2479, 2130, 1845, 1382, 395, -782, -1351, -1350, -1854, -2642, -2269, -1484, -2514, -4283, -4355, -3084, -1663, -1214, -1387, -683, 560, 1578, 2564, 3803, 4450, 4252, 4317, 4470, 3161, 1818, 1923, 1578, 492, -218, -305, 521, 1618, 1782, 1021, 1142, 2289, 2384, 1867, 1424, -88, -1911, -2132, -1510, -1610, -2297, -3006, -3244, -3014, -1951, -1203, -2724, -3368, -1745, -711, -976, -1208, -230, 1633, 2711, 2876, 2837, 2142, 1629, 2234, 2564, 2355, 2239, 2136, 2060, 1678, 918, 217, 421, 902, 540, -85, -544, -1128, -933, -105, -406, -1223, -865, -221, -260, -278, -103, -135, -459, -605, 203, 965, 458, 593, 2322, 3147, 2809, 2957, 3598, 4061, 3816, 2987, 2211, 2379, 2575, 1632, 947, 1315, 1469, 1064, 246, -1016, -1588, -1204, -1009, -1542, -2159, -1985, -1219, -947, -1157, -1445, -2117, -2511, -2234, -2215, -2161, -2138, -3027, -3447, -2333, -1051, -220, 166, -274, -1072, -1290, -501, 69, -303, -702, -1275, -1924, -1214, -680, -1683, -2189, -2202, -2502, -2836, -2865, -1828, -1297, -2518, -3180, -1697, -653, -2184, -4269, -4616, -4233, -4105, -3781, -3389, -2146, -530, -415, -708, -358, -228, -466, -1163, -1583, -1247, -1626, -2324, -1785, -1062, -1417, -1465, -164, 495, -461, -644, 321, 859, 865, 888, 869, 626, 643, 1482, 2062, 1241, -130, -860, -721, -620, -1193, -1845, -2432, -2866, -1599, 304, 31, -968, -399, 1028, 1135, 111, -55, 284, 265, -301, -1097, -373, 727, -769, -2792, -2549, -1339, -800, -891, -692, -201, 115, 294, 234, 37, -722, -1660, -1702, -1532, -1848, -1587, -1430, -2387, -2693, -1713, -1696, -3098, -3522, -2389, -1184, -1700, -2592, -1525, -311, -616, -1148, -1310, -301, 1550, 1999, 1403, 726, 500, 928, 843, -168, -1462, -1871, -1585, -2069, -2393, -1802, -2525, -3555, -2526, -2216, -2845, -2188, -2132, -3267, -3605, -2994, -2435, -2364, -2300, -1333, 193, 1378, 2635, 3161, 1922, 1066, 1589, 2198, 1834, 493, -319, -350, -955, -1427, -622, -104, -491, -566, -583, -1181, -1505, -860, -101, 478, 1382, 1300, -124, -454, 180, -46, -518, -866, -982, -489, -264, -762, -1540, -2436, -2885, -1832, -909, -2381, -3703, -2712, -2195, -3084, -3384, -3195, -3312, -3277, -3236, -3385, -3117, -2024, -966, -778, -684, -264, 134, 302, 37, -195, -126, -24, 78, 236, -160, -1336, -2313, -2310, -1958, -2117, -3114, -4099, -3138, -1517, -1239, -960, 18, 545, 319, -44, -123, 566, 1070, 456, -303, -996, -1666, -2242, -2429, -2488, -3829, -4638, -3248, -1951, -2769, -4067, -4323, -4044, -3209, -2168, -1165, -540, 141, 1358, 1760, 1560, 1291, 286, -263, -220, -1326, -2864, -2939, -1907, -867, -1254, -3204, -3779, -2091, -772, -1409, -2713, -3238, -3251, -3304, -3413, -3715, -3549, -2764, -3055, -4505, -5106, -4920, -5135, -4649, -3569, -3498, -3774, -3136, -1898, -1689, -2700, -3158, -2450, -1605, -1726, -3134, -3915, -2843, -2599, -4160, -4913, -4460, -4037, -3494, -3191, -2603, -1540, -1591, -1417, -604, -382, -517, -1225, -2466, -2331, -1464, -1872, -1823, -1093, -1482, -1871, -1573, -1729, -1906, -1250, -188, 829, 1485, 1698, 1898, 1533, 145, -427, 351, 423, -1107, -3081, -3631, -2754, -2563, -3175, -3800, -4212, -3928, -3278, -3017, -2442, -1204, -739, -809, -163, 537, 137, -832, -897, -358, -80, 43, 169, 101, -49, 273, 280, -760, -902, -4, -140, -761, -662, -121, 860, 1823, 670, -884, -230, -211, -1893, -2511, -2109, -1763, -929, -3, 120, 368, 835, 419, -282, -465, -124, -46, -236, 904, 2145, 1437, 585, 569, 310, -32, -40, -556, -2150, -2843, -2661, -3284, -3453, -3298, -3348, -2436, -2373, -3270, -2886, -1875, -1311, -737, 333, 1233, 1731, 1469, -31, -1548, -1468, -569, -842, -1529, -1329, -1781, -2164, -266, 1146, 239, 305, 1710, 1355, 93, -455, -297, 426, 723, 419, 515, 703, 875, 1370, 1308, 94, -1079, -814, -85, 196, 412, -115, -1168, -830, 293, 133, -528, 116, 1286, 729, -656, -825, 373, 1191, 201, -692, 206, 1601, 1544, 923, 613, -239, -778, -240, -277, -925, -1292, -2339, -2795, -1948, -1877, -2681, -2836, -1977, -1853, -2661, -2583, -2941, -3759, -3149, -2350, -2358, -1941, -1269, -800, 353, 1081, 190, -438, 703, 1587, 1458, 2175, 3489, 3928, 3689, 3485, 2791, 1875, 1530, 1256, 986, 1142, 632, -478, 17, 891, -38, -497, 626, 589, -847, -1157, 379, 1850, 2050, 1469, 1111, 1219, 1165, 462, -213, -101, -116, -89, 891, 1566, 1703, 2238, 2313, 2011, 1674, 1068, 798, 509, 357, 1390, 1281, -701, -1177, -686, -1523, -2131, -1223, 373, 1451, 1508, 1167, 480, -231, 95, 1322, 1273, -290, -146, 921, 246, -514, -686, -1119, -662, -360, -1595, -1390, 453, 601, 263, 645, 271, -57, 410, 609, 659, 1038, 1013, 423, -597, -1372, -812, -89, -1173, -2578, -2297, -1802, -1510, -395, 1217, 1673, 267, -1150, -1410, -1287, -1168, -1217, -1298, -1272, -1893, -2021, -1659, -2596, -3010, -1608, -416, -438, -615, -131, 1108, 2224, 2058, 869, -117, -160, 169, 440, 36, -904, -1649, -2494, -2490, -1020, 360, 637, 354, 8, -176, -206, -75, 163, 324, 137, -333, -634, -182, 1405, 2255, 725, -1084, -1274, -1392, -2078, -2433, -2332, -1571, -1077, -1732, -1845, -492, 1072, 1940, 1603, 934, 1094, 1330, 1592, 2936, 3895, 2744, 1129, 950, 1081, 814, 1203, 1185, 727, 1628, 2118, 969, 874, 1446, 1486, 1667, 1254, 854, 1691, 2073, 1263, 947, 1241, 1266, 1058, -19, -1194, -875, -952, -1387, -563, -868, -1796, -801, 935, 1891, 1981, 2117, 3112, 3833, 3378, 2834, 2706, 2578, 2043, 942, -151, -1212, -1796, -1548, -1390, -1445, -1421, -1240, -458, 336, 164, -6, 896, 2385, 2899, 1534, -529, -1197, -767, -1020, -2062, -2045, -432, 764, 1348, 1530, 1480, 2068, 2914, 3580, 3534, 2024, 234, -435, -430, -945, -2367, -2800, -1463, -400, -263, -716, -701, 1105, 2506, 1236, -250, 311, 1174, 1716, 2534, 2377, 1508, 1684, 2463, 1944, 119, -572, 53, -347, -1331, -1496, -1370, -675, 501, 1493, 1629, 505, -574, -500, 949, 1663, 416, -172, 737, 1462, 1526, 1755, 2043, 1817, 2072, 3366, 3948, 3176, 2352, 1741, 1610, 3090, 5027, 5685, 4998, 3779, 3734, 4017, 2965, 2733, 2860, 1477, 812, 749, 178, 449, 764, 433, 338, 232, 663, 1376, 799, -396, -595, 170, 820, 1093, 1966, 2801, 2448, 2133, 2246, 1969, 1985, 2081, 1925, 2408, 2579, 2135, 1740, 1488, 2135, 3182, 3966, 3885, 2252, 1608, 3189, 3306, 1620, 1047, 885, 328, 152, 415, 1002, 1328, 588, 966, 3191, 3582, 1833, 702, 989, 2300, 3590, 3741, 3435, 4135, 4771, 4481, 4040, 3886, 4040, 3636, 2758, 3033, 3263, 2249, 1550, 1044, 656, 1184, 2322, 3897, 5410, 4922, 3419, 3034, 2681, 1792, 745, -560, -1399, -899, -219, -721, -1209, -1075, -90, 2468, 3908, 2944, 2907, 3689, 3275, 2939, 3094, 2237, 1310, 1714, 1563, 275, -849, -1032, -289, 387, 69, -246, 994, 2235, 2262, 1808, 1030, 884, 2245, 3258, 2575, 1735, 1103, 373, 512, 1308, 1305, 441, 525, 1833, 2904, 2783, 2565, 3351, 3375, 2188, 1809, 2559, 2556, 2307, 2369, 1291, 737, 1630, 1992, 1838, 1319, 667, 1390, 1834, 1097, 965, 979, 870, 1481, 2707, 3328, 3109, 3052, 2781, 2236, 2197, 2401, 2589, 2781, 2664, 1890, 1077, 1291, 2126, 2235, 1295, 129, -96, 554, 522, -382, -1221, -1185, -679, -885, -1129, -613, 53, 683, 1275, 1378, 1393, 2172, 2702, 1770, 961, 995, 565, -211, -245, -314, -866, -725, -138, 267, 1256, 2382, 2146, 927, 547, 1233, 1718, 1519, 1497, 1950, 1792, 556, -332, -17, 34, -287, -156, -693, -1483, -918, 194, 878, 1405, 1694, 2757, 4460, 4359, 2439, 999, 787, 1129, 1682, 1812, 1557, 1553, 1999, 2666, 2510, 1192, 163, 538, 2317, 2811, 1173, 315, 1002, 1987, 2259, 2435, 2902, 2502, 1420, 801, 511, -56, -386, -135, -49, -529, -560, 19, 591, 1264, 1313, 325, 745, 2883, 2637, 1093, 1970, 2842, 2024, 1840, 2223, 1880, 1018, -307, -383, 615, 872, 1398, 1526, -135, -934, 609, 1539, 326, -297, 704, 724, -138, -45, 459, 219, -497, -845, -454, -90, -575, -1607, -2124, -1503, -611, -1154, -2520, -2591, -1330, -344, -755, -1549, -1094, 120, 311, 471, 1611, 2138, 1358, 809, 1337, 2029, 2310, 1887, 1612, 2111, 2024, 926, 96, -181, -470, -843, -1163, -1086, -184, 594, 430, -32, -34, 84, -151, 34, 594, 151, -1281, -2290, -2057, -1718, -1842, -1583, -789, 242, 662, 543, 820, 1348, 2022, 2173, 1512, 1296, 2262, 3771, 3691, 1513, 776, 2663, 3356, 1628, 99, -403, -497, -251, -842, -1851, -1764, -2091, -2281, -794, 41, -678, -1018, -200, -74, -1928, -3166, -2384, -1455, -1261, -391, 791, 989, 1410, 2388, 2027, 759, 464, 1046, 1784, 2045, 1769, 1516, 698, -516, -1107, -1176, -669, 238, 343, -713, -1842, -2285, -2244, -1549, -724, -233, 76, -7, 119, 484, 594, -211, -1247, -677, 553, 686, 319, 439, 467, -144, -1064, -1385, -691, -183, -632, -1019, -1050, -572, 458, 1212, 1117, -67, -977, -1305, -1262, -291, 229, -861, -1943, -1543, -834, -1121, -1472, -944, -780, -1491, -1400, -921, -1207, -1024, -660, -1268, -651, 1175, 1142, 686, 970, 558, 165, 904, 1806, 1466, 441, 279, 779, 438, -562, -1264, -1564, -1264, -782, -1264, -2802, -4162, -3158, -1429, -1634, -1128, 578, 186, -754, -138, 456, 204, -384, -1032, -1383, -1221, -893, -476, -363, -259, -185, -634, -578, 555, 745, -941, -1788, -1023, -373, -625, -704, -432, -428, 82, 734, 398, -71, 275, 833, 1239, 1535, 890, -809, -1356, -432, -382, -1238, -956, -216, -737, -1839, -2331, -2486, -2887, -3029, -2473, -1300, -598, -1059, -1518, -1082, -358, -368, -582, -215, -560, -1105, 161, 1891, 2390, 2317, 1891, 1477, 1639, 2208, 2525, 1876, 1039, 1252, 1275, 726, 1210, 1722, 1104, 1151, 1821, 896, -1173, -1936, -1269, -1250, -1975, -1862, -1585, -1522, -742, -765, -2753, -4173, -3439, -2147, -2125, -2641, -2149, -1546, -1397, -1206, -1048, -558, 216, -150, -1622, -1813, -968, -248, 771, 641, -661, -1022, -289, 170, 73, -248, -1204, -2201, -1762, -476, 17, 198, 348, 540, 538, -652, -1834, -1477, -771, -888, -965, -345, 460, 287, -380, -81, 107, -514, -272, 697, 1063, 376, -193, 210, 13, -1068, -512, 1087, 647, -150, 853, 1596, 978, 240, 489, 1277, 962, -834, -2080, -1342, 4, -28, -1281, -1082, 823, 1347, 135, -614, 996, 2312, 589, -306, 423, 362, 795, 1437, 518, -1738, -3172, -1976, -300, 122, 390, -21, -692, -322, -314, -1058, -1485, -1543, -1862, -2344, -1906, -1287, -1607, -1696, -857, 77, 814, 1726, 2465, 1860, 661, 314, 266, -263, -1232, -2340, -2602, -1406, -216, -247, -1155, -1715, -723, 334, -447, -1794, -2162, -2242, -2310, -1498, -1086, -2237, -1999, -18, 160, -1249, -2415, -2540, -1619, -979, -470, 92, 113, 348, 595, 85, -624, -415, 587, 996, -433, -2503, -3221, -3226, -2917, -2819, -3423, -3949, -3441, -2496, -2710, -3451, -3619, -3259, -3160, -3263, -3573, -4325, -3911, -2315, -1591, -1923, -2539, -2507, -1432, -362, 525, 377, -926, -844, 894, 1637, 480, -1162, -2049, -1663, -1025, -1421, -1807, -1431, -1862, -2953, -2844, -2564, -2993, -2951, -2584, -2101, -1401, -1101, -951, -327, -76, -681, -681, 178, 399, -18, -410, -495, 5, 548, -233, -1429, -1345, -1093, -1007, -428, -836, -2070, -1555, -284, -240, -703, -839, -1431, -1945, -1161, -275, -370, -527, -684, -958, -878, -1233, -1956, -2755, -3434, -2691, -1653, -1526, -1711, -1776, -1473, -933, 326, 1982, 2285, 1533, 797, -464, -522, 1255, 2016, 807, -625, -1586, -1536, -773, -1487, -2619, -1534, 583, 770, 99, 848, 1376, -405, -2878, -3432, -2950, -3407, -3425, -2559, -1977, -1247, -116, 878, 275, -1529, -1865, -1015, -776, -1247, -1742, -1549, -885, -459, -599, -1865, -3282, -2465, -1482, -3249, -4416, -2859, -1595, -1925, -2239, -2158, -2004, -1593, -1171, -689, -685, -2032, -3530, -3466, -3011, -3822, -4412, -3309, -1999, -1483, -864, -97, 477, 643, 194, 182, 997, 1035, -1, -431, -1131, -1802, 94, 2090, -63, -3411, -4146, -4031, -4182, -4104, -3850, -3564, -3879, -4686, -4403, -3512, -3130, -2372, -1690, -1823, -1698, -1898, -2964, -3330, -3035, -2861, -1950, -787, -298, 201, 385, 295, 222, 318, 300, -15, 175, 146, -642, -1290, -541, 874, 603, 110, 1675, 3391, 3172, 2187, 1971, 1962, 1287, 901, 942, 103, -334, 458, 428, -398, -879, -1281, -1292, -818, -1177, -1521, -1085, -1897, -2916, -1703, -500, -1733, -2752, -1778, -1315, -1753, -1614, -2356, -3626, -3079, -1611, -1437, -1967, -1419, -325, -719, -1937, -1822, -953, -357, 194, 80, -538, -517, 15, 256, -14, -132, 277, 1365, 2817, 3553, 3137, 2033, 1416, 1416, 1519, 1952, 1609, 474, 130, -549, -2093, -2320, -1416, -1267, -1178, -421, -786, -2473, -2930, -2812, -3987, -4322, -2922, -1949, -2055, -2478, -2605, -2263, -1776, -883, 542, 1469, 1514, 1165, 342, 310, 1902, 1901, 478, 112, -476, -1341, -883, 331, 116, -962, -965, -569, -258, 220, -137, -664, -857, -2266, -4274, -5229, -5773, -6497, -6409, -5012, -3443, -2861, -2512, -1237, -314, -931, -2429, -3046, -2219, -2771, -4807, -5084, -4448, -4764, -4907, -4458, -4217, -4009, -3787, -4071, -4079, -2904, -1780, -1570, -813, 853, 1063, -450, -1221, -1253, -2412, -3914, -4452, -4584, -3806, -2889, -3288, -3777, -3402, -2176, -578, -109, -568, 109, 1127, 378, -951, -754, -96, -614, -1121, -1540, -2673, -2321, -240, 932, 428, -25, 542, 1528, 1898, 976, 43, 697, 1384, 274, -550, 80, 93, -1082, -1171, -31, -464, -2763, -4198, -4165, -4193, -5098, -6604, -6927, -5077, -2746, -1710, -1815, -2205, -1581, 197, 1121, 340, -325, 300, 1380, 1671, 852, 665, 1290, 1246, 533, 252, -57, -1063, -630, 573, 643, 987, 1804, 1975, 1401, -360, -1592, -798, -237, -966, -1569, -1884, -2579, -2853, -2363, -2285, -2319, -1439, -92, 798, 797, 1102, 1729, 1314, 735, 367, 344, 1189, 1574, 858, -420, -1037, -396, 139, 248, 597, 1008, 1162, 1308, 1696, 1664, 840, 381, 1358, 2361, 2411, 2238, 1759, 2416, 3633, 2400, 356, 264, 603, 550, 1047, 1185, 183, -391, 800, 1160, -251, -401, 961, 1637, 1289, 1001, 645, -104, -780, -1156, -1064, -112, 1319, 1790, 1258, 1399, 1972, 1901, 2153, 2515, 1683, 584, 132, -114, -424, 188, 1720, 2289, 1309, 99, 499, 1225, -505, -2527, -2586, -2185, -3147, -4387, -4084, -3278, -3342, -3118, -1681, -180, -47, -565, -596, -61, 737, 1247, 1265, 1055, 849, 41, -245, 1320, 2962, 3767, 4312, 4034, 3105, 2186, 1745, 1757, 1957, 2376, 2128, 227, -1265, -452, 231, -1147, 2195, -58, -540, 1159, 2843, 2119, -467, -2073, -1317, -311, -1455, -3710, -4430, -2943, -1127, -1331, -3381, -4718, -3984, -2704, -3053, -5150, -6771, -5614, -2592, -1037, -1762, -2129, -82, 2963, 3711, 1473, -809, -581, 1238, 1693, -112, -1861, -1285, 892, 1860, 368, -1963, -2757, -1314, 219, -513, -2735, -3517, -2165, -1160, -1990, -3681, -4363, -3187, -1784, -2268, -4318, -5223, -3528, -1319, -1076, -2748, -3955, -2578, -303, 6, -1591, -2899, -2009, 155, 821, -530, -1845, -1426, 464, 1407, -109, -2153, -2138, -328, 769, -132, -1756, -1950, -397, 587, -641, -2783, -3645, -2701, -1540, -2100, -3899, -4510, -2527, 165, 72, -2600, -4507, -4343, -3508, -3774, -5348, -5952, -4024, -1701, -1596, -3335, -4558, -3506, -1304, -786, -2572, -4230, -3555, -1368, -323, -1334, -2599, -2086, -30, 1073, -231, -2249, -2527, -1050, -164, -1378, -3286, -3512, -1497, 922, 1431, -87, -1312, -626, 268, -889, -3187, -4116, -2942, -1162, -855, -2251, -3010, -1611, 157, -115, -2158, -3742, -3464, -2257, -2407, -4237, -5447, -4489, -2379, -1571, -3254, -5242, -4495, -1615, 104, -622, -1703, -1109, 683, 2160, 2361, 1409, 941, 2050, 3167, 2169, -311, -1434, -304, 889, 262, -1192, -1378, -133, 956, 537, -638, -332, 2151, 4709, 4916, 3046, 1822, 2468, 3628, 3885, 2419, 366, 416, 2243, 2882, 1856, 1150, 1962, 3860, 5202, 4689, 3176, 2758, 4198, 5292, 3929, 1628, 777, 1489, 2468, 1956, -5, -1019, -227, 741, -83, -2079, -2736, -1687, -620, -1236, -3441, -4722, -3511, -1417, -1122, -3152, -5066, -4649, -3114, -3266, -5107, -5708, -3673, -1126, -513, -1676, -2632, -1809, 197, 860, -1135, -3678, -4024, -2442, -1379, -2520, -4642, -4974, -3341, -1990, -2304, -3634, -3875, -2062, -330, -1081, -3247, -3760, -2046, -595, -1531, -4267, -5984, -5063, -3440, -3846, -5798, -6295, -4258, -1905, -1452, -2669, -3560, -2626, -694, 129, -1035, -2676, -2485, -647, 262, -901, -1976, -616, 2179, 3705, 3109, 1837, 1808, 3234, 3688, 1431, -1271, -1169, 897, 1871, 942, -605, -999, 51, 553, -713, -2588, -3292, -2239, -818, -849, -2106, -2700, -1441, 330, 42, -2357, -3964, -3083, -1301, -942, -1931, -2180, -785, 1137, 1678, 142, -1424, -928, 936, 1908, 829, -683, -456, 858, 984, -741, -2751, -3084, -1583, -146, -468, -1911, -2379, -959, 615, -7, -2288, -3267, -1637, 411, 312, -1386, -1894, 186, 2789, 3113, 1267, 23, 1143, 3178, 3606, 1996, 438, 779, 2090, 2069, 72, -1896, -1522, 535, 1532, 340, -1436, -1639, -276, 548, -378, -1616, -1048, 1001, 2221, 1373, -455, -1171, -143, 799, -87, -2015, -2343, 15, 2595, 2976, 1966, 1901, 3540, 5048, 4482, 2332, 850, 1249, 2329, 1947, -234, -1777, -634, 1629, 2066, 353, -1289, -1071, 400, 1068, -300, -2131, -1899, 102, 1500, 1133, 356, 1131, 3155, 4129, 3002, 798, -512, 864, 3281, 3011, 504, -676, 416, 1821, 1692, -87, -1192, 184, 2161, 2248, 913, 412, 2082, 4488, 4770, 2646, 630, 542, 1357, 542, -2215, -4198, -3500, -1578, -1092, -2506, -3861, -3230, -1006, 276, -841, -2288, -1569, 534, 1504, 269, -1647, -1975, -594, 404, -421, -2184, -2697, -1071, 875, 724, -1104, -1919, -558, 1101, 385, -2143, -3238, -1492, 1280, 1970, 103, -1194, -27, 1890, 2091, 111, -1778, -1235, 844, 1578, -23, -1644, -1009, 1039, 2157, 1332, 109, 823, 3046, 3976, 2350, 34, -549, 686, 1677, 808, -710, -703, 990, 2439, 1661, -580, -1450, -207, 1172, 1146, 97, -198, 1315, 3149, 2963, 760, -890, -308, 1236, 1232, -787, -2381, -1319, 1357, 2536, 1435, 310, 874, 2471, 3009, 1437, -660, -876, 933, 2140, 881, -963, -505, 1845, 3165, 2116, 275, -23, 1684, 3147, 2597, 897, -221, 528, 2106, 1514, -988, -2110, -920, 430, -6, -1525, -1856, -107, 2016, 2211, 717, -870, -1608, -1228, -1184, -2521, -3603, -2659, -401, 569, -1077, -3175, -2940, -859, 359, -518, -2020, -2072, -652, 90, -1159, -3070, -3359, -1478, 323, -251, -2078, -2742, -2043, -1419, -1915, -3055, -3027, -1069, 970, 1074, -460, -1569, -699, 1185, 1475, -278, -1504, -558, 1044, 980, -738, -2040, -1445, 510, 1669, 900, -68, 902, 3386, 4794, 3835, 2397, 2973, 5167, 6071, 4042, 1026, 30, 1086, 1841, 851, -888, -1019, 959, 2737, 2211, 136, -705, 849, 2722, 2340, 264, -768, 258, 1519, 1152, -441, -1421, -650, 977, 1707, 1223, 814, 1888, 3995, 4696, 2915, 847, 1100, 3056, 3871, 2477, 835, 1039, 2503, 2736, 451, -2089, -1751, 790, 2498, 1864, -19, -726, 235, 955, 75, -1645, -1962, 31, 1908, 1202, -962, -1777, -405, 1515, 1663, -155, -1438, -654, 670, 376, -1610, -2784, -1292, 1325, 2454, 1481, 192, 895, 3113, 3834, 2230, 734, 1162, 2373, 2338, 792, -779, -554, 1507, 3066, 2354, 443, -333, 688, 1269, -401, -2449, -2427, -529, 1111, 826, -876, -1955, -1152, -48, -865, -2860, -3593, -2209, -58, 669, -601, -1485, 52, 2416, 2902, 1702, 1105, 2512, 5130, 6286, 4628, 2332, 2081, 3378, 3788, 2411, 739, 933, 2981, 4287, 3106, 994, 551, 1852, 2442, 812, -1321, -1713, -501, 684, 323, -1133, -1679, -588, 685, 307, -1167, -1413, 190, 1903, 1832, 156, -843, 395, 2484, 2672, 842, -314, 429, 1822, 2170, 947, -158, 823, 2750, 2933, 1383, 119, 233, 1028, 668, -1437, -3711, -4103, -2386, -634, -637, -1897, -2496, -1103, 823, 696, -726, -521, 1700, 3438, 2723, 415, -1005, -346, 880, 280, -2020, -3379, -2303, -346, 7, -1244, -1705, -57, 2341, 3049, 1346, -682, -467, 1431, 1951, 181, -1646, -1393, 609, 1997, 1153, -387, -133, 1714, 2757, 1517, -470, -559, 1165, 2408, 1685, -247, -1012, 405, 2035, 1412, -856, -1803, -319, 1597, 1481, -489, -1599, -515, 904, 487, -1426, -2523, -1381, 692, 1128, -657, -2413, -1998, -187, 426, -1462, -3735, -3291, -463, 1654, 1218, -63, 531, 2620, 3404, 1689, -706, -1389, -24, 1426, 1071, -233, -201, 1642, 3368, 2738, 375, -663, 646, 1983, 1107, -1193, -2300, -1065, 1054, 1810, 567, -1038, -1025, 142, 106, -1919, -3595, -2957, -1486, -1333, -2520, -3676, -3247, -1327, -273, -1423, -2896, -2259, 59, 1317, -14, -1786, -964, 1946, 3707, 2598, 209, -592, 993, 2551, 1626, -629, -1450, 16, 2181, 2678, 1425, 794, 2097, 3598, 2874, 361, -1437, -1028, 744, 1285, -444, -1863, -732, 1594, 2546, 1490, 192, 557, 2222, 2948, 1714, 140, 201, 1715, 2702, 1778, 299, 806, 3144, 4641, 3635, 1532, 1023, 2499, 3729, 2884, 1023, 375, 1488, 2865, 2493, 505, -689, 373, 1980, 1678, -136, -1001, 277, 2060, 1829, -671, -2768, -2260, -285, 550, -566, -1736, -1003, 789, 1443, 279, -992, -367, 1533, 2511, 1726, 441, 405, 1876, 3308, 2836, 1118, 1005, 2882, 4018, 2715, 272, -601, 559, 1379, 326, -1610, -2267, -758, 1161, 1072, -1095, -2752, -2282, -866, -527, -1850, -2870, -1871, -210, -34, -1434, -2599, -1669, 870, 2197, 1034, -423, 114, 2034, 2989, 1792, 99, 179, 1591, 1947, -12, -2467, -2699, -726, 1093, 859, -765, -1174, 530, 1870, 743, -1515, -2337, -1042, 685, 842, -663, -1812, -972, 474, 189, -1403, -1944, -592, 1228, 1523, 21, -1074, 34, 2246, 3027, 1311, -1105, -1425, 112, 580, -1014, -2579, -1889, 598, 2138, 1367, -89, -372, 466, 967, -145, -2262, -3021, -1587, -43, -486, -2383, -3275, -1984, -305, -595, -2515, -3348, -1640, 410, 129, -1722, -2637, -1567, 353, 916, -497, -1753, -1106, 434, 869, -379, -1380, -218, 1925, 2390, 434, -1707, -1599, 212, 1311, 525, -956, -1142, 268, 1310, 210, -2013, -2807, -1532, -395, -1640, -3916, -3942, -1423, 875, 894, -576, -1164, 16, 1243, 681, -1221, -2381, -1408, 631, 1387, 196, -993, -290, 1354, 1651, 89, -1639, -1587, -183, 227, -1174, -2601, -2082, 34, 1375, 768, -167, 611, 2866, 4197, 2967, 642, -120, 982, 1923, 905, -1571, -2865, -1447, 536, 337, -1377, -2039, -547, 1461, 1432, -335, -1048, 339, 1976, 1767, -56, -1205, -77, 2081, 2704, 1198, -321, 172, 1992, 2655, 940, -1115, -693, 1204, 1550, -194, -2004, -1683, 667, 2490, 1989, 679, 1040, 2948, 4003, 2560, -31, -981, 460, 2001, 1389, -431, -678, 1255, 2619, 1448, -655, -1379, -255, 1070, 534, -1579, -2871, -1726, 367, 454, -1623, -3064, -2181, -136, 843, -86, -1304, -666, 1687, 3396, 2764, 1059, 856, 2206, 2570, 859, -1065, -1008, 1046, 2926, 2679, 1230, 892, 2013, 2832, 1782, -261, -921, 313, 1478, 830, -1030, -1876, -534, 1340, 1092, -1210, -2873, -2151, -133, 518, -878, -1850, -407, 2158, 3165, 1840, 90, 305, 1846, 1906, 27, -1486, -881, 1308, 2861, 2325, 1045, 1313, 2910, 3473, 1816, -533, -1193, 61, 1100, 243, -1439, -1707, -146, 1312, 798, -868, -1244, 164, 1379, 968, -461, -1248, -306, 1458, 1873, 289, -1280, -753, 1076, 1682, 501, -383, 725, 2889, 3912, 2885, 1113, 858, 2284, 2805, 1268, -343, -97, 1528, 2458, 1533, -298, -1090, -14, 1262, 532, -1419, -1713, 467, 2754, 2495, 313, -536, 1223, 3452, 3639, 1936, 1021, 2579, 4646, 4565, 2655, 1225, 1639, 2779, 2454, 419, -902, 340, 2741, 3570, 2283, 806, 1163, 2890, 3403, 1494, -762, -838, 462, 404, -1546, -3370, -3305, -1620, -427, -1438, -3394, -3687, -2014, -460, -747, -2260, -3034, -2368, -1767, -2862, -5094, -6288, -5024, -2713, -2083, -3130, -3353, -1397, 1174, 1896, 770, 127, 1263, 2928, 3028, 1269, -352, 38, 1980, 2875, 1313, -565, -388, 1173, 1834, 539, -1267, -1467, -55, 822, -211, -2068, -2588, -1073, 714, 409, -1839, -3280, -2379, -946, -1320, -3131, -3920, -2176, 305, 625, -986, -2014, -1179, 300, 177, -1789, -3209, -2332, -345, 418, -612, -1468, -228, 1846, 2317, 741, -978, -813, 770, 1818, 1439, 430, 419, 1764, 2752, 1770, -40, -31, 2093, 3646, 2280, -843, -2390, -1319, -109, -805, -2414, -3215, -2440, -737, -364, -1983, -2947, -1638, -3, -200, -2012, -3298, -2114, 585, 1644, 108, -1518, -1086, 420, 496, -1424, -3239, -2952, -1264, -721, -2280, -4098, -3805, -1368, 453, -218, -1744, -1647, -6, 1165, 492, -1198, -1715, -401, 717, -415, -3074, -4665, -3964, -2577, -2701, -4377, -5293, -3635, -1069, -580, -2103, -2860, -1228, 1190, 1612, -285, -1846, -1000, 1149, 1936, 701, -483, 133, 1848, 2397, 841, -996, -1025, 313, 854, -495, -2446, -2820, -1310, -26, -802, -2635, -2822, -533, 1769, 1473, -430, -1060, 205, 1483, 975, -942, -1866, -533, 1360, 1495, -32, -823, 581, 2683, 2862, 931, -567, 156, 1947, 2099, 73, -1713, -1424, 188, 1091, -122, -2185, -2371, -697, 167, -1283, -3624, -4433, -3340, -2195, -2761, -4587, -5227, -3666, -2017, -2391, -3938, -4234, -2629, -1184, -1793, -3485, -3848, -2073, 49, 361, -739, -1007, 729, 2962, 2960, 613, -1062, -194, 1846, 2454, 849, -855, -322, 1783, 2511, 832, -984, -814, 650, 989, -949, -3425, -3642, -1602, -279, -1285, -2907, -2759, -593, 1313, 957, -476, -445, 1597, 3763, 3677, 1386, -289, 449, 1814, 1396, -591, -1908, -1173, 85, -508, -2727, -4006, -2879, -582, 560, -216, -912, 190, 1929, 2381, 1214, 85, 750, 2539, 2894, 922, -997, -521, 1489, 2481, 1276, -934, -1804, -812, -126, -1339, -3252, -3556, -1783, -150, -555, -1901, -1798, 210, 2009, 1686, -75, -1003, 183, 2140, 2410, 861, -121, 1023, 3033, 3428, 1549, -395, -292, 962, 1130, -450, -2156, -1889, -169, 498, -697, -2261, -2494, -1330, -746, -2328, -4371, -4286, -2580, -1386, -1811, -3175, -3324, -1466, 98, -767, -2900, -3602, -2197, -521, -337, -1124, -735, 1404, 3213, 2909, 958, -550, 76, 1877, 2370, 1007, -369, -11, 1721, 2316, 359, -1795, -1241, 1161, 2337, 1032, -974, -1243, 201, 1066, -330, -2580, -2907, -1330, -309, -1493, -3583, -3716, -1428, 500, -196, -2174, -2402, -420, 1320, 795, -1069, -1613, 20, 2002, 2152, 502, -895, -632, 603, 783, -913, -2390, -1408, 964, 1749, 343, -748, 228, 1954, 2098, 261, -1644, -1677, -298, 60, -1452, -2804, -2249, -237, 1501, 1246, -560, -1165, 218, 1172, 57, -1984, -2683, -1297, 497, 718, -515, -1230, -143, 1761, 2077, 158, -1422, -513, 1324, 1466, 77, -252, 1961, 4602, 4921, 2916, 870, 873, 2247, 2395, 467, -1599, -1667, -78, 704, -491, -2131, -2122, -344, 786, -786, -3625, -4577, -2957, -1366, -2313, -4700, -5533, -4018, -2245, -2402, -3728, -3795, -1738, 646, 990, -358, -988, 167, 1705, 1640, 141, -568, 631, 2408, 2660, 1042, -237, 545, 2146, 2340, 769, -872, -696, 964, 1527, -426, -2923, -2953, -720, 491, -862, -2744, -2727, -972, 179, -698, -2216, -2046, -118, 1215, 345, -1529, -2031, -615, 763, 119, -1927, -2774, -1396, 421, 481, -1188, -2212, -912, 1279, 1873, 576, -315, 1017, 3591, 4691, 3068, 1128, 1623, 3629, 4233, 2597, 850, 1394, 3848, 5156, 3892, 2221, 2382, 4055, 4948, 3450, 876, -143, 970, 2321, 1979, 490, 281, 2052, 3540, 2893, 1080, 251, 1260, 2738, 2782, 1355, 488, 1965, 4572, 5154, 3118, 1292, 1622, 2649, 2158, 124, -1493, -1074, 731, 1576, 470, -771, -470, 771, 1191, -299, -2309, -2225, -357, 507, -750, -2467, -2371, -420, 990, 348, -1254, -1532, 349, 2423, 2477, 1067, 665, 2207, 3893, 3777, 2111, 990, 1791, 3335, 3367, 1531, 29, 783, 2771, 3411, 2057, 886, 1710, 3166, 2663, 213, -1704, -1589, -283, 403, -435, -1800, -1727, -6, 1192, 339, -1125, -1055, 551, 1644, 583, -1428, -1907, -431, 1054, 920, -422, -857, 1013, 3550, 4096, 2657, 1641, 2563, 4131, 4058, 2143, 511, 868, 2305, 2499, 748, -931, -213, 1910, 2330, 608, -909, -586, 794, 1215, -204, -2054, -2113, -231, 1167, 299, -1434, -1638, -186, 728, -281, -2066, -2528, -1218, 61, -397, -1901, -2237, -831, 391, -257, -1889, -2373, -737, 1740, 2679, 1598, 595, 1636, 4015, 4868, 3189, 1394, 1756, 3393, 3599, 1691, 117, 1034, 3219, 3842, 2511, 1369, 1967, 3513, 4095, 2650, 293, -309, 1368, 2596, 1549, -413, -759, 1052, 2780, 2461, 738, -262, 530, 1513, 732, -1037, -1276, 940, 3380, 3328, 1271, 347, 1857, 3844, 3791, 1625, 88, 1119, 3228, 3630, 1886, 152, 595, 2522, 3111, 1240, -1099, -1447, -218, 2, -1800, -3673, -3345, -1212, 224, -589, -2224, -2194, -409, 795, -189, -2043, -2211, -77, 2273, 2535, 1033, 279, 1627, 3453, 3510, 1863, 632, 1496, 3712, 4656, 3344, 1967, 2498, 3813, 3385, 881, -1195, -980, 530, 1179, -87, -1771, -1458, 418, 1145, -392, -2544, -2874, -1193, -64, -1264, -3204, -3146, -1022, 536, 227, -746, -820, 565, 1915, 1033, -1166, -1739, 108, 2429, 2609, 652, -533, 238, 994, 558, -522, -1507, -991, 934, 1504, -325, -1869, -897, 1094, 1186, -992, -2986, -2630, -731, 138, -889, -2057, -1470, 468, 1592, 389, -1938, -2593, -1021, 338, -705, -3014, -3311, -804, 1548, 1004, -1165, -1793, -256, 1344, 1091, -486, -892, 1001, 3048, 2755, 670, -673, 221, 2117, 2477, 898, -380, 364, 2130, 2656, 1190, -321, 162, 1852, 2469, 1023, -1221, -1770, -352, 442, -644, -1840, -1031, 1693, 3751, 3048, 1027, 443, 1772, 3045, 2482, 941, 661, 2292, 4204, 4176, 2617, 2198, 3686, 4896, 3886, 1445, 32, 708, 2055, 1953, 326, -698, 223, 2172, 2855, 1098, -1167, -1610, -903, -1170, -2863, -4427, -3822, -1058, 1150, 932, -162, 251, 1823, 2363, 1094, -422, -252, 1527, 2982, 2400, 458, -7, 2063, 4354, 4264, 2242, 844, 1282, 2293, 1869, -15, -998, 98, 1739, 1889, 43, -1818, -1599, -395, -512, -2234, -3843, -3354, -1444, -677, -1698, -2776, -2209, -307, 697, -723, -2788, -2766, -948, 322, -422, -2118, -1923, 690, 2900, 2548, 718, -30, 1232, 2521, 1496, -944, -1926, -523, 1320, 1170, -941, -2423, -1523, 24, -349, -2236, -3558, -3112, -1701, -1481, -2846, -4047, -3793, -2726, -2697, -4266, -5439, -4491, -2304, -984, -1579, -2625, -1833, 444, 1506, 140, -1843, -2062, -254, 1286, 601, -891, -669, 950, 1665, 384, -1807, -2869, -1768, 54, 120, -1637, -2591, -1127, 1118, 1385, -588, -1913, -748, 1260, 1475, -272, -1402, -534, 896, 1108, -230, -1654, -1138, 817, 1357, -367, -2124, -1843, 116, 1280, 67, -1669, -1279, 1000, 2783, 2493, 1020, 556, 1889, 3120, 2217, 61, -774, 451, 1863, 1507, -215, -947, 413, 2063, 1694, -376, -1622, -669, 914, 846, -893, -2260, -1937, -709, -375, -1747, -3418, -3258, -1481, -709, -2005, -3673, -3865, -2568, -1612, -2187, -2969, -1976, 548, 2025, 1088, -513, -658, 800, 2093, 1698, 239, -331, 1114, 3030, 2914, 1205, 416, 1301, 2179, 1327, -594, -1536, -723, 550, 280, -1479, -2559, -1842, -419, -278, -1952, -3472, -3150, -1683, -998, -2176, -3672, -3157, -1031, 132, -1030, -2881, -2611, -73, 1916, 1480, 98, 394, 2246, 3255, 1964, -321, -783, 999, 2400, 1512, -631, -1724, -832, 445, -181, -2420, -3438, -2043, -435, -766, -2820, -4638, -4274, -2591, -2356, -4155, -5705, -5093, -3300, -2680, -3681, -4565, -3891, -1967, -515, -1132, -2747, -2597, -582, 682, -377, -2029, -1644, 585, 2178, 1194, -1450, -2632, -1332, 7, -607, -2200, -2473, -903, 627, 321, -1310, -2171, -1055, 849, 1012, -1214, -3184, -2420, -184, 599, -696, -1962, -1158, 914, 1534, -93, -1741, -1200, 1110, 2798, 2170, 513, 521, 2082, 2698, 1204, -954, -1288, 455, 1765, 985, -572, -559, 1335, 2910, 2038, -634, -2097, -1158, 47, -392, -1847, -2377, -1025, 940, 1177, -549, -1641, -484, 1304, 1479, -37, -1313, -694, 1029, 1409, -236, -1733, -1158, 433, 718, -877, -2715, -2918, -1497, -228, -527, -1526, -995, 1328, 3076, 2449, 383, -625, 411, 1723, 1270, -287, -613, 881, 2252, 1624, -7, 0, 2182, 4154, 3797, 1962, 995, 1846, 3227, 2812, 383, -1529, -1215, 38, -92, -1970, -3721, -3733, -2607, -2515, -4340, -6012, -5330, -3121, -2045, -3211, -4757, -4429, -2418, -1022, -2005, -4000, -3980, -1736, 205, 404, -242, 58, 1847, 3571, 3370, 1600, 696, 1904, 3509, 3338, 1938, 1533, 2975, 4865, 4599, 1952, -93, 209, 1332, 1086, -887, -2687, -2361, -773, -699, -2802, -4886, -5001, -3603, -3362, -5353, -7166, -6709, -4504, -2771, -3012, -3924, -3310, -1066, 873, 639, -1070, -1494, 156, 1902, 1682, -429, -1582, -258, 1315, 1022, -729, -1906, -946, 872, 957, -626, -1607, -737, 772, 711, -1030, -2630, -2505, -882, -204, -1676, -3113, -2264, -14, 634, -1431, -3858, -4028, -2080, -367, -819, -2398, -2264, -306, 975, 218, -1613, -2282, -871, 394, -675, -2869, -3787, -2548, -485, -129, -1596, -2248, -859, 1109, 1613, 431, -585, 346, 2554, 3391, 1987, 671, 1466, 3365, 4013, 2543, 326, -135, 1494, 2157, 302, -1799, -1750, 193, 1397, 113, -1897, -1590, 1108, 3133, 2586, 1058, 829, 2166, 3572, 3120, 1334, 1103, 3294, 5283, 4725, 2777, 2116, 3542, 5237, 4610, 1818, -108, 224, 1061, 589, -1169, -2546, -1911, -202, 234, -938, -1686, -625, 1262, 1988, 978, -280, 117, 2128, 3297, 2076, 161, 125, 1933, 3029, 1903, 73, 182, 2666, 4612, 3790, 1973, 1609, 2552, 3105, 2022, -98, -1474, -1038, 323, 460, -1070, -2036, -709, 1139, 939, -1216, -3237, -3256, -1953, -2058, -4303, -6286, -6025, -4436, -4042, -5476, -6364, -4802, -1947, -309, -927, -2396, -2289, -452, 651, -273, -1804, -1965, -560, 813, 628, -804, -1146, 663, 2476, 1977, -112, -1020, 124, 1148, 366, -1170, -2123, -1856, -397, 465, -501, -1568, -659, 1326, 1660, -325, -2584, -3120, -2047, -1484, -2876, -4834, -5049, -3719, -3079, -4054, -5342, -4903, -2508, -774, -1518, -3002, -2718, -763, 596, -112, -1610, -1814, -565, 372, -658, -2941, -4116, -3471, -2663, -3287, -4848, -5467, -4138, -2169, -1836, -3279, -4272, -3455, -2008, -1565, -2349, -3046, -1914, 571, 1335, -569, -2263, -1820, -305, 239, -1206, -3075, -2883, -1012, -93, -1325, -3170, -3415, -1901, -509, -869, -2159, -2154, -629, 491, -322, -2417, -3481, -2532, -1609, -2573, -4425, -5022, -3756, -2210, -2627, -4940, -6249, -4835, -2547, -1542, -1873, -2016, -280, 2547, 3630, 2159, 692, 1545, 3655, 4197, 2321, 553, 1165, 2856, 3402, 2316, 548, -100, 955, 1628, 157, -2104, -2702, -1409, -307, -1053, -2898, -3689, -2432, -704, -1059, -3115, -3532, -1297, 882, 707, -1111, -2075, -864, 942, 1024, -758, -2297, -1525, 778, -20038, -12278, 6427, 11556, -3460, -18032, -12651, 5617, 12204, -1592, -17517, -15539, 1129, 9896, -1508, -17610, -16083, 1934, 13748, 5416, -11125, -14210, 658, 13552, 5893, -12793, -18409, -4517, 9891, 5206, -13116, -21600, -9150, 8215, 8124, -8714, -18965, -8251, 8823, 9597, -6635, -18835, -11002, 6578, 10166, -5160, -19129, -13213, 5302, 12308, -637, -15175, -11300, 6384, 14724, 2929, -13293, -12971, 3245, 13773, 4239, -13218, -15640, 316, 12560, 3902, -14696, -19828, -5332, 9490, 4916, -12750, -20415, -8087, 8514, 7315, -10319, -19921, -7539, 10583, 10912, -6043, -17860, -9530, 7515, 9977, -6510, -21128, -15360, 2222, 7818, -5890, -20776, -16508, 2362, 11478, -396, -16985, -16442, 500, 10915, 144, -17831, -19363, -2553, 10468, 3291, -13832, -18081, -3385, 10686, 5168, -12809, -19730, -6494, 8916, 5885, -11397, -20235, -8683, 8389, 8404, -8419, -19521, -9865, 7906, 10039, -6152, -19387, -12436, 4964, 8836, -6356, -21057, -16174, 2290, 10164, -2719, -19199, -17800, -383, 9979, -77, -16400, -16766, -264, 11342, 2894, -14354, -17665, -2443, 10890, 4546, -12761, -18050, -3529, 12320, 8391, -10067, -19310, -8710, 6180, 4584, -12309, -22603, -11875, 6480, 8815, -6670, -18442, -10263, 7809, 11898, -3749, -18779, -14236, 2503, 8260, -5273, -21130, -18534, -764, 8469, -2694, -19556, -20585, -4647, 6464, -2947, -20489, -22544, -5982, 7710, 1208, -16467, -21438, -6175, 9300, 4611, -13710, -21952, -9892, 5674, 3290, -14496, -24948, -14598, 3092, 4910, -11225, -22948, -13359, 5369, 9441, -4835, -17846, -11429, 6928, 12695, -1828, -17385, -13952, 3679, 12008, -202, -17119, -16488, 1188, 12386, 2225, -15842, -18050, -1814, 10805, 3513, -13781, -18578, -4443, 9756, 4809, -12688, -19720, -7316, 7768, 4872, -12488, -21103, -9223, 7828, 7896, -9110, -21205, -12442, 5976, 10280, -4480, -17991, -11298, 7156, 12486, -2271, -17599, -13538, 4252, 11462, -1561, -17765, -16337, 897, 10922, 167, -16940, -17657, -1016, 10722, 2095, -15634, -19682, -4873, 9021, 3501, -14183, -20686, -6823, 9458, 6755, -10837, -20011, -8867, 7535, 7119, -9429, -20046, -10445, 7257, 9897, -6144, -19665, -12941, 4525, 9081, -5486, -20381, -16292, 1280, 8363, -5072, -21367, -19207, -2214, 6513, -4418, -20839, -21687, -5737, 5833, -2719, -19958, -22851, -7941, 4798, -809, -17170, -22597, -8752, 7056, 4262, -13046, -21403, -9604, 6358, 5474, -10942, -21447, -11508, 6140, 7909, -7882, -19943, -12726, 4595, 9367, -5078, -19587, -14599, 3442, 10524, -2515, -18159, -15947, 633, 8925, -3218, -20855, -21065, -3815, 7560, -1348, -17680, -19809, -4229, 9737, 3879, -14083, -19652, -4979, 9886, 4993, -13290, -21570, -9489, 6768, 5667, -10779, -19861, -8519, 8873, 9558, -6826, -18925, -11379, 5746, 9175, -6025, -19961, -14360, 3349, 9689, -3503, -18714, -15433, 2570, 11308, -746, -17493, -17457, -1224, 9723, 1009, -15642, -17443, -1346, 11006, 3094, -14674, -19201, -4801, 9303, 4681, -12481, -19492, -6237, 10166, 7781, -9713, -18719, -7256, 9896, 10616, -5480, -17312, -9445, 7797, 11366, -3221, -16625, -11207, 6135, 12158, -1084, -15574, -11927, 5128, 12730, 557, -15369, -13896, 3243, 13519, 3678, -13138, -14730, 1209, 13674, 6451, -10456, -14400, 511, 14918, 9913, -6988, -13092, -415, 14692, 12111, -5035, -13762, -2237, 14014, 13100, -4146, -15344, -5782, 11884, 14684, -365, -13253, -6917, 10476, 15565, 1194, -13743, -9709, 7257, 13757, 696, -15346, -13477, 4282, 14454, 3802, -13179, -13900, 2980, 15309, 6929, -10841, -14366, 1355, 15656, 9659, -9126, -16610, -2727, 13484, 10268, -7300, -15946, -4296, 12227, 11657, -4694, -14389, -4131, 12498, 13157, -3496, -16099, -7800, 11067, 15971, 1401, -13047, -8693, 8261, 14148, 50, -15853, -13309, 3278, 11483, 387, -16110, -16477, 192, 11189, 1794, -15199, -17556, -1949, 11340, 4971, -12214, -17212, -3077, 11889, 8093, -9256, -17120, -4659, 12186, 11510, -4670, -13876, -3377, 13054, 13335, -3192, -15169, -7319, 9384, 12643, -1654, -14831, -9392, 8159, 14475, 811, -14916, -12080, 5795, 14975, 3560, -12393, -11447, 5409, 16387, 7337, -9497, -11608, 4024, 16418, 9374, -7320, -11467, 2822, 16596, 10876, -7854, -15941, -3304, 12683, 10928, -5148, -13503, -2505, 13854, 14223, -1700, -12731, -4153, 12324, 14222, -1479, -14629, -8082, 9846, 15637, 1714, -13305, -9347, 8313, 16199, 4230, -11925, -11345, 5065, 14948, 4587, -12806, -14104, 2632, 14770, 6822, -9561, -12585, 1974, 15457, 10143, -7166, -13685, -969, 13743, 10719, -6217, -14718, -3027, 13620, 13580, -2629, -13639, -4417, 13179, 15712, 143, -12732, -5986, 11333, 15959, 1348, -13231, -8707, 8160, 14302, 1246, -14388, -12459, 4696, 14106, 3013, -13674, -13605, 3558, 15441, 6733, -10462, -13226, 2292, 15935, 10091, -7009, -12648, 645, 15303, 12012, -4769, -12894, -1093, 15416, 14607, -2462, -13147, -3313, 13757, 15390, -236, -12418, -4933, 12184, 15753, 778, -13426, -8160, 9966, 17098, 4553, -10275, -7432, 9355, 17062, 5057, -11007, -10796, 5015, 15165, 5649, -10814, -12485, 2890, 15509, 8686, -9080, -14485, -164, 15123, 11310, -5904, -12848, 300, 16571, 14760, -2475, -12474, -2448, 13717, 14054, -2453, -14404, -5903, 11641, 14899, 162, -12964, -6787, 11225, 17188, 3804, -10316, -6047, 11754, 20259, 8635, -7718, -7332, 8856, 18455, 7979, -9633, -12422, 2259, 14010, 6224, -11749, -16197, -1025, 13487, 8642, -8771, -15866, -3170, 12312, 10081, -6344, -14828, -3392, 13680, 14236, -1876, -12799, -3929, 13113, 15734, 231, -12798, -6125, 10826, 15542, 2212, -11655, -7255, 10434, 17935, 5300, -10314, -8080, 9221, 18864, 8098, -9050, -10168, 5978, 17591, 9254, -7755, -10568, 4993, 18613, 12752, -4491, -10363, 2973, 17766, 14214, -3488, -12648, -1402, 15023, 14852, -1059, -11177, -1646, 15167, 16661, 691, -12026, -5058, 12304, 16630, 2340, -11081, -5256, 12723, 19351, 6228, -9371, -7228, 9744, 18667, 7331, -9588, -10424, 5549, 17074, 9233, -7097, -9751, 6056, 20237, 14206, -3311, -8548, 5405, 19780, 15037, -3312, -11410, 1165, 16782, 14322, -2760, -12182, -1631, 15474, 16869, 594, -11835, -4120, 12417, 15052, 14, -13867, -9009, 8087, 14442, 1312, -13703, -9918, 8290, 17035, 5689, -9878, -8889, 7915, 18562, 8997, -7773, -9258, 6905, 19723, 12540, -5052, -9785, 4442, 18621, 14289, -2216, -8731, 3616, 18606, 16015, -1296, -11065, -963, 15145, 15385, -865, -11945, -3051, 14080, 17085, 2325, -10681, -4708, 11804, 15884, 1113, -14191, -10761, 6579, 14627, 2809, -12755, -11290, 5487, 15718, 6120, -10452, -11321, 5678, 18192, 10455, -6174, -9480, 5421, 19232, 13768, -3510, -9704, 3159, 17682, 14577, -2197, -10903, 444, 17225, 16745, -852, -12912, -4237, 12882, 15148, -36, -12030, -5000, 11751, 15702, 1033, -13098, -8113, 9110, 15619, 3119, -11893, -9603, 7618, 17467, 7345, -8939, -9104, 7658, 18766, 9362, -8227, -11450, 3759, 17664, 12058, -5650, -12221, 1044, 16610, 13819, -3425, -11693, 743, 17271, 15268, -2790, -13835, -4552, 12104, 14067, -1279, -13764, -6227, 11389, 15783, 2101, -10894, -5122, 12909, 20056, 7479, -7871, -5278, 12441, 21698, 9743, -7773, -7993, 8579, 19532, 10699, -5847, -8226, 6635, 18525, 10938, -6722, -11771, 2134, 16421, 12226, -4762, -12079, 83, 15575, 13795, -3250, -13209, -2591, 14562, 15502, -536, -12092, -4102, 12525, 15455, 444, -13109, -7700, 8764, 13715, 65, -14554, -10526, 7856, 17457, 6862, -8633, -7269, 9586, 19503, 9513, -7929, -10560, 5085, 18116, 11247, -6140, -10563, 4192, 18416, 13251, -4674, -12438, -365, 14539, 11120, -6829, -15714, -3863, 13076, 13523, -1846, -11747, -2182, 14869, 17105, 1423, -11897, -5402, 12268, 17757, 4021, -10943, -6863, 11411, 19147, 6300, -9893, -8395, 8710, 18013, 6133, -12213, -13912, 2432, 14637, 6640, -10282, -13527, 862, 13953, 8301, -9074, -15004, -1564, 12827, 8871, -8332, -16608, -5166, 11107, 11354, -3587, -12870, -2645, 15039, 17380, 1943, -10329, -3233, 13904, 18071, 3165, -11558, -6913, 10598, 17417, 4610, -10927, -8594, 8751, 17686, 5691, -12378, -14048, 1665, 12702, 4077, -12447, -14760, 1080, 14785, 8628, -8694, -14286, -964, 13162, 9015, -8155, -15840, -3681, 12124, 10632, -6170, -16452, -6780, 9686, 10611, -5254, -16764, -8209, 9780, 14097, -179, -13860, -8399, 9038, 14966, 2081, -12135, -8500, 8921, 17453, 6281, -9870, -10120, 6012, 16739, 7481, -8882, -10395, 5050, 17123, 9930, -7312, -12235, 2256, 16948, 11904, -5569, -12510, -5, 15806, 14010, -3157, -13059, -2446, 14464, 14892, -1659, -13310, -4754, 12488, 15553, 1041, -11275, -4228, 13839, 19296, 5190, -9721, -6033, 11004, 18360, 6042, -10040, -9355, 6917, 16853, 6769, -10221, -11606, 4603, 16653, 8484, -8859, -12837, 1241, 14637, 9884, -6616, -12481, 1533, 17715, 14807, -3162, -12548, -1350, 15206, 15337, -663, -11461, -2338, 14986, 17459, 1965, -11121, -4903, 11785, 15943, 1362, -13541, -9525, 7905, 15029, 2364, -13000, -10528, 7092, 17172, 6713, -10745, -12753, 2700, 13918, 5293, -11883, -15362, -187, 13867, 8167, -8739, -13219, 1348, 16363, 12860, -4255, -12260, -236, 15377, 13709, -2972, -13774, -4952, 12054, 14442, -918, -13346, -5987, 11392, 15360, 408, -13877, -8654, 8916, 15251, 1789, -14143, -11860, 5816, 15386, 3890, -13371, -13240, 4039, 15306, 6121, -11230, -14267, 921, 13939, 7006, -10800, -15635, -935, 14180, 10872, -5323, -12333, -95, 15567, 13485, -3825, -13580, -3257, 13410, 14495, -1737, -14271, -6599, 10913, 14822, 261, -13414, -7666, 10611, 17128, 3582, -11135, -7168, 10020, 17609, 5464, -11373, -11525, 5057, 15959, 6366, -11117, -13088, 3500, 16532, 8823, -9238, -14154, 465, 14895, 9509, -8629, -15833, -2873, 12899, 10526, -7219, -17991, -8429, 8052, 8702, -7499, -18828, -9864, 7925, 11183, -3923, -16742, -9942, 7408, 12143, -2116, -16940, -12744, 5519, 14162, 2541, -13334, -12341, 3878, 12999, 2064, -15194, -16322, 165, 11997, 3675, -12997, -15862, -489, 13842, 8664, -9087, -16384, -4298, 10268, 7136, -9442, -16855, -4522, 12503, 13017, -2988, -14158, -5055, 12321, 14331, -1549, -14334, -7575, 9554, 14058, -552, -15124, -10478, 7177, 15055, 3429, -12242, -10896, 5858, 15103, 4315, -11893, -11905, 4153, 14341, 4340, -13524, -16801, -2097, 10714, 4682, -11970, -16899, -2874, 12357, 9350, -7482, -15910, -4632, 11072, 9446, -7394, -16731, -5754, 12105, 14159, -1774, -13944, -5852, 11954, 16343, 1825, -12426, -7027, 11289, 17977, 4759, -10315, -7852, 8526, 16930, 5832, -10769, -11523, 4160, 14714, 5684, -11344, -14590, -6, 12614, 5445, -12388, -17087, -2558, 11703, 7189, -10073, -17885, -5754, 10513, 9335, -7307, -17027, -6984, 9180, 9536, -6584, -17799, -8842, 8890, 12371, -2546, -16103, -10052, 7949, 13909, 146, -15438, -13396, 2892, 10826, -1105, -17744, -17777, -1410, 9816, 1179, -15429, -17473, -1950, 10533, 3395, -13818, -17991, -2968, 11900, 7891, -8713, -15193, -1901, 14342, 12408, -4568, -13845, -2946, 14015, 14891, -704, -11697, -3548, 12817, 15032, -482, -13626, -7255, 10233, 15318, 888, -14297, -10816, 6400, 14810, 3609, -11936, -10474, 6403, 15959, 5105, -12200, -13566, 2392, 14396, 6512, -11001, -14980, -107, 13364, 6643, -11823, -17859, -4172, 10765, 7603, -9616, -18478, -7176, 9373, 9409, -6554, -16771, -7212, 9672, 11759, -3390, -16053, -9713, 7172, 11647, -2380, -16206, -11489, 5754, 12411, -726, -16680, -14981, 1797, 10962, -45, -16754, -17043, -181, 12024, 4291, -12067, -14613, 328, 12852, 6287, -10994, -16401, -2263, 12805, 8920, -8124, -16019, -4653, 11220, 10196, -7291, -18551, -8715, 8909, 10931, -4467, -16159, -8107, 9539, 13204, -2254, -16377, -10536, 7013, 12676, -718, -15461, -12168, 5399, 14501, 3430, -12943, -13090, 2889, 13001, 2982, -14292, -16291, -509, 12381, 5447, -12295, -17410, -2933, 11569, 6715, -10857, -18501, -6217, 9705, 7970, -8159, -16345, -4660, 12959, 13580, -3954, -16865, -9028, 7769, 10451, -4163, -17043, -11664, 5594, 12450, -253, -15446, -12252, 5654, 14546, 2653, -14059, -13551, 2843, 12628, 2858, -13904, -16019, -130, 13140, 6480, -11053, -16033, -1876, 11635, 6095, -10955, -17164, -4015, 11772, 10096, -5864, -14089, -2712, 13652, 13101, -4011, -15696, -7214, 9505, 11605, -3765, -15929, -8318, 9754, 15545, 2556, -11672, -8187, 8355, 15372, 2675, -13913, -13029, 3823, 13551, 3050, -13698, -14909, 764, 12312, 4381, -12629, -16550, -1652, 12900, 8307, -7850, -12496, 1927, 17506, 14448, -2795, -11480, -284, 15211, 13606, -3973, -16188, -8239, 8549, 10944, -4212, -16245, -8948, 8170, 12696, -1013, -14529, -9234, 8532, 15335, 2492, -12833, -10499, 6499, 15541, 4393, -12681, -13890, 1361, 11680, 2541, -14601, -17679, -2768, 10289, 4087, -13070, -17992, -2845, 13580, 10287, -7678, -16363, -4726, 10963, 9324, -8111, -19060, -9037, 8487, 10239, -5297, -17184, -9242, 8539, 12724, -1873, -15772, -10469, 7611, 14614, 1526, -13135, -9576, 6891, 14244, 2102, -14917, -15007, 1571, 12135, 3136, -12672, -14164, 1283, 13913, 6924, -10772, -15589, -900, 13465, 8538, -8631, -15706, -3768, 11516, 9639, -7856, -18457, -8203, 9073, 10167, -5791, -17125, -9014, 7924, 11394, -3549, -17510, -12057, 5333, 11591, -742, -14527, -10546, 6839, 14994, 3300, -13063, -12763, 4011, 14757, 4864, -12413, -14338, 1450, 13801, 6148, -11443, -15564, -407, 14012, 8788, -8975, -16127, -3552, 11547, 8341, -9475, -18893, -7604, 9416, 9697, -6466, -17369, -8606, 8167, 10485, -4881, -17624, -10762, 6473, 11490, -1714, -15781, -11827, 5520, 12970, 470, -15109, -13256, 3583, 13432, 3700, -12267, -12712, 3364, 14738, 6589, -10869, -15450, -1071, 13032, 7525, -10340, -16556, -2950, 12107, 8976, -7801, -16031, -4370, 11830, 11016, -5451, -15691, -5563, 11761, 13241, -2798, -15448, -8435, 8611, 12664, -1729, -16037, -11583, 6022, 13253, 877, -14358, -12028, 5366, 14598, 3381, -13022, -13073, 3326, 14716, 6192, -10915, -14071, 857, 13535, 6820, -10647, -16259, -2208, 13210, 9367, -8425, -16442, -4000, 12748, 12275, -4329, -15250, -5910, 10885, 11910, -4419, -16973, -9662, 7971, 12775, -1209, -14581, -8595, 9446, 16037, 3006, -12177, -9543, 7446, 15978, 3973, -13006, -12300, 5202, 16620, 7716, -9358, -12170, 3427, 16876, 10109, -7532, -12665, 1030, 15068, 10479, -7218, -14896, -2634, 12704, 10713, -5692, -14835, -4273, 12755, 14119, -1623, -13004, -4349, 13151, 16686, 2268, -10675, -4702, 12269, 17430, 3708, -11620, -9004, 7694, 15588, 3816, -11944, -10326, 7192, 17599, 7290, -10228, -12621, 2571, 14706, 7322, -9790, -13429, 2115, 16907, 12293, -4758, -11354, 1790, 17250, 14388, -3017, -12560, -2048, 14287, 13921, -3238, -14851, -6054, 10985, 13435, -1785, -14716, -8197, 9792, 15608, 1966, -12348, -8108, 9329, 16946, 4554, -11646, -10416, 5845, 14465, 3693, -12629, -13196, 3395, 15820, 8668, -7900, -11831, 2836, 16870, 11153, -7019, -13590, -78, 14698, 10973, -5431, -12778, -1392, 14351, 13730, -2702, -13190, -3820, 12824, 14572, -876, -13483, -6881, 9923, 14399, 974, -12171, -6805, 10911, 18070, 5892, -9224, -7479, 8766, 17486, 6314, -10585, -11447, 4504, 15522, 6091, -11865, -15191, -113, 13023, 6554, -10950, -16617, -3310, 10982, 7151, -9472, -16747, -4081, 12811, 12032, -4803, -15162, -5270, 11454, 12321, -4250, -17143, -9769, 7736, 11978, -1893, -15390, -10728, 5949, 11686, -1514, -16394, -13538, 3944, 13546, 2974, -13140, -12739, 4040, 14793, 5396, -11533, -13766, 1398, 13726, 7155, -9543, -13880, 832, 15350, 10771, -6237, -13143, -930, 13886, 11481, -5191, -14468, -3480, 14259, 15955, 532, -10345, -1827, 15022, 17801, 1968, -12689, -7607, 9487, 14834, 948, -13898, -10140, 7357, 15419, 3258, -13043, -11761, 5393, 15790, 6087, -11108, -13397, 2546, 15748, 8707, -9001, -13264, 1858, 15780, 9709, -8581, -15972, -3775, 11205, 8531, -8800, -17756, -5882, 11199, 11165, -5121, -15810, -6556, 10561, 12968, -2011, -14274, -7320, 10194, 15940, 3174, -11086, -7743, 9035, 16170, 3522, -12343, -10921, 5527, 15107, 5152, -11555, -13049, 2830, 14519, 6295, -11152, -15145, -313, 13469, 8110, -8539, -14126, -295, 15619, 12872, -4489, -13473, -2315, 13851, 13071, -3558, -13998, -4375, 12401, 13908, -1684, -14285, -7693, 9603, 14675, 475, -14062, -8812, 9675, 16751, 3967, -10868, -8406, 7844, 16173, 5108, -11441, -12139, 3915, 15121, 6175, -11164, -13884, 1726, 14964, 8156, -9990, -15724, -1753, 13005, 8929, -8553, -16368, -3799, 12525, 11002, -5612, -15322, -5192, 12162, 14307, -1366, -14001, -6743, 10343, 13718, -1020, -14191, -8876, 8041, 14756, 2354, -12795, -10079, 7167, 15899, 4812, -11081, -10598, 6092, 17121, 7847, -9458, -12169, 3048, 15976, 9389, -8156, -13690, -200, 14087, 9437, -8603, -15892, -2308, 14369, 13138, -3441, -13699, -3949, 12866, 14018, -2058, -13827, -5437, 11899, 15042, -266, -14505, -9315, 8219, 14218, 661, -13973, -10147, 7148, 15190, 3282, -13444, -13636, 2352, 12194, 1707, -15952, -17784, -1235, 12397, 6286, -10199, -14350, 137, 14393, 9643, -7574, -14218, -940, 14833, 12504, -4225, -13037, -2058, 14574, 15082, -1346, -12758, -3803, 12909, 14993, -601, -14476, -8964, 8066, 13405, -329, -15497, -12232, 5146, 12937, 448, -15702, -13966, 3523, 13603, 3604, -12972, -14652, 937, 13113, 5648, -11335, -15018, 281, 14714, 9502, -7921, -14449, -1126, 14238, 10979, -6118, -14528, -3511, 12193, 11490, -5145, -15808, -6270, 10469, 12024, -3918, -16955, -9959, 8052, 13318, -708, -14799, -10004, 7144, 14073, 1937, -13428, -11630, 5793, 16208, 5549, -12312, -14031, 2195, 14115, 5779, -11212, -14572, -425, 12273, 6506, -10090, -15155, -1466, 13026, 9470, -7086, -14876, -3629, 11416, 9732, -7064, -17109, -6550, 10957, 12651, -2970, -15218, -7795, 9486, 12954, -2675, -17286, -12588, 4217, 10751, -1509, -16182, -12957, 4970, 14339, 3386, -12558, -11853, 4953, 15834, 6801, -10048, -12566, 2798, 15532, 8337, -9614, -15076, -1137, 13402, 9390, -7726, -15658, -3585, 12406, 10573, -6301, -15728, -4820, 12843, 14395, -1433, -13165, -5250, 11172, 13338, -2264, -16232, -11207, 6201, 13078, 994, -13031, -9538, 7778, 16320, 4948, -11144, -11077, 4824, 15693, 6945, -10007, -12385, 3176, 15651, 8124, -9293, -13779, 164, 14007, 9079, -8643, -15834, -3205, 12082, 9833, -6777, -15548, -4309, 12313, 12378, -4150, -15760, -7292, 9685, 12184, -2875, -15408, -8863, 8539, 13901, 83, -14583, -10840, 6191, 13456, 802, -15254, -13521, 4047, 14765, 5289, -11115, -12030, 4330, 16298, 8242, -8819, -12231, 2862, 16674, 11018, -6323, -12526, 564, 15507, 12637, -3958, -12692, -1954, 14270, 14125, -2604, -13765, -4283, 13105, 15030, -1010, -14188, -7830, 8840, 13032, -906, -14724, -9771, 8623, 16407, 3553, -12053, -9511, 7810, 17354, 6887, -10149, -12050, 3007, 14091, 5694, -11297, -13911, 2045, 15915, 10145, -7067, -13084, 33, 14649, 10978, -6195, -14077, -2319, 12935, 10980, -6436, -17363, -7621, 9979, 12738, -2100, -14190, -6583, 11093, 15337, 288, -14254, -8553, 10109, 17090, 3858, -11851, -9331, 7947, 16760, 5787, -10386, -10395, 6441, 18014, 9252, -7754, -10662, 4493, 17900, 11579, -6280, -12168, 1315, 15871, 12028, -5195, -13002, -825, 15012, 13588, -2758, -12376, -1963, 15395, 16716, 127, -12650, -5217, 11718, 14982, 174, -13337, -7549, 10463, 17263, 4393, -10905, -8237, 9286, 18303, 6838, -9710, -10015, 5606, 15991, 6783, -10433, -13140, 1942, 14331, 7323, -9703, -13553, 1673, 16482, 11779, -5903, -13280, -933, 14560, 12605, -4065, -12896, -1202, 16072, 16454, 163, -11393, -3466, 13356, 16755, 2025, -11441, -5328, 12042, 16769, 2558, -12486, -9569, 6994, 14747, 2879, -13239, -12248, 4719, 15225, 5748, -11023, -13140, 2158, 13769, 5727, -10992, -14389, 196, 14124, 9175, -8322, -15172, -1803, 14176, 12277, -3140, -10375, 1227, 17687, 17586, 1155, -9660, -589, 16271, 18610, 3044, -10724, -4922, 11943, 15625, 72, -14813, -10327, 7271, 15126, 3518, -11806, -9910, 7641, 18031, 7796, -9386, -10803, 5164, 16456, 7596, -9909, -13701, 805, 14134, 8460, -8518, -14347, -1232, 13381, 10290, -6015, -13716, -1702, 14913, 14265, -2302, -12442, -2680, 13774, 14784, -1513, -14477, -7411, 9875, 13875, -449, -13893, -8429, 9267, 16055, 3360, -11925, -9610, 7858, 17756, 7306, -9408, -10376, 5632, 17007, 8035, -9839, -13553, 1212, 14259, 7833, -9629, -14662, -338, 14217, 10193, -6460, -13763, -2016, 13159, 11680, -4655, -14613, -4674, 12221, 13612, -1903, -13224, -4456, 13762, 17916, 2993, -11329, -6801, 9586, 14780, 422, -15639, -13235, 3580, 12330, 1452, -14826, -14784, 2128, 13532, 4611, -12077, -14240, 1337, 14553, 8282, -8812, -13775, 176, 14379, 9769, -7447, -14083, -767, 15316, 13390, -4009, -14659, -4738, 12067, 12577, -4112, -16123, -8076, 8978, 12557, -1202, -13508, -7532, 9423, 14924, 1526, -13676, -10948, 6281, 14995, 4052, -10777, -8418, 9190, 19180, 8992, -7537, -9020, 6621, 19022, 12037, -4657, -8750, 5652, 19703, 14034, -4515, -12169, -277, 14004, 10938, -5881, -14603, -3831, 12443, 13080, -2654, -13793, -5465, 10914, 13178, -2072, -15038, -8413, 9206, 14258, -78, -15446, -12452, 4440, 12260, 98, -15693, -13574, 4240, 14807, 5066, -11121, -11413, 5391, 17022, 8228, -8994, -12335, 2357, 16050, 10744, -7010, -13942, -984, 13897, 10510, -6577, -14926, -4016, 11031, 9830, -6360, -16033, -5558, 12290, 14556, -1776, -15471, -8974, 8378, 13215, -728, -14937, -10542, 6898, 13922, 1051, -14358, -11610, 6051, 15428, 4853, -10999, -11349, 4346, 15124, 6192, -11057, -13994, 1533, 14812, 8488, -8343, -13154, 647, 14728, 10242, -6811, -14177, -2456, 12832, 11380, -5296, -15615, -5998, 10630, 11928, -3834, -15907, -8559, 8109, 11596, -3023, -16882, -11437, 7032, 14625, 1960, -13396, -10944, 5936, 14760, 3909, -12133, -11750, 5015, 16358, 8132, -7928, -9666, 6146, 18355, 10033, -8646, -14534, -1133, 13174, 8765, -9077, -16677, -4100, 11413, 9458, -6861, -15522, -4336, 12573, 13605, -2097, -14326, -7466, 8855, 11863, -3160, -16753, -10967, 7030, 13754, 1019, -13545, -9925, 7776, 16127, 4330, -11507, -10405, 5768, 15024, 4933, -11726, -13536, 2091, 14566, 7577, -9266, -13522, 627, 14235, 9088, -2672, -3304, -3641, -3400, -2742, -2452, -2408, -2226, -2310, -2815, -2996, -2573, -2274, -2465, -2727, -2673, -2209, -1848, -2076, -2496, -2698, -2833, -2546, -1943, -2867, -4603, -4325, -2891, -1829, -963, -602, -709, -467, 566, 1960, 2256, 1557, 1516, 1487, 1091, 229, -2225, -4414, -4788, -5105, -5237, -4309, -3830, -3996, -3504, -2822, -2121, -940, -154, -199, -257, -11, 72, -345, -975, -1111, -914, -795, -571, -373, -707, -1815, -2503, -2147, -2225, -2906, -3178, -3747, -4073, -3365, -3758, -5915, -7301, -6966, -6262, -6079, -5814, -4705, -4023, -4589, -5198, -5782, -6367, -6164, -5761, -5974, -6488, -6731, -6154, -4451, -2964, -3524, -4807, -4738, -3826, -3580, -4296, -5242, -5641, -5378, -4741, -4133, -4244, -4488, -3448, -2707, -4095, -5367, -5436, -5322, -4826, -4489, -4679, -4388, -3519, -2867, -2735, -2651, -2256, -1791, -1682, -2053, -2535, -2865, -3017, -3237, -3888, -4279, -3815, -3324, -3459, -3693, -4413, -5513, -5609, -5342, -5385, -4601, -2919, -1561, -1704, -2554, -2245, -1336, -960, -812, -933, -1320, -1540, -1622, -1506, -1455, -1815, -2528, -3891, -5346, -6038, -7009, -8358, -7732, -5846, -5334, -5342, -4408, -3132, -2277, -1798, -2312, -4095, -5504, -5976, -6363, -6371, -5868, -6563, -8347, -8690, -8147, -8708, -9921, -10542, -10259, -9518, -8485, -7170, -6023, -4917, -4046, -3972, -3468, -2199, -1847, -2618, -2931, -3145, -4641, -5605, -5098, -5017, -5865, -6247, -5815, -5708, -5707, -5320, -4923, -4380, -3041, -1540, -1826, -3049, -2542, -1526, -2140, -3101, -3744, -4544, -4717, -4467, -4627, -5122, -5014, -3471, -2794, -4335, -5226, -5102, -5310, -5200, -4784, -4552, -4241, -3390, -2038, -1128, -1041, -1292, -1735, -2517, -3436, -3746, -2951, -2520, -3969, -4942, -4432, -4299, -4331, -3844, -3244, -3009, -2756, -2184, -1551, -1148, -1436, -1991, -1136, 92, -622, -1216, -438, -69, -347, -866, -1729, -2147, -1439, -108, 1349, 2621, 3531, 4143, 4909, 5989, 6705, 5969, 4102, 3515, 3957, 3219, 1722, 899, 750, 276, -765, -1333, -1417, -2044, -2726, -2873, -3540, -4901, -5243, -3850, -2537, -3255, -4561, -4686, -4190, -4193, -4419, -4098, -4163, -4706, -4687, -4605, -4915, -5056, -5104, -5374, -5849, -5975, -5285, -5610, -7096, -7046, -5684, -4886, -4332, -3430, -3105, -3981, -4996, -4950, -3989, -3024, -2730, -2723, -2337, -2164, -2234, -2008, -2022, -2722, -3147, -2747, -2204, -1630, -1008, -727, -603, -149, 291, 184, -265, -800, -1862, -3010, -2513, -1397, -2183, -2844, -1192, 892, 2009, 2828, 3438, 3407, 3091, 2776, 1990, 690, -686, -2036, -2426, -691, 1827, 2119, 1281, 2169, 3563, 3935, 3730, 3086, 2300, 1724, 628, -417, -153, 811, 1082, 974, 1125, 1587, 2387, 2925, 3128, 3914, 4490, 3887, 3793, 5029, 5972, 5984, 5769, 5536, 4938, 3396, 1285, -59, -368, -333, 0, 489, 708, 1174, 1702, 1563, 1385, 1768, 2327, 3037, 3814, 3394, 2656, 3676, 4495, 3650, 3897, 5089, 4481, 3324, 3737, 4476, 4443, 4404, 4451, 4390, 4703, 5102, 5056, 5060, 5436, 5840, 6200, 6518, 7308, 8816, 8930, 7405, 7080, 7853, 7929, 7031, 5886, 4890, 4048, 3991, 4505, 4606, 4413, 4511, 4807, 4763, 4631, 5697, 7096, 6319, 4569, 4408, 5126, 5329, 5135, 5530, 5851, 4965, 4355, 4736, 4294, 2963, 2174, 2311, 3106, 2929, 1336, 832, 1608, 2119, 2778, 3463, 3221, 3277, 4660, 5890, 5537, 4271, 3417, 3044, 2479, 2040, 2241, 2081, 1352, 1707, 3144, 4110, 4804, 5206, 4809, 4109, 3396, 2887, 2972, 3202, 3440, 4237, 4789, 3763, 2301, 1714, 1545, 1600, 2130, 2757, 2597, 2434, 3090, 3616, 3633, 3795, 3786, 3619, 3941, 3476, 1983, 1199, 893, 636, 735, 919, 469, -403, -297, 866, 2139, 3140, 3611, 4112, 5492, 5831, 3902, 3214, 4510, 4942, 4736, 4551, 3918, 3516, 3500, 3297, 3188, 2929, 2360, 2500, 3680, 4192, 2614, 1267, 1240, 919, 863, 1164, 863, 610, 957, 1562, 2586, 3889, 3949, 2748, 2389, 2806, 2639, 2203, 2568, 3799, 4413, 3665, 3235, 4299, 4955, 4094, 3791, 4437, 4958, 5410, 5282, 4132, 3145, 3315, 3766, 2937, 1639, 1446, 1875, 2309, 2590, 2235, 1404, 1339, 2353, 3450, 4094, 4489, 3887, 3003, 3600, 4788, 5852, 6650, 6802, 6758, 6400, 5991, 5781, 4885, 4452, 5260, 5835, 5870, 6318, 7587, 8206, 6811, 5124, 5615, 6962, 7323, 6973, 6334, 5956, 5600, 4932, 4656, 4828, 4570, 4104, 4405, 4032, 2449, 2124, 2714, 2315, 1547, 1353, 1353, 1468, 1565, 1236, 1500, 1909, 1354, 1526, 2765, 3636, 4052, 4492, 5158, 4991, 3781, 3649, 4058, 2844, 2081, 3175, 4051, 4080, 4234, 4562, 4453, 4952, 5586, 3996, 2419, 3109, 3727, 3400, 3438, 3787, 3715, 3900, 4841, 4972, 4270, 4779, 5419, 4523, 3116, 2187, 1856, 1907, 1684, 1666, 3104, 3767, 1498, -6, 1192, 2331, 2516, 2816, 3586, 4117, 4009, 4055, 4936, 5121, 3503, 2563, 2931, 2772, 2257, 2371, 2742, 2751, 2720, 2731, 2924, 3550, 3123, 1689, 1274, 2182, 3560, 4205, 3917, 3563, 3302, 2587, 1843, 1698, 444, -2097, -2895, -2237, -2530, -3405, -3546, -2840, -1969, -1458, -1380, -1462, -655, 721, 944, 971, 1681, 2346, 3003, 3488, 3596, 3552, 3693, 4904, 6057, 4816, 3383, 3595, 3488, 2604, 2230, 2391, 2494, 2560, 2176, 1847, 2593, 2784, 1071, -56, -129, -729, -893, -645, -768, -386, 339, 288, 991, 3228, 3533, 1923, 1464, 1507, 953, 555, 577, 751, 1016, 1171, 1573, 2295, 1870, 666, 443, -184, -2394, -4261, -4913, -5414, -5395, -4329, -3010, -1625, -46, 417, -213, -191, 389, 1108, 1772, 2000, 1346, 143, -473, -541, 244, 1529, 910, -369, 136, 812, 850, 737, 220, -243, -319, -674, -963, 62, 914, -10, -100, 1417, 2593, 3357, 3697, 3649, 3534, 3079, 2068, 921, 745, 953, -221, -1444, -999, -611, -832, -392, 575, 1034, 590, -232, -286, 527, -109, -2010, -2390, -1707, -1236, -462, 181, 56, 352, 1579, 1953, 967, 659, 1388, 2159, 2734, 3176, 3364, 3102, 2503, 2133, 2132, 2831, 4711, 6000, 5295, 4878, 5348, 4688, 3635, 2968, 1839, 922, 792, 1186, 2196, 2438, 776, -885, -1393, -1622, -1547, -1187, -1163, -1423, -1020, 290, 1681, 1484, 73, 77, 1101, 1234, 803, 492, 204, 248, 1066, 1563, 320, -415, 855, 1684, 1002, -167, -727, -207, 279, 289, 1020, 1259, -697, -2328, -2265, -2380, -2960, -3612, -4085, -3467, -1904, -1014, -1010, -147, 1407, 1741, 1614, 2237, 2481, 1840, 1104, 618, 1072, 2823, 3589, 2000, 1188, 2028, 2376, 2509, 2741, 2475, 2167, 1846, 1350, 673, -1087, -2718, -1754, 149, 834, 912, 980, 1417, 2146, 2431, 2635, 3207, 3390, 3594, 4472, 4223, 3106, 3425, 3944, 3316, 2397, 1725, 1510, 1769, 1798, 1685, 2291, 2796, 2074, 1355, 1437, 1012, 402, 764, 1065, 1318, 2131, 2576, 2879, 3508, 3029, 997, -39, 399, 233, -601, -1011, -1027, -1067, -1266, -1401, -842, -549, -2203, -3811, -4148, -5013, -6042, -5992, -5139, -4302, -4009, -3938, -2846, -551, 378, -1247, -2216, -1605, -1285, -1541, -1608, -1310, -1092, -534, -35, -919, -1658, -535, 565, 411, 77, 527, 1652, 2493, 2488, 2010, 2113, 2238, 572, -1112, -1164, -1465, -2216, -1984, -893, -364, -686, -4, 1949, 2248, 917, 1107, 2182, 2518, 2477, 1917, 894, 187, 346, 764, 1442, 2791, 2772, 1249, 862, 998, 418, -141, -823, -2045, -3149, -3288, -2590, -2366, -3529, -4814, -4495, -3146, -1788, -465, 241, -131, -765, -1081, -1569, -2449, -2898, -2307, -2226, -3284, -3818, -3511, -3113, -3077, -2993, -2453, -2675, -4077, -4289, -3263, -4150, -5416, -4003, -2072, -888, 290, 884, 1223, 2283, 2195, 186, -1068, -1157, -1307, -1393, -1492, -2019, -2561, -2888, -3524, -4135, -3515, -2354, -3093, -4669, -4090, -2360, -1459, -1621, -2381, -2856, -2863, -2701, -1930, -980, -847, -259, 1007, 1300, 844, 497, 317, 132, 246, 1022, 1950, 2982, 4001, 3645, 2734, 3295, 3889, 2943, 2275, 2963, 3312, 2716, 2347, 1233, -1147, -2164, -1674, -1682, -2033, -1764, -597, 746, 1100, 719, 593, 813, 1841, 2864, 1314, -1293, -2140, -1975, -1464, -886, -658, -419, -97, -399, -1488, -2069, -915, 578, -675, -3004, -2930, -1946, -2044, -2277, -1576, -720, -229, 177, 320, 223, -122, -127, 496, 199, -526, -296, -77, -275, -216, 326, 466, -23, 446, 1634, 1436, 96, -521, -475, -735, -1209, -1461, -1455, -858, -73, 143, 275, 620, -5, -1463, -1630, -757, -143, 460, 839, 566, 262, 408, 667, -114, -1377, -1339, -858, -877, -1304, -1737, -1106, 153, 647, 840, 1426, 2296, 3480, 3376, 2072, 1654, 1617, 1448, 1570, 1729, 2011, 2086, 1306, 444, 884, 2641, 3199, 400, -2476, -2497, -1735, -1598, -1253, -577, -275, 313, 1466, 1170, -718, -1310, -319, 288, 526, 897, 941, 817, 721, 641, 469, 33, 669, 2651, 3377, 2452, 2358, 3319, 3799, 3391, 2656, 1842, 1457, 1867, 2015, 1945, 1553, 171, -416, -45, -420, -1373, -1769, -1403, -1504, -2519, -3339, -3514, -2693, -1321, -1050, -1771, -2329, -3120, -4045, -4194, -3959, -3706, -3079, -2450, -1789, -1226, -1777, -2318, -1694, -1227, -1743, -2827, -3404, -2820, -2359, -2860, -3114, -2659, -1710, -1506, -2961, -3706, -2752, -1586, -664, 214, 990, 1507, 1449, 1150, 1263, 1394, 1716, 1978, 772, -631, -577, 62, 541, 891, 768, 112, -671, -1364, -1592, -994, -191, -411, -603, 336, 573, -479, -1359, -1552, -1566, -1791, -1860, -1806, -2293, -2506, -2350, -3788, -5410, -4918, -4162, -4281, -4383, -4523, -4779, -5107, -5539, -5593, -5362, -4610, -2961, -2679, -4379, -4659, -3544, -3064, -2660, -2219, -2367, -2226, -1449, -867, -343, 645, 748, -1159, -2598, -1940, -560, 229, -318, -1162, -1226, -1398, -1948, -2143, -1990, -1368, -878, -1862, -2570, -1731, -1433, -1426, -692, -915, -2019, -2215, -1532, -1398, -2280, -2302, -919, 150, 243, -78, -213, -102, -481, -1659, -2390, -2597, -3303, -3465, -3524, -4815, -4580, -2346, -1469, -1997, -1949, -1659, -1821, -2433, -3205, -2966, -1626, -265, -333, -1624, -1922, -997, -13, 580, 650, 55, -1369, -3148, -4092, -3702, -3580, -5115, -6180, -5553, -4554, -3688, -3467, -3718, -3700, -3780, -4552, -4754, -2911, -1607, -2801, -3099, -1669, -1084, -964, -593, -582, -507, -42, -14, -119, 164, 606, 1068, 26, -2452, -3085, -2024, -1713, -1883, -1790, -1794, -1969, -2098, -1709, -378, 609, -751, -2918, -3612, -3752, -3919, -4076, -4313, -4011, -3522, -3030, -1541, 278, 379, -504, -169, 601, 780, 1195, 1568, 1329, 1254, 1133, 443, 427, 582, -1186, -2917, -2710, -2615, -3210, -3533, -3640, -3472, -2913, -2309, -2161, -2191, -1225, 301, -112, -1633, -1590, -1117, -1694, -2479, -2712, -2751, -2699, -2261, -1879, -1937, -1893, -1253, 282, 863, -870, -1775, -713, -63, -32, 219, 211, -419, -1203, -973, -771, -2627, -4519, -4199, -3142, -2949, -3220, -3418, -3437, -3387, -3779, -4541, -4398, -2699, -1730, -3438, -5199, -4535, -3122, -2307, -1721, -1573, -2130, -2677, -3031, -3868, -4233, -3538, -4230, -5648, -5427, -5449, -6847, -7680, -7340, -6463, -4978, -3481, -2412, -1834, -2701, -4604, -5008, -3876, -3221, -2620, -1512, -1097, -1103, -725, -997, -1559, -1043, -1058, -1911, -1263, 87, 537, 636, 1243, 2409, 3365, 3463, 3242, 3335, 2215, -229, -1427, -1457, -1362, -952, -408, 127, -66, -1061, -1190, -481, -509, -456, 703, 1166, 233, 244, 1307, 1731, 1655, 1756, 1482, 327, -399, 379, 305, -1493, -1797, 166, 2004, 2598, 2425, 2021, 1265, 275, -112, -316, -787, -1254, -1145, -285, -255, -769, -442, -270, -55, 756, 995, 542, 472, 1340, 2648, 2905, 2398, 3388, 4952, 3635, 1090, 1018, 1530, 1131, 1164, 930, 119, 63, 140, 94, 553, 1034, 2005, 2601, 1093, -390, -188, -103, -542, -123, 337, -21, 62, 772, 955, 652, 764, 1021, 217, -559, 253, 894, 490, 141, -78, -338, -437, -463, -484, 37, 1128, 679, -1795, -2982, -2575, -2379, -2008, -1781, -1947, -1999, -1470, -530, -1097, -2611, -2606, -1537, -952, -1257, -1534, -1024, -187, 576, 1012, 1663, 2602, 1568, -398, -345, 295, 116, 396, 863, 704, 759, 1172, 1709, 2089, 1735, 1125, 1610, 2147, 903, -380, -380, -319, -296, 225, 394, -335, -922, -669, -819, -1298, -645, -126, -1673, -3171, -2932, -2310, -2014, -2080, -2327, -1799, -408, 614, 965, 1564, 2122, 1149, -164, -67, 258, 185, 244, 356, 425, 389, 682, 1875, 1828, 220, 218, 1239, 1455, 919, -280, -1391, -1799, -2416, -3143, -3019, -2439, -2187, -1273, 52, -647, -1920, -1337, -429, -508, -691, -827, -1446, -1371, -252, -58, -173, 813, 446, -1304, -1339, 73, 1252, 1765, 2150, 2556, 2649, 2598, 2534, 2582, 2507, 2055, 1332, 517, 146, -7, 63, 449, 569, 185, -191, -213, -81, 143, -47, -822, -501, 1512, 2012, 427, -10, 417, 155, -7, 167, -63, -495, -290, 384, 730, 748, 459, 107, 1259, 2633, 1191, -921, -674, 287, 625, 1398, 2334, 2204, 1666, 1557, 1477, 1019, 132, 292, 1545, 1408, 542, 535, 829, 1495, 2094, 1719, 1161, 1305, 1369, 1160, 1612, 1960, 1851, 3468, 5739, 5272, 3321, 2832, 3067, 2888, 2578, 1792, 1317, 2256, 2982, 2588, 2383, 2431, 2400, 3313, 4175, 2581, 953, 1800, 2801, 2570, 2206, 2164, 1671, 771, -112, -900, -754, -96, -924, -2037, -1810, -2464, -4176, -3695, -1376, -136, -80, 621, 1731, 1642, 915, 951, 833, -326, -727, 311, 344, -1040, -1288, -160, 910, 1653, 2254, 2706, 3140, 3311, 2814, 2230, 2812, 3699, 2693, 1333, 1748, 2613, 3080, 3722, 3876, 3293, 3091, 3271, 3028, 1495, -788, -1412, -197, 1087, 1319, 259, 136, 1739, 2175, 1341, 1766, 2890, 2872, 2513, 2788, 2742, 2140, 2222, 3306, 3535, 1871, 673, 926, 1155, 1687, 2948, 3291, 2836, 3295, 3674, 3254, 2878, 2913, 3601, 3795, 2239, 718, 655, 1297, 1600, 1376, 1332, 1535, 1206, 605, 1397, 2198, 940, -319, 125, 1300, 1564, 719, 557, 1050, 1064, 1457, 2197, 2036, 1590, 2338, 3541, 2650, 167, -699, 29, 254, -8, 284, 747, 541, -107, 176, 1241, 905, 96, 652, 1016, 890, 1080, 912, 435, 214, 401, 795, 657, 277, 998, 1756, 977, 279, 550, 791, 1231, 2041, 1678, 674, 604, 39, -1173, -1094, 56, 215, -743, -609, 208, -179, -956, -784, -259, -245, -333, 795, 2036, 1275, 720, 1508, 1473, 1405, 2195, 2259, 1885, 2061, 1875, 1151, 643, 374, 256, 812, 1519, 1078, 484, 760, 811, 385, 81, -456, -1319, -1467, -957, -484, -210, 176, 1002, 653, -926, -1069, 47, 522, 844, 1830, 2684, 2561, 2300, 2549, 3457, 4955, 5043, 3618, 3627, 4846, 4579, 2858, 1665, 874, -220, -561, -674, -1234, -357, 1662, 2002, 1305, 1473, 1368, 901, 865, 857, 585, 541, 783, 677, 1455, 3394, 3293, 1320, 1174, 2000, 1523, 798, 713, 1130, 1821, 1913, 1401, 1393, 1815, 1929, 1723, 987, 232, 422, 686, 800, 1423, 1930, 1756, 1706, 1810, 967, 66, 334, 70, -742, -426, 359, 762, 843, 307, -222, 20, 201, 56, 88, -411, -678, 729, 1518, 620, 996, 2455, 2737, 2565, 2644, 2248, 1154, 557, 1072, 1364, 1133, 1755, 1965, 762, 487, 1116, 1111, 994, 1155, 1392, 1373, 893, 552, 1007, 2115, 3517, 4096, 2781, 1797, 2455, 2638, 1492, 511, 790, 1115, 600, 409, 1076, 1019, -134, -24, 1505, 2385, 2262, 2313, 2859, 3256, 3368, 3305, 3407, 4080, 4660, 4162, 3322, 3453, 4505, 4299, 2028, 564, 864, 1481, 1518, 1182, 1243, 1458, 1331, 568, -337, -309, 287, -123, -726, 319, 1478, 1939, 2514, 2784, 2378, 1481, 745, 678, 897, 976, 1378, 2416, 2734, 1601, 1733, 3061, 3239, 2955, 2776, 2391, 1622, 1048, 1232, 1653, 1719, 1290, 1086, 1299, 1367, 1586, 1526, 1099, 1308, 1513, 1261, 1503, 2068, 2854, 4356, 5043, 3439, 2092, 2602, 3035, 2978, 3035, 2472, 1852, 2010, 2129, 1820, 1003, 608, 1441, 1023, -1102, -1825, -1038, -458, -253, 239, 450, -122, -695, -436, 1017, 1404, -441, -921, 458, 927, 471, 426, 1154, 1559, 815, 406, 1356, 1758, 849, 547, 1024, 1233, 1048, 618, 295, 56, -207, -169, 150, 214, 621, 1549, 1170, -379, -756, -338, -569, -870, -399, 481, 1060, 719, -98, -67, 190, -43, 578, 1750, 1006, -308, 121, 1127, 1510, 1016, 304, -200, -968, -1681, -1719, -1279, -586, -92, 345, 2226, 4070, 3082, 1336, 578, -150, -822, -1139, -1827, -2735, -3063, -2993, -2702, -2125, -1366, -1087, -1633, -1431, -329, -978, -2713, -2713, -2047, -2375, -2779, -2636, -2461, -2518, -2387, -2230, -2899, -3985, -3747, -2577, -3639, -5970, -5678, -3417, -1791, -1469, -1675, -1415, -1635, -2942, -3674, -3274, -2700, -2441, -2097, -1181, -994, -2248, -2288, -910, -420, -226, 588, 1372, 1649, 1478, 1180, 758, 184, 302, 1558, 2312, 1091, -97, 69, 371, 563, 416, 0, -131, -201, -817, -1488, -1477, -855, -216, -1077, -2253, -1145, 597, 515, -321, -104, 612, 935, 1107, 1609, 2750, 3415, 2399, 1415, 1684, 1527, 567, 168, 87, -168, -309, -697, -1220, -1131, -927, -1101, -742, -615, -1654, -2065, -1892, -2313, -2528, -2252, -2209, -2157, -1889, -1583, -566, 499, -509, -2103, -1847, -814, -535, -855, -911, -735, -993, -1885, -2328, -1499, -1340, -3039, -3754, -2584, -1904, -1879, -1498, -1853, -2841, -2638, -1457, -525, -75, -447, -1891, -3118, -2709, -1471, -1966, -3768, -4207, -3558, -3231, -2732, -1592, -753, -881, -1253, -1169, -1215, -1533, -1016, -380, -1432, -2610, -2144, -1149, -825, -865, -774, -577, -1026, -2240, -2662, -2429, -2893, -3121, -2704, -2557, -2469, -2292, -2164, -2848, -4042, -3854, -2473, -1476, -883, -205, 161, -326, -1452, -1720, -443, -222, -2656, -4515, -4117, -3669, -4167, -4476, -3869, -2582, -1391, -412, 934, 1722, 831, -313, -441, -1387, -3994, -5033, -3535, -2382, -2270, -1836, -1305, -748, 294, 725, -354, -1617, -1575, -1354, -1298, -589, -989, -2120, -1659, -428, 593, 1585, 2182, 2128, 1591, 798, 19, -220, 29, -527, -1513, -1620, -2289, -3315, -2870, -2402, -2746, -2769, -2389, -2583, -3685, -4052, -2475, -184, 746, 560, 1614, 2872, 1796, 198, 182, 304, -384, -779, -390, -733, -1322, -810, -1068, -1871, -1267, -365, -575, -1403, -1713, -1484, -1103, -698, -478, -615, -808, -1060, -1428, -1010, -219, 635, 2832, 4230, 3277, 3319, 4090, 3378, 2759, 2977, 3357, 3810, 3674, 2694, 2241, 3666, 4769, 2959, 774, 794, 1789, 2517, 2385, 1702, 2135, 3451, 3626, 2663, 1993, 2087, 2844, 2378, -561, -3210, -3619, -3572, -4443, -5408, -5675, -5837, -5669, -4576, -4106, -4371, -3092, -907, -977, -2158, -1009, 1092, 1225, 393, 398, 770, 1224, 1824, 2344, 2798, 2694, 2282, 3323, 4180, 1555, -1684, -1923, -1292, -1611, -1868, -1745, -1882, -2287, -2375, -2143, -2562, -3723, -4052, -2223, -1429, -3375, -3858, -2225, -1033, -704, -607, -9, 696, 382, -1083, -2266, -2253, -1506, -803, -58, 929, 1777, 1570, 1040, 1890, 2988, 3557, 3846, 2813, 1070, -164, -1376, -1700, -1314, -1994, -1841, 92, 590, -193, 1142, 2446, 605, -1500, -2062, -2608, -3704, -4078, -3575, -4260, -5352, -4919, -4345, -4082, -2764, -687, 912, 2043, 1996, -217, -1561, -523, -474, -2491, -3528, -3026, -2930, -2983, -2132, -1615, -2341, -2946, -2873, -2006, -821, -1520, -3796, -4089, -2250, -398, 1425, 2560, 1940, 463, -440, -119, 1009, 1168, 1, -435, -423, -80, 768, 12, -1038, -656, -668, -810, 200, 505, -848, -1470, -684, -219, -758, -1711, -2398, -2603, -1911, -760, -1342, -3067, -2686, -1191, -1425, -2495, -3197, -3448, -3600, -3838, -3289, -2722, -3334, -3377, -2219, -995, -267, -552, -1935, -3007, -2740, -2223, -2085, -1421, -76, 125, -1175, -1406, 23, 931, 592, 58, -298, 19, 1609, 1519, -922, -1298, 437, 579, -994, -1517, -912, -1395, -2377, -2523, -2854, -4019, -4695, -4366, -4071, -3791, -3352, -3573, -3690, -2609, -2137, -3115, -3365, -2863, -3609, -4416, -3612, -2277, -1966, -2460, -2292, -1441, 70, 1859, 719, -2294, -2349, -708, -639, -1370, -1566, -1058, -487, -635, -736, -70, 225, -474, -638, -702, -2289, -3088, -1454, 397, 1001, 1148, 1427, 766, -730, -1344, -1381, -1495, -1712, -2375, -2401, -1718, -1265, -329, 358, -554, -1675, -2280, -2525, -1463, -118, 374, 399, 104, 184, 705, 1000, 1646, 2861, 3007, 2496, 3199, 2953, 729, -225, 477, 915, 543, -410, -311, 1097, 631, -1377, -1557, -365, 228, -35, -461, 285, 2129, 1755, -1403, -3003, -2276, -2072, -2123, -1454, -943, -531, 252, 1159, 1448, 1183, -1618, -1722, -1757, -1365, -1021, -1053, -1357, -2033, -2725, -2842, -3122, -3498, -2833, -1593, -761, -282, 75, 277, 557, 1180, 1338, 137, -1624, -2943, -3335, -2750, -2281, -1961, -1222, -908, -1217, -1330, -1201, -961, -616, -480, -689, -600, 138, 316, -313, -589, -633, -861, -722, -369, -246, 182, 471, 37, 131, 875, 1039, 1085, 1564, 1400, 992, 1529, 2009, 1662, 1209, 945, 791, 621, 181, -628, -1350, -1513, -1344, -1248, -1500, -1853, -1978, -2657, -3449, -2845, -1653, -956, -205, 631, 696, 153, -46, 161, 56, -396, -641, -805, -991, -1176, -1354, -1496, -1991, -2224, -1375, -120, 781, 1202, 985, 0, -1207, -2138, -2675, -2880, -2507, -1604, -707, 126, 460, 226, 375, 921, 1112, 576, -569, -1657, -2262, -2674, -2899, -2884, -2835, -2844, -3019, -3119, -3035, -3138, -3185, -3060, -3100, -3222, -3094, -2403, -1386, -534, 177, 662, 804, 536, -120, -436, -114, 89, -350, -909, -751, 47, 657, 508, -177, -764, -1057, -1473, -2170, -2603, -2425, -2012, -1580, -1136, -1253, -2076, -3091, -3747, -3494, -2554, -2228, -2436, -1983, -1311, -618, 588, 1407, 1011, 555, 602, 182, -376, -193, 190, 360, 1099, 2509, 3534, 3722, 3742, 3723, 3244, 2706, 2246, 1488, 924, 905, 414, -982, -2288, -2898, -3169, -3264, -2924, -2431, -2484, -2618, -2506, -2725, -3120, -2932, -2438, -2521, -2965, -2896, -2245, -2085, -2545, -2455, -1533, -313, 926, 1859, 2021, 1580, 918, 437, 783, 1469, 1186, 262, -153, -582, -1350, -1312, -627, -218, 181, 598, 793, 1099, 1358, 1297, 1153, 906, 334, -180, -85, 195, 215, 368, 559, 416, 111, -33, -276, -869, -1715, -2388, -2395, -2188, -2217, -1917, -1136, -272, 800, 1596, 1656, 1914, 2473, 2335, 1841, 1658, 1538, 1393, 1098, 643, 315, 146, 128, -9, -513, -1233, -2067, -2740, -3123, -3340, -3280, -2980, -2740, -2551, -2076, -1389, -1017, -812, -126, 484, 436, 560, 1288, 1870, 1723, 1013, -116, -911, -338, 643, 1020, 1254, 1868, 2650, 2685, 2025, 1440, 1017, 409, -528, -1474, -1883, -1807, -1819, -2302, -3033, -3231, -2806, -2414, -2337, -2302, -2191, -1943, -1245, -505, -438, -570, -579, -898, -1231, -1005, -530, -356, -191, 320, 927, 1390, 1661, 1749, 1904, 2207, 2489, 2664, 2741, 2588, 2134, 1315, 205, -838, -1619, -2313, -2843, -2875, -2653, -2121, -911, 244, 228, -684, -1425, -1507, -1244, -1327, -1548, -1117, -809, -1493, -2147, -2247, -2323, -2202, -1730, -719, 686, 1376, 1095, 785, 550, 100, 19, 446, 587, 324, 466, 661, -37, -1178, -2237, -3383, -3989, -3676, -2982, -2383, -1863, -1134, -327, 214, 435, 543, 863, 1179, 1243, 1039, 590, 255, 183, 396, 549, 378, 643, 1284, 1187, 554, -66, -807, -1100, -907, -920, -807, -403, -79, 81, 64, -315, -1152, -1842, -1849, -1401, -751, -534, -770, -823, -1041, -1422, -1367, -1314, -1686, -1717, -1115, -644, -365, 169, 952, 2009, 2888, 2850, 2329, 1952, 1399, 255, -969, -1413, -982, -488, -601, -603, -276, -374, -743, -1191, -1892, -2200, -1587, -722, -573, -1093, -1268, -1052, -1188, -1130, -418, -124, -535, -518, -317, -582, -504, -114, 3, -1, -56, 13, 387, 467, 107, 102, 395, 502, 555, 515, 81, -420, -510, -142, 210, 48, -490, -1071, -1423, -1580, -1563, -1058, 86, 757, 221, -74, 535, 765, 689, 1143, 1348, 894, 559, 345, -442, -1561, -2269, -2475, -2533, -2522, -2443, -2075, -1031, 235, 951, 1033, 664, 171, 55, -111, -746, -1178, -1276, -1451, -1545, -1584, -1629, -1264, -733, -597, -721, -627, -550, -1055, -1565, -1414, -1335, -1730, -1878, -1633, -1411, -1317, -1225, -1090, -865, -288, 444, 893, 1359, 2021, 2590, 3286, 3973, 4345, 4433, 4135, 3804, 3330, 2494, 2223, 2653, 2421, 1390, 660, -239, -1730, -2958, -3646, -3810, -3331, -2690, -2075, -1309, -552, 190, 962, 1421, 1662, 1821, 1512, 753, -377, -1667, -2342, -1979, -737, 621, 1353, 1428, 1360, 1554, 1563, 1059, 785, 1078, 1080, 589, 342, 327, 536, 955, 906, 398, -42, -204, -388, -517, -208, 10, -340, -781, -715, -391, -203, -2, 252, 623, 1356, 1992, 2231, 2588, 2952, 2820, 2533, 2186, 1389, 724, 656, 864, 1144, 1279, 1099, 854, 1076, 1476, 1439, 1089, 776, 796, 948, 834, 627, 500, -66, -757, -672, -140, 354, 783, 1211, 1908, 2797, 3545, 4259, 4531, 3763, 2953, 2949, 2875, 2130, 1314, 870, 640, 241, -320, -739, -523, 541, 1841, 2551, 2388, 2141, 2356, 2457, 2156, 1775, 1677, 1925, 1722, 853, 271, 161, 11, -204, 136, 1121, 2007, 2444, 1917, 751, 5, -835, -1708, -1504, -506, 279, 737, 1323, 1934, 2018, 1561, 1403, 1683, 1473, 672, -315, -1030, -1179, -888, -431, 54, 701, 1131, 1362, 1925, 2479, 2733, 3013, 3312, 3290, 3100, 2926, 2435, 1599, 764, 190, 83, 439, 661, 390, -122, -454, -410, -418, -695, -747, -675, -976, -1234, -758, -198, -475, -859, -845, -964, -1376, -1600, -1226, -459, -1, 104, 393, 525, 247, 11, -87, -177, 171, 754, 895, 1113, 1505, 1689, 2277, 2803, 2084, 1279, 1607, 1950, 1761, 1713, 1561, 1099, 894, 814, 387, 90, 70, -131, -360, -206, 49, -131, -613, -671, -196, 93, 195, 477, 696, 530, 0, -281, -163, -181, -41, 102, -38, 253, 841, 987, 1085, 1144, 395, -420, 87, 992, 303, -1264, -2119, -2362, -2396, -2184, -1555, -780, -754, -952, -399, 202, 636, 1527, 2518, 2889, 2855, 2767, 2149, 1309, 1155, 866, -13, -449, -594, -1270, -2168, -2410, -2100, -1612, -1183, -1251, -1584, -1835, -1861, -1569, -1247, -1264, -1251, -875, -323, 66, 120, -22, 56, 494, 764, 898, 1547, 2445, 2627, 2159, 2091, 2723, 3448, 3864, 4009, 3966, 3448, 2414, 1537, 859, 82, -981, -2345, -3079, -2380, -1454, -1628, -1777, -1126, -931, -1497, -1882, -2089, -2277, -2201, -1840, -1583, -1705, -1474, -827, -465, -461, -637, -853, -1061, -1063, -722, -339, -66, 101, 190, 711, 1527, 1644, 1120, 636, -2, -712, -927, -914, -1188, -1332, -697, 172, 348, -20, -323, -387, -634, -1300, -1946, -2139, -2071, -2314, -2446, -2104, -1870, -1712, -1186, -581, -226, 39, 31, -87, 209, 695, 926, 1187, 1632, 1716, 1242, 784, 586, -11, -684, -664, -484, -486, -392, 296, 1499, 2282, 2837, 3434, 3427, 3095, 2642, 2049, 1876, 1723, 712, -505, -1193, -1378, -1163, -1025, -1179, -1113, -730, -414, -13, 735, 1830, 2685, 3000, 3322, 3638, 3583, 3273, 2934, 2757, 3084, 3587, 3424, 2965, 2746, 2490, 1878, 1006, 373, 120, -111, -309, -278, 31, 63, -612, -1271, -1548, -1587, -1362, -788, 52, 649, 858, 910, 944, 917, 702, 537, 794, 1388, 1544, 1133, 1053, 1392, 1643, 1803, 1413, 807, 1209, 1675, 1160, 1111, 1992, 2131, 1428, 1098, 1668, 2800, 3677, 3955, 3737, 3395, 2998, 1991, 837, 447, 448, 451, 655, 900, 922, 898, 1086, 1193, 1027, 965, 471, -556, -1244, -1454, -1301, -539, 622, 1202, 1108, 1319, 1635, 1294, 652, 587, 1122, 1403, 1164, 846, 533, -2, -736, -1578, -2348, -2314, -1636, -1184, -1074, -1207, -1292, -802, 19, 29, -1093, -2515, -3565, -4019, -4022, -3891, -3486, -2525, -1282, -150, 954, 2047, 2753, 3109, 3196, 3061, 2891, 2813, 3117, 3722, 3953, 3734, 3521, 2984, 2249, 1892, 1518, 836, 484, 629, 469, -328, -992, -1024, -739, -824, -1229, -1647, -2352, -3215, -3768, -4167, -4326, -3759, -3129, -2969, -2836, -2629, -2628, -2461, -1897, -1621, -1121, 27, 933, 1274, 1315, 1229, 1157, 998, 482, -6, 88, 428, 525, 670, 1238, 1588, 1416, 1112, 604, 253, 370, 429, 192, 1, -118, -276, -298, -470, -1047, -1537, -1614, -1842, -2379, -2451, -2327, -2493, -2383, -1916, -1735, -1759, -1563, -1057, -396, 568, 1726, 2371, 2373, 2220, 2303, 2521, 2730, 2876, 2857, 2470, 1809, 1473, 1202, 997, 1334, 1613, 1708, 2062, 2375, 2216, 1771, 852, -589, -1405, -1079, -622, -675, -536, 247, 1104, 1572, 1520, 1172, 620, -81, -438, -326, -204, -333, -228, 10, -199, -271, 175, 407, 362, 380, 92, -582, -858, -565, -239, 99, 937, 2382, 3818, 4931, 5469, 5181, 4849, 4796, 4280, 3367, 2536, 1880, 1428, 1144, 737, 320, 310, 661, 1213, 1670, 1680, 1601, 1750, 1649, 1181, 616, -60, -804, -1585, -2268, -2647, -2803, -2787, -2495, -1905, -957, 179, 1152, 1704, 1577, 1364, 1649, 2053, 2295, 2172, 1527, 1058, 1504, 2145, 2236, 2150, 1985, 1365, 443, -286, -473, -23, 732, 1249, 1654, 2180, 2297, 1695, 955, 559, -369, -1844, -2320, -1950, -1828, -1713, -1219, -511, 9, -40, -443, -588, -443, -324, -148, 678, 1806, 2228, 2317, 2641, 2734, 2378, 2271, 2532, 2382, 1802, 1617, 1871, 1726, 1062, 575, 176, -140, -72, -323, -791, -311, 557, 1022, 1677, 2682, 3279, 3277, 2699, 1212, -605, -1732, -2093, -1940, -1550, -1138, -623, -195, -77, -21, -154, -652, -1189, -1234, -618, -49, 509, 1330, 1742, 1459, 841, 844, 1442, 1464, 988, 817, 1118, 1475, 1333, 798, 422, 336, 62, -827, -1596, -1559, -1272, -1207, -1182, -1079, -1175, -1298, -783, -150, -440, -1256, -1635, -1371, -1128, -1372, -1412, -849, -146, 447, 757, 742, 1204, 2341, 3034, 3110, 3404, 3698, 3539, 3125, 2688, 2174, 1557, 1261, 1232, 937, 481, 244, -66, -458, -347, -24, 184, 462, 416, -60, -381, -249, -249, -650, -769, -380, 216, 614, 698, 285, -210, -200, -262, -398, 19, 580, 753, 992, 1650, 2325, 2334, 1881, 1714, 1571, 949, 298, 247, 350, 63, -215, -359, -801, -1334, -1856, -2319, -2147, -1672, -1334, -962, -862, -964, -593, -277, -618, -990, -1232, -1699, -2099, -2682, -3590, -3674, -2631, -1701, -1280, -548, 432, 835, 746, 937, 1259, 1166, 785, 702, 791, 553, 277, 129, 63, 7, -167, -371, -666, -1083, -1322, -1461, -1878, -2179, -2102, -2290, -2286, -1625, -1564, -2287, -2606, -2371, -2215, -2395, -2764, -2775, -2035, -1185, -796, -656, -534, -43, 901, 1481, 1407, 1345, 1853, 2498, 2445, 1922, 1724, 1859, 1952, 1957, 1966, 1528, 638, 74, -261, -703, -1308, -2003, -2032, -1603, -1872, -2251, -1747, -1201, -1433, -1874, -1830, -1904, -2314, -2155, -1506, -692, 86, 196, -123, 89, 920, 1361, 1053, 779, 842, 567, -228, -829, -831, -397, 441, 1291, 1504, 1521, 1648, 1293, 674, 519, 370, -214, -510, -278, -29, 71, 45, -99, -34, -10, -284, -381, -650, -1312, -1385, -865, -553, -126, 600, 967, 858, 768, 757, 587, 443, 674, 1354, 1866, 1706, 1255, 867, 885, 1175, 1064, 563, 54, -263, -148, 153, 235, 295, 362, -168, -1234, -1996, -2190, -2146, -1851, -1271, -361, 606, 1330, 2230, 3607, 4811, 5039, 4213, 2752, 1521, 761, -178, -950, -600, 281, 892, 1710, 2178, 1343, -97, -1347, -2167, -2444, -2221, -1366, -324, 166, 271, 606, 1245, 1911, 2372, 2344, 2318, 2508, 2019, 890, 218, 346, 649, 737, 757, 855, 644, -359, -1689, -2566, -2864, -3214, -3705, -3739, -3423, -3055, -2439, -1678, -1063, -357, 665, 1424, 1464, 1111, 819, 841, 1199, 1542, 1575, 1555, 1575, 1598, 1758, 1745, 1496, 1421, 1173, 344, -424, -216, 730, 1635, 2351, 2309, 1601, 1432, 1332, 701, 223, -266, -1099, -1615, -1549, -1033, -220, 298, 660, 1445, 2008, 1875, 1917, 2393, 2587, 2313, 1936, 1420, 757, 155, -171, -333, -268, 72, 110, -99, 174, 829, 856, 159, 41, 377, -48, -662, -483, -225, -722, -1426, -1373, -618, -209, -416, -891, -1373, -1844, -2384, -2359, -1332, -66, 782, 1094, 1072, 1040, 771, 549, 579, 544, 909, 1429, 1718, 2509, 3123, 2651, 1811, 1357, 1181, 848, 192, -646, -1325, -1502, -1278, -727, 210, 924, 1042, 1012, 829, 314, -65, -211, -528, -768, -715, -709, -1050, -1515, -1271, -305, 200, 175, 429, 777, 1007, 1447, 1949, 2025, 1670, 1454, 1423, 878, 400, 816, 1196, 1073, 1216, 1589, 2065, 2358, 1920, 1611, 1831, 1247, 98, -321, -528, -879, -672, -215, 36, 493, 1149, 1607, 1787, 1843, 1493, 422, -729, -1413, -1449, -868, 0, 1219, 2271, 2613, 2819, 2842, 2147, 1303, 834, 576, 339, 367, 644, 851, 1314, 1862, 1872, 1736, 1593, 836, -183, -535, -543, -657, -461, -854, -1979, -2294, -2251, -2503, -2530, -2376, -2060, -1463, -981, -714, -592, -660, -1016, -1683, -2247, -2050, -1397, -1505, -2020, -1868, -1268, -915, -874, -813, -633, -325, -138, -204, -551, -1173, -1535, -1247, -842, -948, -1093, -1072, -1477, -1820, -1681, -1831, -2188, -1894, -1235, -1004, -932, -875, -1099, -1139, -958, -788, -652, -565, -635, -1216, -1808, -1602, -907, -332, -147, -393, -685, -359, 731, 1696, 1807, 1632, 1612, 1447, 1329, 1715, 2224, 2467, 2543, 2243, 1593, 1088, 1047, 1209, 1082, 777, 716, 775, 970, 1113, 1025, 1029, 1341, 1794, 1996, 1961, 1811, 1628, 1546, 1473, 1291, 1111, 1026, 1282, 1867, 2377, 2373, 1702, 824, 424, 367, -22, -554, -599, -123, 638, 1567, 2677, 3758, 3816, 2792, 2015, 1864, 1791, 1677, 1622, 1624, 1645, 2188, 3082, 2979, 2110, 1592, 1232, 835, 699, 549, 285, 325, 406, 277, 222, 44, -329, -634, -644, -468, -830, -1327, -1016, -386, -189, -82, 219, 579, 1067, 1270, 952, 825, 1139, 1387, 1397, 1444, 1582, 1587, 1481, 1085, 477, 189, 256, 614, 836, 568, 485, 880, 824, -36, -702, -867, -1430, -2193, -2030, -1389, -1071, -712, -617, -771, -310, 60, -218, -667, -1212, -1594, -1706, -1910, -1813, -1304, -813, -405, -301, -537, -594, -83, 215, -200, -457, -148, -176, -631, -485, 75, 206, -147, -432, -544, -624, -769, -1286, -1678, -1364, -689, -324, -594, -1341, -2101, -2454, -2574, -2587, -2413, -2247, -2139, -1936, -1589, -1064, -620, -941, -1909, -2586, -2517, -2172, -1830, -939, 217, 849, 1259, 1665, 1924, 2065, 1714, 802, -24, -351, -293, 78, 695, 1203, 1300, 1205, 1055, 801, 947, 1004, 358, 34, -127, -794, -1045, -470, 370, 913, 504, -57, 356, 735, 461, 452, 931, 1428, 1845, 1931, 1785, 1991, 2244, 2156, 1795, 1219, 929, 1230, 1766, 2180, 2591, 3043, 3226, 3326, 3648, 3905, 3404, 2549, 2181, 1839, 976, 56, -291, -287, -400, -534, -545, -717, -1271, -1770, -1753, -1797, -2061, -1798, -1293, -1117, -795, -135, 153, 126, 197, -170, -966, -1372, -1306, -1203, -1322, -1693, -1887, -1612, -1487, -1735, -1786, -1681, -1708, -1705, -1658, -1835, -2160, -2215, -2244, -2473, -2446, -2093, -1879, -2002, -2297, -2511, -2426, -2343, -2361, -2026, -1486, -1399, -1877, -2455, -2756, -2670, -2298, -1866, -1338, -955, -1056, -1141, -483, 448, 385, -335, -611, -572, -629, -741, -696, -411, 210, 720, 636, 93, -564, -1056, -1335, -1594, -1769, -1680, -1403, -943, -454, -220, -266, -691, -1454, -2098, -2339, -2072, -1740, -1781, -1607, -1015, -791, -1035, -1431, -1601, -1223, -961, -911, -540, -359, -396, -104, 359, 811, 1107, 878, 327, 54, -22, -264, -564, -685, -583, -228, 292, 558, 433, 318, 176, -336, -741, -627, -777, -950, -638, -718, -1007, -736, 78, 832, 1021, 790, 491, 156, -237, -442, -295, -71, -189, -638, -1004, -1155, -1287, -1419, -1191, -562, -102, -9, -225, -433, 86, 749, 361, -103, 214, 270, -397, -1221, -1572, -1252, -690, -364, -256, -443, -781, -618, -34, 15, -429, -890, -1447, -1989, -2579, -3077, -2998, -2284, -1391, -1111, -1525, -1772, -1457, -1120, -1230, -1490, -1411, -1227, -1372, -1687, -1693, -1150, -714, -829, -960, -1008, -1349, -1564, -1375, -1665, -2341, -2747, -3142, -3451, -3390, -3148, -2841, -2580, -2555, -2518, -2313, -2294, -2294, -1946, -1699, -1836, -1854, -1610, -1484, -1669, -1908, -1621, -1293, -1722, -2090, -1737, -1379, -1406, -1471, -1506, -1623, -2083, -2804, -3139, -3154, -3224, -3048, -2564, -2075, -1669, -1576, -1844, -2128, -2322, -2449, -2535, -2703, -2770, -2227, -1226, -559, -539, -865, -1118, -1308, -1705, -2318, -2602, -2236, -1894, -1914, -1886, -1605, -1242, -998, -958, -1016, -1233, -1451, -987, -241, 136, 504, 690, 459, 279, -279, -1272, -1724, -1751, -1657, -1167, -648, -434, 34, 876, 1358, 1049, 182, -363, -534, -1251, -2177, -2402, -2044, -1446, -1181, -1469, -1431, -819, -442, -352, -359, -754, -932, -606, -617, -867, -873, -527, 443, 1381, 1533, 1358, 1290, 816, -296, -1312, -1869, -2022, -1809, -1080, 16, 724, 872, 1209, 1536, 671, -938, -1963, -2414, -2740, -2661, -2079, -1626, -1596, -1394, -963, -725, -722, -910, -1225, -1506, -1863, -2336, -2279, -1816, -1338, -1006, -1280, -1577, -1428, -1482, -2138, -2674, -2588, -2619, -2944, -2849, -2486, -2512, -2533, -2231, -2116, -2499, -3454, -4512, -4929, -4983, -5134, -5117, -4822, -4422, -4179, -4173, -4033, -3934, -4328, -4638, -4639, -4624, -4116, -3579, -3625, -3486, -3124, -3104, -3081, -2707, -2372, -2270, -2305, -2421, -2500, -2467, -2443, -2524, -2592, -2748, -2957, -2945, -2928, -3022, -2769, -2179, -1985, -2074, -2015, -2108, -2269, -2435, -2975, -3437, -3370, -3451, -3847, -3788, -3229, -2887, -2502, -1809, -1472, -1598, -1844, -2003, -2096, -2325, -2457, -2147, -1662, -1104, -490, -290, -422, -428, -156, 281, 312, -134, -247, -136, -492, -1046, -1230, -1064, -853, -660, -296, -132, -396, -484, -132, -39, -435, -429, -224, -633, -932, -671, -389, -235, -103, -7, -28, -127, -324, -819, -1114, -596, 193, 688, 685, 532, 959, 1339, 1025, 930, 1510, 2164, 2376, 2089, 1771, 1778, 1835, 1592, 1330, 1286, 1434, 1735, 1886, 1977, 2033, 1983, 2104, 2166, 1852, 1476, 1346, 1179, 745, 157, -336, -349, 222, 692, 612, 347, -16, -548, -867, -1315, -2029, -2511, -2738, -2880, -2986, -2804, -2421, -2166, -1720, -988, -512, -369, -488, -813, -930, -733, -529, -454, -216, 533, 1363, 1796, 2047, 1955, 1410, 897, 618, -123, -1285, -1935, -2149, -2158, -1880, -1222, -542, -520, -718, -325, 175, 221, 320, 600, 539, 573, 1162, 1682, 1891, 2222, 2375, 2130, 2089, 2053, 1567, 968, 461, -185, -738, -1185, -1923, -2448, -2657, -3210, -3877, -4250, -4499, -4514, -4391, -4203, -3948, -3932, -3785, -3742, -4500, -5087, -4975, -4920, -4534, -3536, -2870, -2621, -2248, -1695, -911, -168, 228, 461, 215, 62, 691, 1055, 825, 702, 727, 712, 600, 252, -412, -1155, -1559, -1522, -1185, -851, -534, -484, -1108, -2029, -2816, -3412, -3710, -3633, -3635, -3709, -3513, -3272, -3043, -2295, -1229, -560, -315, -592, -1164, -1530, -1487, -867, 184, 1214, 1837, 1971, 2162, 2811, 3439, 3460, 2822, 2476, 2477, 2008, 1772, 2135, 2439, 2456, 2188, 1463, 371, -72, 626, 1005, 272, -120, 496, 1015, 1134, 1631, 2554, 3335, 3608, 3307, 2823, 2413, 1794, 1177, 937, 696, 457, 301, -360, -1249, -1738, -2206, -2699, -2484, -1885, -1410, -566, 265, 437, 551, 1097, 1852, 2436, 2918, 3342, 3704, 4242, 4487, 4388, 4539, 5031, 5613, 5780, 5430, 4750, 3867, 3014, 2217, 1346, 432, -264, -864, -1591, -1892, -1306, -716, -926, -1358, -1150, -932, -1442, -1200, 224, 787, 239, 550, 2013, 2888, 2821, 2695, 2570, 2323, 2191, 1857, 1315, 723, -181, -1178, -1975, -2503, -2731, -2788, -2889, -2798, -2500, -2265, -2181, -2647, -3577, -4388, -4803, -4854, -4672, -4399, -3798, -2538, -1271, -871, -610, 210, 964, 1204, 1344, 1701, 1734, 1152, 589, 623, 907, 670, 411, 1381, 2982, 3571, 3157, 2731, 2407, 1795, 1210, 620, -494, -1600, -2380, -3162, -3895, -4649, -5397, -5344, -4482, -3767, -3282, -2796, -2526, -2499, -2528, -2535, -2339, -2183, -2080, -1344, -661, -1186, -2040, -2028, -1992, -2538, -2750, -2667, -2689, -2597, -2745, -3158, -3100, -2505, -1889, -1256, -653, -280, -3, 277, 434, 462, 702, 1330, 1822, 1568, 934, 466, 40, -520, -1071, -1449, -2051, -2843, -3214, -3671, -4561, -4945, -4386, -3649, -3330, -2886, -2034, -1545, -1348, -954, -897, -971, -471, 55, 282, 846, 1486, 1641, 1482, 1302, 1362, 1654, 2189, 2455, 2113, 1955, 2595, 3349, 3130, 2298, 1569, 931, 448, -17, -742, -1238, -1013, -550, -42, 323, 56, -451, -643, -447, 39, 345, 524, 1530, 2753, 2912, 2489, 2385, 2333, 1910, 1260, 669, 516, 931, 1287, 1156, 941, 925, 766, 290, -358, -1225, -2024, -2258, -2092, }; +int16_t hanning[256] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, 28, 28, 27, 27, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 24, 23, 23, 23, 22, 22, 22, 21, 21, 21, 20, 20, 19, 19, 19, 18, 18, 17, 17, 17, 16, 16, 16, 15, 15, 14, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +int16_t log_amp[160] ={15022, 14435, 12589, 9857, 9560, 9683, 8512, 7275, 7640, 7282, 5392, 5513, 6802, 6592, 4961, 1288, -4195, 1906, 3608, 4537, 5307, 5826, 5776, 4966, 3716, 2832, 1292, -3881, -1812, -694, -124, 1155, 812, -1853, -2006, 275, 792, 237, -1249, -3606, -2837, -879, -319, -1163, -3881, -10316, -6280, -4832, -4362, -4430, -4281, -3217, -2147, -1981, -3217, -3855, -1383, -275, -841, -3922, -7282, -2152, -953, -1160, -2748, -7849, -6348, -4222, -6316, -6581, -2890, -2405, -3901, -6730, -7618, -6372, -4810, -5029, -9132, -6877, -4224, -3878, -3507, -2846, -2821, -2808, -2277, -2183, -3055, -5251, -9905, -6515, -4287, -3665, -3725, -3616, -3418, -3888, -4698, -4637, -5294, -7811, -6255, -5607, -7866, -11726, -10766, -5334, -2761, -1887, -1955, -2344, -2949, -4560, -7339, -5084, -4006, -4962, -7160, -5624, -4191, -4330, -6684, -7971, -3458, -1895, -1883, -3115, -5062, -5718, -4970, -3927, -3205, -3351, -4273, -3966, -2701, -2234, -2636, -3812, -5894, -8129, -7221, -6359, -5904, -5657, -6363, -8413, -8140, -6600, -6901, -10634, -9912, -6228, -5566, -6416, -8138, -8799, -7865, -7102, }; +//int16_t STFT_rearranged[48000] ={15022, 16390, 15545, 7388, 9791, 14435, 15910, 14934, 8889, 9029, 12589, 14368, 13003, 9548, 6344, 9857, 11479, 9461, 8476, -1914, 9560, 7842, 5972, 6077, 3300, 9683, 6443, 5918, 4306, 3938, 8512, 3724, 5741, 5023, 2931, 7275, 3649, 5604, 5232, 3039, 7640, 5448, 5155, 3191, 4248, 7282, 5707, 3886, -1395, 4874, 5392, 5566, 307, 3140, 5102, 5513, 5713, 2597, 3891, 5867, 6802, 5914, 4893, 3388, 6861, 6592, 6289, 5121, 3314, 7333, 4961, 6907, 3998, 3581, 7119, 1288, 7340, 1455, 3347, 6134, -4195, 7221, -649, 2575, 4133, 1906, 6413, 1158, 1360, 639, 3608, 4810, 1664, -862, -2161, 4537, 2477, 1308, -3721, -2389, 5307, 903, -4, -555, -6878, 5826, 1113, -906, 1167, -1543, 5776, 1199, 1884, 1762, 149, 4966, 11, 3047, 1390, -386, 3716, -5616, 2671, -203, 74, 2832, -1861, 1678, -2604, 1596, 1292, 161, 1333, -2384, 1575, -3881, 818, 667, -1833, -390, -1812, 1707, -740, -1805, -3086, -694, 1426, -453, -1980, -790, -124, -648, 361, -3457, 42, 1155, -1014, 791, -13091, -656, 812, 379, 1297, -3332, -2853, -1853, -235, 1618, -420, -3919, -2006, -4401, 1689, 1044, -2273, 275, -565, 1635, 1800, -2376, 792, 2138, 1102, 1969, -2561, 237, 2818, -543, 1624, -310, -1249, 2136, -4400, 904, 920, -3606, 71, -6615, -81, 501, -2837, -1532, -4246, -1490, -2411, -879, -159, -3977, -4394, -7388, -319, -37, -4141, -10580, -1874, -1163, -1711, -3155, -3770, -1572, -3881, -5011, -826, -3183, -2875, -10316, -4701, 956, -4547, -3369, -6280, -4795, 1932, -4555, -2151, -4832, -7088, 2278, -4062, -1050, -4362, -9139, 2188, -5250, -628, -4430, -6307, 1816, -7122, -665, -4281, -3722, 1238, -4499, -856, -3217, -2790, 465, -2960, -1433, -2147, -3077, -434, -3195, -2783, -1981, -2941, -1212, -5049, -5353, -3217, -1690, -1498, -5065, -11050, -3855, -942, -1402, -2999, -6061, -1383, -1013, -1582, -2083, -3332, -275, -1903, -2508, -2036, -2211, -841, -4324, -4298, -2542, -2304, -3922, -6944, -6426, -3393, -3771, -7282, -2375, -9088, -4619, -7090, -2152, -895, -13285, -6205, -9679, -953, -1090, -7111, -6943, -7333, -1160, -2657, -5178, -6399, -4361, -2748, -5439, -4401, -5331, -2684, -7849, -7725, -4121, -4253, -2323, -6348, -6897, -3765, -3744, -2985, -4222, -5344, -3340, -3952, -4292, -6316, -3943, -3635, -5099, -5501, -6581, -3258, -5395, -8104, -6121, -2890, -3694, -8349, -8938, -7267, -2405, -5253, -6570, -6183, -8317, -3901, -6728, -6160, -6023, -6129, -6730, -5623, -7081, -8065, -5117, -7618, -3654, -5993, -12612, -5517, -6372, -2633, -5248, -9541, -6669, -4810, -2844, -6076, -6778, -7488, -5029, -4130, -6289, -5302, -5846, -9132, -5152, -5290, -5980, -4321, -6877, -5027, -5471, -8488, -3290, 10948, 5340, 9881, -583, -1529, 10281, 3184, 9400, 6255, -1363, 7983, 1790, 7839, 8319, -1213, 2985, 5766, 4578, 8716, -1201, 5806, 5972, -7468, 8093, 239, 7278, 3992, 2631, 6914, 2658, 7007, 3013, 4259, 6183, 4335, 5657, 4920, 4879, 6103, 5026, 5172, 5662, 5285, 5893, 4883, 5509, 5524, 5613, 5378, 4402, 4184, 4538, 5872, 4553, 4309, 3084, 2519, 6053, 4412, 4533, 5541, 2182, 5884, 5410, 4304, 6269, 3345, 4957, 5653, 3045, 5565, 3276, 3046, 4418, 1028, 4272, 2407, 595, 1213, 734, 3636, 1612, -1021, -9, 1479, 3416, 1031, -324, 1364, 1998, 3255, 94, 588, 973, 1467, 3470, -317, 408, -256, -1566, 3966, 176, -148, -1555, -5910, 4403, -381, 149, -3399, -1218, 4406, -3162, 1043, -3706, -2034, 3699, -6969, 1255, 13, -2967, 2095, -928, 675, 2541, -309, -742, 1059, -55, 3772, 276, -5152, 1483, -1167, 3918, -918, -2310, 600, -2456, 3234, -4253, -629, -1699, -803, 2143, -8360, -748, -4480, 187, 920, -4510, -2796, -5722, -657, -732, -2852, -6555, -8562, -5101, -1617, -1578, -3238, -2751, -2692, -76, -473, -1770, -1006, 672, 1164, 146, -1307, -1054, 1972, 1728, -76, -1108, -747, 2401, 1777, -1105, -617, 737, 2292, 1237, -496, 491, 1494, 1811, -216, 1202, 1623, 1157, 1162, -1153, 1656, 2217, -332, 552, 898, 776, 2074, -3098, -150, 2083, -258, 1096, -4664, -1276, 2076, 269, -817, -3732, -2660, 1252, 403, -3595, -2332, -3627, 139, -804, -5568, -652, -4610, -491, -4906, -5112, 12, -5653, -40, -5243, -4091, -766, -6220, 444, -1562, -3606, -3645, -7870, -40, -1055, -4503, -10695, -8347, -1875, -1973, -6634, -7025, -5321, -3534, -3721, -6422, -10405, -3470, -2072, -5833, -8296, -6307, -2409, -1348, -8634, -8763, -3250, -1734, -1712, -13134, -3935, -2113, -1132, -2943, -10088, -2782, -1927, -552, -3587, -7851, -3207, -2420, -210, -2134, -5907, -4824, -3031, -288, -1175, -4432, -6584, -2800, -678, -1292, -3739, -5705, -2132, -1039, -2508, -3901, -3854, -1624, -1437, -5728, -4955, -2528, -1266, -2274, -7524, -5831, -2232, -1272, -3370, -2624, -5012, -3195, -2200, -3783, -947, -4277, -4836, -4802, -3420, -488, -3943, -4317, -5543, -2886, -691, -4040, -4122, -3597, -2892, -1142, -4925, -6452, -3758, -4002, -1519, -5252, -10060, -5054, -4808, -1904, -3326, -4930, -4535, -2874, -2275, -1642, -3491, -3392, -1585, -2128, -765, -3125, -2599, -1366, -1867, -687, -3101, -1848, -2227, -2471, -1521, -3092, -1584, -4873, -5110, -4002, -3221, -2450, -8948, -5746, -11796, -3989, -5450, -4673, -2300, -3014, -6275, -6993, -3629, -1265, -1233, -13060, -3994, -3325, -1129, -1401, -6473, -2795, -2634, -856, -3122, -4984, -1852, -2143, -668, -4531, -4954, -1543, -2277, -1158, -4444, 8135, 6088, 8626, -4024, 9938, 7329, 6317, 8147, 3034, 9253, 4904, 6099, 7090, 5534, 7062, 4788, 5168, 5821, 5756, 2868, 6323, 4576, 3219, 3312, 1833, 6494, 3735, 3133, -3194, 4473, 5760, 1781, 5247, 3503, 5033, 4322, 154, 5491, 4139, 2895, 2112, -1883, 5106, 3344, 1160, 567, -8604, 5398, 2834, 5248, 2441, -1097, 6168, 3530, 5936, 4900, 904, 6690, 4608, 5104, 6129, 2446, 6590, 5040, 5192, 6005, 3385, 5551, 4266, 6075, 4500, 3096, 3111, 1873, 6379, 1400, 1015, -337, -2432, 6535, -3148, -6312, 1153, -3379, 6387, -4178, -2431, 1960, -3097, 5323, -2846, -282, 1735, -1790, 2714, -1477, 1123, 1114, 483, -5178, -288, 2408, 349, 2279, -962, 828, 2867, -310, 3205, 602, 1651, 2089, 248, 3324, 1195, 1919, -836, 1723, 2724, 2721, 1435, -8160, 2498, 1506, 3795, -83, -1480, 2126, 141, 3702, -2304, -1676, 632, -186, 2139, -1688, -2840, -452, 758, 749, -1085, -1050, 84, 1955, 2587, -1448, -667, 47, 2776, 3314, -1334, -1973, -584, 3074, 2871, -1128, -4037, -927, 2914, 2029, -1831, -4223, -893, 2430, 1750, -3735, -1903, -725, 1721, 2124, -4438, 91, -814, 695, 2326, -1846, 1159, -718, -1112, 1779, -605, 1229, 953, -4285, 161, -1077, 226, 2278, -2549, -3196, -1597, -1233, 2448, -61, -10037, 1326, -207, 1631, 1238, -5459, 2800, 1173, 597, 1719, -2662, 2475, 1064, 234, 1395, -1008, 22, -931, 85, 225, -520, -10125, -1692, -101, -2013, -1056, -3239, -169, -365, -5623, -1918, -2721, -886, -713, -4148, -1070, -4144, -4883, -992, -3366, -504, -5371, -7334, -1451, -4299, -1722, -5860, -5572, -2058, -2407, -3307, -5420, -9669, -1902, -626, -800, -3278, -4000, -1470, -465, 514, -2492, -1965, -1758, -2323, 435, -3628, -1768, -2921, -5922, -956, -9229, -2309, -4942, -927, -4084, -4407, -2502, -9038, 836, -8231, -2095, -2284, -5389, 1066, -5365, -1906, -1985, -2756, 264, -3891, -3017, -2226, -2262, -1447, -4557, -4960, -3502, -3466, -3976, -11280, -5981, -3511, -5119, -4299, -3848, -5230, -2657, -3228, -2919, -1482, -4701, -3847, -1903, -2750, -1004, -4962, -9136, -1535, -4156, -1487, -5918, -5496, -1578, -9790, -2332, -7666, -4300, -1746, -6635, -2932, -11718, -5430, -1928, -3956, -3045, -13570, -7603, -2016, -3785, -2822, -9656, -7021, -2159, -4384, -2470, -5004, -4553, -2859, -3625, -2045, -2525, -3046, -5049, -2807, -1748, -1425, -2589, -10651, -3267, -2273, -1223, -2394, -5327, -4768, -4832, -1712, -1883, -4089, -3759, -6611, -2592, -1631, -4451, -2098, -3778, -2317, -1688, -4707, -1511, -4370, -1104, -1674, -5347, -1880, -7616, -511, -1990, -8962, -3392, -5659, -637, -3117, -7329, -6851, -5500, -1134, -4374, -4297, -12628, -9453, -1507, -3914, -3602, -7923, -7498, -4224, -5554, -4353, -4133, -2129, -3878, -7270, -2473, -2452, -1737, -3507, -7586, -2008, -2512, -2831, -2846, -5254, -3025, -3418, -5986, -2821, -3714, -5611, -3744, -7985, -2808, -3010, -13840, -2935, -6763, -2277, -2991, -6283, -2459, -7017, -2183, -3789, -3468, -3366, -5831, -3055, -6182, -2980, -5755, -4109, -5251, -13347, -4226, -3284, -3689, -9905, -6728, -7062, -1040, -4341, -6515, -5290, -10547, -88, -4173, -4287, -5037, -9538, 15, -3219, -3665, -4580, -5533, -670, -3366, -3725, -4293, -3755, -2433, -5426, -3616, -4979, -3342, -5897, -10483, -3418, -6809, -4226, -5644, -6907, -3888, -7436, -6950, -4348, -6768, -4698, -5425, -7290, -5661, -11547, -4637, -4024, -4705, -7820, -7789, -5294, -3717, -3606, -4001, -4241, -7811, -4602, -2791, -2423, -2364, -6255, -6510, -1775, -2276, -1164, -5607, -6340, -1017, -3077, -580, -7866, -4238, -901, -4310, -652, -11726, -3115, -1541, -5083, -1309, -10766, -3063, -2977, -5072, -2160, -5334, -3219, -5153, -4673, -2549, -2761, -2681, -5813, -4537, -2539, -1887, -2418, -4519, -5214, -2776, -1955, -2947, -4445, -6446, -3623, -2344, -4213, -5961, -6591, -5118, -2949, -6336, -7215, -6457, -7136, -4560, -9194, -6317, -7439, -9810, -7339, -9647, -7399, -9089, -8084, -5084, -8196, -10603, -8142, -4773, -4006, -6529, -5264, -6082, -3144, -4962, -5245, -3482, -4467, -2991, -7160, -4667, -3534, -3485, -4536, -5624, -4729, -5032, -3222, -8808, -4191, -5173, -6219, -3555, -16024, -4330, -5943, -5030, -4186, -8660, -6684, -6669, -4314, -4229, -3671, -7971, -6376, -4176, -3187, -1670, -3458, -5898, -4030, -2731, -1236, -1895, -5622, -3478, -3836, -1952, -1883, -5111, -2565, -7553, -3555, -3115, -4399, -1740, -7056, -5274, -5062, -4108, -1482, -5186, -5586, -5718, -5093, -2065, -5623, -4664, -4970, -9301, -3493, -7925, -3350, -3927, -8207, -4928, -13647, -2286, -3205, -5647, -5288, -11389, -1695, -3351, -5048, -5436, -10277, -1476, -4273, -3759, -5299, -11084, -1462, -3966, -2469, -4478, -12156, -1510, -2701, -2149, -3377, -9283, -1412, -2234, -3086, -2832, -6406, -1068, -2636, -6186, -3387, -5200, -747, -3812, -10087, -5553, -4196, -911, -5894, -5260, -12137, -2698, -2137, -8129, -4371, -9214, -1973, -5654, -7221, -4905, -7118, -2635, -11761, -6359, -5793, -7149, -5285, -7383, -5904, -6008, -8398, -8178, -8107, -5657, -6536, -9448, -5544, -5874, -6363, -8914, -8639, -5672, -4566, -8413, -10223, -8665, -9040, -4611, -8140, -6790, -7995, -9845, -5443, -6600, -5701, -5196, -5562, -6064, -6901, -5391, -3432, -4047, -5589, -10634, -4751, -2899, -3579, -5435, -9912, -4255, -3442, -3902, -5816, -6228, -4453, -4620, -5031, -6518, -5566, -5374, -5341, -6901, -8805, -6416, -7360, -5643, -8714, -17696, -8138, -11290, -6006, -9255, -12064, -8799, -7964, -6673, -10575, -9542, -7865, -5755, -8615, -10922, -5114, -7102, -4998, -11781, -6158, -3484, -4628, -2421, -3126, -2497, -6789, -5250, -4794, -4449, -4410, -7477, -9881, -6436, -5064, -3607, -3449, -4608, -4046, -5613, -2139, -2217, -2871, -2510, -6822, -1828, -2235, -3843, -2185, -5537, -2152, -3064, -6329, -3289, -4432, -2550, -4718, -4122, -6236, -4556, -2730, -8599, -3320, -6537, -4686, -2432, -7789, -4202, -4618, -4608, -2175, -3777, -6026, -3566, -6205, -2668, -2263, -7801, -2576, -13093, -4308, -2029, -9251, -1785, -4928, -7375, -3049, -8052, -1709, -2944, -9674, -6259, -5386, -2760, -2434, -9137, -6066, -4239, -5655, -2581, -6472, -3521, -4001, -10908, -3366, -5255, -3280, -3305, -4920, -6014, -6907, -4092, -2406, -3021, -9081, -10022, -4709, -2289, -2635, -3189, -5011, -4448, -3296, -3604, -1475, -4570, -4321, -5646, -6025, -1196, -5631, -5608, -5570, -5345, -1726, -3948, -8925, -3247, -3919, -2528, -2846, -4629, -2085, -3725, -3203, -2884, -1340, -1892, -3501, -3959, -2956, 213, -2570, -3436, -5344, -3247, 385, -3672, -4179, -7922, -4596, -782, -4517, -4623, -10663, -5247, -3613, -5710, -4269, -7357, -3805, -8204, -7537, -4200, -4774, -3261, -3386, -9210, -3521, -3260, -4029, -1266, -10245, -2801, -2777, -6779, -618, -8283, -3242, -3408, -5810, -806, -5770, -5696, -4816, -2843, -1404, -3474, -12002, -4835, -2324, -2230, -1947, -5336, -3635, -4445, -3446, -1253, -3757, -2754, -9328, -5841, -1357, -3536, -2539, -2725, -13317, -2351, -3881, -3123, -1220, -7147, -4485, -4898, -4220, -1221, -5824, -7862, -8392, -5317, -2285, -6768, -11502, -7970, -6846, -4558, -7862, -6879, -3544, -8386, -8920, -5639, -3193, -1802, -5582, -16426, -4403, -1478, -1162, -3322, -11213, -4289, -1030, -1320, -2236, -7203, -4753, -1637, -2259, -2066, -5910, -5082, -3287, -4154, -2592, -7050, -4526, -5607, -7379, -3425, -5504, -4246, -5552, -9774, -4065, -2373, -5163, -4380, -8617, -4242, -1009, -7160, -3989, -7901, -3963, -876, -8081, -4222, -6692, -3726, -1778, -6391, -4630, -5593, -4172, -3764, -4734, -4670, -5500, -5797, -7407, -4288, -4354, -7442, -8769, -8786, -5317, -4301, -11498, -6984, -5990, -8221, -4744, -5009, -4564, -5757, -9903, -4512, -3263, -3106, -7633, -8076, -3552, -3447, -2234, -11771, -6541, -3325, -5117, -1930, -12667, -4415, -4296, -5804, -2117, -11981, -2877, -7575, -5708, -2684, -12463, -2311, -10012, -7172, -3786, -17520, -2856, -5074, -5329, -5509, -11698, -4665, -4276, -3556, -6559, -7320, -4445, -5423, -3139, -6032, -4982, -2432, -6815, -3515, -5233, -3675, -1834, -5983, -4451, -4885, -3100, -2452, -6053, -5609, -4813, -3412, -3794, -7398, -6187, -4484, -5126, -5070, -8555, -5637, -4332, -8942, -6059, -7890, -4903, -4780, -8156, -5664, -6966, -5044, -5826, -7445, -4759, -6094, -6121, -7366, -8944, -5258, -4845, -7107, -8586, -12286, -7313, -4354, -6859, -8099, -16158, -6273, -5653, -6242, -7236, -8803, -5182, -11020, -6046, -6956, -5479, -6656, -1536, -2950, -4414, -6079, -3604, -1428, -2411, -7541, -5139, -1848, -1324, -2361, -9913, -4836, -1486, -1298, -2802, -4591, -3959, -2406, -1573, -3744, -2758, -1712, -4194, -2495, -5418, -2422, -42, -5054, -4591, -9189, -3442, 459, -3980, -9195, -8925, -4492, -230, -2899, -11097, -5822, -3678, -2121, -2792, -12465, -5374, -3936, -5487, -3382, -10965, -6491, -4860, -13201, -3897, -6980, -8176, -4223, -4575, -4537, -5943, -7331, -4482, -2722, -5484, -5427, -5826, -5564, -2821, -5674, -5105, -4386, -3766, -4394, -4608, -5164, -2664, -1603, -5443, -3593, -4710, -1555, -639, -4933, -2796, -3042, -1221, -1098, -6719, -1430, -1246, -1225, -3395, -11421, -447, -162, -1211, -8133, -7246, -627, 167, -1171, -4891, -10083, -2175, -139, -1219, -3020, -7058, -4571, -1084, -1635, -2768, -4466, -3412, -2470, -2518, -4109, -4079, -1188, -3285, -3544, -6015, -4011, 137, -3802, -3376, -4381, -3608, 518, -4965, -1353, -3572, -3037, -126, -7139, 168, -4533, -3447, -1934, -13471, 690, -7204, -6408, -3553, -5680, 417, -9220, -8269, -2607, -3936, -222, -8050, -5319, -2079, -4119, -761, -4771, -4550, -1746, -4482, -1413, -3437, -3790, -1023, -3611, -2864, -3832, -3177, -620, -2645, -4979, -5815, -2643, -652, -2136, -4731, -10493, -2648, -695, -2344, -4163, -10081, -3430, -880, -3418, -4701, -6001, -2792, -1648, -5340, -4910, -4263, -1434, -2959, -6768, -3486, -3360, -1291, -4215, -5259, -2557, -2870, -2715, -5327, -4127, -2717, -2591, -6908, -7188, -3928, -3565, -2566, -9345, -9250, -4424, -3837, -3153, -6026, -6089, -5596, -3329, -4823, -4115, -4029, -5332, -3093, -7403, -2244, -3228, -3730, -3423, -6394, -1321, -3169, -3120, -4030, -4822, -1391, -3856, -3352, -4019, -4452, -2389, -6223, -4162, -3507, -5531, -3885, -11595, -5537, -3763, -9584, -4454, -7117, -6049, -5539, -11492, -4732, -8537, -4404, -6531, -8904, -4400, -6582, -2673, -5208, -8826, -2727, -2659, -1747, -5819, -5655, -2061, -1277, -1705, -9453, -4239, -3059, -1187, -2241, -10353, -4868, -6682, -1802, -3158, -5447, -8286, -8509, -2649, -4713, -3619, -12757, -5460, -3539, -4764, -3014, -12636, -4901, -4068, -3348, -2840, -8742, -5394, -4270, -3392, -2768, -4667, -6856, -5074, -5305, -2984, -3324, -7579, -6296, -6783, -3459, -3532, -4949, -5979, -5328, -4029, -5532, -2721, -5319, -5970, -4667, -14849, -1369, -6133, -10401, -5585, -6837, -790, -12638, -8761, -7334, -5777, -937, -6287, -6741, -9955, -8368, -1808, -3420, -7326, -12278, -8497, -3363, -2912, -8770, -16695, -5559, -4951, -4095, -8610, -13416, -4846, -5025, -7435, -7926, -11937, -3580, -4428, -9001, -6381, -11803, -2464, -4303, -6744, -4580, -13182, -2617, -4979, -6343, -3508, -14602, -4359, -6610, -6657, -3260, -15423, -8127, -8838, -6860, -3720, -14890, -7968, -8299, -6477, -4389, -9173, -6467, -6679, -6249, -4327, -7138, -6132, -6455, -6392, 992, 7886, 7836, 5707, 2952, 5763, 7674, 7512, 5744, 3131, 7257, 7047, 6697, 5594, 2840, 6944, 6137, 5861, 5029, 1656, 6387, 5254, 5171, 4191, 1669, 6716, 4499, 4157, 3252, 2364, 6445, 3756, 2809, 2540, 1949, 4670, 3162, 2233, 3092, 910, 3710, 3344, 2679, 4147, 410, 5517, 4146, 3327, 4671, 452, 6178, 4380, 3727, 4620, 2149, 6053, 3711, 3627, 3805, 4693, 5401, 2486, 3007, 1193, 6237, 3584, 1501, 2138, -2809, 6624, -1377, 1312, 1430, 1631, 5874, -740, 1336, 1335, 2278, 3788, 1232, 544, 1760, 1376, -797, 984, -1787, 1610, 858, -4456, -16, -4421, 402, 1445, -841, -510, -1344, -1367, 1905, -616, -34, -459, -2302, 2253, -1120, 504, -1942, -2912, 2376, -1730, 720, -3838, -5891, 1875, -2627, 388, -695, -5800, 806, -4711, -673, 741, -1852, 50, -11015, -2310, 1308, -789, -233, -8245, -3429, 1893, -426, -743, -6045, -3855, 2501, -212, -1327, -3983, -5484, 2535, -521, -2006, -2393, -6745, 1562, -1584, -3385, -1364, -4140, -858, -3071, -6674, -598, -3454, -2410, -4007, -10510, -171, -4255, -203, -4907, -4974, -243, -6219, 582, -5832, -3180, -1018, -8783, -28, -4707, -1608, -2965, -5414, -2510, -3392, -581, -7330, -3019, -3582, -2700, -677, -6955, -1847, 35, -2277, -1773, -3219, -1611, 1252, -2376, -2733, -1083, -2530, 694, -4002, -2387, -716, -5145, -2053, -9433, -1461, -2429, -5676, -2719, -10283, -1021, -1831, -3878, -761, -5449, -1362, 475, -3664, -1287, -2617, -1862, 915, -3556, -2383, -2085, -1446, 149, -2817, -670, -4159, -375, -472, -2112, 394, -5643, 323, -35, -1757, 248, -2140, 192, 320, -1983, -1029, -1086, -983, -22, -2932, -3865, -1238, -3894, -1474, -4558, -9183, -1959, -7920, -3368, -5977, -7833, -2767, -2841, -1495, -4291, -6174, -3929, -1107, -176, -2147, -2464, -4110, -851, -181, -1039, -299, -2417, -2003, -1071, -1016, 578, -2123, -5311, -1919, -1861, 617, -3951, -4696, -2089, -1896, 235, -9294, -2333, -2652, -733, -288, -6439, -1996, -4479, -339, -1155, -4501, -2973, -7503, -1126, -2682, -2749, -3114, -5895, -3277, -4758, -822, -1788, -4046, -8511, -7487, 437, -1922, -3277, -7813, -5958, 551, -5066, -3319, -4848, -2147, -756, -6046, -3552, -4780, 106, -3455, -2730, -2710, -5057, 1332, -4293, -3013, -1523, -5034, 1646, -4528, -6230, -887, -6935, 891, -6414, -9181, -812, -4640, -1659, -7119, -6210, -1117, -2365, -14029, -5370, -6259, -1621, -1609, -3314, -5115, -7142, -1958, -1108, -2256, -7398, -7089, -1758, -994, -2106, -4836, -5489, -1371, -1982, -2098, -2545, -3927, -1402, -4561, -3066, -2233, -3486, -2416, -7078, -4875, -3155, -4911, -5524, -4643, -4758, -5020, -7861, -12217, -3992, -3582, -9911, -4628, -6038, -4259, -2813, -6597, -3333, -5671, 4431, 6956, 4647, 3404, 3214, 3330, 6394, 4445, 4636, 4919, -2018, 4626, 3869, 5670, 6749, 174, 1203, 3186, 5540, 7498, 1979, -3313, 3158, 4216, 7309, 89, 504, 3878, 1072, 6525, -7332, 2160, 4371, 83, 5384, -1885, 2720, 4121, 2851, 3793, -2387, 2886, 3245, 3140, 2596, -131, 3575, 2615, 2064, 2369, 2750, 4385, 2649, 2541, 1643, 4474, 4335, 2717, 3876, 2216, 5069, 3125, 2641, 4261, 3761, 4424, 1483, 2251, 3750, 4483, 2485, 1454, 1283, 2464, 4432, 1067, 1443, 85, 569, 3826, 2180, 401, 47, -1340, 3066, 2822, -1339, 182, -2231, 2563, 2587, -1558, -920, -2301, 1920, 1218, 336, -3313, -1700, 683, -1842, 1950, -4908, -599, -386, -1289, 2887, -5087, -836, 463, 149, 3227, -887, -4338, 1261, -594, 3167, 1502, -1816, 1038, -2955, 2939, 2548, 680, 327, -2472, 2629, 2745, 1043, 51, -1627, 2053, 2212, 948, -302, -2321, 933, 785, 1074, -1594, -3706, -838, -1956, 601, -3409, -3084, -3032, -6554, -656, -3464, -1611, -4914, -7763, -1656, -4244, -1174, -4880, -6737, -1234, -2011, -1233, -4355, -3618, -340, 526, 47, -5364, -1510, -318, 1544, 1463, -7198, -750, -1860, 1727, 1828, -5679, -1416, -7268, 1307, 931, -6528, -3862, -4626, 11, -1518, -4014, -6626, -1510, -2411, -4306, -437, -6696, -397, -3961, -3760, 1004, -6606, -513, -3297, -2746, 1013, -5990, -1930, -2778, -663, -172, -11236, -2111, -3063, 473, -2169, -4851, -144, -4907, 464, -3009, -1982, 781, -8275, -439, -1982, -1424, 776, -9936, -1390, -912, -1763, 71, -6078, -531, -87, -1362, -1265, -4817, 709, 402, -298, -2933, -7191, 1147, 411, 464, -3762, -5416, 641, -36, 858, -3242, -3244, -878, -725, 974, -2772, -4068, -3062, -1369, 786, -3532, -4200, -3880, -2030, 165, -5898, -1956, -3455, -3426, -1106, -5290, -1439, -3346, -6797, -3430, -3721, -2194, -3895, -5475, -7296, -2447, -2540, -5088, -2472, -7216, -1279, -1260, -6922, -1288, -5455, -683, -66, -6827, -1382, -4648, -376, 376, -4007, -2543, -4856, -190, 93, -2386, -3378, -5880, -477, -515, -2070, -2682, -4918, -1273, -1178, -3491, -2129, -3087, -1615, -2334, -12014, -1948, -2105, -1411, -4243, -2991, -1997, -1792, -1734, -8766, -470, -2496, -1876, -2784, -5016, 104, -3838, -1877, -4591, -1105, -731, -6301, -1746, -9082, 199, -3223, -8534, -2817, -6844, -58, -8548, -7309, -10561, -3983, -1936, -10120, -5995, -3376, -3673, -4603, -20985, -4612, -1454, -2665, -1776, -7189, -3343, -2512, -930, -299, -4932, -3211, -7404, -583, -305, -4692, -4774, -3010, -1973, -1335, -5472, -5595, -369, -4883, -2031, -6404, -3584, 783, -3635, -1048, -6310, -2819, 852, -2206, -154, -5323, -1834, -93, -1718, 30, -4480, -626, -1947, -1728, -541, 4174, 4649, 8112, 4717, 10466, 5280, 6423, 7948, 6862, 10222, 6501, 8002, 7664, 8295, 9563, 6769, 8408, 7456, 8429, 8561, 6127, 7730, 6905, 7644, 7034, 5048, 5903, 5514, 5941, 4594, 4185, 2543, 3305, 2660, 982, 3149, -888, 1426, -2564, -1865, 1011, 1471, 735, 1166, -1159, -5527, 2616, -306, 1632, 314, -106, 3024, -43, -844, 734, 2930, 3341, 2467, -2478, 2614, 3788, 3719, 3345, 2597, 4789, 2812, 3667, 2827, 4269, 5884, -511, 3317, 2219, 4869, 6290, 1704, 3473, 2860, 4963, 6365, 3274, 3591, 3308, 4690, 6044, 2644, 2936, 2953, 4056, 5092, -557, 1584, 1968, 2995, 3317, -4360, 179, 891, 1167, 815, 452, -215, 513, -2135, 86, 1319, 299, 907, -1288, 765, 870, 155, 1373, 1199, 403, 686, -2036, 1276, 2295, -1164, 1208, -6659, 115, 2607, -2310, 701, -1110, -2708, 2307, -1258, -1150, -328, -2530, 1467, -1410, -736, -1907, -296, 883, -2029, -52, -5263, 495, 1564, 553, -1306, -5543, 797, 2156, 1991, -3684, -3848, 1128, 1951, 1912, -3782, -1034, 1249, 1359, 895, -5389, 388, 952, 1349, 218, -6377, 657, 576, 1456, 759, -2880, 335, 729, 494, 1309, -1657, 478, 1458, -2099, 866, -473, 1422, 2292, -1460, -620, -50, 1993, 2768, -94, -1113, -2239, 1399, 2583, -751, -410, -4992, -1336, 1481, -2172, -510, -476, -3462, -839, -1211, -841, -618, -17, -2638, -555, 273, -3499, 496, -876, -1009, 1572, -1315, -297, 196, -2170, 2027, -228, -1264, 454, -3745, 1439, -1464, -2322, 81, -4717, -381, -5409, -4077, -907, -4231, -3575, -11310, -5445, -2337, -2910, -8052, -6921, -5310, -4192, -1845, -13976, -4606, -4917, -4348, -2024, -8954, -3415, -5146, -1546, -3490, -8070, -3267, -5532, -149, -4645, -5821, -3369, -4589, 86, -4673, -3846, -4033, -4557, -413, -2522, -2014, -7275, -7793, -1331, -262, -1161, -6355, -4242, -2505, 707, -1661, -2821, -1515, -4093, 563, -3620, -1675, -1146, -6469, -473, -6858, -1510, -2831, -7219, -1769, -5947, -1635, -7801, -5863, -2385, -4331, -2407, -5390, -5883, -3613, -4909, -5852, -2773, -7221, -9159, -8695, -6468, -1251, -7432, -3003, -8598, -3055, -955, -3342, -265, -7250, -2386, -2007, -710, 612, -7422, -1428, -3766, 347, 364, -4521, -496, -3947, -144, -697, -1507, -547, -3434, -2881, -2096, 292, -1598, -3256, -5414, -2594, 965, -3239, -3247, -2169, -2317, 652, -4359, -2603, -1742, -3337, -557, -4459, -1171, -2509, -10715, -2786, -4692, -227, -3927, -3425, -7108, -6957, -226, -4770, -818, -4731, -6172, -1041, -2897, -248, -2449, -1775, -2384, -1771, -697, -2684, -90, -5076, -1110, -1802, -6855, 99, -9796, -337, -4902, -5453, -1061, -2976, -36, -5415, -2246, -3853, -1317, -549, -918, -1705, -3747, -2112, -4001, -3034, -4635, -4213, -1260, -3727, -2473, -2438, -6982, -367, -3185, -1593, -982, -4534, 264, -2079, -1182, -222, -2747, 483, -2456, -1750, 35, -2512, 388, -5304, -3164, -88, -2206, 140, -4527, -3982, -532, -1428, -144, -2873, -3008, -1346, -1345, -365, -3984, -1784, -2639, -2397, -697, -6265, -1517, -3277, -2307, -1651, -4134, -2354, -1553, -288, -3640, -3791, -3550, 65, 652, -3861, -4141, -3568, 950, 228, -2067, -2900, -2781, 1302, -1954, -1289, -2053, -2108, 1342, -6273, -1345, -1988, -2096, 1204, -4779, -1906, -1653, -3694, 637, -5027, -1988, 82, -10105, -1492, -629, -486, 2110, -1648, -3002, 1882, 1459, 3378, 657, 1358, 2660, 2603, 3623, 1185, 2820, 2130, 2627, 2740, 637, 2565, 365, 1434, 560, -235, 841, -2650, -1067, -3141, -370, -1308, -5821, -3575, -5607, 47, -1692, -6442, -2726, -5532, -168, -2738, -4904, -1480, -7712, -1903, -4340, -3564, -672, -11754, -6389, -3800, -3243, -417, -5924, -5494, -2953, -3758, -816, -4087, -4188, -2255, -4726, -1998, -3790, -4542, -1674, -5694, -3952, -5810, -5381, -1442, -6169, -5589, -7299, -5101, -1910, -5950, -4971, -2468, -4109, -3935, -6223, -3510, -1109, -4084, -12610, -7526, -2798, -1748, -4875, -2691, -6655, -3009, -5180, -3571, -299, -4560, -3222, -5909, -1531, 345, -3402, -2278, -3277, -663, -382, -2929, -1166, -3916, -1028, -2305, -2012, -494, -7351, -2594, -3089, -610, -250, -8475, -5069, -3070, -48, -487, -5563, -7464, -4932, -943, -1479, -3054, -7030, -5903, -3367, -3876, -1946, -5475, -4377, -2021, -7366, -2306, -4082, -4492, -563, -4662, -4219, -2805, -3707, -1053, -3735, -9693, -2621, -1912, -4055, -3845, -8011, -3894, -912, -8948, -3433, -5298, -6418, -661, -3656, -2446, -5489, -10928, -1071, -2590, -1764, -7680, -8049, -2208, -2121, -1662, -6862, -3920, -4199, -1926, -2121, -4885, -2611, -7311, -2486, -3145, -4183, -2502, -6901, -3554, -5151, -3631, -2937, -4649, -4186, -7162, -2699, -4051, -3461, -4742, -5468, -2078, -6172, -2738, -5050, -5448, -2188, -5573, -2471, -5332, -7820, -3023, -4144, -2849, -8141, -9531, -4575, -4189, -3847, -6521, -7025, -4941, -5784, -4681, -3328, -4626, -2908, -10587, -4944, -2513, -3434, -1903, -8857, -6083, -3079, -3631, -2184, -6619, -7385, -4605, -4939, -3503, -7520, -4832, -5781, -5437, -4992, -16740, -3000, -5635, -4065, -5684, -7742, -2005, -6065, -2885, -6214, -5278, -1464, -7700, -2155, -7036, -4340, -1287, -9068, -1918, -8916, -4106, -1409, -10187, -2433, -8882, -4859, -1646, -9359, -4090, -7672, -7479, -1849, -6429, -6578, -10293, -11893, -2146, -5860, -5821, -9577, -9527, -2889, -7698, -5002, -5400, -10978, -4290, -10471, -5225, -4621, -9688, -5863, -8450, -5468, -6029, -7785, -7006, -10558, -5211, -9458, -7926, -8354, -10826, -5036, -5769, -9321, -8951, -3863, -401, -4910, -2323, -2099, -3046, -1484, -5082, -3636, -4300, -1990, -3768, -3293, -6039, -2892, -1020, -3385, -4360, -10286, -1381, -255, -1195, -8361, -4200, -844, 278, 114, -2769, -1775, -811, 435, 634, -894, -1206, -1477, -8, 381, -142, -2189, -3598, -1427, -717, 335, -4704, -8123, -5223, -2835, 417, -4946, -7597, -6079, -6358, -351, -3272, -5801, -2029, -7051, -2202, -2890, -3212, -1142, -3754, -3082, -3662, -1664, -2077, -2099, -2011, -3470, -1050, -5634, -1766, -1891, -1794, -940, -8934, -2247, -2760, -858, -1262, -3438, -2825, -4027, -444, -2366, -964, -2952, -3780, -62, -4754, 1092, -744, -1225, 785, -3777, 2671, 1289, 547, 1815, -1385, 3401, 2002, 1037, 2102, -919, 3093, 1419, 302, 1159, -2604, 1611, -615, -1667, -1151, -6590, -1305, -4651, -4417, -2579, -2497, -5931, -3787, -3795, -2262, -1112, -6328, -1578, -2133, -2192, -1282, -5249, -492, -1608, -1433, -1872, -5463, 56, -2829, -1033, -1877, -6735, 108, -8921, -1287, -2722, -7527, -461, -2687, -1650, -8005, -5833, -1891, -802, -2093, -3565, -4344, -4628, -1311, -2714, -996, -3912, -7108, -4596, -2647, -767, -3612, -5606, -7922, -2412, -2013, -1807, -5153, -3394, -3264, -3955, -187, -5528, -2571, -5326, -4593, 284, -4498, -2853, -4618, -4179, -632, -2208, -3530, -2875, -3441, -3109, -724, -4099, -2419, -2947, -2721, -181, -4229, -3471, -2999, -1022, -361, -3709, -7384, -3834, -599, -967, -3015, -8685, -5134, -711, -1899, -2887, -5903, -3554, -765, -3358, -3166, -5754, -1923, -714, -3785, -2993, -5364, -1627, -914, -2953, -2677, -4464, -2332, -1681, -3383, -2699, -3035, -3388, -3309, -3892, -3248, -1738, -3700, -6108, -2633, -5378, -1179, -2604, -4500, -2448, -6191, -1404, -1393, -2437, -4005, -3079, -2358, -977, -2288, -5299, -2310, -4056, -1572, -3908, -3726, -3124, -5777, -3196, -5321, -2909, -5437, -4515, -4846, -3710, -2791, -11497, -2689, -5536, -3021, -3005, -9364, -1774, -7165, -3170, -3541, -5741, -2088, -5895, -4048, -4716, -2782, -4370, -4907, -6604, -7144, -759, -6454, -7052, -7518, -8122, 162, -3555, -4903, -4158, -5895, 171, -3090, -2152, -3245, -5270, -458, -3873, -1626, -3560, -5052, -1399, -4831, -2721, -3192, -3680, -2242, -6011, -5172, -1962, -2520, -2037, -8181, -5573, -1320, -2241, -1316, -8217, -4278, -1378, -2414, -1338, -6014, -3858, -2009, -2515, -2295, -5196, -4232, -3320, -2881, -3690, -5759, -4847, -5692, -3846, -4289, -8306, -4073, -8223, -5282, -3679, -16164, -3100, -6849, -6858, -3166, -9936, -3173, -6371, -6714, -3424, -8925, -4364, -5933, -6648, -3920, -7339, -6037, -4464, -9019, -3779, -6133, -6647, -3996, -10396, -3640, -6068, -6735, -5136, -8205, -3995, -6796, -7047, -8061, -8816, -4599, -6902, -7482, -10407, -11258, -4973, -5821, -7887, -7805, -11952, -5019, -5191, -8094, -3997, -1225, -1726, 455, -2235, -1923, -1850, -2943, 550, -3777, -1445, -2087, -3342, -100, -5814, -1953, -2336, -3153, -1103, -4142, -2632, -4684, -3320, -1695, -2613, -2901, -8141, -4337, -1264, -1490, -2999, -2810, -6058, -562, -465, -3671, -2464, -7398, -133, 2, -5802, -5233, -7651, 29, -553, -6365, -4151, -6733, -20, -2718, -6204, -1790, -5319, -477, -5304, -14004, -1346, -5160, -1726, -2391, -5560, -1932, -7949, -4745, -808, -3556, -3041, -3434, -9599, -338, -2007, -3100, -831, -3094, -916, -500, -1744, -360, -1619, -2268, -816, -956, -1394, -1788, -2899, -8095, -2464, -3479, -2063, -2920, -96, -6021, -2134, -158, -528, 2698, 497, 628, 1616, 1838, 3059, 2030, 1896, 2141, 2847, 1232, 1605, 1912, 1225, 2745, -8986, -425, 926, -1296, 1901, -483, -2512, -753, -2453, 956, 843, -1462, -2673, -1688, 9, 95, -537, -4408, -2272, -2437, -1608, -347, -5766, -2994, -5430, -3559, -711, -6027, -2730, -1048, -6876, -1160, -5132, -2448, -191, -9054, -1174, -3723, -2641, -1234, -7680, -999, -2339, -3458, -3787, -4533, -1345, -1551, -4958, -4962, -1365, -2678, -1656, -4757, -4839, -255, -4576, -3032, -2895, -6716, -603, -5046, -6251, -2278, -6261, -1986, -4877, -5405, -3344, -5445, -3752, -4363, -3169, -7274, -8626, -5077, -4816, -2093, -8234, -4423, -6048, -8315, -1521, -5655, -2150, -7367, -4908, -1421, -4987, -2215, -8890, -2915, -1900, -3782, -4512, -8844, -3645, -2610, -2110, -11768, -7070, -6387, -2648, -642, -5088, -5925, -2978, -2638, 160, -3597, -6593, -1333, -4099, 112, -3402, -10426, -1467, -8395, -890, -3571, -6303, -2852, -3149, -3120, -4245, -3113, -4508, -964, -7471, -4544, -1674, -5138, -434, -8217, -3670, -1793, -6248, -1070, -7179, -3860, -3207, -11460, -2975, -7530, -5558, -2942, -8060, -6450, -4451, -7461, -2403, -5962, -4914, -1935, -10274, -3799, -6274, -3149, -605, -5873, -6762, -4510, -3147, -166, -3850, -6233, -2935, -4624, -373, -4159, -5653, -2806, -7555, -1092, -5467, -7347, -3662, -11322, -2169, -5232, -6273, -4987, -12250, -1931, -6186, -3310, -6732, -12012, -704, -11559, -2685, -8575, -6899, -460, -3157, -3793, -10286, -3554, -1608, -737, -6339, -9748, -1825, -4462, -94, -7832, -6802, -1348, -6603, -749, -7260, -7043, -2270, -5405, -2259, -6798, -13103, -5551, -4543, -3056, -6387, -5503, -8667, -4196, -3570, -6220, -3738, -5031, -5614, -4747, -6335, -4764, -4838, -14754, -2743, -6782, -10976, -6079, -6492, -839, -8010, -3814, -6350, -4274, -270, -10839, -1667, -4784, -3521, -885, -8579, -1418, -3388, -3149, -2850, -6281, -2455, -2546, -3133, -7300, -6330, -4263, -2585, -3700, -11042, -7839, -5477, -3646, -4679, -6705, -5640, -5430, -5216, -5187, -4908, -3996, -4950, -5622, -5062, -3597, -3962, -5171, -5520, -5080, -3056, -5109, -6746, -6170, -4909, -3343, 12256, 8004, 12464, 10904, 8416, 11661, 8838, 11745, 10292, 7837, 9829, 9223, 9416, 8226, 5859, 6696, 8767, 5290, 3434, 1111, 2977, 8757, 4969, 1397, -464, 2108, 8772, 5794, 2522, 410, 3623, 7901, 5356, 2679, -1019, 5245, 5907, 2704, 4437, 2837, 6340, 1941, -1646, 4585, 4770, 6369, -1679, 2483, 2553, 5902, 5187, 2214, 1437, -1825, 6887, 4304, 3741, 84, 2872, 7698, 4748, 5084, 4322, 4584, 8097, 3880, 6081, 5659, 4890, 7818, 404, 6185, 5249, 4249, 6527, -7291, 5006, 2951, 2881, 3497, -5240, 2206, -4488, 1561, -9294, -62, 927, -185, 1006, 283, 2058, 2088, 1229, 656, 1421, 2252, 1775, 1014, 258, 2453, 1699, 199, 430, -287, 3213, 2191, -2181, -57, -1054, 2911, 3325, -3151, -687, -1903, 1542, 3738, -1571, -2331, -1605, -940, 3089, 510, -6440, -368, -8987, 1177, 1854, -1607, -59, -1887, -1725, 2033, 1828, -1407, 592, -2381, 864, 3501, -5873, 1064, -2537, -1580, 3845, -3362, 542, -1505, -2445, 2886, -229, -405, 220, -2483, 444, 1400, -1286, 1392, -3217, -2656, 2135, -1229, 2661, -1199, -1080, 1981, -101, 3840, 256, 738, 747, 983, 4422, 182, 1386, -1648, 1393, 4214, -1355, 859, -838, 572, 3078, -2979, -575, 1179, -2779, 1287, -2136, -2727, 2186, -603, 978, -480, -6706, 2734, 2007, 1252, 808, -2298, 2885, 2142, 482, 891, -647, 2223, -222, -882, 48, -1264, 701, -928, -1442, -453, -2690, 1267, 2068, -781, -1361, -3028, 2620, 2817, -385, -2744, -5865, 2610, 2421, -936, -733, -3840, 1366, 1544, -2087, 10, -1101, -272, 683, -2789, -693, -877, -801, 163, -3096, -1309, -2391, -582, 299, -3274, -1850, -6029, 58, 616, -2384, -4761, -7028, 879, 179, -883, -6516, -4411, 1277, -1468, 34, -2535, -2780, 952, -4018, -129, -857, -2165, 261, -4386, -1751, 839, -3254, 107, -2568, -3835, 2081, -8946, 80, -1732, -2107, 2452, -4218, -605, -3095, -1867, 1838, -2078, -1614, -6924, -5828, -12, -2580, -2200, -2167, -3131, -2820, -2926, -3767, -1126, 719, -1176, 479, -6279, -2542, 2094, 49, 2495, -2044, -5879, 2347, -592, 3243, -1135, -5126, 1748, -3047, 3057, -3205, -4156, 138, -1356, 2208, -7246, -1605, -2387, 720, 1134, -3015, 104, -1286, 1267, 413, -3284, 616, 176, 843, 110, -6889, 398, 697, -193, -436, -11669, -33, 829, -1605, -2037, -10863, -448, 101, -2500, -5866, -5674, -1045, -2758, -2960, -12132, -2950, -1885, -5134, -5512, -10490, -2075, -2092, -2006, -4752, -10492, -2218, -1038, -1937, -3669, -4559, -1907, 129, -3237, -4189, -2470, -812, 589, -2988, -1045, -2067, -276, -42, -1464, 325, -2838, 109, -2212, -1060, 380, -3663, 1003, -7791, -1896, 621, -2976, 1814, -2913, -403, -258, 8045, 9550, 7186, 501, 120, 7325, 8675, 6888, 1718, -160, 4903, 5702, 5722, 2833, -1728, 3467, 5928, 3912, 3925, -1514, 5284, 7940, 4257, 4699, 1072, 4933, 8041, 4843, 5014, 3906, 1122, 6909, 4358, 5019, 5623, 1005, 5540, 3590, 4792, 6091, 4076, 4906, 3947, 3907, 5549, 3769, 3762, 4786, 890, 4882, 741, 1371, 5631, -291, 4994, 728, 1159, 6304, 4450, 4886, 3321, 2554, 6345, 5797, 3780, 3904, 2829, 5709, 5579, 1185, 3568, 1699, 4629, 4263, -2447, 2989, -2181, 3142, 3186, 129, 2449, -5138, 1168, 3525, 1168, 1787, -1819, 195, 3274, 742, 1218, -663, 1042, 1324, -866, 1954, 1364, 1572, 1662, -4443, 3379, 2084, 1684, 4019, -8671, 4064, 1194, 1955, 4407, -4026, 3688, 230, 2287, 3023, -2688, 2463, 1878, 2236, 1119, -1896, 1342, 2899, 2547, 2351, -1459, 192, 2690, 3911, 2889, -558, -3703, 1611, 4897, 2077, 1155, -4453, 1426, 4812, 253, 2535, -1286, 2192, 3359, -1729, 3156, -1705, 2219, -457, -1692, 2994, -4273, 1368, -6251, -398, 2085, -4517, -325, -1626, 744, 1019, -1348, -3731, -2295, 1545, 1093, 732, -3623, -5882, 1875, 1617, 2194, -270, -4617, 1827, 2031, 3166, 506, -916, 1703, 1981, 3615, -387, 1276, 1579, 173, 3603, -2179, 2473, 1186, -3435, 3314, -2054, 2724, 140, 1652, 3011, 491, 2149, 1076, 2844, 2872, 2244, 1128, 3283, 1936, 2805, 2588, 349, 3957, -821, 2510, 1202, -190, 2950, -1257, 1734, -4619, -1319, 204, -250, 544, -1348, -2007, 294, -875, -352, 1091, -997, 1688, -2024, -425, 1248, -1371, 1668, -855, -262, 382, -5691, 956, 510, -302, -817, -2914, 1049, 907, -595, -1920, 502, 1943, 448, -821, -2724, 1601, 2352, -661, -746, -3330, 1475, 2140, -2026, -671, -4629, 392, 1396, -2031, -648, -7270, -1545, -146, -264, -553, -5524, -5040, -3276, 1055, -589, -3499, -9133, -5950, 1530, -979, -2698, -4207, -2716, 1158, -1913, -2031, -4130, -1612, -210, -3641, -1409, -6419, -2059, -2883, -5326, -565, -1954, -4178, -5976, -4314, 748, 198, -8769, -5558, -2953, 1516, 195, -7740, -4682, -1797, 1192, -2740, -4010, -3483, -331, -413, -5649, -2104, -2098, 1117, -2120, -1314, -1318, -954, 2108, -357, -1250, -1381, -306, 2503, 958, -537, -1893, -644, 2144, 961, 741, -1843, -2192, 590, -137, 519, -1748, -1145, -2490, -1252, -1332, -2488, 606, -797, -2951, -2477, -3125, 1038, 190, -3824, -112, -2300, 779, -1038, 313, 1460, -1318, 19, -3384, 1074, 2146, -964, -1678, -3315, -616, 2249, -1141, -4332, 867, -1709, 1865, -1088, -9021, 3321, 629, 1195, -654, -782, 4100, 1998, 1048, -939, 2199, 3533, 2857, 1285, -2908, 3349, 1691, 3051, 932, 8460, 8764, 11352, 9229, 2753, 7994, 8949, 10816, 8749, 4209, 6432, 8797, 9288, 7514, 4087, 3028, 7763, 7221, 6280, 2883, 4307, 6429, 6286, 6063, 5151, 7170, 5960, 7057, 6742, 5915, 7885, 5807, 7424, 7641, 5033, 6634, 4701, 7023, 8459, 3040, 2317, 292, 6300, 8670, 1377, 4805, 1482, 5279, 7906, 2178, 6627, 4124, 3261, 6187, 1619, 6761, 5003, 2385, 4000, -1840, 6090, 5749, 4444, 149, 435, 4690, 5625, 4623, 68, 1056, 2124, 4213, 2140, 3875, -22, -3026, 2354, -1857, 4641, 1532, -8310, 1683, 2757, 4313, 3311, -7519, 872, 3382, 3707, 4183, -6729, -44, 2501, 2651, 4306, -3805, -1024, 1050, 4, 4095, -3055, -2232, 319, -2462, 4125, -2696, -1606, 834, 1370, 4268, -2410, -1369, 1480, 2791, 4182, -2101, -3471, 1399, 2977, 3828, -1520, -10223, 1, 2121, 3192, -775, -2869, -4311, -529, 2125, -186, -1618, -5470, -6680, 279, -352, -75, -2436, 917, -2823, -2656, 1519, -1145, 3016, -804, -4637, 1827, 182, 3785, 2504, 898, 1495, 964, 3725, 4232, 2812, 2149, 1390, 2948, 4710, 3434, 2418, 1520, 1436, 4089, 3316, 1374, 1283, -1088, 2899, 2824, 1657, 994, -7632, 2226, 2433, 2951, -5, -3054, 1144, 2270, 2699, -55, 100, -2935, 1379, 725, 3089, 1043, -1725, -2073, -2755, 4658, 399, 1008, -1394, -4091, 4839, -2461, 1439, 629, -1411, 3963, -2723, 695, -1442, -2145, 2462, 299, -1740, -1715, -2818, 1113, 1355, -2852, 2143, 2129, 732, 1797, 736, 2904, 3268, 1169, 2289, 1744, 1974, 1867, 1005, 2571, 1211, -754, -5190, -349, 2287, -231, -8360, 810, -1871, 1834, -1632, -3091, 2122, -1322, 2495, -2923, -1269, 1075, -755, 3536, -2198, -695, -2012, -865, 3776, -238, -991, -3860, -1450, 2933, 160, -2163, -644, -2220, 1230, -1354, -3734, 1575, -2364, 379, -5293, -4967, 2724, -1855, 144, -3369, -5844, 2915, -1599, -1240, -2022, -5521, 2148, -1625, -2487, -1109, -3257, 70, -1427, -1644, 471, -1981, -5198, -595, -705, 1684, -2131, -6811, 346, -443, 2197, -3951, -6458, 798, -2139, 1940, -8099, -3504, 634, -5089, 805, -6176, 47, 469, 671, -1372, -7883, 1266, 1254, 2689, -5451, -5118, 975, 2109, 3192, -9195, -643, -664, 2208, 2548, -3472, 822, -3077, 1423, 640, -719, 902, -5188, 621, -3357, 1233, 509, -7465, 1372, -8998, 2263, 412, -1372, 1921, -3528, 2170, 457, 1163, 1371, -1897, 689, 419, 2608, 199, -990, -2223, 406, 3461, -518, -285, -1417, 524, 3722, -721, -471, -59, 846, 3468, -3, -2518, -219, 1216, 2950, 769, -6634, -1664, 1267, 2254, 1212, -4126, -3522, 954, 1146, 1796, -4887, -2688, 562, -252, 2150, -5063, -1078, 15, -607, 1798, -1354, 64, -2422, 1217, -1222, 2356, -549, -826, 1359, 46, 2528, 77, 703, 1093, 540, 2047, 385, 1584, 810, 575, 906, 905, 1793, 607, -30, -280, 928, 1335, 127, -2231, -579, 524, 372, -1104, -3372, -1242, 594, -759, -2885, -1276, -2669, 1271, -2051, -1787, -2151, 731, 1607, -3941, -142, -2902, 2755, 1031, -2410, 257, 526, 3356, 338, 368, -416, 1648, 3127, 1169, 1554, -883, 1187, 2447, 1919, 1349, 35, -355, 1505, 2010, -49, 491, -1493, 290, 1885, -1012, -189, -706, -1402, 1835, -653, -1342, 414, -4049, 1445, -1380, -835, 1399, -2753, -656, -1061, 407, 2389, 328, -5594, 1578, 1699, 3256, 1557, 1803, 3104, 2721, 3595, 1262, 3600, 3538, 2988, 3157, -425, 3530, 3049, 2241, 2007, -2748, 1807, 1702, 292, 913, -2749, -1753, -271, -1737, 416, -410, -2780, -2211, -796, -825, 738, -3053, -3166, 224, -4159, 388, -6781, -1350, 778, -7538, -684, -6021, 40, 794, -8075, -1196, -2613, 194, 186, -5381, -1710, -796, -846, -876, -3076, -2264, 450, -3535, -2173, -2795, -2610, 1111, -3248, -2985, -3229, -2763, 942, -1127, -3091, -2968, -2029, -564, -957, -3445, -2602, -2077, -4367, -1931, -2600, -3586, -4953, -599, -2966, -1270, -6257, -3913, 1906, -3599, -1194, -3077, -125, 2630, -4263, -2647, -1461, 1024, 1879, -4804, -1485, -2161, 636, -401, -5464, 880, -7517, -1091, -1523, -7686, 1802, -3875, -3391, -522, -10960, 1715, -893, -3458, 65, -4600, 963, 83, -1659, 494, -638, -385, 426, -37, 215, 1234, -2347, 531, 777, -961, 1538, -3032, 550, 806, -2996, 382, -1489, 670, 104, -6353, -2430, -72, 764, -1070, -7499, -7218, 711, 512, -2166, -6543, -16015, 894, -116, -4145, -8256, -4972, 799, -1035, -9862, -3472, -1895, 662, -2096, -2376, -442, -683, 312, -2580, -257, 980, -586, -284, -2829, 219, 1468, -997, -665, -3893, -358, 1381, -1313, -924, -5072, -1739, 1043, -1979, -2041, -4316, -4271, 900, -3999, -5376, -3714, -10667, 1246, -9268, -12061, -4294, -2703, 1723, -5847, -6724, -5843, -451, 1670, -3115, -8155, -5466, -5, 553, -2213, -8196, -3675, -928, -2179, -2481, -5031, -2801, -2871, -5236, -2656, -4252, -2905, -3313, -4565, -1879, -5726, -3708, -2167, -4952, -1631, -9692, -4346, -1480, -4648, -2599, -3388, -4863, -1423, -3280, -5618, -1103, -6256, -2118, -2033, -7619, -369, -4822, -3878, -1391, -3919, -476, -2701, -7312, -1380, -2864, -804, -2024, -5814, -1760, -2468, -1219, -2327, -3750, -2191, -2058, -2263, -2831, -3560, -2300, -2160, -4133, -2731, -4973, -1943, -3298, -4746, -2163, -8332, -1633, -5245, -3793, -1897, -9267, -2145, -4547, -3877, -2678, -7678, -4342, -3610, -5656, -5583, -6145, -6009, -4297, -9752, -11844, -3874, -3231, -9564, 3317, -1712, 2495, -249, -4231, 2333, -4860, 1441, -2319, 472, 214, -2134, 332, -6326, 2920, -5387, -2290, -772, -1964, 3892, -958, -9231, -1652, 802, 3680, 1596, -2025, -1339, 1828, 2542, 1900, 188, -1396, 1656, 1022, 311, 218, -2450, 361, -494, -5238, -143, -2696, -2148, -2685, -3968, 428, -2002, -5779, -3974, -1723, 596, -1375, -7355, -2275, -1966, -382, -1209, -4313, -1981, -1460, -2295, -2147, -1661, -4310, -181, -3322, -3900, 111, -7570, -182, -3673, -3565, 1099, -2872, -1643, -4352, -1997, 1367, -1554, -2401, -4965, -514, 875, -433, -1869, -6022, 566, -330, 1229, -3502, -2602, 1703, -1157, 2667, -3167, -378, 2998, -711, 3240, 137, 101, 3765, -609, 2728, 1359, -902, 3624, -1976, 1083, 1316, -2345, 2389, -8600, -1322, 389, -1026, -309, -758, -3238, -266, 437, -6312, 2126, -4703, 816, 1101, -3475, 3235, -5948, 1770, 967, -999, 3122, -5564, 1828, -395, -227, 1573, -3359, 1194, -5735, 255, -3600, -2273, 303, -2483, 1032, -1824, -2752, -632, 326, 1326, 840, -5005, -1329, 466, 820, 941, -4284, -1794, -1498, -222, -125, -1421, -2664, -5865, -1489, -924, 146, -2813, -1618, -2149, -70, 669, -2351, 367, -1519, 961, -46, -1477, 1177, -1038, 1226, -1699, 628, 1361, -486, 532, -76, 2150, 963, 527, -1000, 1627, 2592, 101, 1346, -1927, 2020, 1908, -700, 1647, -1514, 1653, -332, -1236, 1406, -1411, 1325, -10068, -989, 667, -924, 1690, -1303, 515, -409, -10, 2410, 1293, 1728, -1478, -109, 2706, 2163, 2160, -2210, -2149, 2184, 1921, 1908, -2428, -9430, 658, 573, 1130, -1598, -8966, -2020, -2038, -112, -240, -6766, -3364, -3674, -1602, 690, -1499, -2217, -1771, -1832, 920, 140, -2417, -677, -1264, 421, -87, -4587, -576, -1291, -567, -1831, -8048, -1305, -1898, -875, -4965, -3671, -2780, -2956, 215, -9928, -2334, -4840, -3151, 960, -8429, -2557, -4926, -2364, 391, -4029, -3040, -2353, -2119, -1905, -2826, -2297, -703, -1551, -2284, -3370, -806, -431, -283, -701, -2411, 257, -1976, 712, -781, -110, 523, -5822, 1049, -1996, 1024, 18, -2396, 621, -3525, 1091, -1011, -1452, -564, -4353, 241, -1537, -3027, -1276, -3894, -1498, -1273, -1980, -230, -3036, -4200, -1669, 593, 335, -2142, -8792, -3426, 1475, -195, -1508, -9505, -5679, 1171, -1675, -1465, -6397, -4053, 5, -4040, -2016, -6187, -2771, -1603, -8102, -3353, -6786, -2667, -2941, -7881, -5242, -6067, -3708, -3427, -6175, -3917, -4149, -5051, -3540, -5787, -2668, -2366, -3368, -4009, -4915, -2502, -1633, -1766, -4810, -3513, -2509, -2258, -1212, -5520, -2392, -2325, -4518, -1430, -6411, -2023, -2446, -5615, -2144, -7517, -2545, -2686, -4291, -2848, -6527, -3844, -1880, -4841, -1145, -145, 628, 475, 457, -2957, -10, -1570, 1391, -133, -4206, 52, -6385, 1664, -1805, -3079, 145, -4327, 1253, -3114, -1486, -819, -975, 374, -2454, -1235, -5610, 467, -293, -1797, -3162, -3606, 815, -758, -304, -3796, -1578, 354, -1073, 797, -583, -2625, -499, -771, 551, 92, -2287, -1511, -778, -390, -1734, -786, -2860, -1886, 191, -5805, -598, -3619, -3831, 690, -130, -1444, -1214, -2643, 209, 1606, -3083, 1408, -614, -1114, 2381, -4094, 2906, 633, -6743, 2871, -2164, 3295, 1471, -1532, 2341, -551, 2600, 1803, 1710, -254, -1350, 670, 852, 2520, 1150, -2959, -1344, -3412, 1716, 3180, 1734, 1280, -675, -265, 2878, 3379, 3075, 1577, 593, 564, 3251, 3563, 1385, 2170, 651, 1874, 3033, -583, 2850, 2123, 884, 1686, -4414, 3101, 1837, 1719, -398, -9515, 2822, 99, 2401, -3167, -4597, 1589, -2826, 2676, -4771, -1401, -138, -5814, 2910, -6350, -610, -104, -6063, 3013, -8985, -1488, -619, -3875, 2957, -8283, -2294, -2217, -1501, 3230, -2237, -1782, -1127, 361, 3596, 688, -1570, -753, 1476, 3297, 1530, -1263, -1992, 1754, 1762, 584, -332, -3281, 1156, -2419, -2802, 614, -2246, -349, -3108, -5652, 727, -1032, -2545, -441, -2741, -363, -1151, -3433, -692, -2244, -2517, -3094, -2801, -2605, -2152, -2148, -5145, -2558, -3874, -1905, -258, -4390, -2293, -3149, -1464, 888, -6111, -1497, -3126, -774, 1634, -5495, -650, -2098, -295, 1935, -2774, -379, 67, -790, 1403, -1358, -1010, 1457, -3443, -11, -51, -2306, 1889, -3109, -284, 1057, -4607, 1583, 263, 789, 1584, -6906, 976, 1375, 1056, 1371, -1678, 582, 1247, 544, 460, -635, 136, 304, -188, -774, -1331, -1029, -952, -1160, -2151, -918, -1051, -1310, -2378, -3368, 140, 174, -419, -310, -2190, 673, -106, 227, 1558, -1586, 1039, -2416, -134, 2027, -2991, 893, -6580, -1703, 1269, -6484, -115, -5723, -4105, -856, -2971, -2238, -3554, -6704, -5229, -939, -6743, -2910, -7597, -3618, -429, -10337, -4056, -6796, -1566, -1561, -6673, -4428, -12669, -1216, -7896, -6061, -3668, -2993, -1485, -2882, -5866, -4362, -584, -1137, -280, -6184, -5742, -232, -590, 311, -7151, -6190, -1667, -693, 372, -10047, -5120, -7048, -1029, 73, -10798, -3369, -4997, -1002, -1285, -5770, -2927, -2547, -1148, -2374, -4233, -4789, -2791, -1988, -447, -4173, -8613, -4557, -3999, 457, -4995, -3105, -6255, -7731, -100, -6188, -1730, -7142, -5266, -2370, -6593, -2111, -11767, -3767, -5091, -5145, -3803, -7493, -3824, -2533, -4008, -6733, -4307, -4295, -1719, -4287, -10252, -3294, -4072, -2339, -5571, -8014, -3507, -3417, -3899, -3474, -6660, -4456, -2442, -6205, -1628, -7007, -4803, -1214, -10809, -1319, -8609, -4288, -465, -10738, 11098, 5212, 12300, 10731, -13274, 10442, 6685, 11667, 10185, -5310, 8302, 7186, 9625, 8459, -3020, 3785, 5776, 5462, 5253, -2244, 1023, 3996, -1424, 287, -1736, 2976, 4149, 407, -1784, -605, 3079, 3114, -722, 661, 89, 2958, 784, -5, 1303, 325, 3135, 1756, -86, -672, 1340, 3989, 2726, 137, -26, 2416, 4821, 2709, 1082, 3029, 3017, 4752, 3030, 538, 4385, 3491, 3277, 4047, -3489, 4673, 3810, -348, 4441, -1135, 3980, 3758, 216, 3628, 293, 2357, 3336, 1802, 1749, -2091, 829, 2509, 1505, 768, -891, 395, 811, 631, 636, 1899, 109, -4455, 226, -296, 2648, 168, -1596, -540, -1523, 2391, 272, 1368, -1774, -3220, 1437, 265, 1752, -1880, -5949, -332, 528, 741, -1641, -3799, -3154, 1030, -656, -1690, -2449, -3611, 1340, -1832, -1245, -2534, -2997, 1490, -4817, -374, -2040, -4587, 1682, -2789, -169, -908, -9040, 1674, -187, -1274, -1075, -8328, 1255, 257, -3880, -3698, -4611, 584, -873, -5979, -5615, -2235, 163, -3707, -9433, -1926, -1347, 160, -9210, -7969, -1200, -1870, 103, -12453, -4893, -2052, -4712, -220, -7170, -5432, -4455, -7397, -715, -3549, -7741, -7953, -2554, -1232, -1773, -5242, -5832, -1528, -1503, -1547, -2831, -3492, -2060, -1501, -3042, -1437, -1902, -3381, -1917, -4839, -896, -1487, -4409, -3751, -2231, -1335, -2925, -5361, -9173, -752, -2493, -11578, -7925, -5094, -347, -2519, -3585, -18176, -3398, -604, -1625, -1877, -10374, -3873, -1355, -1285, -2854, -12016, -6563, -2503, -1518, -6327, -12043, -7376, -3559, -2105, -3820, -7938, -4767, -3599, -2760, -2402, -6678, -4353, -3201, -3089, -2845, -6013, -5385, -3098, -2942, -4488, -4418, -8138, -3288, -2847, -6622, -2408, -14394, -3652, -3416, -8079, -1161, -5638, -4190, -4624, -8116, -831, -2668, -4954, -5222, -6976, -1189, -1206, -5770, -5339, -5479, -1860, -828, -5995, -6444, -4132, -2620, -1298, -5463, -7908, -3071, -3510, -2244, -4449, -6470, -2511, -4811, -3266, -3517, -4756, -2817, -6980, -3990, -3400, -4214, -4423, -6924, -3501, -4595, -5061, -7353, -5594, -2586, -6687, -5601, -7305, -5826, -2433, -5014, -4189, -6156, -7004, -3291, -3297, -3931, -4989, -7679, -4740, -2520, -5206, -4326, -7732, -5585, -2025, -5975, -4052, -6323, -7057, -1360, -4578, -2613, -4732, -12016, -683, -3435, -1212, -4410, -7504, -294, -2585, -828, -5621, -6556, -375, -2187, -1415, -5592, -8070, -1032, -2424, -2718, -3489, -9643, -1973, -3028, -4759, -3094, -7536, -2619, -3475, -9114, -5000, -4308, -3469, -3501, -6100, -6687, -2197, -4270, -3029, -3362, -3660, -1111, -3131, -3031, -2650, -3297, -786, -2407, -4677, -3325, -5145, -1064, -3122, -10750, -5078, -6277, -1863, -5590, -9095, -6716, -4257, -3437, -10057, -8470, -7109, -3506, -7310, -10609, -11511, -6290, -2969, -8178, -5305, 1585, 3305, 8481, 3947, -7373, 857, 2438, 7871, 4483, -5163, -1996, -93, 5893, 4989, -1325, -1659, 841, 2403, 4908, 1273, 2099, 2461, 2031, 4779, 2616, 3751, 2638, 2640, 5051, 3061, 4361, 2355, 1685, 5346, 2837, 4441, 2016, 406, 5189, 2082, 4328, 247, 1849, 4410, 1080, 4039, -3195, 3468, 3163, -336, 4027, 2040, 4662, 1497, -3365, 4988, 3859, 5658, -982, 38, 5693, 4172, 5994, -1242, 3006, 5278, 3567, 5174, -822, 4260, 3458, 2747, 2548, -2184, 4354, 706, 2516, 58, -2813, 3520, 445, 2291, 2562, -2896, 2005, 192, 1550, 2941, -4081, 194, -869, 734, 1859, -4434, -1360, -785, 930, 155, -3206, -2027, 300, 1899, -530, -2885, -1699, 1254, 2444, 93, -5182, -1408, 1767, 2207, 423, -10119, -1961, 1778, 1408, -459, -6219, -2644, 1226, 771, -1880, -1894, -2940, 111, 722, -634, 805, -3221, -589, 873, 577, 1830, -1550, 239, 766, 783, 1632, -334, 995, 95, 209, 354, -388, 892, -717, -877, -2339, -1423, -500, -449, -1883, -4972, -3426, -5195, -1, -1938, -2367, -8461, -3421, -187, -1485, -1279, -4852, -866, -240, -1510, -1196, -1826, -1293, 206, -2200, -1447, -684, -4666, -29, -3118, -1524, -475, -6737, -1703, -3556, -973, -677, -4775, -4770, -3481, -59, -841, -4117, -4457, -3387, 502, -1063, -2478, -3343, -3405, 513, -1847, -1872, -2763, -3513, 216, -3158, -1954, -3293, -3491, 6, -1841, -2078, -6307, -3108, -39, -34, -2676, -4200, -3202, -70, 295, -4143, -1613, -4699, 133, -1057, -5056, -933, -8726, 735, -5222, -4775, -1032, -7064, 1143, -6540, -5723, -1051, -4089, 856, -4798, -7549, -1215, -2400, -195, -7213, -5635, -2425, -1542, -1435, -6176, -4819, -4529, -1232, -2289, -3326, -6213, -3064, -863, -4036, -3085, -8323, -2295, -451, -4993, -4715, -5061, -4020, -749, -2752, -3877, -3576, -6565, -1875, -2479, -2051, -3764, -3560, -2217, -3992, -1880, -5381, -3341, -1708, -5812, -3022, -4445, -4321, -1992, -6653, -5129, -2650, -3498, -3241, -5129, -7028, -2528, -2897, -4728, -3051, -5802, -4167, -3519, -5969, -2871, -4319, -7325, -4670, -9996, -4331, -3595, -4791, -4604, -7482, -4786, -3318, -3351, -3509, -5488, -4479, -3763, -3662, -3008, -6282, -6129, -6270, -5514, -3122, -7904, -5156, -9061, -7791, -2629, -5439, -3320, -3932, -5454, -1852, -3039, -2650, -2778, -3742, -1820, -1611, -1754, -3548, -3505, -2607, -1143, -1164, -7063, -4740, -3944, -1745, -1874, -6602, -7379, -5275, -3118, -4641, -2947, -5731, -4220, -3162, -4582, -1783, -3739, -2276, -2644, -2088, -1782, -3252, -1601, -3260, -1424, -2322, -3649, -2494, -4660, -1975, -3063, -4196, -5663, -5993, -3845, -3228, -4619, -8550, -9567, -6095, -2124, -4831, -5158, -8780, -3685, -1638, -4736, -3700, -5019, -2600, -2706, 3707, 2638, 6935, 2367, -409, 2736, 2365, 6486, 3751, 2168, 1377, 1343, 5470, 4876, 3115, 3163, -681, 4488, 4624, 1773, 4089, -697, 2993, 2655, -2576, 3762, 1709, 329, -2962, -906, 2292, 2976, 233, -1112, 746, -870, 3029, 587, -145, 458, -5764, 1947, 2, -1787, -2017, -2262, -4, 430, -2562, -3108, -14, -1930, 1231, -1716, 1821, 1788, -2410, 1649, -1517, 3826, 2804, -1236, 1710, -143, 4544, 3057, -441, 1395, 1775, 4359, 2635, 418, 578, 2847, 3582, 1434, 1425, -1172, 2693, 2857, -1028, 1644, -3601, 1070, 2653, -6563, 865, -687, -76, 2631, -10669, -513, 830, 1328, 2475, -6428, -1739, 525, 1282, 2073, -2958, -2828, -1301, -1020, 1441, -2750, -4133, -3430, -16441, 646, -4168, -2603, -3920, -2047, 242, -486, -225, -4235, -270, 624, 1024, 1000, -3784, 359, 546, 493, 1237, -3623, 640, -679, -2010, 381, -3130, 969, -2732, -3305, -2278, -1646, 1447, -3567, -2123, -7752, -834, 1559, -1510, -2701, -3584, -997, 908, 148, -4190, -2956, -1853, -521, 587, -4177, -3973, -2802, -2053, 103, -3373, -5826, -3259, -2014, -1133, -3022, -7751, -3502, -801, -3851, -2864, -7128, -4058, 12, -6858, -2197, -5368, -4733, -156, -2515, -1500, -4914, -3531, -1289, -1601, -2129, -5401, -1761, -934, -3359, -5833, -5855, -929, 961, -7624, -2855, -4490, -885, 1960, -1611, -733, -2348, -960, 2037, 345, -1164, -1348, -729, 1452, 1044, -3845, -1594, -613, 382, 974, -4552, -3003, -778, -1558, 95, -3389, -5396, -859, -5068, -1692, -3932, -3957, -712, -2859, -2906, -4352, -1844, -920, -1314, -2445, -3971, -1383, -2114, -710, -2151, -3884, -2316, -5126, 123, -1625, -4171, -3896, -7733, 660, -1102, -4685, -3933, -2734, 588, -702, -5475, -3649, -655, 67, -528, -6936, -4077, -101, -1149, -1218, -10007, -4253, -984, -4323, -3259, -7527, -2958, -3909, -5933, -3525, -3866, -1383, -6203, -2006, -1102, -2139, -615, -2993, -907, 107, -2018, -870, -1857, -1267, 143, -3948, -1987, -1685, -2792, -1038, -8334, -3092, -2154, -4408, -3392, -4299, -3602, -3363, -4114, -3630, -3513, -4155, -6059, -3263, -2461, -5321, -4200, -9254, -2273, -2403, -14087, -3900, -5744, -1227, -3193, -4042, -4117, -5267, -476, -3996, -1661, -4803, -7994, -240, -3732, -892, -5842, -10145, -634, -3205, -1265, -7545, -5716, -1846, -2950, -2523, -9839, -4877, -4653, -3034, -3705, -7522, -4084, -5418, -3877, -4613, -4659, -3178, -2218, -5807, -7387, -3785, -3515, -1403, -8260, -11497, -4984, -6182, -2172, -9360, -6346, -6504, -6892, -4239, -7743, -4428, -4122, -4123, -6879, -7008, -3190, -3511, -4579, -10967, -6432, -2575, -3400, -5683, -7842, -4646, -2471, -1945, -3157, -3757, -4293, -2553, -1025, -2473, -2903, -5273, -2585, -1288, -3610, -4283, -4097, -9523, -5943, -2164, -5581, -2444, -7776, -7923, -2002, -6584, -1324, -6893, -10160, -3126, -8249, -1242, -5853, -5730, -6185, -7069, -1318, -4999, -4494, -11606, -4761, -1033, -4625, -4512, -9209, -2764, -895, -4675, -5093, -5432, -2392, -906, -5316, -6753, -2629, -4217, -506, -7343, -12258, -1117, -18640, -111, -9723, -7977, -691, -4660, -501, -6642, -6882, -1346, -3457, -2156, -5205, -9530, -3231, -4659, -6435, -3930, -12152, -6519, -8626, -5634, -3154, -7490, -9589, -6737, -2102, -3723, -7020, -9157, -4072, -731, -5013, -8657, -9415, -2941, -398, -4607, -10880, -9679, -2876, -754, -5311, -14843, -9054, -4567, -1638, -14356, -6364, -8733, -13294, -3056, -4994, -2996, -4463, -5328, -4725, -2286, -1904, -2246, -4056, -4127, -1121, -2429, -1557, -5177, -2582, -734, -4504, -1938, -7300, -2004, -1035, -7966, -3344, -7584, -2366, -1927, -7388, -7014, -5819, -3508, -3280, -5943, -7778, -3259, -5056, -4883, -5403, -3711, -1761, -6577, -5724, -3812, -2815, -1334, -10214, -6432, -2134, -3513, -1800, -7198, -8335, -1299, -5112, -3064, -4323, -6722, -1216, -6206, -5131, -3659, -5068, -1666, -8050, -8021, -4004, -4996, -2605, -8072, -11208, -4015, -6186, -4652, -4438, -10588, -3273, -8792, -9297, -3155, -7707, -2889, -9015, -5467, -3343, -5270, -3625, -6067, -3545, -4613, -3311, -6748, -5065, -2944, -6260, -2057, -9865, -6187, -2925, -7114, -1475, -5008, -6917, -3686, -7323, -1268, -4218, -3167, -5852, -7615, -1271, -4439, -1312, -6944, -8678, -1771, -3908, -680, -4782, -8846, -3161, -3446, -825, -4036, -8856, -5418, -4445, -1466, -4437, -10779, -6813, -5622, -2382, -5802, -4930, -7126, -3128, -3724, -7505, -1874, -8631, -1671, -6449, -8103, -453, -13228, -1267, -9744, -7564, -269, -10195, -1356, -6865, -6983, -1270, -7884, -1598, -7550, -8264, -3377, -6582, -1809, -13209, -10664, -5900, -4933, -2029, -6603, -7333, -6637, -3141, -2649, -4805, -5579, -4607, -2065, -3786, -4159, -4530, -3556, -1958, -4434, -4021, -3946, -3579, -2653, -4115, -5443, -4218, -3204, -3892, -4038, -9143, -6128, -2134, -4915, -5295, -4613, -13797, -1494, -3796, -8152, -2934, -8834, -1618, -2501, -3860, -2776, -7296, -2660, -1837, -2081, -3349, -6771, -4973, -1725, -2184, -4176, -7035, -10012, -2470, -3850, -4867, -10270, -8530, -4484, -7644, -4945, -11567, -5452, -7947, -13246, -4593, -7648, -4465, -13331, -8972, -4690, -7031, -4486, -11865, -9795, -5755, -7391, -4672, -9503, -9418, -6950, -7780, -4682, -16058, -7030, -6089, -6621, -4720, -7791, -5977, -5453, -5265, -4802, -5117, -5921, -6064, -4721, -5110, -5085, -8222, -8408, -4431, -5728, -7469, -7815, -12098, -3763, -6161, -10741, -3895, -8584, -3051, -5790, -8524, -2729, -7566, -2674, -5077, -9058, -3014, -8564, -2654, -4944, -7027, -4310, -8408, -2854, -6054, -5405, -6337, -6067, -3169, -7725, -5604, -8646, -5427, -3730, -6045, -7173, -9349, -5644, -2745, -4435, -3255, -5100, -10319, -2409, -5707, -5709, -3217, -4289, -2904, -8567, -10219, -1759, -1428, -4532, -10403, -10345, -2067, -360, -8814, -11601, -8343, -3550, -360, -6021, -10113, -5433, -2952, -1047, -2621, -6476, -3020, -2146, -2014, -1286, -3590, -1799, -3138, -3347, -1293, -2157, -2028, -4382, -6207, -2485, -2222, -3986, -3157, -6363, -4376, -3953, -6302, -2993, -3178, -4933, -8381, -5066, -4482, -2127, -4846, -12400, -4240, -7919, -2555, -6214, -8454, -3503, -7013, -4322, -5684, -6272, -2668, -4389, -4535, -3199, -3959, -1933, -3414, -2477, -2617, -2243, -1718, -3123, -1327, -3827, -1305, -2294, -2093, -1066, -7001, -1076, -3850, -801, -1632, -8388, -1685, -6329, -498, -2998, -7507, -3648, -5368, -1515, -4982, -7466, -7383, -3325, -2655, -7653, -7390, -5273, -2413, -1555, -14324, -6261, -3707, -2532, -1035, -9651, -4787, -3281, -3732, -1629, -5854, -4420, -3728, -5714, -2317, -4014, -5483, -5742, -5663, -2378, -3529, -7319, -8604, -4638, -3085, -4334, -6198, -5104, -4462, -5674, -6502, -5078, -3689, -4555, -14132, -11050, -5171, -3450, -4259, -13545, -9341, -5933, -3294, -3862, -8457, -5184, -6151, -2572, -4167, -4497, -3611, -5143, -1653, -5473, -3356, -3468, -3974, -1278, -6098, -3895, -4212, -3747, -2331, -4030, -5500, -5145, -5045, -7589, -2336, -6391, -5749, -7203, -4400, -1870, -5463, -6348, -6143, -2208, -2193, -4082, -7322, -4906, -2997, -1735, -2751, -4971, -3830, -7372, -806, -1731, -2704, -3698, -7334, -695, -1307, -1781, -5715, -4778, -1785, -1633, -1760, -9078, -4864, -4826, -2603, -2323, -4936, -5444, -10881, -3398, -3460, -4051, -6080, -4726, -3330, -5913, -4514, -9708, -2940, -3278, -9419, -5049, -7931, -2193, -3486, -4353, -4575, -4653, -2333, -3719, -1933, -3317, -4288, -3790, -4057, -585, -2619, -6018, -6452, -4951, -5, -3009, -13340, -4646, -7322, -224, -4531, -8298, -3373, -11910, -1415, -6536, -5687, -3711, -8413, -4246, -7867, -4259, -5131, -4938, -8504, -10451, -3386, -6804, -2993, -4161, -10671, -3469, -9349, -2556, -2815, -8378, -5085, -9094, -3620, -2359, -9030, -9748, -5670, -6663, -1707, -10671, -5964, -4925, -6982, -1238, -6904, -4084, -6098, -4870, -1593, -4780, -4367, -8449, -4262, -3044, -3837, -7028, -7802, -3321, -5930, -3460, -13684, -7987, -2254, -10288, -3088, -6700, -13398, -1980, -7907, -2537, -5443, -5852, -2529, -5309, -2281, -5477, -3144, -3454, -3354, -2779, -6270, -2284, -3982, -2010, -4131, -8456, -2577, -3993, -1443, -5248, -14405, -3869, -3884, -1780, -5301, -7072, -6484, -3667, -3182, -6687, -4773, -11855, -3411, -6299, -13380, -4030, -9727, -3625, -13249, -6993, -4150, -8273, -5127, -5833, -5646, -4561, -7768, -9798, -3523, -7344, -4823, -7563, -9133, -2409, -13634, -5072, -8797, -8460, -2152, -6157, -5646, -14285, -14051, -2812, -4474, -6838, -10685, -8765, -4529, -4371, -9026, -8921, -7190, -2538, -2793, -5336, -3947, -3232, -2447, -6203, -5527, -1346, -4646, -2657, -11648, -5577, -289, -7774, -3120, -5916, -4942, -409, -4535, -2327, -3789, -3437, -1664, -3652, -1306, -2676, -2158, -4312, -5043, -1433, -2688, -1550, -4704, -12021, -2924, -4046, -1718, -2938, -6369, -5811, -5486, -2140, -2456, -4418, -9238, -4771, -1672, -2623, -5173, -7536, -5012, -1027, -2916, -7563, -5388, -6455, -1047, -3534, -5747, -3857, -6470, -1762, -6188, -4386, -2362, -5764, -3270, -7302, -3486, -1317, -5339, -5938, -2043, -2596, -977, -5002, -5752, -567, -2031, -1364, -5686, -4356, -871, -1595, -2485, -9444, -4559, -3048, -1263, -4310, -9670, -4284, -9537, -1203, -5912, -6224, -3258, -4981, -1598, -5220, -6752, -3456, -3016, -2725, -4270, -13093, -3992, -2290, -3813, -4408, -7856, -1929, -1810, -2808, -6610, -6766, -300, -1490, -1837, -12281, -9620, 182, -1437, -1396, -4540, -5758, -268, -1434, -1067, -2260, -3563, -1245, -1335, -1237, -1190, -3551, -1476, -1500, -2333, -991, -4916, -812, -2049, -2009, -1888, -4600, -483, -2455, -390, -4537, -3079, -788, -2471, -38, -8360, -2618, -1859, -2379, -449, -5758, -2959, -4411, -2219, -90, -6016, -3160, -7765, -2225, 307, -9508, -2980, -4024, -2636, -255, -5505, -3532, -2875, -3524, -1276, -2591, -5988, -3067, -5231, -1555, -1350, -8221, -4186, -8034, -1763, -1154, -3675, -7696, -8156, -2892, -1762, -1783, -8195, -7268, -4659, -2969, -1119, -3649, -6626, -3255, -4262, -1365, -2163, -6289, -1846, -4546, -1670, -1498, -6156, -1979, -4453, -425, -943, -4181, -3783, -5071, 723, -488, -2102, -7526, -5890, 759, -454, -991, -7736, -5490, -412, -1108, -886, -9249, -5507, -2500, -2611, -1753, -11330, -8110, -3541, -4951, -3085, -6498, -11560, -2818, -6163, -3838, -5476, -7744, -1613, -4473, -4503, -4895, -10538, -787, -3815, -4152, -4471, -9289, -772, -5325, -2438, -4617, -7042, -1681, -12156, -1011, -4078, -11124, -3652, -4463, -221, -3429, -6484, -6516, -2117, -224, -4362, -3413, -8298, -1303, -1142, -8465, -2652, -10619, -1620, -3147, -4694, -2958, -9320, -3078, -5244, -2625, -3493, -7538, -4728, -4215, -2782, -3538, -7417, -5557, -4010, -5181, -3169, -3829, -6440, -6266, -8421, -2777, -1878, -4202, -11497, -4542, -2452, -1751, -2812, -4234, -3385, -2148, -2715, -2843, -2160, -3604, -1954, -2837, -3958, -1415, -4855, -2031, -2412, -5695, -1431, -6987, -2535, -2219, -6285, -1866, -8006, -3450, -1908, -5988, -2553, -5303, -4148, -2209, -7158, -3775, -2744, -4606, -3348, -12623, -6204, -1360, -6610, -3959, -7071, -11644, -1069, -13710, -4590, -5496, -9894, -1583, -5968, -8329, -6387, -6163, -2172, -4522, -6894, -9424, -4457, -2212, -4798, -3904, -7938, -4179, -2202, -6264, -3431, -5745, -5168, -2666, -9482, -4409, -5407, -7155, -4061, -10419, -6791, -6801, -8847, -7855, -5501, -8849, -10972, -7787, -7849, 11195, 15123, 10025, 6099, 8571, 11019, 14694, 9644, 5733, 7741, 10391, 13372, 8577, 4369, 4786, 9563, 11038, 6931, 1192, -2344, 9374, 7356, 4436, -3542, 1962, 9099, 3349, 1630, -2046, 1944, 7586, 6115, 2811, -531, 935, 5291, 7372, 2914, 1121, 1036, 6408, 7321, 1143, 1454, 2072, 7296, 6291, 1497, 1177, 3087, 6928, 5468, 3598, 1443, 4050, 5664, 5714, 4290, 2105, 4939, 3856, 6142, 3746, 2319, 5591, 727, 6849, 1885, 1557, 5915, -7395, 7137, -2519, -389, 5801, -1126, 6483, -4415, -2680, 5201, -1921, 4721, -769, -2403, 4188, -739, 1647, -162, -594, 2599, 794, 821, -656, 91, -466, 1178, 2644, -1822, -1098, -11217, 1390, 3262, -1618, -5779, -4820, 1147, 2935, 896, -7053, -5800, -464, 1555, 2522, -6062, -6045, -5268, -1479, 3020, -9656, -3864, -1743, 964, 2638, -5107, -3853, -203, 3374, 1760, -4036, -6396, -1279, 3921, 776, -4029, -16551, -3809, 2968, -236, -3220, -8143, -3589, 368, -1465, -2442, -7889, -10233, -2711, -3780, -2795, -5569, -709, -936, -8300, -5686, -3273, 2446, 737, -3423, -7181, -2279, 3543, 1442, -1155, -2180, -1762, 3392, 861, 137, -815, -746, 2232, -1795, 961, -896, 52, 239, -5979, 1433, -1863, -189, -2099, -897, 1622, -3121, -1718, -3985, 551, 1557, -3537, -2905, -5520, 686, 1261, -2232, -1677, -7394, 27, 715, -885, -1237, -8488, -1059, -213, -377, -2039, -4980, -2121, -1747, -830, -4073, -2595, -3249, -4097, -2325, -6630, -1691, -4229, -7405, -4772, -5486, -2005, -3586, -7187, -7279, -4017, -3260, -3248, -4533, -7752, -3357, -5022, -4191, -3047, -4702, -3228, -5988, -5489, -2174, -3104, -3376, -4316, -6122, -1603, -2904, -3414, -2785, -8958, -1317, -3641, -3062, -2009, -8828, -1351, -4858, -2576, -1824, -4507, -1595, -6319, -2447, -2153, -3322, -1869, -7238, -2943, -2892, -4009, -2192, -6063, -3927, -4048, -7471, -2810, -5060, -5006, -6336, -7996, -4013, -5153, -6513, -12027, -5008, -6226, -6290, -9703, -6730, -4456, -10684, -7420, -12876, -5063, -4618, -8828, -6957, -13355, -4465, -4695, -6007, -6580, -10569, -3031, -4757, -4748, -6951, -6650, -1852, -5345, -4392, -8115, -5484, -1897, -6110, -5073, -11001, -5880, -3632, -5574, -7318, -9674, -5604, -9235, -5218, -9011, -7118, -4163, -8010, -6298, -7697, -7118, -3950, -7467, -7900, -8856, -9572, -5670, -9525, -7093, -9777, -8870, -11966, -4224, -6722, -7543, -6720, -9695, -2019, -7078, -7268, -6368, -8813, -1415, -6884, -7908, -6644, -10736, -2124, -5611, -8390, -6536, -9810, -4488, -4537, -9472, -6533, -7881, -9121, -4070, -12403, -7430, -6232, -5549, -3898, -14521, -8280, -5120, -4089, -3925, -8328, -6393, -5058, -4425, -4379, -6126, -4521, -6278, -5827, -5537, -5533, -3452, -9027, -5927, -8372, -6073, -3144, -11883, -5083, -12795, -7374, -3693, -10706, 7471, 1317, 4615, -14033, 6451, 6761, -946, 3861, 2250, 6218, 4361, 2064, 1361, 3975, 5565, 1245, 4653, -2752, 3802, 4901, 3821, 4949, -1612, 2915, 4689, 5122, 3530, -928, 2833, 4410, 5379, 619, -784, 3273, 3654, 5126, 1850, -228, 3372, 2809, 4595, 4245, 1260, 3195, 2679, 3317, 5555, 3236, 3066, 3585, 2570, 6007, 4835, 3199, 5060, 5802, 5615, 5821, 3574, 6185, 7650, 4281, 6151, 3833, 6600, 8050, 1836, 5719, 3310, 6301, 7191, -1342, 4359, 947, 5430, 4988, -2155, 1953, -4581, 4275, 1230, -1996, -855, 1888, 3139, -1090, -3080, -2669, 3627, 1920, -848, -2718, -4740, 3998, -120, -600, -370, -6840, 3703, -4798, 942, 482, -5468, 3139, -1418, 2099, 270, -1744, 2580, 254, 2134, 83, 206, 1939, -599, 1174, 971, 901, 592, -4386, -109, 2158, 709, -1687, -3201, -668, 2771, -56, -1057, -2015, -653, 2568, -1020, 370, -4131, -1203, 1562, -1873, 813, -8413, -3746, 260, -2548, 481, -4924, -3734, 66, -3146, -998, -6771, -975, 696, -3602, -5177, -5184, -1115, 1081, -3284, -2797, -2198, -5771, 1062, -1997, 6, -1363, -1954, 769, -720, 941, -1541, 928, 396, -202, 718, -2197, 1581, 51, -822, -701, -3020, 1164, -226, -3019, -3831, -3029, 261, -275, -7997, -4819, -2221, -863, -369, -19659, -2074, -2177, -2305, -1211, -8690, -561, -3244, -3692, -3153, -4836, 423, -3537, -3659, -4844, -3733, 1030, -1982, -2668, -3175, -3808, 1179, -958, -1967, -1121, -3089, 819, -892, -1758, -304, -2016, 0, -1850, -1648, -1034, -1839, -1084, -3559, -1352, -3952, -2599, -2187, -4248, -1182, -6726, -3883, -3331, -3728, -1352, -4597, -5022, -4866, -3655, -1972, -5668, -6061, -5979, -4598, -3524, -7075, -7941, -4363, -6821, -7352, -4790, -10153, -3141, -8647, -7694, -4560, -8181, -3059, -8163, -5139, -5967, -6999, -3522, -7499, -4662, -4430, -7789, -3323, -7236, -5095, -2678, -13015, -2370, -8770, -6402, -2326, -8020, -1428, -15172, -5738, -2779, -5912, -718, -6714, -3872, -3293, -6246, -269, -4852, -3756, -3844, -8584, -248, -5726, -6181, -5197, -8974, -895, -9090, -9187, -7961, -7599, -2222, -3604, -4499, -7550, -8094, -3415, -1637, -3358, -5196, -9103, -3766, -1415, -3280, -4638, -8634, -4531, -2375, -3022, -6155, -8514, -6723, -3882, -2388, -12957, -8294, -10702, -4611, -2183, -6208, -6294, -8596, -4624, -3030, -4294, -4482, -6502, -4505, -5533, -4369, -3588, -5140, -4437, -9778, -5678, -3492, -4094, -5129, -8125, -5901, -3924, -3454, -7825, -6824, -5268, -4546, -3504, -13669, -6096, -6415, -5086, -4449, -6758, -6129, -8657, -5754, -5507, -5122, -6649, -5868, -7418, -4495, -4525, -6668, -4849, -10128, -3423, -4501, -6654, -5680, -9210, -3299, -5553, -7664, -8110, -9114, -4008, -9971, -8777, -8515, -9887, -5323, -8213, 2153, 1795, 3912, 3587, 5834, -1016, 1537, 4466, 5109, 5613, 2066, 1108, 5719, 6749, 5662, 4755, 1217, 6345, 7241, 5840, 4602, 781, 5804, 6512, 5032, 2445, -1165, 4060, 4580, 2896, 1283, -330, 1412, 1818, 314, 2223, 989, -1502, -594, 801, 1915, 805, -2466, -1993, 3264, 2110, 52, 1217, -2491, 4804, 3837, -370, 3461, 1191, 5229, 5129, 1590, 4442, 3359, 5230, 5439, 3535, 4021, 3458, 5420, 4640, 4053, 1234, 1504, 5143, 2771, 2996, -656, -252, 3689, 1434, 58, 2848, 505, 725, 1598, -723, 3135, -993, -1702, 1350, 456, 1419, -4105, -508, 626, 15, -3113, -8520, -826, -156, -918, -6508, -1488, -4348, -47, -1237, -2357, 1393, -258, 649, -1318, -869, 2277, 2002, 1054, -1786, 235, 2361, 2321, 970, -2298, 985, 2258, 1436, 338, -2189, 1162, 1883, 110, -861, -1995, 521, 926, -600, -2784, -1977, -1188, -663, -1187, -5786, -2009, -2750, -2117, -1153, -5734, -2331, -1468, -1559, -424, -3789, -3391, -846, -124, -271, -2616, -5094, -1425, 568, -635, -1514, -7855, -2307, 193, -1079, -957, -6199, -1955, -1183, -242, -1688, -1225, -674, -3158, 874, -4361, 557, 144, -2714, 775, -2997, 622, 45, -932, -462, -885, -746, -456, -966, -1615, -916, -3384, 16, -3805, -3124, -3523, -8639, 1030, -4263, -9598, -4733, -6012, 1482, -1416, -4817, -1442, -2525, 1284, -727, -3537, -1493, -2039, 938, -420, -4252, -4997, -2887, 726, -354, -6085, -5058, -2260, 126, -945, -11731, -2710, -1154, -1202, -1769, -7325, -3777, -1094, -2891, -2222, -4635, -9826, -1999, -3706, -3273, -3883, -7014, -3719, -3379, -6908, -5244, -4869, -5933, -2992, -7082, -10324, -5168, -7420, -3277, -4263, -5530, -7436, -7158, -4667, -4579, -4126, -15350, -6271, -7759, -7094, -4505, -11147, -6313, -8923, -7329, -4495, -10853, -8293, -6150, -3947, -3008, -9408, -7699, -4367, -1877, -2408, -9026, -4849, -2898, -1183, -3101, -12385, -3941, -1949, -1875, -4788, -11231, -4544, -1903, -3954, -6879, -9517, -6720, -3039, -5178, -8548, -9850, -8467, -5021, -4193, -7323, -13018, -5354, -5141, -3844, -6560, -9112, -2811, -4752, -4008, -7486, -4419, -1606, -4762, -4680, -7503, -2441, -1777, -4502, -5971, -6081, -1754, -3403, -4646, -6904, -7030, -1869, -5849, -5379, -6375, -17535, -2471, -5899, -5749, -5793, -5734, -3495, -5789, -5025, -5445, -3960, -5428, -6367, -4398, -4889, -4138, -9359, -7064, -5009, -4619, -5597, -7328, -7851, -7654, -5160, -7970, -5438, -9383, -9530, -6483, -9446, -5387, -12105, -8456, -7893, -9236, -6564, -11607, -10606, -7852, -10832, -7544, -11498, -9134, -6662, -15210, -6070, -8433, -6344, -5589, -10395, -4950, -6170, -5338, -4885, -8898, -5055, -5460, -5829, -4232, -8021, -6466, -5481, -9062, -3557, -8159, -9262, -5154, -10191, -3290, -10077, -5350, -5843, -8811, -5320, -9128, -7464, -3738, -10143, -7960, -8100, -9496, -3235, -12739, -9271, -7889, -5974, -4061, -12627, -9218, -7999, -4389, -6014, -9309, -7709, -7663, -4306, -6351, -8323, -6228, -6876, -6256, -4848, -8023, -5981, -6369, -22941, -3874, -7185, -6829, -7207, -7048, -3467, -7086, -8196, -10378, -6642, -3479, -9258, -9857, -7156, -11084, -3651, -9220, -14935, -5104, -7677, -3819, -5829, -12594, -4775, -5058, -4090, -4704, -10755, -5069, -4478, -4545, -4855, -12465, -4925, -4561, -5231, -5501, -8389, -4510, -4559, -6212, -5288, -5943, -4715, -4564, -6756, -4783, -5362, -6670, -5045, -5267, -4956, -6155, -12391, -5872, -3268, -5009, -7774, -4679, -6195, -2051, -4210, -7952, -2658, -5427, -1662, -3561, -6643, -2372, -4257, -1872, -3409, -5854, -3374, -3473, -2318, -3894, -6110, -5644, -3255, -2620, -5374, -7144, -8270, -3633, -2712, -6792, -7214, -7604, -4796, -2792, -5905, -6319, -6949, -7097, -2972, -6274, -5927, -6965, -8726, -3185, -10383, -6426, -6650, -7111, -3338, -7288, -8155, -5905, -6216, -3604, -4812, -10773, -5450, -6311, -4407, -4748, -8935, -5538, -7599, -6173, -6452, -7096, -5857, -10204, -9091, -10233, -5895, -5855, -9265, -11213, -18393, -4744, -5604, -7013, -10177, -15188, -3829, -5427, -5872, -8567, -13044, -3467, -5386, -5846, -7906, -14226, -3806, -5568, -7225, -8231, -15640, -4867, -6064, -7962, -8570, -15315, -6491, -6603, -5666, -8093, -12325, -8361, -6551, -4535, -7626, -8564, -10203, -5893, -4544, -7566, -6681, -10950, -5123, -5408, -7591, -5847, -10538, -4421, -7186, -7343, -5592, -11590, -3902, -11545, -6836, -5673, -13925, -3799, -10239, -6406, -6118, -7636, -4267, -5771, -6545, -7258, -5346, -5225, -3950, -7375, -9963, -4827, -6336, -3422, -8649, -19154, -5777, -7520, -3945, -11323, -9199, -8682, -8992, -5413, -13915, -6826, -13591, -9162, -7564, -8499, -5978, -9332, -7473, -9923, -7084, -6291, -8315, -6112, -12872, -7505, -7801, -8927, -5640, -20680, -9918, -9336, -11811, -6077, -12715, -18131, -8541, -12484, -7082, -9311, -15387, -8505, -8095, -7985, -7318, -16632, -10172, -6551, -8789, -6129, -15036, -11625, -6071, -10040, -5623, -14149, -10038, -5712, -12652, -5786, -8795, -8596, -5150, -17093, -6398, -6442, -7428, -4844, -10921, -6799, -6098, -6908, -5106, -9167, -6896, -7377, -7247, -5934, -9277, -6995, -10019, -8436, -7206, -11837, -6677, -11714, -9005, -8900, -14474, -6423, -10326, -7606, -10715, -8786, -7193, -9644, -7153, -10266, -6949, -9861, -9951, -8611, -9436, -6413, -15358, -10963, -12247, -10379, -6633, -11458, -15410, -11217, -13295, -7154, -11108, -12643, -12588, -9742, -7396, -11499, -9731, -11903, -7479, -7161, -11064, -10301, -8998, -6598, -6914, -11898, -16542, -9630, -6623, -7180, -13601, -11254, -10157, -7547, -8109, -9983, -8363, -6865, -9548, -8945, -8289, -6601, -5682, -12160, -8646, -8391, -5706, -5913, -11865, -8276, -10447, -5925, -6935, -9121, -8354, -7604, -6798, -9462, -6838, -4716, -6822, -6549, -8462, -7693, -4000, -6594, -7895, -6769, -7586, -4973, -6013, -8419, -5617, -7780, -7360, -5270, -5937, -5635, -9492, -7264, -4908, -4523, -7270, -15655, -6850, -5062, -4234, -9884, -13528, -8888, -5614, -4852, -7523, -10928, -7270, -6215, -5311, -6747, -7114, -4923, -6566, -4600, -7739, -4724, -4564, -7040, -4242, -8549, -3727, -5943, -8435, -4850, -7798, -3812, -9394, -9503, -6331, -8229, -4845, -8458, -8618, -8332, -10959, -6702, -8161, -9438, -10704, -9777, -8455, -12745, -8288, -18293, -7542, -8917, -6757, -5409, -10329, -7475, -8013, -4059, -4109, -6316, -7180, -5499, -2730, -3871, -4034, -4328, -3872, -1852, -4352, -2859, -2390, -3590, -1313, -5337, -2758, -1733, -4776, -1285, -6561, -3900, -2343, -8214, -2047, -8071, -6182, -4479, -13300, -4172, -9847, -5768, -6314, -8925, -10777, -7609, -4552, -4439, -8330, -7203, -5519, -4559, -3779, -8590, -5127, -4699, -4959, -4239, -9071, -5260, -4944, -4503, -5149, -10096, -6423, -6439, -3922, -5556, -12913, -7777, -9690, -4341, -5107, -11462, -9815, -12056, -6622, -4521, -7703, -10977, -13298, -11830, -4439, -5979, -7696, -10712, -5605, -5086, -5555, -6830, -6915, -3485, -6244, -6340, -8277, -5108, -2779, -6934, -8530, -14756, -4508, -3014, -6373, -12795, -8122, -4962, -3946, -5447, -20497, -5840, -6385, -5337, -5108, -16593, -5327, -8387, -7255, -5739, -11819, -6191, -10161, -7649, -7019, -10547, -9152, -10066, -5847, -6470, -14486, -10060, -8501, -5217, -5286, -9341, -5770, -7874, -5880, -5256, -5970, -3900, -8430, -7759, -6395, -5144, -3241, -9640, -11092, -7933, -6040, -3405, -10804, -14053, -8638, -9004, -4054, -13237, -11551, -9299, -12484, -5009, -14033, -10711, -9999, -8460, -6175, -9999, -11959, -10288, -7217, -6379, -8146, -14966, -9243, -7447, -6123, -7424, -10787, -8123, -8228, -7030, -7654, -9525, -8109, -7544, -8848, -8383, -10883, -8998, -5887, -8280, -8208, -19806, -10114, -4968, -7492, -8023, -12012, -11740, -5422, -7524, -9341, -8940, -12506, -8279, -6865, -13448, -6894, -7999, -13915, -5800, -15544, -6065, -5780, -8611, -5322, -10285, -6815, -5080, -9507, -5177, -8316, -10562, -5325, -9006, -5229, -8222, -10018, -6044, -6886, -5836, -10249, -6882, -7736, -7052, -6820, -14958, -6880, -13252, -7863, -7128, -11928, -9877, -7676, -7032, -6802, -11699, -13657, -5602, -7377, -6714, -12093, -8943, -5430, -10822, -6575, -10612, -8469, -6471, -9368, -5754, -10230, -9748, -8396, -7060, -5243, -10757, -16112, -9310, -7211, -5730, -10197, -11386, -7731, -8958, -7499, -9370, -9610, -6667, -10252, -10601, -8998, -11204, -6622, -9982, -9833, -8612, -10396, -7354, -10764, -8613, -8016, -8505, -7972, -13083, -8838, -7443, -9133, -7421, -22329, -9933, -7356, -13400, -6717, -12747, -10748, -8053, -11388, -6577, -9403, -10115, -9711, -8863, -6951, -8050, -9368, -13137, -8426, -7709, -8026, -9329, -16157, -9241, -8961, -9285, -10204, -10665, -4364, -6294, -3836, -7219, -9365, -3929, -6002, -5580, -4914, -8936, -4243, -7687, -8215, -4495, -10010, -5284, -8697, -7519, -5838, -12775, -6430, -8266, -7565, -10654, -11040, -7006, -10283, -10751, -9930, -10448, -7897, -13324, -7606, -7022, -9663, -9744, -8958, -4818, -6295, -6927, -10911, -7584, -3691, -5889, -5940, -10517, -7192, -3582, -5363, -7219, -9895, -7168, -4360, -5180, -9619, -8691, -7961, -5198, -5803, -5978, -7237, -10391, -4804, -7380, -4833, -6109, -10396, -4192, -9450, -5547, -5263, -9089, -3209, -10289, -6763, -4585, -6318, -1948, -8639, -6093, -4576, -4159, -1231, -6172, -5231, -5832, -3620, -1236, -4528, -3804, -6468, -4263, -1849, -3621, -2225, -4256, -4723, -2965, -2791, -1475, -3322, -4411, -4578, -1826, -1700, -3905, -4468, -6272, -1273, -2831, -6034, -4816, -5906, -1430, -4717, -8818, -4714, -4902, -2262, -6920, -8330, -4036, -4736, -3635, -8333, -7975, -3348, -5249, -4955, -8431, -7728, -2994, -6889, -5195, -8476, -6570, -3102, -13434, -5928, -9587, -5214, -3852, -6093, -7567, -11295, -4506, -5399, -3752, -5774, -9771, -4808, -6523, -3233, -4852, -8863, -5962, -6095, -3654, -5989, -8809, -6196, -6473, -4103, -7589, -9073, -5738, -7981, -4108, -5257, -8939, -6148, -8299, -4780, -3803, -6527, -6477, -6990, -7861, -3288, -4499, -6232, -6105, -10866, -3259, -3479, -6646, -5314, -6065, -3503, -3374, -7567, -4174, -5087, -3853, -4226, -8037, -3362, -5254, -4256, -6220, -8814, -3278, -6154, -5008, -9116, -10928, -3834, -7891, -6764, -9195, -9869, -4800, -10372, -11778, -8982, -7745, -6119, -11778, -10249, -10527, -7539, -7762, -9666, -7519, -11275, -9557, -9285, -7147, -7933, -10382, -14017, -13071, -6178, -12286, -10424, -9186, -10255, -7514, -11687, -8993, -7492, -6503, -9128, -10698, -7872, -7326, -5508, -4999, -16246, -7830, -8372, -6157, -3467, -8183, -8341, -9524, -8154, -3266, -6474, -8933, -10035, -9500, -3579, -6851, -9384, -10592, -9732, -3931, -8966, -10573, -9352, -10725, -4621, -8411, -12677, -8166, -8141, -5573, -6177, -10671, -6396, -7005, -5019, -5664, -8539, -4903, -7998, -4353, -6129, -7154, -4439, -8108, -5015, -6479, -6239, -4922, -6675, -6239, -7302, -5595, -5903, -7161, -5943, -9650, -5466, -6010, -10543, -6084, -7520, -6087, -5225, -15220, -7054, -5292, -6691, -4902, -11189, -6657, -4647, -6504, -5288, -11743, -5961, -5358, -6616, -6282, -13219, -6286, -7658, -6664, -7806, -14203, -7961, -9002, -6051, -8918, -12693, -12553, -6606, -6071, -8136, -9552, -11452, -5097, -7414, -7769, -7945, -8942, -4260, -9978, -9190, -7114, -9340, -4201, -10764, -13846, -5954, -15349, -5477, -9096, -10039, -4706, -9028, -10172, -7495, -8385, -4112, -5674, -7674, -6897, -8848, -4367, -4294, -4688, -7419, -10627, -5427, -3950, -3679, -8725, -9351, -7109, -4392, -3577, -9706, -6925, -9179, -5632, -4123, -9339, -5498, -11658, -7746, -5061, -8542, -4782, -13051, -8615, -5995, 10207, 11289, 9083, 11137, 8447, 9430, 10944, 8381, 10592, 8026, 7216, 9886, 6198, 8985, 6673, 6633, 8129, 4138, 6584, 4431, 7475, 6153, 5042, 4490, 3804, 6993, 5102, 5109, 3740, 4357, 5154, 4561, 3913, 3153, 3361, 3044, 3469, 1068, 2251, 46, 5734, 1797, -3758, 2245, -1866, 7030, 564, 1773, 1725, 1478, 6789, 625, 3127, -1614, 3713, 6222, 488, 3036, -562, 5623, 5979, 1255, 3515, 3295, 6951, 4547, 3822, 4257, 4597, 7390, -822, 4900, 3891, 4550, 6732, 826, 4401, 2104, 3719, 4627, 2534, 2473, -938, 2962, -219, 1731, -34, -1834, 2546, -1652, 296, -325, -1352, 2012, -161, 110, -52, -1516, 1491, -1138, 1025, -483, -1726, 1399, -1913, 1741, -1410, -987, 1403, -1115, 1689, -1125, -40, 831, -211, 353, 543, -80, -702, -268, -1854, 1470, -1423, -4196, -1443, 1014, 1393, -2236, -3751, -2075, 2777, 588, -92, 156, -1659, 3229, -489, 1328, 1353, -2081, 2877, -1334, 1669, 744, -1109, 1810, -1551, 1024, -2013, 743, 890, -1334, -573, -3908, 1664, 2001, -1130, -2663, -2071, 1890, 2865, -872, -2943, -3700, 1837, 2831, -270, -1210, -6507, 1574, 2720, -90, 239, -577, 784, 2899, -1803, 1098, 983, -818, 2646, -5786, 1519, 789, -3360, 1812, -615, 1551, -667, -9003, 940, 404, 1184, -1470, -3667, 193, -742, 497, -1471, -710, -601, -2693, -262, -4084, 478, -929, -1549, -687, -2203, 1135, -674, -381, -561, 895, 1537, -720, -271, -731, 1593, 1380, -1903, -1418, -2215, 596, 488, -5180, -3958, -6036, -2502, -1253, -8537, -4943, -11206, -5160, -4763, -5640, -3247, -5166, -1946, -7933, -5692, -1330, -1766, -398, -2854, -7819, -79, -219, 665, -1759, -10432, 51, -41, 1234, -2617, -5774, -1231, -1204, 1088, -5262, -3406, -5013, -4180, 88, -4682, -2510, -7221, -6368, -1986, -2630, -2390, -4973, -4483, -5984, -1756, -2469, -4899, -4610, -6454, -1856, -2687, -3228, -6005, -3629, -3222, -3783, -2565, -6734, -2752, -7600, -6444, -3639, -5262, -2601, -7169, -2645, -4663, -2591, -2349, -4601, -60, -3248, -847, -1804, -5712, 1000, -2539, -362, -1421, -7959, 1097, -3055, -943, -1731, -5327, 408, -4410, -1942, -2930, -5813, -1139, -4321, -2170, -3867, -7668, -4112, -3678, -1571, -3272, -4025, -6533, -4260, -973, -2701, -2626, -3591, -6282, -1033, -2514, -2780, -2551, -9603, -1826, -2444, -3987, -2360, -8058, -2500, -2464, -5667, -2311, -6635, -2500, -3015, -6611, -2884, -7232, -2174, -4393, -6850, -3689, -11287, -1442, -5914, -7380, -1876, -8607, -1157, -5547, -5864, -537, -7727, -2009, -4643, -3494, -603, -8298, -4132, -4745, -2530, -1954, -3908, -5005, -6482, -3294, -4320, -2201, -3564, -8216, -7161, -5690, -2257, -2733, -6127, -9394, -4781, -2998, -2583, -3481, -7349, 5426, 7847, 9313, 7297, 4636, 5085, 7058, 8906, 6891, 6119, 4043, 4658, 7771, 5909, 7459, 2156, 2417, 6234, 5217, 7788, -1435, 1624, 5049, 5095, 7408, -7233, -3838, 4569, 4327, 6644, -901, -94, 3901, 1247, 5628, 546, 2292, 3526, -2961, 4485, 1089, 2669, 4078, 1769, 4119, 257, 2406, 3876, 672, 4579, -46, 2191, 2664, 96, 5252, 4383, 2794, 2833, 4355, 5809, 6437, 3970, 3823, 5731, 5659, 6971, 4748, 3719, 5315, 4453, 6348, 4851, 2532, 2791, 2260, 4618, 4379, 1086, -8967, 813, 1747, 3504, 474, 1170, 1665, 656, 2502, -629, 2487, 2435, 1586, 1424, -1338, 2665, 2198, 903, -639, 1323, 2723, 670, -3224, -1740, 2583, 2562, -3183, -2303, 757, 2232, 1425, -3889, 1318, 1349, 528, -629, -666, 2355, 216, -310, 590, -34, 2543, -2223, 1015, 1222, -286, 2181, -3519, 1729, -234, -448, 874, -4004, 1344, -1421, -769, -2573, -5363, -1150, -254, -1731, -6367, -5754, -2257, -787, -1895, -884, -4020, 1781, -3247, -481, 896, -1826, 2605, -3712, -117, 1559, -668, 1196, -2059, -1999, 1519, -1375, -2616, -1751, -10551, 1487, -6260, -456, -2258, -1066, 1966, -3019, 589, -2636, 819, 2356, -1004, 39, -3487, 1438, 2445, -993, -1235, -4447, 1845, 2441, -462, -2703, -3742, 2280, 2201, 496, -1995, -2080, 2322, 1166, 981, -201, 444, 1756, -1499, 868, 431, 1756, 806, -3667, -112, -238, 1637, -78, -1968, -1412, -2136, 109, -646, -3260, -733, -5007, -2825, -1485, -9342, 109, -10058, -5639, -4041, -4338, 254, -9527, -5977, -12869, -2969, 285, -5502, -5068, -4607, -1379, 469, -3507, -3972, -3367, -219, 405, -2348, -2465, -3265, -347, -173, -1863, -1051, -3589, -1807, -931, -1612, -414, -4401, -4781, -861, -1242, -673, -5615, -13421, -194, -944, -1880, -6549, -7062, 327, -1004, -4253, -7672, -4454, 748, -1496, -5510, -13924, -3132, 923, -2578, -3646, -7889, -2116, 404, -5211, -3170, -5116, -1094, -1253, -7590, -3962, -4729, -190, -4422, -3925, -4724, -5366, 176, -4380, -3646, -4135, -5588, -196, -2938, -6095, -2935, -4876, -1312, -2734, -8116, -2162, -4472, -3171, -3102, -10162, -2307, -5976, -5890, -3760, -5903, -3491, -9974, -7713, -4368, -1577, -6112, -5954, -5608, -3784, 30, -7232, -4160, -3885, -2656, 375, -4147, -1974, -3448, -2591, -104, -2696, -669, -4437, -3507, -1342, -2292, -787, -6889, -3156, -3878, -2933, -2172, -8951, -2564, -14786, -4893, -3482, -6806, -3435, -5097, -4805, -2796, -4327, -5656, -3335, -3204, -1890, -3247, -6490, -4428, -3529, -1462, -2997, -4216, -10286, -6461, -1467, -2295, -3052, -2273, -15047, -1709, -1113, -4487, -3, -7242, -1887, -336, -7340, 491, -3356, -2034, -380, -1820, -228, -857, -2469, -1405, -209, -1899, 295, -2879, 9652, 7124, -6527, 7067, 8584, 9372, 7627, 4321, 7288, 8635, 8507, 8128, 6618, 7542, 8691, 6993, 7912, 7318, 7372, 8450, 5156, 7030, 7061, 6655, 7534, 4824, 5754, 6076, 5354, 5562, 5020, 4152, 4597, 3849, 2168, 3748, 1157, 3080, 3905, -862, -888, -4556, 1962, 4386, 440, 1776, 1834, -482, 3628, 2068, 4814, 2591, -2346, 2446, 1044, 6083, 3325, 3300, 3420, -8072, 6245, 4934, 4483, 3509, 1315, 5062, 5033, 2977, 2414, 1922, 1231, 2650, -7803, 3735, 4001, -994, -396, 3097, 4750, 6221, 2117, 3058, 4447, 4182, 6836, 1332, 3289, 3808, 2267, 6175, -2967, 1953, 2041, -705, 4531, -3984, 268, 555, -6472, 2323, -252, -245, 1111, -3071, 1547, 589, 90, 2149, 168, 2513, -158, -521, 2545, 1469, 3099, -3443, -3551, 2239, 1852, 3305, -5347, -5659, 1439, 1681, 3407, -1643, -2718, 664, 1044, 3140, -836, -3775, 451, -421, 1750, -909, -8705, 356, -2317, -2939, -1755, -3895, 55, 313, -1306, -2954, -3244, 290, 2307, 1473, -2253, -2582, 1121, 2993, 1894, -1241, -812, 1586, 2776, 1418, -694, -196, 1431, 1897, 301, -354, -91, 871, 447, -2935, -300, 497, 132, -1759, -1713, -692, 664, -1077, -5634, 1413, -1322, -130, -2534, -9987, 2011, -1774, -1518, 21, -4793, 692, -783, -4924, 2058, -2960, -3722, 1082, -4365, 2653, -2402, -2916, 1796, -616, 2184, -3321, -672, 892, -837, 1125, -5352, -197, -2158, -4373, -104, -2044, -116, -4696, -799, -1885, 108, -455, -3788, 609, -3943, 912, -1172, -5821, -365, -3853, 922, -1494, -10726, -3632, -4144, 351, -1992, -13746, -7281, -6012, -870, -4088, -7003, -8955, -9928, -2215, -10930, -4801, -4130, -9607, -1677, -6667, -4013, -2026, -7841, -1256, -4379, -3478, -2305, -7516, -2244, -2726, -3069, -5169, -7457, -3927, -1566, -3072, -5952, -8071, -4662, -1407, -3683, -3284, -12012, -6466, -2627, -5559, -2466, -8503, -8260, -7049, -12068, -1939, -6263, -5644, -5535, -5532, -1498, -8145, -3326, -1547, -2922, -1460, -8897, -1785, -83, -2035, -1681, -3586, -1615, 262, -2335, -1801, -1720, -3506, 34, -3925, -1776, -1105, -7138, -351, -7320, -2071, -1136, -2049, -1030, -13759, -3510, -1246, -409, -2428, -11366, -7703, -1434, -345, -3435, -6548, -4630, -2223, -1301, -2075, -4725, -2506, -3777, -3015, -810, -3991, -2467, -5095, -5961, -163, -3725, -3751, -5199, -6350, -106, -4025, -4216, -6003, -3078, -822, -4461, -2049, -9318, -1990, -2599, -3994, -206, -8426, -2517, -5395, -3002, 684, -5990, -5066, -4987, -2271, 701, -4272, -9414, -2754, -1898, 125, -2779, -4829, -1562, -1654, -710, -2591, -4261, -1492, -1627, -1909, -3583, -5441, -2417, -2053, -3650, -2863, -2625, -3523, -2894, -4334, -1597, -473, -3340, -4067, -3633, -1699, 232, -2580, -4067, -2308, -3084, -1180, -6092, -4239, -1293, -4354, -36, -2800, -3728, -1102, -5333, 72, -1672, -1911, -1753, -4297, -556, -1852, -986, -3200, -4189, -1704, -2067, -1346, -5424, -6356, -3116, -1528, -2690, -6495, -5987, -3808, -981, -3077, -4233, -4180, -3316, -640, -2510, -2383, -6287, -2277, -429, -2864, -1384, -5192, -1512, -475, -3355, -1349, -966, -1403, -881, -2271, -2630, 389, -1847, -1543, -1237, -4508, 338, -2645, -1930, -979, -2698, -646, -3822, -1645, -1614, -1494, -1975, -5789, -1433, -3747, -1685, -2633, -8070, -1757, -8432, -3345, -3061, -5691, -1998, -3004, -8269, -4698, -4254, -1247, -599, -4812, -2980, -4254, -336, 249, -2421, -411, -4544, -81, -145, -2301, 396, -4487, -860, -1777, -4124, -241, -4998, -3200, -3160, -8355, -2338, -5146, -7469, -2295, -9141, -5032, -3662, -5895, -1874, -5905, -5154, -2514, -5081, -2382, -4328, -6181, -2148, -4711, -4073, -4849, -8862, -2655, -3913, -8250, -4878, -8104, -4369, -3010, -6854, -3375, -5052, -6610, -2190, -4762, -2965, -3345, -5969, -1668, -5101, -3189, -3193, -5337, -1630, -7802, -3245, -4524, -4370, -2125, -8453, -3168, -6898, -3635, -3126, -6650, -3888, -6152, -4153, -4874, -7013, -7049, -4643, -6797, -8176, -7959, -7043, -4792, -14044, -4507, -7943, -3770, -7443, -6466, -1643, -7323, -3277, -7378, -5406, -580, -7269, -4736, -4354, -6025, -960, -8876, -6648, -4096, -7668, -2995, -12681, -3646, -6702, -9556, -6765, -12470, -1753, -6742, -7613, -4703, -9559, -975, -2850, -4852, -3019, -7457, -1062, -1342, -2897, -2641, -6713, -1993, -831, -1659, -2941, -6644, -3833, -972, -1070, -3118, -6411, -6991, -1778, -1119, -3081, -6290, -8705, -2943, -1677, -3203, -7092, -5220, -2945, -2155, -3704, -7188, -3990, -2399, -2346, -4409, -5589, -4399, -2796, -3158, -4166, -5033, -6164, -4740, -5073, -3487, -5275, -8020, -9252, -5519, -3013, -5280, -7049, -6241, -4112, -2602, -5002, -4342, -4485, -3499, -2209, -5353, -2726, -3989, -3586, -1779, -7542, -2447, -3624, -4131, -1538, -10178, -3316, -3414, -4716, -1680, -6510, -4780, -3717, -4943, -1959, -5807, -5592, -4417, -5193, -2187, -6896, -5312, -4970, -5971, -2826, -9528, -4553, -5374, -7619, -4631, -11720, -4032, -6466, -10981, -9776, -9626, -3596, -7883, -7643, -7926, -9450, -3189, -6556, -4514, -5081, -10063, -3555, -5838, -3001, -4330, -5326, -5705, -6934, -2437, -4379, -3222, -13828, -8629, -2534, -4638, -3081, -6308, -7829, -3122, -4884, -4988, -4575, -8347, -4172, -5425, -12266, -3980, -12652, -5641, -6592, -8644, -3517, -9681, -6087, -8262, -6792, -3360, -7437, -5156, -9033, -6179, -3928, -7239, -4846, -7804, -6242, -5451, -7585, -5468, -6124, -7393, -7578, -6948, -6962, -4992, -10180, -8464, -5689, -10150, -5007, -9271, -9298, -5037, -12223, -7211, -6436, -12225, -5674, -6543, -12220, -5783, -11803, -8592, -4992, -5941, -3157, -170, -3957, 419, -2841, -3929, -1142, -4620, -314, -3270, -2281, -2919, -3992, -1859, -5558, -532, -5426, -4294, -4450, -10597, 248, -5391, -4548, -9407, -3583, -35, -3340, -3159, -7880, -1402, -1515, -2693, -2726, -6853, -692, -4796, -3774, -3899, -7827, -1072, -6084, -8339, -5251, -6331, -2497, -3400, -7077, -4072, -4268, -4882, -2502, -4276, -3589, -3245, -7636, -2608, -3600, -4090, -3282, -9546, -3455, -3308, -4841, -4708, -8275, -4656, -2979, -5731, -9120, -5274, -5088, -2714, -6845, -9933, -3065, -4837, -2564, -7328, -5654, -1960, -4820, -2365, -6734, -3859, -2256, -5088, -1539, -5890, -4024, -4679, -4334, -322, -4506, -10133, -2871, -2397, 300, -2445, -3656, -186, -1113, -244, -1247, -620, 543, -552, -2311, -1136, 177, -4, -276, -3337, -1706, -466, -1231, -500, -2301, -2313, -2774, -2075, -2132, -3227, -2650, -6498, -2054, -7939, -3448, -2781, -5073, -1721, -3973, -1305, -3086, -6035, -1765, -1945, -533, -4356, -16899, -2541, -1818, -706, -6369, -5265, -4491, -2578, -1216, -4346, -3699, -10344, -3971, -1983, -3044, -4514, -7241, -6979, -2824, -3433, -10366, -5372, -9833, -3742, -6117, -5688, -5513, -3639, -6728, -9176, -3372, -5632, -1562, -6172, -3954, -3871, -4747, -992, -3247, -2446, -7278, -3462, -1548, -3282, -1876, -5573, -2696, -2417, -4861, -1604, -2894, -2699, -1627, -3137, -1879, -1806, -3529, -636, -1494, -2835, -1315, -5640, -629, -1268, -3994, -1102, -7340, -1609, -2153, -4626, -1179, -3667, -3165, -4117, -4095, -1683, -1811, -4122, -7872, -3229, -2724, -1385, -3690, -10671, -2923, -4360, -2363, -2690, -6183, -3171, -6327, -5682, -2145, -4540, -3834, -6881, -12452, -2398, -4211, -4850, -5589, -7662, -2900, -5063, -5796, -4179, -7179, -2366, -6936, -5940, -3622, -3547, -1541, -6389, -6049, -4282, -2157, -1368, -4364, -7178, -6198, -2702, -2154, -3233, -9029, -6981, -5334, -4461, -2787, -7655, -3614, -9777, -7026, -2835, -5070, -1319, -8361, -4223, -3253, -3094, -448, -9863, -3240, -3538, -2131, -806, -18134, -3532, -2913, -2198, -1992, -9332, -4367, -2200, -3003, -2578, -7431, -5050, -2440, -3693, -2335, -6507, -5188, -4258, -3720, -2648, -5348, -4864, -6207, -3824, -3727, -4056, -4372, -4311, -4385, -5038, -3425, -3762, -4365, -5165, -6263, -3861, -2949, -5523, -5803, -7267, -5535, -2440, -3450, -6491, -6583, -7471, -2905, -2155, -7149, -5838, -7255, -5139, -2232, -6117, -5664, -7448, -9986, -3195, -5670, -6103, -9060, -5480, -4686, -7828, -7515, -11807, -4176, -6412, -10395, -8694, -8353, -4366, -7673, -6264, -7269, -4235, -5007, -7954, -5487, -5539, -2070, -5206, -7984, -5717, -4639, -1338, -5335, -9191, -5433, -4683, -1827, -6415, -13691, -4209, -5045, -3519, -8156, -12743, -3118, -4772, -6756, -6671, -9288, -2765, -4329, -8963, -6039, -8329, -3145, -4475, -6576, -7427, -8702, -3934, -5309, -6314, -5477, -3410, -3167, -66, -2262, -5855, -3498, -5408, -1286, -2858, -5521, -3041, -5328, -4032, -4533, -6361, -2287, -3867, -20243, -4777, -10200, -2155, -2661, -5044, -3543, -9783, -3018, -1798, -4161, -3724, -4886, -4616, -1429, -7303, -5895, -2396, -4869, -1700, -6545, -6492, -949, -3431, -2717, -2493, -2300, -565, -2311, -4681, -1593, -456, -1694, -1798, -8494, -2401, -264, -6883, -1563, -11681, -4056, -1761, -3721, -1230, -5505, -3650, -5053, -947, -821, -2387, -3506, -3741, -358, -624, -405, -3536, -2328, -642, -790, 472, -970, -2018, -1064, -1438, 77, 912, -1657, -583, -2990, -2015, 1734, -664, 340, -4616, -3717, 1779, 565, 722, -2975, -1722, 1200, 1446, 669, -2045, -1682, 17, 1739, 477, -2367, -3931, -1958, 1421, -69, -3265, -7861, -5522, 510, -1234, -3364, -5265, -17262, -914, -2866, -2765, -4489, -7162, -2282, -3834, -2555, -3742, -5362, -3331, -3263, -2447, -3105, -3817, -6616, -3147, -1883, -3630, -2625, -6406, -4667, -1269, -5446, -2050, -2187, -9455, -626, -7359, -1879, -1076, -5427, 148, -6831, -1534, -1283, -2948, 483, -4340, -944, -2099, -2338, -155, -3232, -947, -2821, -3413, -2428, -3920, -2179, -3242, -7184, -12341, -7016, -4100, -3160, -5233, -3558, -14145, -3318, -2490, -3249, -1710, -7597, -2832, -2170, -3325, -1787, -6355, -3936, -2602, -4810, -2898, -5908, -5624, -3795, -8726, -3745, -5841, -3629, -5146, -8145, -4212, -6266, -1858, -3569, -3990, -6194, -5008, -1244, -2718, -2468, -10348, -2920, -1426, -4559, -2215, -7165, -2210, -2518, -10184, -2919, -6182, -3111, -6181, -2783, -4790, -6442, -3864, -3545, -859, -16235, -6619, -1850, -595, -2, -3783, -5489, -641, 56, 310, -930, -3593, -440, -895, -13, -139, -2242, -907, -3589, -963, -691, -2010, -1697, -8947, -1732, -1890, -2865, -1927, -12190, -1474, -2324, -3764, -1104, -6571, -1214, -2128, -3762, -508, -5101, -1675, -1924, -4087, -850, -5613, -2976, -2142, -5175, -2255, -4302, -4548, -3586, -6211, -4518, -3139, -4060, -8390, -5934, -6325, -4610, -2357, -7488, -5683, -6163, -7341, -1213, -4894, -4927, -6371, -2692, -1206, -5002, -3591, -9952, -1444, -3129, -5790, -2942, -8019, -1823, -13260, -5479, -3063, -4223, -3022, -3420, -5042, -3514, -3078, -3803, -1685, -5575, -3754, -3408, -4172, -1592, -8212, -3633, -5294, -4751, -2493, -10080, -3281, -8064, -4468, -4490, -5562, -2984, -6170, -3963, -7899, -4475, -3326, -5320, -4466, -5433, -4894, -5054, -5898, -6387, -3080, -5548, -10698, -6944, -9742, -2464, -5787, -7323, -7028, -11875, -3031, -6788, -4895, -6152, -15868, -3168, -8866, -4532, -5277, -7629, -2080, -10652, -5437, -4903, -5330, -1388, -10577, -7358, -5212, -4795, -1010, -9603, -9015, -6117, -5454, -606, -8182, -9363, -6617, -7009, -517, -6436, -9368, -6261, -6469, -1053, -6020, -8244, -6454, -4848, -2195, 6928, 7161, 7582, 9663, 3009, 6574, 6930, 7288, 8942, 2336, 5736, 5959, 6643, 6362, 551, 4880, 4033, 6077, -2389, 1134, 4115, 3344, 5678, 3457, 2681, 3483, 3649, 5306, 3935, 2660, 2102, 2126, 4541, 2237, 516, -2154, -289, 2802, 3058, -1716, 3671, 2723, 322, 4541, 2205, 5567, 3995, -57, 4703, 3907, 5418, 4148, -1085, 3697, 5001, 3807, 4239, -3546, 1478, 6029, 1668, 4889, 818, -144, 6718, 1282, 5574, 2393, 1204, 6736, 1982, 5516, 2036, 1773, 5835, 1456, 4272, -5, 1474, 3807, -453, 1723, -367, 723, 1272, 1176, 589, 1470, -87, -532, 1951, 1410, 2149, -182, -2145, 820, 1516, 1956, 714, 1835, 1723, 1139, 1227, 1601, 3241, 4201, 697, 407, 1961, 2985, 5495, 625, 86, 1831, 1753, 5665, 644, 258, 1375, 101, 4633, 408, 428, 591, 101, 1964, 73, 586, -1114, 1791, -3599, 341, 1153, -5101, 2327, -3064, 1556, 1648, -5711, 1436, -3218, 2393, 1225, -6239, -1028, -2614, 2159, -112, -3314, -6108, -490, 634, -104, -935, -7254, 1131, -2714, 266, -725, -2490, 2436, -5403, -995, -1625, 141, 3343, -2207, -1860, -1732, 1613, 3657, -1396, -380, -920, 2091, 3269, -2605, -115, -694, 1471, 2147, -8207, -1260, -1161, -634, 487, -5559, -2514, -1353, -5645, -720, -3252, -1475, -1312, -5870, -873, -3397, -1416, -2092, -3917, -921, -4442, -3653, -3683, -3276, -1468, -2817, -6368, -4562, -2547, -2602, -945, -5453, -3824, -2102, -3643, -496, -10197, -3446, -2567, -3957, -1277, -5898, -4932, -4097, -3617, -2940, -3369, -12484, -5700, -3037, -4624, -2317, -5191, -6881, -2797, -4694, -1040, -3485, -9315, -3042, -3857, -200, -3721, -8256, -3425, -3250, -339, -3769, -6949, -3035, -2842, -1585, -1973, -5703, -2145, -2747, -3759, -602, -4099, -1649, -3167, -5274, -249, -3214, -1890, -4350, -6286, -1009, -3009, -3173, -7507, -6186, -3358, -3037, -6044, -9712, -3886, -9717, -2858, -4379, -4317, -3178, -6481, -2575, -1477, -2575, -4203, -5782, -2697, -165, -2142, -5758, -7880, -3698, -55, -2516, -4626, -9078, -6360, -1198, -3214, -4071, -7936, -8296, -3909, -3814, -5051, -7098, -4863, -6324, -4723, -6959, -5957, -3596, -5381, -6863, -5569, -4869, -3771, -5398, -9812, -3639, -3449, -5759, -6330, -7022, -2587, -2509, -9998, -7825, -5322, -2124, -2606, -5872, -7187, -4567, -1959, -3973, -4872, -7178, -4412, -1840, -7693, -6145, -8514, -5065, -1816, -10338, -9791, -6354, -6935, -2090, -5574, -7507, -5249, -10146, -2684, -4477, -6408, -5846, -8380, -3063, -4549, -7633, -7512, -6250, -2611, -4874, -9968, -9417, -5461, -2196, -5033, -10329, -9230, -5494, -2565, -5050, -7495, -7770, -5990, -3404, -4994, -5494, -7295, -6686, -3496, -5244, -5669, -7175, -7101, -3513, -5959, -9259, -6859, -6415, -4417, -6444, -6359, -1981, 7876, 7695, 8495, 8237, -2844, 7481, 7270, 7862, 7545, 1019, 6019, 5665, 6034, 5202, 3039, 2185, 2306, 5340, -953, 3467, -1751, 3379, 6516, -117, 3658, 2522, 4529, 6607, 2003, 4490, 2914, 3987, 5438, 1648, 5270, 2903, 3379, 3369, -873, 5512, 2931, 3175, 1822, -2892, 5008, 2496, 1168, 220, -3019, 3421, 1830, -4198, -2965, -1917, 2406, 1767, 2827, 1174, 509, 4688, 2281, 4282, 2522, -37, 5930, 2738, 4040, 2101, -5544, 6003, 2823, 2793, 766, -3529, 5412, 2160, 1395, -503, -2334, 4763, 194, 657, -1395, -5836, 4156, -4541, -263, -2714, -6537, 2816, -3596, -1707, -728, -2451, -1709, -784, 231, 1996, -855, -251, 214, 1987, 2531, 152, 3082, 342, 2359, 300, 813, 3486, 164, 1775, -2561, 1035, 2136, 271, 621, 2147, 408, -696, 702, -1360, 3150, -1099, -2018, 944, -8521, 3171, 847, -1162, 473, -2446, 3282, 2751, 143, -1128, 31, 3279, 2878, 1415, -2750, 35, 2765, 1139, 2366, 390, -2352, 1736, -3317, 2803, 2860, -7559, 611, -4770, 2225, 4179, -3502, -87, -5472, -484, 4644, -5787, -1006, -3457, -4922, 4405, -4343, -2748, -1305, 943, 3514, -212, -2991, -843, 2521, 2064, 748, -836, -1403, 3056, 516, 233, 886, -1366, 2921, -400, -794, 2005, -3, 1891, -1284, -1647, 2547, 456, -449, -3947, -3161, 2391, -251, -4949, -10357, -2631, 1181, -1484, -7207, -6178, -821, -2308, -2560, -5659, -11313, -580, -5646, -2848, -3473, -2267, -1680, -967, -2630, -2106, 56, -3239, -401, -3008, -2384, 407, -4374, -1663, -3304, -4877, -627, -4487, -4751, -4659, -9247, -2585, -2020, -9640, -8211, -5383, -3012, -327, -11648, -2926, -5704, -2565, 378, -6753, -1507, -7532, -3347, 483, -4807, -2080, -3945, -4303, 264, -4548, -4391, -2012, -3684, -187, -4851, -6521, -1326, -3289, -980, -4349, -5678, -1515, -2131, -2063, -3427, -6038, -2768, -864, -2668, -2829, -7045, -6107, -792, -2995, -2743, -6596, -12351, -2175, -3964, -3177, -5050, -7948, -4977, -3998, -3949, -3822, -7796, -6941, -3381, -4913, -3246, -4481, -7580, -4051, -6255, -3220, -2724, -7102, -5431, -6488, -3589, -2407, -5400, -5885, -4847, -4463, -2929, -4341, -6888, -4257, -6679, -3643, -3892, -5181, -5014, -18357, -3975, -4023, -3273, -6397, -5969, -4322, -4631, -3067, -6547, -3801, -5631, -4851, -4139, -5174, -3317, -8692, -4473, -5120, -3951, -3770, -9338, -4609, -5421, -3673, -4699, -8021, -5558, -6945, -4439, -5838, -9140, -6951, -8590, -6337, -7444, -14789, -8155, -6678, -9408, -9408, -12676, -8249, -5398, -12206, -9098, -11849, -6063, -4893, -14348, -8102, -14796, -3920, -5688, -8043, -8041, -11395, -3023, -9351, -5778, -8808, -9526, -3716, -11085, -4731, -10442, -9287, -7182, -8530, -3985, -15913, -9585, -9185, -10307, -3460, -10567, 6844, 8184, 3420, 5950, 6590, 5716, 7520, 2915, 5650, 5578, 1323, 5655, 1526, 4481, 1420, 2109, 4602, 938, 2294, 15, 4468, 5518, 3231, 2469, 3187, 5793, 5964, 4592, 3694, 3339, 6224, 5655, 4528, 4454, 2352, 5057, 4221, 3430, 5324, 971, 1833, -301, 2190, 5579, 373, 2644, 850, 1098, 4721, 980, 4056, 3616, -1585, 2925, 537, 4012, 4156, -3087, 1117, -3988, 3210, 4093, 1451, -2670, -2487, 1519, 3634, 2380, -613, -810, -2387, 2590, 568, 2761, -6471, -488, 1010, -5312, 3534, 340, 1823, -1565, 1888, 3010, 3257, 1775, -3382, 3422, 2002, 4252, -685, -951, 3397, 1173, 4308, -3154, 168, 2609, -479, 3921, 1052, 588, 1830, -3238, 3553, 2378, 610, 1794, -208, 3373, 2364, 113, 2254, 1288, 3176, 1322, -1241, 2383, 1270, 2722, -950, -4485, 1628, 102, 1826, -5666, -8227, -513, -1899, 410, -4133, -3782, -6552, -905, -1388, -2513, -747, -3604, 1420, -3010, -3860, 972, -216, 2714, -628, -2463, 1139, 963, 3132, 1691, 105, 357, 731, 2731, 2376, 650, 659, -968, 1401, 1577, -86, 1151, -5024, -280, -273, -1284, 615, -7242, 329, -1523, -2322, -285, -1319, 1239, -3131, -4030, -1557, 1273, 1204, -2623, -4930, -4765, 2533, 382, 31, -3846, -2702, 2810, -1149, 1031, -2436, -2306, 2244, -3404, 1046, 817, -8994, 1047, -4395, 638, 2113, -1506, 182, -2293, 232, 1249, 408, 245, -443, 303, -2615, -457, 2, 388, 1146, -1225, -3270, -964, 114, 1823, 69, -1130, -1849, -1146, 1661, -1202, -555, -1365, -2727, 687, -4664, -2784, -860, -4224, -719, -8293, -6623, -1237, -5927, -2521, -5505, -3504, -1674, -4074, -4433, -3443, -3662, -1029, -1584, -4872, -3436, -5480, -604, 87, -4061, -6831, -6373, -954, 895, -2930, -4665, -5970, -1481, 869, -3005, -1678, -6194, -1725, 102, -4007, -1213, -7330, -2515, -1336, -4220, -2492, -4365, -4748, -3634, -3468, -6231, -2036, -8618, -7015, -2416, -10932, -1345, -8476, -5322, -2055, -7350, -2131, -10709, -3277, -3007, -7164, -4938, -10398, -2347, -5087, -6032, -11826, -6451, -1985, -5375, -5476, -6386, -5870, -1782, -5321, -6190, -5095, -7148, -1297, -6906, -7337, -4828, -9918, -793, -7903, -6343, -5432, -7696, -862, -6090, -4809, -7046, -5531, -1731, -4551, -4415, -5858, -5221, -3339, -4088, -5435, -4033, -6463, -4688, -4882, -8282, -4049, -8560, -3891, -6749, -9165, -6707, -8658, -2887, -8564, -7138, -10402, -6502, -2670, -9858, -6370, -4903, -4838, -3343, -10015, -6338, -3947, -4444, -5240, -7141, -7775, -4739, -5188, -6116, -4346, -12681, -6528, -6728, -3824, -2500, -6372, -8095, -9228, -2730, -1680, -4190, -7241, -11071, -2502, -1914, -3767, -4542, -8579, -2851, -3341, -4537, -3365, -7100, -4257, -5807, -6160, -3938, -6677, -8386, -5363, -6487, -5417, -4831, -5399, -3595, -6606, -5220, -4098, -3955, -2996, -6791, -5518, -4339, -2958, -3813, -5029, -4855, -6573, -2456, -5830, -3627, -3990, -10242, -2583, -6572, -3503, -3955, -5694, -3498, -5733, -4531, -4720, -4080, -4973, -6642, -6336, -5565, -3660, -5397, -11244, -7572, -5403, -3796, -4399, -9624, -6943, -4976, -4501, -3341, -7751, -6284, -4998, -6524, -2623, -7953, -6400, -5125, -13720, -2499, -7962, -6581, -4922, -9675, -3201, -6947, -6428, -4554, -8044, -5125, -5239, -7512, -4496, -6154, -8552, -3600, -12902, -5097, -3938, -6733, -2506, -12785, -7219, -2296, -6245, -2448, -8098, -6875, -793, -7453, -4342, -2270, -1398, 579, -2516, -2953, 237, 929, 1489, 27, 266, 986, 1584, 1656, 936, 1345, 322, 829, 893, 681, 786, -1675, -1400, -934, -484, -1650, -4605, -5233, -3661, -2148, -8273, -7098, -7983, -5542, -3463, -6495, -9317, -6325, -6176, -3798, -6445, -10349, -4891, -7107, -3570, -7094, -11108, -4375, -7870, -3322, -4857, -10823, -4363, -8390, -3422, -3691, -7608, -4723, -10417, -4252, -3535, -5257, -5565, -11499, -5773, -3891, -4566, -6740, -9103, -6320, -4558, -5707, -7907, -7989, -6022, -5807, -10570, -8858, -6677, -6372, -7130, -8773, -8440, -6381, -6672, -7034, -6078, -8636, -9076, -6136, -7177, -5651, -8736, -9553, -5450, -7590, -6840, -7336, -5381, -5011, -6630, -14294, -7488, -4801, -4871, -5848, -6136, -10098, -6286, -5008, -6046, -3235, -11529, -8986, -5317, -6412, -2186, -7462, -8587, -5614, -5608, -2127, -5546, -5993, -5602, -4895, -2768, -4953, -3879, -5369, -5200, -4091, -5580, -3164, -5477, -6772, -6470, -7886, -3903, -6183, -9649, -11308, -9200, -6437, -7719, -8945, -10678, -6182, -9302, -11853, -7614, -9572, -5189, -7009, -10482, -7855, -10849, -5754, -6670, -7654, -7960, -10133, -8021, -8450, -7492, -6982, -9424, -10234, -15495, -8411, -6733, -10228, -7509, -11577, -8767, -7567, -9477, -6263, -9487, -9857, -8789, -7763, -6036, -8615, -16894, -9219, -6594, -6453, -7945, -10252, -9583, -5649, -7061, -7302, -7813, -10419, -4963, -7236, -6595, -7004, -10903, -4924, -7947, -6179, -6655, -10453, -5878, -10923, -6142, -6372, -9527, -7202, -14480, -6401, -6149, -9032, -6310, -9481, -6657, -5984, -9602, -5378, -7495, -6427, -5769, -9697, -5650, -6850, -6403, -5592, -7339, -7131, -7150, -7731, -5749, -5664, -8298, -6849, -11449, -6429, -4910, -7086, -6298, -10534, -7720, -4908, -6514, -6999, -10839, -9769, -5924, -6860, -9561, -13612, -11400, -9204, -6920, -14357, -8162, -11150, -11068, -6493, -12766, -6878, -13047, -6942, -6884, -9274, -7453, -15660, -5989, -8558, -7535, -9432, -9547, -6401, -9898, -7434, -14187, -7718, -7893, -9707, -8867, -13166, -7538, -10498, -11141, -10755, -9815, -8900, -12875, -16967, -9262, -9781, -12291, -11937, -15404, -8060, -13327, -13354, -9920, -12630, -7888, -12745, -11948, -8216, -10002, -7989, -8788, -11573, -7404, -9210, -6686, -15004, -3289, -6328, -7919, -10176, -10887, -3489, -4414, -6566, -8259, -9697, -4196, -4142, -5503, -5290, -11864, -5981, -5954, -4598, -5677, -11430, -11060, -14555, -3737, -8789, -6780, -7117, -8086, -3108, -8413, -5414, -4226, -8755, -3056, -6295, -5370, -2921, -10658, -3642, -5938, -5817, -2362, -5959, -4464, -6230, -6351, -2305, -4802, -5318, -5661, -7355, -2605, -4648, -6030, -4788, -8877, -3153, -4318, -5904, -4916, -9187, -3968, -3807, -6158, -6283, -7416, -4581, -3478, -7312, -8938, -5776, -4128, -3614, -8987, -8870, -4994, -3576, -4325, -11480, -8343, -4380, -3152, -4685, -5002, -9948, -2766, -2348, -3502, -1091, -2435, -586, -914, -1095, 924, 162, 874, 420, 766, 1496, 868, 1184, 908, 1411, 666, 95, 131, 390, 762, -1920, -2085, -2922, -845, -1280, -7756, -4454, -16110, -1966, -4698, -6715, -3873, -5983, -2930, -5724, -6404, -2975, -5321, -4831, -4148, -8149, -2771, -6242, -8405, -2985, -11642, -3082, -7557, -10505, -2280, -10096, -3383, -5472, -15643, -2315, -5910, -3512, -4542, -9302, -3544, -4161, -4119, -5871, -6931, -7014, -3807, -6345, -9365, -7016, -10307, -4311, -9961, -7929, -7821, -5691, -5163, -6055, -8191, -8082, -4467, -6171, -4793, -9507, -9009, -4679, -7184, -4796, -7642, -11541, -6390, -7723, -5518, -7267, -10546, -7902, -8212, -6977, -8316, -7941, -5667, -8984, -8527, -8988, -6911, -4411, -8643, -6370, -8980, -7105, -3989, -8007, -4233, -8228, -7891, -4022, -8794, -3315, -6300, -7934, -4546, -11341, -3481, -5193, -7635, -5755, -12427, -4738, -5205, -8025, -8019, -10792, -7259, -5891, -8796, -13258, -7564, -11530, -6159, -9580, -11920, -5757, -17389, -5882, -11718, -8114, -5523, -15594, -6008, -10143, -6180, -6780, -17090, -6855, -7510, -5038, -8817, -11814, -7704, -6483, -4638, -7888, -8637, -7401, -6001, -5064, -6890, -6993, -7147, -5609, -6385, -7082, -6207, -7481, -5691, -7961, -8353, -5988, -7837, -6738, -7876, -11189, -5943, -7604, -9331, -7787, -19199, -5825, -7175, -12307, -8505, -11676, -5962, -6404, -9173, -8273, -9909, -6757, -5111, -8220, -8439, -9529, -8310, -4397, -8781, -9601, -10027, -9518, -4853, -9488, -6396, -11585, -8235, -6822, -10060, -4537, -9577, -6889, -10416, -8115, -4244, -7183, -6916, -8712, -5559, -5065, -6404, -7819, -6786, -4732, -6745, -6723, -6229, -6014, -5754, -8068, -7727, -4706, -6080, -9574, -6889, -9382, -4416, -6628, -7227, -5957, -10909, -4928, -6618, -5124, -6000, -10310, -5733, -5841, -5155, -6098, -9824, -6774, -5344, -7076, -5466, -9382, -8830, -5583, -13008, -5116, -9364, -14598, -6627, -10457, -5703, -10925, -13134, -7897, -9338, -7078, -17766, -11047, -8228, -10926, -7312, -12329, -10043, -8854, -14096, -6377, -9246, -8903, -12360, -12308, -6179, -7824, -7904, -11876, -9138, -6918, -7406, -6685, -7622, -7962, -8100, -8250, -5658, -6581, -8677, -8669, -11653, -5213, -7600, -11726, -9502, -6275, -7459, -7000, -6470, -3903, -4611, -8854, -5266, -3553, -3567, -3870, -4951, -3609, -2416, -4242, -4366, -4804, -3320, -2270, -5967, -6275, -6972, -4166, -3256, -8507, -10171, -12115, -5676, -6261, -8439, -11299, -12043, -7006, -8492, -5927, -10517, -10697, -7794, -4872, -3723, -11855, -6608, -8993, -3744, -2358, -13710, -4703, -11678, -3516, -1921, -10297, -4260, -14057, -3549, -2336, -7447, -5051, -12593, -3527, -3366, -6283, -7371, -9834, -3390, -4634, -6581, -9859, -7409, -3297, -5936, -8880, -6768, -5974, -3285, -6690, -13443, -5505, -5455, -2978, -6634, -11797, -7806, -6402, -2254, -6693, -7806, -5050, -6959, -1229, -6141, -2174, -264, -2380, 89, -2592, 260, 1781, 74, 1016, -20, 921, 2414, 1007, 941, 1072, 9, 1957, 705, -553, 924, -2636, 564, -799, -4597, -202, -5387, -1546, -3587, -7025, -1771, -6066, -3644, -7205, -3911, -3331, -9450, -4568, -8048, -3349, -4854, -7175, -5245, -7936, -3646, -6327, -6008, -6570, -8861, -4621, -11767, -7183, -7459, -9946, -5893, -6739, -11369, -7622, -9559, -5931, -3608, -13936, -8468, -8911, -4742, -2750, -10183, -10097, -8682, -4374, -2987, -9181, -8548, -8794, -5678, -3069, -8990, -5410, -10167, -9059, -2481, -10011, -3681, -11519, -7713, -2240, -12961, -3158, -7402, -7225, -2629, -14315, -3664, -4975, -8061, -3591, -8715, -5158, -3513, -6182, -5211, -6693, -7881, -2674, -4835, -7763, -6634, -13779, -2476, -4538, -10107, -9065, -12637, -3083, -4685, -6531, -13953, -9700, -4730, -4943, -4833, -7463, -8389, -7154, -5426, -5212, -5979, -7985, -7362, -6888, -8907, -5809, -8836, -7039, -10232, -9569, -6110, -10164, -7723, -6606, -5848, -6181, -8551, -9132, -4796, -5085, -5711, -7127, -12411, -5076, -5321, -5106, -7060, -8607, -7079, -7071, -4767, -8634, -5752, -7579, -8468, -4796, -9544, -5016, -6526, -4435, -5263, -7770, -5677, -6851, -2722, -6394, -7830, -5973, -6828, -2351, -7826, -8200, -4993, -5965, -2867, -7129, -6373, -4708, -5973, -3666, -6375, -5292, -5314, -6838, -3734, -7316, -5384, -6269, -7531, -3386, -10330, -6284, -7143, -7886, -3446, -9316, -7264, -8282, -7969, -3961, -8354, -7454, -9326, -7048, -4575, -9967, -6846, -9308, -6015, -5682, -12094, -6182, -9574, -5562, -8455, -10098, -6251, -8823, -5788, -7933, -10115, -7438, -7179, -5798, -6256, -12729, -9670, -6641, -4424, -6670, -16869, -11702, -7349, -3136, -8626, -11379, -12571, -8894, -2706, -10776, -9858, -12632, -10360, -3202, -9852, -9656, -14351, -11892, -4516, -8120, -10112, -9196, -14718, -6029, -7326, -11073, -6167, -20010, -7015, -7571, -13288, -4933, -16628, -8164, -8158, -15866, -4808, -13887, -8859, -8671, -13006, -5320, -12181, -7866, -10275, -11071, -5975, -11702, -6915, -13457, -9700, -6806, -12271, -6528, -11149, -8831, -8396, -13721, -6934, -8250, -8454, -9442, -13972, -9042, -6740, -8719, -7705, -11615, -17335, -6696, -9993, -6648, -9134, -8087, -7929, 11499, 9653, 11787, 11865, 10918, 10750, 9748, 11068, 11240, 10364, 8109, 9531, 8698, 9336, 8658, -392, 8420, 3495, 6224, 6048, 4468, 6188, -2829, 2992, 4944, 4836, 2886, -1034, 852, 4834, 3423, -314, 929, -354, 3400, 2873, -1496, 1653, 65, -323, 689, -2183, 2935, 767, -6658, -226, -1673, 3889, 816, -6654, 5189, 544, 3523, 1694, 727, 7001, 1280, 3374, 3183, 4394, 7543, 2819, 4609, 4414, 6201, 7338, 5335, 5343, 5008, 6784, 6524, 6594, 5248, 4727, 6186, 4964, 6532, 4685, 3373, 4034, 2635, 5338, 4042, 439, -1698, 1519, 3675, 3143, -3463, -868, 1737, 2813, 1237, 612, 987, 1363, 2305, -3363, 2166, 1556, 1643, 2080, -5536, 2433, 1979, 2425, 2309, -3356, 2424, 956, 2375, 2323, -5877, 2676, -9137, 1643, 1847, -2948, 2781, 1636, 1445, 565, -278, 2290, 4161, 1827, -51, 118, 1184, 4603, 2057, 2119, -766, 999, 3517, 1918, 3192, -1961, 1741, 351, 1084, 2772, -5075, 1823, -9009, -3, 1315, -3513, 1715, -3156, 754, 666, -1, 2060, -6758, 1223, 3, 894, 2448, -4417, -629, -2904, 789, 2644, -1501, -4193, -1362, 779, 2463, -342, 741, -280, 657, 1614, 444, 1940, -2432, -386, 302, 300, 1661, -5600, -2648, -116, -1426, 728, -517, -5816, 42, -8691, -478, 1020, -5590, -492, -2680, -2624, 1193, -3778, -1788, 222, -9612, 248, -3523, -2310, 1328, -4828, -1791, -4731, -1546, 1500, -3774, -4803, -6916, -1462, 950, -6641, -4848, -8218, -1770, 222, -7771, -1963, -6686, -921, 557, -3923, -756, -4622, 123, 1229, -2846, -872, -3909, 554, 1169, -2433, -1846, -5745, 413, 243, -2080, -2755, -6614, -278, -1394, -1921, -2331, -1802, -1389, -2957, -2013, -1209, -272, -2419, -2893, -1213, -627, -236, -2201, -2356, -14, -707, -987, -752, -2093, 439, -940, -1989, 234, -1770, 82, -885, -3121, 317, -1690, -747, -680, -4513, -297, -2330, -1287, -546, -7327, -631, -3621, -1505, -658, -4254, -147, -4817, -2767, -1298, -1704, 213, -5047, -6312, -2616, -1171, 99, -4591, -4520, -3856, -2233, -602, -4570, -3047, -4603, -5501, -2062, -4365, -3248, -5468, -13943, -3893, -2743, -3891, -4549, -8014, -5236, -1218, -3439, -4507, -10182, -5271, -339, -2017, -6499, -6396, -3095, 51, -1278, -5234, -4433, -1926, 180, -1582, -4112, -5251, -1997, 117, -3012, -4723, -5486, -2358, -140, -6067, -5077, -2875, -2262, -540, -4332, -4377, -2761, -2777, -1175, -1347, -4245, -6137, -3431, -2252, 198, -5646, -2423, -1844, -3110, 896, -10059, 0, -490, -2063, 662, -7959, 293, -39, -1037, -1028, -5465, -943, -84, -1061, -5569, -3676, -3524, -278, -2353, -4143, -3071, -6214, -1188, -5856, -2726, -4220, -11237, -4123, -9832, -3171, -6078, -4947, -2949, -10897, 1986, 7534, 7994, 8395, 5655, 1586, 6803, 7469, 7696, 4993, 986, 4683, 6042, 5302, 3663, 1176, 4020, 4165, -290, 3540, 1354, 5071, 1972, 1624, 3711, 1165, 4944, -498, 2650, 3436, 1305, 3929, -780, 2245, 3125, 2022, 2784, 1021, 1914, 2896, 2842, 2606, 2544, 1909, 2503, 3458, 2577, 3509, 1162, 2278, 4319, 2777, 4320, -1679, 3341, 5631, 4337, 5485, 591, 4894, 6571, 5188, 6487, 2665, 5846, 6695, 4848, 6546, 2448, 6016, 6031, 3962, 5257, 374, 5518, 4941, 3891, 1946, -1263, 4519, 4092, 3892, -9767, -732, 3047, 3742, 2274, -3403, 28, 1256, 3246, -4496, -6805, 1456, 9, 2179, -172, -5004, 2240, -1027, 1634, -109, -3777, 2227, -2661, 1529, -2955, -4061, 1781, -4333, -54, 227, -4123, 1286, -2738, -3606, 548, -7285, 702, 202, -2746, -36, -1668, -116, 2048, -502, 1178, -760, 320, 3206, 1792, 1855, -4693, 1439, 3944, 3000, 1660, -2152, 1418, 4259, 3060, 927, -29, -23, 4053, 2125, -517, -1139, -1610, 3269, 301, -1313, -3676, -661, 1878, -2420, 858, -3865, 454, -397, -6488, 1913, -3258, 1317, -4907, -6205, 1205, -992, 1933, -2414, -2780, -2487, 70, 2028, 163, -680, -3970, 142, 1003, 843, 334, -195, -40, -3085, 301, 112, -43, -188, -1548, -1011, -1459, -1898, -666, 1611, -2204, -1343, -6526, -1699, 2298, -2599, 591, -7144, -2901, 1715, -1844, 1237, -4046, -3598, 179, -140, 759, -2406, -3075, -2445, 1180, -335, -1952, -1899, -5612, 1415, -1094, -2214, -1360, -1893, 203, -1459, -1069, -1757, 481, -3330, -2097, 752, -2767, 1624, -7473, -1792, 1782, -2900, 1889, -7712, -101, 1912, -2068, 1430, -5585, 1149, 1283, -1498, 397, -866, 1524, 568, -963, -1106, 495, 954, 497, -188, -3461, -19, -412, 139, 324, -10632, -2949, -900, -1303, -35, -4678, -7384, -163, -3549, -1866, -2417, -2039, -90, -4801, -7138, -2238, -767, -899, -3789, -5957, -2726, -570, -2445, -1632, -2991, -2995, -898, -4903, -717, -1806, -1742, -1512, -8493, -1379, -1798, 585, -1549, -5539, -3625, -3504, 1770, -763, -3517, -3105, -8456, 1591, -119, -3114, -1345, -7055, 92, -21, -4398, -782, -9520, -2433, -808, -6538, -902, -6864, -4298, -3229, -2854, -1191, -3592, -3995, -7376, -1294, -667, -3069, -3510, -3439, -1592, -26, -2002, -4369, -1857, -2227, -397, -443, -3309, -1476, -1091, -2056, 221, -1094, -2369, -668, -4218, -5, -716, -6260, -1626, -3114, -970, -2628, -5218, -2561, -1129, -2134, -2523, -2555, -2529, 148, -2205, 324, -2183, -3484, 433, -2391, 994, -2104, -4388, -687, -4433, -147, -1845, -2974, -4487, -13025, -4452, -1215, -1607, -5702, -5079, -4621, -8, -769, -2473, -2682, -1284, 552, -657, -1852, -1952, -775, -338, 3403, 4132, 7641, 778, 5289, 2552, 4145, 7421, 2383, 6068, 4670, 4212, 7130, 4931, 6997, 6328, 4373, 6985, 5898, 7176, 6003, 4155, 6359, 5214, 6490, 3584, 2785, 4682, 2921, 4968, -3986, -778, 1301, -742, 3260, -539, -3989, -6344, -2274, 2502, -875, -1955, -2882, -434, 1798, -3591, -1851, -1994, 1043, 958, 3027, -70, 38, 2360, 1125, 5424, 2700, 1757, 2968, 1329, 6100, 4469, 1807, 2654, 1037, 5305, 4858, -175, 2820, 2749, 2728, 3599, 755, 3658, 4815, -3318, 76, 2620, 3579, 5670, -6116, 599, 2350, 2258, 5308, -2952, 1593, -76, 344, 3740, -1295, 197, -7631, -293, 1431, -414, -2083, -4705, -32, 454, 1193, -1037, -2916, 140, -87, 2307, -23, -1998, -320, -18, 2491, 240, -1222, -2065, 924, 1975, -38, -567, -6414, 1177, 977, -812, -86, -2158, 1569, -272, -2074, 62, 217, 2576, -712, -3867, -198, 1022, 2926, -117, -3578, -924, 905, 2160, -125, -1289, -2054, 12, 982, -1563, -215, -2503, -1765, 993, -6099, -47, -1659, -4728, 1308, -6373, -203, -670, -5335, 1637, -2661, -739, 229, -3261, 1850, -1322, -2303, 947, -1527, 1748, -928, -5554, 1239, 616, 2135, -1827, -11079, 834, 2152, 2999, -5832, -6189, -473, 2630, 3320, -3403, -2728, -1400, 2094, 2477, -572, -1483, -13, 1139, -474, 25, -1786, 1043, 931, -2991, -845, -3318, 1407, 776, 1042, -2630, -4489, 1405, -256, 2424, -987, -2810, 1333, -2287, 2747, 512, -1553, 1549, -5824, 2282, 279, -2049, 1871, -3869, 900, -1724, -5113, 1702, -1201, -1600, -2784, -3388, 568, -172, -2220, -895, -1663, -2290, 292, -362, -418, -2568, -9930, 580, 503, -1227, -7070, -2603, 429, 437, -2729, -5947, -436, -295, -560, -2611, -3597, 571, -1311, -2955, -1634, -2500, 779, -2367, -6798, -1580, -1228, 83, -3626, -2730, -1961, -159, -1607, -4533, -689, -1789, 222, -2814, -4019, 358, -1588, -452, -1013, -4088, 995, -2319, -2726, 767, -6820, 974, -4507, -8398, 1631, -11130, -303, -2578, -6953, 1518, -6724, -3262, -327, -6716, 421, -8780, -1524, 193, -8230, -1594, -5833, 225, -690, -4076, -3241, -2524, 550, -3379, -1911, -2869, -975, 320, -6486, -1262, -3444, -392, -71, -2338, -1737, -7273, -902, -761, -805, -3112, -5322, -3132, -1739, -753, -4756, -3052, -3407, -2524, -1795, -7989, -2173, -957, -2388, -3114, -6050, -1001, -97, -1763, -3563, -1277, -227, -19, -1780, -4053, 280, -333, -629, -3246, -5652, -96, -1690, -2562, -4260, -11515, -3068, -6057, -6844, -1570, -6403, -7864, -5955, -5304, -902, -3614, -3309, -3410, -4326, -2882, -2501, -2023, -1490, -3336, -7164, -1740, -36, 312, -1321, -2026, -1151, 996, 668, -883, -890, -1372, 643, -586, -3064, -910, -3402, -4482, -2190, -1270, -4262, -3070, -4590, -2040, -2520, -946, -3274, -9669, -4249, -9697, -56, -3661, -5978, -4859, -3848, -493, -3439, -3542, -2771, -1509, -504, -3120, -3970, -2516, -560, 163, -2938, -6862, -2398, -958, 411, -2723, -11590, -1025, -3975, 1108, -3014, -6531, 310, -5335, 1975, -3553, -4511, 957, -1340, 1873, -3638, -4597, 887, -704, 258, -5787, -7724, 248, -1979, -4020, -5723, -4889, -576, -6030, -5557, -1752, -1896, -1048, -5583, -3021, -961, -879, -994, -2977, -1828, -2324, -1161, -756, -2567, -894, -8329, -3006, -890, -3048, -336, -2419, -12398, -1434, -2230, 342, 771, -2734, -174, 527, 1344, 2390, -223, 1634, 2317, 2073, 3055, 210, 2246, 2721, 1891, 2870, -912, 1627, 1673, 245, 1928, -3573, -115, -1050, -3564, 507, -6432, -3262, -4038, -2351, -1054, -6372, -8754, -4753, -938, -2769, -7193, -2761, -4473, -1032, -3845, -10328, -1095, -2632, -1692, -3653, -2631, -1126, -2259, -2446, -3893, -256, -2771, -3310, -2791, -4961, 361, -8126, -5707, -2611, -5749, -245, -7360, -6102, -2940, -5490, -1830, -6736, -4501, -4546, -5568, -4055, -6866, -4259, -6523, -5735, -6537, -2456, -3944, -4694, -5152, -6281, -791, -2729, -3326, -5147, -4384, -636, -1952, -3614, -6397, -3150, -1511, -1616, -7073, -4951, -2081, -2980, -1332, -7338, -2755, -1670, -4406, -1259, -3640, -1452, -2662, -5710, -1451, -3615, -261, -5548, -7769, -1585, -5654, 706, -3476, -12844, -1737, -4974, 1109, -1569, -10018, -2414, -4155, 931, -1372, -8834, -4007, -7511, 348, -2417, -19835, -6770, -5193, -391, -4759, -5253, -7132, -1173, -1144, -7689, -1769, -4823, 228, -1928, -6624, -170, -3580, 522, -2723, -5276, 133, -3197, 312, -3832, -5133, -786, -3275, 86, -6741, -5275, -2979, -3246, -15, -9085, -3240, -6076, -2781, -346, -4076, -2116, -6898, -1822, -1476, -2444, -2481, -5099, -863, -3556, -1673, -3676, -3843, -402, -3266, -1569, -4468, -2131, -551, -2215, -3039, -4968, -340, -1284, -2389, -8551, -5841, 652, -2084, -3633, -3304, -6153, 803, -1768, -9006, -1361, -4735, 202, -833, -4478, -1044, -3627, -1151, -16, -1493, -1415, -3147, -3442, 294, -1194, -2076, -3305, -6063, -281, -2926, -2664, -4702, -3915, -1898, -6565, -2405, -6927, -2282, -3991, -4178, -1692, -5166, -2072, -5567, -3102, -1571, -4346, -2848, -8095, -4080, -2244, -5297, -3728, -11771, -6981, -3029, -8705, -3791, -10247, -6713, -3057, -9979, -3672, -6229, -4608, -3131, -5419, -4169, -4738, -3996, -4066, -3853, -5631, -5869, -5689, -6247, -3266, -7684, -20323, -11907, -7206, -2894, -8001, -5255, -3943, -5052, -2472, -5833, -3593, -2379, -3961, -2063, -4117, -4113, -2539, -3763, -1759, -4145, -4780, -3799, -3579, -1678, -7482, -3796, -5995, -3003, -2008, -6027, -3836, -9554, -3075, -3017, -2896, -5702, -14625, -1504, -2360, -3044, -1487, -4265, -3225, -3986, -9075, -3210, -4127, -2464, -6521, -5388, -6423, -916, -408, -6156, -3486, -9355, -571, 552, -4207, -4319, -8203, -1147, 569, -2249, -4905, -6750, -937, -72, -543, -2242, -4041, -863, -1216, 432, 114, -2699, -2014, -3629, 418, 1352, -3433, -2727, -10814, -681, 1366, -6282, -1958, -2590, -2952, -6, -3716, -2224, -513, -6937, -3433, -2625, -4043, -163, -7808, -13572, -3488, -9508, -1117, -3808, -5312, -4816, -6499, -2760, -1250, -3357, -2952, -2767, -2385, 163, -1731, -865, -1248, -1202, 216, -691, -552, -359, -1048, -1285, -1002, -3070, 1192, -999, -682, -3304, -1531, 2877, 478, 1448, -1240, 1840, 3908, 1324, 1752, 1094, 2880, 4142, 771, 68, 1497, 2483, 3577, -1142, -4927, 401, 872, 2279, -3574, -4789, -1818, -1422, 578, -4474, -4161, -2381, -2721, -792, -3274, -4035, -1915, -2841, -1498, -1655, -3202, -2845, -1530, -2122, -731, -4220, -4852, -346, -3911, -488, -8410, -3948, 17, -11601, -1054, -6930, -2428, -223, -4265, -3181, -5540, -1608, -827, -2590, -7168, -6787, -955, -1883, -2828, -1763, -8574, -293, -4050, -3295, 197, -4504, 297, -6437, -3468, 640, -2015, 398, -3753, -4356, 188, -1034, -732, -2281, -6113, -672, -1381, -4975, -1556, -7557, -1508, -2985, -3857, -829, -5404, -2414, -5159, -1358, 231, -3005, -3667, -5494, -1721, 1210, -1657, -2840, -4258, -4395, 1572, -946, -1003, -4242, -6830, 1068, -494, -228, -7851, -4250, -530, -338, -381, -6428, -3621, -3439, -768, -1361, -3066, -4154, -4575, -2020, -3706, -2565, -5873, -4091, -3450, -8764, -3454, -11360, -3994, -2473, -2757, -5121, -9430, -2536, -1171, -226, -6409, -6764, -1856, -666, 1078, -4370, -4805, -2973, -793, 1676, -2813, -3727, -5223, -1648, 1649, -2899, -4746, -2938, -3744, 960, -4358, -6558, -1958, -7719, -587, -4615, -3112, -2844, -8827, -3886, -3787, -1491, -5185, -4575, -6683, -4287, -1159, -6972, -1822, -2712, -6079, -1790, -7969, -556, -1786, -7156, -3885, -6150, -504, -1647, -6708, -10546, -3778, -1648, -662, -6693, -4053, -3151, -2948, 216, -6619, -2100, -4161, -2211, 7, -6241, -2150, -7819, -1901, -1619, -5625, -4201, -9236, -2125, -5359, -4772, -20035, -6203, -1695, -8961, -3936, -4620, -8137, -1423, -7771, -3168, -2625, -7866, -1884, -10407, -2637, -2134, -3678, -2511, -4562, -2875, -2186, -2574, -2759, -1385, -4470, -2603, -2829, -2964, -151, -5713, -3902, -4024, -2960, -285, -4488, -7391, -6273, -2378, -1600, -5924, -6123, -8840, -1575, -4013, -10024, -3258, -8351, -1241, -8567, -3585, -2348, -6904, -2097, -7621, -2694, -2456, -5419, -5432, -2881, -4705, -3130, -4781, -9225, -949, -11217, -3993, -5228, -5395, -421, -3792, -4698, -6520, -6366, -1110, -2417, -5091, -7604, -8282, -3182, -2698, -5569, -7999, -6149, -3058, -1149, -2782, -5494, -1655, -5423, -4878, -2823, -425, -4758, -4616, -5470, -3528, 1229, -4878, -3694, -2318, -7757, 1559, -807, -1796, -428, -3529, 926, 319, -670, 610, -1132, -507, -59, -806, 775, -582, -1285, -1894, -1604, -11, -1141, -280, -4756, -2209, -1942, -1683, 395, -4392, -3263, -5611, -859, 232, -5596, -6205, -10941, 8, -890, -9871, -9277, -6377, 262, -3581, -4485, -3242, -3582, -180, -7947, -3244, -492, -2391, -1929, -2648, -2125, 1089, -2467, -7535, -184, -1467, 1949, -3488, -1853, 927, -1118, 2048, -5434, -232, 1105, 12, 1109, -8568, -1789, 588, 134, -54, -1893, -2458, 90, -2350, 1154, 1134, 1625, 861, -2206, 1874, 2340, 2891, 1827, 813, 1064, 2174, 2645, 2115, 1368, -1399, 752, 1734, 1801, 465, -4924, -1875, 1555, 987, -998, -3232, -5678, 1800, -332, -737, -1065, -4665, 1480, -1490, 7, -36, -2542, 608, -1714, -508, 265, -2403, -86, -2104, -2181, 70, -4109, 53, -2358, -179, -995, -5926, 423, -1358, 1566, -3229, -3574, 424, -385, 1563, -2794, -2277, -289, 57, 211, -1662, -1919, -2226, 214, -608, -2548, -1864, -5770, 128, -489, -5510, -1845, -4538, -522, -1573, -2361, -2327, -3159, -2097, -2126, -19, -3712, -2801, -5200, -529, 895, -4192, -3067, -14878, 331, 844, -2237, -4676, -5338, 164, -106, -889, -10372, -2762, -871, -1700, -574, -4661, -1659, -1252, -2037, -1288, -1745, -1741, -415, -1122, -1881, -221, -2879, -431, -795, -27, 586, -2664, -1936, -1383, 1453, 760, -877, -5747, -3279, 1713, 230, 48, -9848, -6121, 743, -1223, 33, -6267, -4083, -1491, -4338, -683, -3873, -3319, -3890, -10951, -1470, -2171, -4353, -4587, -6234, -1877, -1456, -6665, -4400, -6122, -2562, -1490, -9262, -2215, -8824, -2936, -2028, -5486, -970, -12518, -1587, -2449, -3870, -1006, -5513, -81, -1884, -5070, -1852, -2270, 846, -1583, -9725, -2673, -446, 1035, -2785, -3642, -3626, 299, 384, -4071, -1697, -5615, 0, -845, -1718, -1073, -7410, -1367, -1028, -814, -935, -6894, -3471, -398, -1648, -916, -3548, -6133, -728, -4499, -965, -830, -6958, -2693, -7097, -1111, 409, -3086, -6713, -4160, -1165, 298, -1895, -3881, -2976, -907, -1067, -2241, -1851, -2797, -502, -2215, -3381, -910, -3517, -345, -1448, -4587, -507, -4985, -745, -742, -5417, -460, -4953, -1722, -290, -5442, -719, -2865, -2546, -433, -6672, -1408, -930, -2768, -1687, -15512, -2698, 113, -3871, -4079, -5756, -4240, 71, -8233, -6080, -4337, -4508, -951, -6482, -6111, -5045, -3690, -1837, -3879, -3679, -6100, -3119, -1430, -3633, -2205, -5399, -3187, -1123, -4720, -2134, -4594, -3773, -1525, -7034, -3457, -4808, -4327, -2954, -13724, -6477, -6667, -4058, -6774, -6851, -6498, -11831, -3388, -5873, 4533, 15493, 7130, 11099, 10872, 8971, 15079, 7409, 10372, 10215, 10477, 13792, 7275, 7939, 8110, 10115, 11471, 5974, 2071, 4093, 8807, 7904, 3893, -401, 596, 7640, 6406, 2632, 291, 246, 6353, 7830, 1705, 498, -2133, 5933, 8178, -99, 1669, -1466, 7015, 7495, -3209, 1380, 906, 6642, 5809, -2085, 420, 2649, 3011, 3101, 467, 890, 4060, 2610, 1239, 3134, 2438, 5095, 6134, 4168, 4923, 3666, 5672, 6390, 6574, 5504, 4339, 5666, 5175, 7432, 4771, 4364, 4716, 3611, 6811, 2487, 3671, 2068, 2734, 4441, 897, 2214, -1551, 1422, -1480, 1980, 145, 404, -1713, -829, 1479, -1429, -400, -2830, -620, -980, -1508, -4595, -937, -4509, -5950, -843, -3942, -436, -956, -3109, -86, -2002, -692, 253, -1534, 309, -1370, -1942, -1167, -2427, 197, -874, -4390, -7899, -2739, -461, -450, -4445, -2005, 564, -1706, -673, -4643, 937, 1953, -3334, -2247, -9197, 2447, 1896, -3203, -7384, -2865, 3140, 702, -1405, -4796, -1206, 3044, -1300, -192, -2152, -1597, 2136, -2908, 125, -1193, -3364, 442, -2540, -592, -655, -6300, -1686, -1452, -2733, -319, -2385, -3504, -1146, -6747, -114, 418, -6151, -1916, -7425, -50, 1525, -8056, -3061, -8010, -273, 1413, -4908, -3606, -8036, -740, 45, -4499, -3707, -9333, -1100, -3493, -4605, -2349, -7706, -1075, -5940, -4116, -1488, -4490, -1074, -2420, -4716, -2222, -4322, -1688, -1937, -7574, -5472, -7708, -3210, -2954, -9068, -8547, -8071, -5093, -4749, -6216, -4839, -4324, -4994, -4740, -5370, -4755, -3714, -4619, -3586, -5709, -6445, -4542, -5527, -3203, -6705, -7296, -6022, -7614, -3491, -7190, -5463, -5318, -7737, -3294, -6641, -3769, -3574, -6598, -2733, -6292, -2699, -2511, -6223, -3322, -7125, -2528, -1985, -6367, -6489, -9032, -3192, -1758, -6932, -10492, -10363, -3831, -1862, -7547, -5582, -7436, -3718, -2684, -7591, -4955, -4703, -3850, -5169, -7156, -5282, -3324, -4932, -15759, -6365, -5603, -2636, -7772, -5235, -5242, -5591, -2536, -7604, -3910, -4440, -5019, -3328, -4982, -4552, -4531, -4227, -5154, -4938, -6666, -5498, -4315, -7384, -6805, -10403, -6424, -6270, -8430, -6066, -14886, -5957, -8237, -9381, -4709, -7991, -4773, -6516, -15946, -5086, -4770, -4046, -7510, -8213, -7473, -3115, -3811, -5936, -6036, -13292, -2612, -3598, -3212, -6093, -7140, -2970, -3330, -2197, -7069, -5339, -3798, -3249, -2596, -7484, -4894, -4503, -3658, -4898, -7717, -5436, -4681, -5182, -7703, -9217, -6569, -4421, -10267, -4587, -15266, -5999, -3847, -8154, -4051, -14168, -5103, -3525, -4809, -5255, -9670, -5175, -3853, -3862, -7668, -5919, -5897, -4642, -4121, -8586, -4629, -7287, -5715, -5258, -7177, -5460, -9161, -7852, -7043, -6614, -7702, -10597, -16619, -8897, -6982, -6417, -13152, -8491, -8037, -7590, -5676, -7926, -5771, -7079, 8378, 264, 6883, 11011, 8143, 7556, 1695, 6137, 10467, 7604, 4780, 3511, 3566, 8760, 5905, -1905, 4481, 1645, 5576, 3317, -5876, 4662, 3831, 483, 3090, -657, 4234, 4030, 917, 3836, 2385, 3349, 2513, 2198, 3803, 3375, 2196, -346, 2695, 3488, 3584, 819, -176, 2702, 3452, 2746, 335, -412, 2651, 3857, 1787, 2832, 1422, 3444, 4373, 5252, 4678, 5194, 4458, 4573, 7185, 5288, 6970, 4627, 4164, 7558, 4889, 7263, 3451, 2960, 6666, 3846, 6129, 1351, 758, 4646, 2817, 2960, 2364, -3368, 1865, 2292, -15868, 3155, -5752, -564, 1822, -116, 2577, -2844, -2178, 610, -161, 1399, -2842, -3605, -1454, -690, 520, -2531, -955, -1400, -539, -353, -1441, 1152, -124, -2240, -2051, -868, 1843, 464, -11447, -4585, -824, 1495, 678, -1738, -5301, -1185, 281, 745, -280, -5586, -1797, -1825, 459, -992, -6544, -2607, -5670, -649, -4226, -6437, -4093, -9434, -2416, -5874, -4257, -7643, -4370, -1347, -2625, -2606, -5330, -3094, 283, -2130, -1978, -2963, -3396, 824, -3189, -1573, -2398, -5621, 448, -5830, -798, -2397, -12478, -642, -10395, -161, -1970, -5002, -2176, -11549, -242, -785, -3316, -4916, -7381, -1520, 502, -2597, -9442, -4302, -5125, 1082, -1579, -3107, -2656, -2112, 665, -1043, -2269, -1962, 1021, -494, -1698, -4389, -2045, 2453, -1441, -4094, -4653, -3063, 2833, -2423, -13200, -2195, -5171, 2263, -4770, -6279, -2685, -4206, 699, -11234, -4126, -5226, -2200, -889, -6141, -3336, -2471, -1746, -560, -3305, -3339, -1170, -2899, -506, -3067, -4504, -2083, -7249, -1161, -4422, -7364, -6452, -7606, -1149, -5031, -7721, -5413, -4786, -466, -5029, -5662, -2999, -6071, -230, -5115, -4645, -3330, -11883, -811, -4326, -4105, -5245, -6769, -2428, -3992, -4199, -6936, -6518, -5211, -4770, -5177, -5351, -9277, -5506, -7365, -5638, -2906, -9850, -3555, -18071, -4137, -2140, -6688, -2506, -11084, -3154, -3833, -4152, -2146, -9314, -3232, -7623, -2662, -2270, -6701, -4756, -2688, -2446, -2726, -5357, -10055, -1806, -3670, -3392, -5184, -7186, -3235, -6329, -4180, -5034, -5349, -8245, -7533, -4973, -4501, -5329, -6564, -8702, -5175, -4938, -4572, -3817, -13587, -3909, -6498, -3654, -2700, -8833, -2464, -4797, -3378, -2376, -7217, -1812, -3428, -3628, -2944, -6491, -2063, -3960, -3761, -4608, -6658, -3034, -6518, -2849, -6431, -8580, -3801, -7431, -2009, -6121, -16045, -3344, -5560, -2096, -5897, -10675, -2850, -5160, -3323, -6165, -8817, -3093, -5969, -6089, -6663, -8860, -4081, -8848, -13227, -7866, -10554, -5060, -9306, -10594, -9882, -12794, -4854, -5107, -7765, -7546, -9109, -4704, -3508, -6253, -4799, -6608, -5836, -3334, -5350, -3322, -5327, -9282, -4326, -4660, -2846, -5363, -7109, -5836, -3927, -3251, -7120, -4339, -5865, -3254, -4504, -9555, -3564, -5144, 1256, 8194, 9051, 8438, 6129, 650, 7937, 8480, 7806, 6110, 593, 6913, 6782, 5746, 5680, 1396, 4326, 4193, 1459, 4087, 699, -3885, 2269, -3077, 178, -1300, 2669, 2316, -3257, 1229, -395, 4207, 1878, -348, 2806, -745, 3878, -490, 2326, 2043, -6821, 2190, -9079, 2726, -404, 2215, 355, -1577, 2680, 1752, 5378, 1813, 1864, 4276, 4284, 6994, 4431, 3807, 5208, 5306, 7530, 5770, 4359, 4429, 4896, 6988, 5456, 3166, 388, 2751, 5161, 2708, -623, -360, 3728, 1734, -3842, 1396, 2724, 6103, -350, 2628, 2636, 1996, 6816, -647, 3185, 1600, -2459, 6482, -3023, 2185, -1368, -3164, 5709, -7149, 372, -6559, -756, 4888, -5411, -2287, -12196, -1359, 3713, -2871, -4511, -9419, -3677, 1748, -2653, -5209, -5848, -5567, -924, -4604, -8946, -3825, -3525, -2421, -15332, -4285, -2637, -2461, -1599, -5356, -2543, -1760, -1539, -2080, -2989, -3332, -1242, -553, -7473, -2254, -4298, -1333, 51, -966, -2558, -1966, -1802, 158, 1360, -3677, -1343, -2179, -240, 1463, -4227, -2395, -2938, -1199, -487, -3520, -3483, -4805, -2796, -7193, -2827, -3956, -7252, -5226, -2860, -2057, -5333, -12403, -8461, -1370, -1333, -4898, -4867, -4416, -1209, -1339, -4761, -1651, -1420, -763, -2458, -3962, -610, 30, -99, -4593, -2531, -997, 341, -220, -6698, -3370, -2282, -267, -1783, -5861, -10912, -1765, -1616, -2858, -4350, -3667, -232, -3596, -457, -4035, -2491, -17, -4169, 839, -4041, -4380, -1642, -2772, 1037, -3197, -3931, -6408, -1924, 423, -1948, -1864, -4142, -621, -571, -1301, -2064, -2997, 731, -961, -1589, -4497, -4267, 1250, -926, -2992, -8958, -8864, 917, -1474, -7457, -6750, -7896, 44, -2788, -5957, -6933, -5080, -899, -4510, -2528, -7146, -4167, -1538, -5667, -2113, -6172, -3159, -2182, -5590, -3646, -5813, -2198, -3796, -5537, -7502, -5014, -1999, -8334, -5487, -8382, -4255, -2704, -10080, -4584, -7250, -4315, -4114, -7922, -3508, -7169, -4759, -5307, -12536, -2807, -5831, -4859, -4921, -8245, -2569, -4107, -4743, -4018, -5103, -3040, -3088, -5043, -3730, -3963, -4918, -2810, -6461, -4368, -3629, -10136, -2912, -10574, -6007, -3890, -5810, -3042, -11332, -8360, -4947, -3876, -3399, -7554, -10480, -6989, -3516, -4362, -5965, -12544, -6735, -3533, -5859, -5315, -14505, -4827, -3209, -7345, -5893, -14616, -4171, -3017, -9808, -8271, -13590, -4636, -3677, -14120, -9644, -9215, -6100, -5605, -12666, -8331, -6548, -8048, -7381, -10863, -10016, -5139, -7709, -5938, -6204, -15211, -4551, -6454, -4807, -4875, -8887, -4491, -6128, -3721, -5659, -7500, -4682, -6747, -2556, -7675, -6139, -4864, -7890, -1964, -6667, -4402, -5188, -8256, -2320, -4996, -3710, -6703, -7762, -3806, -4001, -4335, -11670, -7648, -6396, -3930, -6030, -5334, -8387, -8283, -5021, -7927, -3020, -9673, -7495, -8041, -6548, -6351, -4577, -6923, -7329, -8284, -6631, -4061, -7063, -5307, -8390, -6378, -4222, -7515, -4424, -7435, -5524, -5190, -6242, -5340, -6891, -6092, -6443, -4482, -9412, -6512, -8504, -7151, -3780, -6509, -6541, -7944, -7748, -4030, -3881, -7323, -6572, -8041, -5028, -3184, -8845, -7005, -7553, -6481, -3803, -8940, -8206, -6558, -7744, -6040, -6500, -8761, -6037, -7925, -10519, -5080, -9533, -6506, -7240, -9368, -4760, -9287, -8232, -7063, -10010, -4792, -7236, -12589, -7486, -9919, -5057, -5658, -8648, -7374, -7534, -6010, -4564, -5838, -5932, -5664, -6665, -3232, -6002, -4453, -3240, -4373, -1650, -13290, -3202, -865, -1386, -185, -2610, -1208, 688, 185, 948, 143, 530, 1179, 389, 1454, 963, 1243, 482, -607, 1088, 355, 836, -1785, -2522, -295, -1720, -758, -8318, -4503, -2747, -4915, -3800, -5798, -5229, -5997, -5149, -7227, -3822, -5190, -8891, -5027, -5935, -4036, -5501, -11012, -5751, -5296, -5407, -5933, -14699, -6245, -5838, -7147, -5933, -7333, -6323, -7869, -6831, -5364, -5247, -6471, -12393, -6155, -4895, -4878, -6556, -8509, -6499, -4992, -5571, -6484, -6755, -7576, -5429, -6747, -6782, -6913, -8912, -5640, -6000, -7704, -8167, -8864, -5128, -4469, -8921, -8017, -6624, -4493, -4273, -9640, -7406, -5049, -4473, -5991, -9343, -7561, -4418, -5066, -13268, -8643, -6815, -4450, -5720, -8838, -8074, -5190, -4799, -5812, -7425, -8578, -3930, -4919, -5457, -8368, -10504, -3413, -4635, -5151, -10434, -8473, -3847, -4677, -5001, -14928, -6745, -5601, -5846, -4794, -13557, -6224, -9763, -9292, -4507, -10355, -6021, -7168, -9656, -4467, -9557, -6503, -4641, -8241, -5059, -8694, -8687, -3764, -11422, -6437, -8146, -8778, -3950, -7103, -7453, -9133, -6146, -5314, -4463, -7307, -13477, -5448, -8279, -4093, -8118, -10718, -6447, -8181, -5475, -10931, -8180, -10001, -7192, -8322, -15204, -7878, -10771, -9099, -7508, -16281, -8573, -8246, -11432, -6265, -15411, -7892, -8576, -7119, -6237, -10841, -6883, -9984, -5696, -6866, -8892, -7123, -7987, -5549, -7763, -7957, -8032, -6305, -6345, -8954, -7489, -7324, -5799, -7600, -10486, -7290, -6169, -5854, -7392, -9232, -7372, -5691, -6019, -6508, -7284, -7752, -5822, -6340, -6327, -6590, -8314, -6392, -7067, -6831, -6989, -8911, -6713, -8579, -7890, -7869, -9445, -6372, -10999, -9800, -7776, -9341, -6414, -10052, -11851, -7401, -8415, -7597, -8164, -10261, -8170, -7870, -9737, -7401, -10459, -10877, -8278, -9718, -7889, -16067, -13568, -9071, -9638, -9811, -10978, -12213, -8858, -12121, -9877, -8305, -12370, -8594, -13135, -9242, -7339, -8537, -8928, -9409, -11784, -6960, -6211, -9573, -8126, -11065, -7114, -5472, -10652, -8225, -8324, -8287, -5949, -10635, -9908, -8492, -11586, -7270, -8860, -15514, -11024, -18718, -8410, -7806, -11134, -12072, -14639, -8466, -7747, -8489, -10385, -18810, -8197, -8742, -7493, -9563, -13499, -2908, -6699, -7247, -4378, -5073, -3327, -10845, -5664, -6704, -5999, -5316, -12007, -4681, -6668, -8456, -11358, -7040, -4423, -5286, -14984, -5540, -5199, -5265, -5211, -8728, -3696, -4677, -7107, -6611, -6682, -3638, -5055, -7761, -13025, -6529, -4707, -5934, -7805, -8128, -7618, -5980, -6600, -9058, -5764, -8213, -6226, -6227, -8087, -6096, -7454, -6407, -5201, -6920, -7532, -7107, -6511, -4581, -7163, -6288, -7064, -6532, -4870, -6736, -5605, -7004, -7435, -6602, -5552, -6552, -6745, -7886, -12200, -5388, -7769, -6227, -6979, -6980, -5654, -7796, -5688, -6463, -4928, -6064, -6473, -4840, -4803, -5437, -11898, -3453, -2951, -2292, -4249, -3831, -573, -738, -575, -1265, -669, 1261, 600, -18, -52, 336, 1930, 743, -753, -352, -12, 1425, -450, -3087, -2171, -1392, -310, -3143, -7103, -6068, -3344, -3185, -5780, -7571, -8065, -5057, -5027, -6312, -6455, -6798, -6420, -4856, -6105, -4670, -7252, -9081, -4674, -4671, -4106, -7864, -13386, -4465, -4086, -5220, -8621, -10281, -4309, -4242, -8559, -9005, -10797, -4498, -4461, -7752, -8497, -7325, -5414, -4277, -5370, -7797, -5059, -7937, -3897, -4982, -6640, -4296, -11752, -3836, -6238, -6072, -4338, -6354, -4438, -6660, -6407, -4700, -4666, -5675, -4453, -7390, -5256, -4511, -6533, -3547, -8897, -6522, -4832, -6306, -4020, -11184, -10382, -4960, -6389, -5959, -13516, -10335, -6209, -7820, -11066, -12590, -6437, -14322, -12986, -10320, -10129, -5207, -6874, -10885, -6944, -7587, -4943, -4813, -8883, -5362, -5973, -5279, -5283, -7056, -4170, -5508, -6155, -8576, -4767, -3337, -6284, -7542, -11029, -3905, -3103, -7915, -10062, -6884, -4627, -3659, -6884, -16473, -5993, -7170, -5101, -5139, -8567, -5852, -10715, -7398, -4371, -6536, -5670, -11270, -10348, -4382, -5992, -5626, -18778, -9143, -5134, -5752, -6121, -9399, -6596, -6755, -5309, -7402, -6917, -5445, -8929, -5428, -9935, -6312, -5132, -10054, -7106, -10118, -6658, -5255, -9667, -13075, -7099, -6394, -5653, -7872, -8792, -5678, -5288, -6438, -6763, -7146, -5493, -4663, -7384, -6729, -7684, -6347, -4530, -7160, -7379, -9507, -7291, -4559, -6680, -8148, -11206, -6599, -4802, -7142, -8712, -10361, -5839, -5422, -8417, -9661, -8222, -5888, -6181, -9920, -13604, -6597, -6609, -6751, -11337, -11829, -5824, -7493, -7258, -12042, -7840, -5990, -8131, -7717, -10880, -6602, -7278, -8949, -8032, -9651, -6747, -10059, -10509, -8548, -9624, -8103, -13261, -12531, -9616, -10733, -10395, -12730, -10939, -9319, -11676, -10460, -12527, -9983, -8093, -10785, -9309, -12955, -10411, -7973, -9245, -8938, -13295, -9574, -8281, -8789, -9000, -9805, -9090, -8248, -9757, -9125, -7776, -10044, -8898, -9633, -9117, -7390, -9505, -10617, -8342, -8800, -8461, -8786, -12609, -8822, -8115, -10808, -10312, -19216, -11882, -7526, -10971, -18444, -11727, -11604, -7828, -9439, -10460, -9691, -10746, -10399, -8907, -8269, -10319, -6878, -9851, -2641, -8407, -6705, -6866, -10729, -3982, -6529, -7147, -5880, -8550, -8117, -5432, -9053, -5592, -6433, -7111, -4552, -9303, -5849, -4964, -5221, -3781, -6290, -6387, -3769, -5732, -3360, -4621, -6109, -2878, -8342, -3383, -4350, -4191, -2694, -9240, -3989, -5223, -3001, -3438, -6009, -5375, -6996, -3143, -5046, -4195, -6291, -10745, -4699, -6768, -3080, -5204, -10279, -7260, -7703, -2416, -4464, -6950, -7035, -7753, -2151, -4372, -6527, -6596, -7208, -2333, -4532, -8309, -8248, -6634, -3117, -4632, -15361, -9623, -5373, -4999, -4484, -9217, -6905, -4820, -12682, -4436, -6508, -6933, -4762, -5006, -3898, -3783, -3713, -1910, -1481, -1738, -1064, -643, 227, 177, -122, 543, 585, 909, 595, 257, 852, 386, 309, -314, -640, -275, -1112, -1534, -3212, -2963, -3566, -3883, -4501, -7127, -6597, -9483, -7485, -7128, -4571, -7375, -4444, -11865, -7870, -5313, -7155, -3428, -11077, -7770, -9125, -8310, -3381, -7399, -6912, -8765, -11503, -3966, -6346, -6521, -7168, -11360, -5531, -7257, -7706, -7116, -7068, -7660, -12054, -10682, -8340, -5558, -7006, -8854, -9587, -9526, -6069, -6389, -7118, -9337, -5638, -9274, -6453, -8845, -12604, -3441, -10968, -6227, -14733, -10009, -2529, -10137, -5697, -8539, -7247, -2413, -12264, -5425, -8522, -6545, -2854, -6333, -5646, -12419, -7328, -3787, -4279, -6259, -8824, -9771, -4800, -3838, -6481, -7261, -8563, -4664, -4541, -6203, -7890, -6232, -4045, -6420, -6541, -6816, -5547, -3955, -9842, -7972, -5009, -5959, -4435, -10213, -10475, -4682, -6963, -5504, -7886, -11744, -5499, -7792, -7511, -7102, -11514, -5834, -7854, -9814, -7475, -13256, -4957, -7573, -8841, -7927, -13400, -4683, -7644, -7727, -7390, -9887, -5684, -8306, -7013, -6861, -7521, -8562, -10015, -6961, -6447, -5779, -15776, -10543, -8142, -6028, -4576, -14903, -7085, -10275, -5988, -4022, -9449, -6034, -10182, -6406, -4355, -7039, -7576, -10481, -6594, -5971, -6042, -10735, -12139, -6102, -10077, -5147, -6540, -9336, -5684, -13039, -4449, -5644, -7173, -5861, -10946, -4710, -6404, -6152, -6929, -12656, -6287, -6600, -5901, -9247, -8756, -9140, -5629, -6384, -11170, -6098, -9513, -5078, -7412, -10098, -4956, -7975, -4866, -7864, -9491, -4904, -7755, -4930, -7681, -8716, -5856, -9063, -5549, -8024, -7235, -7838, -10883, -6812, -8157, -5775, -11198, -10213, -8346, -7342, -5226, -16470, -8954, -9620, -7158, -5899, -10835, -8071, -10983, -8544, -7222, -10022, -7876, -13422, -12045, -7091, -14439, -8548, -15395, -10606, -6787, -10761, -10332, -12884, -8817, -7185, -8085, -10652, -10287, -8365, -7504, -8403, -8478, -8341, -8698, -7538, -8349, -7415, -7562, -8799, -7687, -6477, -7272, -7897, -8144, -8004, -5823, -7833, -8661, -8029, -8453, -6541, -9320, -8159, -8876, -9742, -9087, -11904, -7116, -10415, -10815, -14632, -10865, -6658, -11041, -7507, -8806, -9105, -6804, -9543, -5818, -7707, 10155, 12746, 13112, 9384, 6364, 9425, 12279, 12488, 8807, 5785, 6856, 10838, 10468, 7169, 4021, -1794, 8320, 6370, 5113, 1089, 3338, 4773, 2049, 3570, -2031, 4578, 1878, 3081, 2124, -3039, 4190, 2224, 1344, 426, -4825, 2790, 3118, -1476, -3958, -4895, 1593, 3326, -3336, -3215, -40, 1441, 2672, -2582, -63, 2254, -2078, 622, -2736, 1020, 3521, -1089, -6869, -1708, 2853, 4154, 1811, 1747, 62, 4384, 4192, 1339, 4130, -49, 4952, 3521, 776, 4507, -2725, 4560, 2308, 2035, 3068, -3883, 3154, 2592, 2099, -2045, -1190, 368, 3919, 780, -955, -1675, -4758, 4235, -493, 1643, -5914, -2613, 3299, -102, 2175, -3555, -576, 1433, 323, 1824, -2409, 554, -344, 524, 616, -3957, 1226, -3936, 628, -124, -3020, 1340, -3346, 361, 1304, -944, 997, 114, -405, 2360, 69, 317, 418, -1152, 2405, 535, -1268, -1198, -1069, 1531, 603, -5980, -5265, -577, -49, 269, -6258, -4021, -918, -1856, -616, -3713, -1023, -2786, -3457, -2425, -4304, 609, -1514, -5701, -4607, -6379, 1493, 253, -5339, -5188, -10266, 1581, 28, -1870, -4916, -5895, 550, -2190, -734, -3085, -3294, -2146, -4314, -1378, -3039, -1655, -2526, -1846, -3501, -6895, -253, -421, -642, -5841, -5964, 766, 65, -417, -6885, -2925, 1104, -557, -677, -3422, -2869, 680, -2226, -977, -1882, -4846, -307, -5870, -1316, -2482, -7492, -1746, -5986, -1963, -3896, -4590, -4094, -2960, -2495, -1718, -4834, -5027, -2262, -2106, -268, -14176, -4192, -2772, -1617, -161, -4262, -5206, -3131, -1845, -1199, -2457, -5959, -2018, -2950, -3579, -2876, -5138, -300, -4511, -8852, -4098, -5770, 1085, -5111, -8511, -4172, -8071, 1678, -4856, -3797, -3774, -9588, 1229, -5366, -1471, -3627, -6087, -643, -7686, -479, -3710, -3453, -3701, -5377, -581, -3755, -2312, -1745, -2660, -1705, -3430, -2398, -620, -1427, -4016, -2901, -3232, -1016, -1039, -7903, -2776, -4205, -2516, -1344, -7185, -3750, -5736, -4869, -2431, -5456, -6694, -7873, -7378, -4341, -5246, -10595, -12277, -6725, -5936, -6069, -6533, -6152, -4723, -5557, -6075, -3954, -2296, -3849, -4801, -4137, -2590, -1009, -4258, -4566, -2724, -2469, -1338, -5936, -5982, -2265, -3786, -3074, -8221, -11402, -2912, -6822, -5872, -8258, -4370, -5367, -4966, -7581, -7360, -2243, -6281, -3751, -6287, -7066, -1808, -2884, -5122, -5047, -6901, -2359, -1531, -9857, -5059, -5925, -3686, -1311, -7128, -6167, -4822, -6161, -1804, -6896, -5863, -4475, -6151, -2600, -9974, -4072, -5347, -3663, -2725, -15938, -3560, -8575, -2717, -1770, -10213, -4551, -7879, -2768, -787, -9373, -4406, -4310, -3255, -205, -9962, -2890, -2963, -3422, 1, -6661, -3392, -2844, -3029, -170, -4916, -8209, -3539, -3108, -942, -4675, -3966, -3962, -3867, -2982, -4586, -1818, -3373, -4092, 7465, 10363, 10751, 7892, -896, 6569, 9725, 10121, 7108, 489, 3261, 7811, 8164, 4473, -38, 1488, 4891, 4774, -1000, -2812, 3807, 1945, 981, -1314, -4478, 3427, -937, 259, -2409, -518, 2267, -4716, 342, -3855, 954, 2702, -1194, -894, -4800, 1416, 3355, 2541, -24, -4117, 1331, 3433, 3956, 950, -5606, 1135, 2957, 4417, -231, -2425, 1451, 1445, 4334, -740, -4, 1960, -2938, 3566, 1676, -36, 2061, -443, 1518, 2270, -1102, 1814, 2329, -4486, 1457, -1257, 1751, 3119, -2316, 873, -678, 2230, 2757, -404, 1232, 550, 2768, 1250, -906, 1095, 1159, 2764, -1686, -2178, 629, 491, 1950, -1012, -2263, 502, -1620, 151, 803, -1032, 320, -5347, -2789, 1188, -332, -302, -9984, -2968, 1024, -469, -936, -8802, -1426, 921, -1322, -874, -4464, -1272, 774, -3355, -300, -1727, -1962, 407, -4289, 192, -290, -2721, -63, -741, 414, -45, -2883, -413, 1133, 417, -1107, -2659, -597, 1776, 49, -3274, -3075, -661, 1373, -1110, -2215, -5329, -642, -89, -3609, -769, -10998, -851, -2524, -9132, -735, -5260, -666, -4873, -5634, -1800, -3680, 670, -5591, -1939, -3299, -4235, 1397, -7483, -350, -4024, -6442, 682, -10761, 74, -5944, -1923, -2142, -4543, 208, -6266, 39, -12373, -2914, 956, -2055, -71, -3681, -2241, 2248, -784, -2158, -2380, -1894, 3287, -867, -2712, -2920, -1889, 3491, -1740, -699, -3844, -2384, 2524, -3659, -485, -2494, -3500, 9, -4356, -2160, -1864, -3123, -1755, -2585, -8293, -2174, -1722, -256, -2470, -4448, -2638, -1516, -185, -4057, -2350, -3833, -3287, -1331, -7535, -2298, -6043, -7242, -2531, -11586, -3140, -4751, -2519, -1968, -9226, -3707, -3978, -1185, -1044, -6128, -3021, -5076, -1576, -888, -4336, -2184, -6571, -3061, -1757, -3834, -2065, -5168, -5343, -3763, -4201, -2827, -3367, -9239, -5769, -4884, -4592, -2241, -8583, -5319, -6652, -7865, -1871, -5208, -5235, -6257, -10939, -1962, -4412, -6054, -2774, -7764, -2222, -5460, -5720, -1289, -4814, -2796, -6417, -5008, -886, -3633, -4235, -4891, -5366, -1022, -4116, -7967, -4810, -6575, -1521, -4923, -11224, -7129, -7925, -2409, -3956, -6990, -17269, -8064, -3622, -3433, -5957, -8662, -6873, -4986, -3865, -5455, -5338, -6159, -7519, -4616, -5257, -3224, -7325, -9523, -4790, -5156, -2448, -9371, -3567, -4489, -5697, -2821, -5314, -1640, -4708, -8441, -3770, -3707, -1381, -6199, -8236, -3921, -3471, -2251, -8708, -4559, -3491, -3836, -3328, -8789, -3216, -3637, -4449, -3813, -9644, -3129, -4424, -5738, -4748, -7124, -3965, -4513, -6723, -5711, -4060, -5275, -3835, -4397, -3995, -2311, -5990, -4048, -3026, -2356, -1567, -5673, -5713, -2770, -1660, -1904, -5196, -10226, -2655, -1716, -3442, -3897, -6594, -1813, -2358, -5478, -2519, -3534, -912, -3236, 2816, 10853, 11130, 7971, 5305, 2639, 10384, 10551, 7334, 5102, 1951, 8983, 8721, 5502, 4500, 472, 6733, 5317, 2994, 3652, -2632, 4136, 846, -685, 2731, -942, 2498, 250, -2235, 1608, 1547, 2032, -817, 2360, 1113, 2142, 1255, -1477, 3248, 2007, 2181, -258, -1515, 2199, 2816, 2574, -934, -2617, -551, 3123, 3037, -17, -2686, 1598, 2910, 3264, 1765, 319, 3044, 1515, 3095, 3165, 1646, 2554, -4918, 2191, 3454, 1129, 531, 1550, 591, 2469, -2124, -1176, 4667, 243, 798, -3351, -1221, 6207, 202, 977, -39, -1104, 6777, -1813, 1461, 366, -318, 6336, -1875, 1209, -607, -15, 4776, 1149, 936, -2417, -791, 2440, 2332, 1056, -3948, -2974, 1560, 2195, 1417, -3292, -8100, 1569, 929, 1661, -1614, -3619, 997, -930, 1448, -901, -1155, -156, -1963, 846, -2205, -348, -1919, -2811, 257, -8398, -214, -3453, -4946, -206, -1537, -170, -7124, -10364, -164, 402, 115, -4540, -12621, 588, 652, 896, -1195, -16424, 900, 60, 1597, -1237, -7107, 278, -1201, 1633, -3867, -3272, -858, -4112, 939, -2844, -900, -1321, -10210, -263, -1175, 454, -1039, -4481, -2017, -716, 561, -736, -6075, -5001, -71, -1380, -522, -4911, -1851, 211, -5301, -51, -100, 645, -415, -538, 199, 1670, 1488, -1398, 29, -730, 1896, 1173, -1821, -2739, -3889, 487, -216, -2279, -6894, -6878, -3666, -2184, -3296, -2486, -6489, -1177, -1264, -4863, -3892, -11466, 696, 258, -4590, -6984, -3988, 744, 570, -2274, -3033, -2936, -16, -459, -1090, -1224, -4081, -1101, -2535, -1339, 120, -7075, -3108, -1752, -3254, 546, -14394, -7204, -355, -3727, -306, -8928, -4062, 58, -1666, -2335, -5461, -2334, 28, -982, -2879, -4177, -2322, -84, -990, -2306, -3866, -3444, -366, -908, -3226, -3878, -5506, -1203, -564, -6448, -4126, -11451, -2910, -152, -8746, -4208, -6954, -3861, 100, -5412, -3887, -4327, -2458, 36, -4128, -4020, -4759, -1580, -462, -3551, -4817, -5465, -1384, -1518, -3568, -5537, -2972, -1548, -2904, -4034, -5937, -1743, -2046, -3334, -4066, -7162, -1717, -2720, -2923, -3738, -10740, -2582, -2337, -2918, -4108, -10690, -4479, -1383, -3176, -5674, -9109, -8246, -1332, -2751, -8263, -9485, -10896, -2741, -2023, -8803, -4645, -7508, -5089, -2009, -7045, -2053, -5038, -2886, -2801, -4004, -1291, -3449, -1253, -3022, -2556, -2207, -3232, -859, -2392, -2889, -4765, -5100, -1269, -2410, -4490, -4375, -12314, -2208, -3197, -4435, -3202, -5109, -3341, -4380, -3450, -3109, -3996, -4346, -6059, -1620, -2968, -4817, -5390, -7471, 117, -2499, -5740, -6338, -5152, 752, -2173, -6120, -6169, -4065, 257, -2365, -8440, -4260, -4972, -1232, -3283, -8427, -2650, -7703, -3235, -5008, -4629, -2540, -7609, -4511, -5536, -3071, -5195, -7715, -2229, -7725, -3696, -1743, -3123, -402, -3041, -2461, -2227, -3511, 82, -1098, -1439, -2126, -3625, -604, -1073, -1291, -1826, -3226, -2174, -2719, -2504, -1520, -3114, -3895, -6905, -3542, -946, -4190, -5272, -7702, -2073, -304, -9118, -7403, -5800, -2159, -127, -4725, -6445, -6421, -5627, -774, -2103, -3377, -9635, -5046, -2299, -1817, -1608, -11314, -1802, -3645, -3641, -607, -7169, -1155, -3617, -5895, -97, -5934, -1594, -3750, -2787, -76, -5338, -2697, -4602, -1917, -767, -3873, -3565, -4736, -2394, -2683, -2203, -2411, -3080, -3139, -8290, -1188, -1566, -2246, -3717, -6051, -1043, -2144, -2269, -4135, -3166, -1736, -4665, -1541, -3420, -2445, -2807, -5714, -428, -1720, -2671, -3901, -3742, -133, -304, -3534, -6730, -4461, -635, 196, -4999, -9280, -10084, -1368, -461, -6250, -3601, -7678, -1850, -2531, -4963, -1718, -6610, -2500, -5824, -3788, -911, -10839, -4332, -5219, -3619, -707, -7788, -9632, -2921, -4230, -945, -5913, -8131, -1636, -5498, -1431, -6064, -7834, -1339, -7316, -1910, -6401, -7193, -1225, -7706, -2012, -5833, -4882, -998, -6730, -1463, -4220, -3883, -1552, -7327, -1007, -3446, -3715, -3291, -9721, -1335, -4379, -4961, -4267, -8177, -2680, -8030, -7886, -4251, -8146, -4898, -11524, -5527, -6364, -9818, -4962, -9179, -4559, -12750, -7549, -3475, -7716, -5543, -10002, -6633, -2922, -5897, -8312, -16142, -5658, -3029, -4932, -15307, -9516, -4894, -3818, -4216, -12433, -8084, -5217, -6432, -3736, -10402, -5130, -4942, -11180, -3459, -8452, -2451, -4563, -6610, -3042, -5685, -1321, -6302, -7019, -2659, -3931, -1369, -14280, -10820, -2711, -3088, -2285, -9053, -9099, -3352, -2633, -3749, -11980, -9436, -4253, -2509, -5009, -8102, -13941, -4320, -3419, -4522, -5168, -12003, -4059, -7399, -3655, -4747, -14360, -4608, -6510, -3954, -5312, -8539, -5475, -3113, -6467, -5601, -6161, -5400, -2508, -12457, -6038, -5294, -5312, -3169, -5293, -7629, -4882, -5578, -4175, -3787, -8540, -4697, -6554, -3984, -4043, -7789, -5165, -8141, -2751, -6578, -7592, -7204, -6154, -2242, -11739, -5629, -15877, -4579, -3361, -5185, -3711, -7014, -3568, -8555, -3553, -2900, -4905, -2461, -5455, -2903, -3147, -4420, -1824, -2925, -2480, -4606, -4717, -2029, -2581, -2166, -8433, -5083, -3066, -3064, -2108, -11378, -5143, -4636, -3586, -2551, -7590, -5327, -5433, -4131, -3709, -8176, -6163, -4356, -4980, -5464, -13694, -8437, -3324, -5727, -7051, -11130, -12397, -3008, -6211, -8993, -9184, -8892, -3231, -7306, -7476, -9969, -7742, -3573, -10203, -4634, -12684, -7927, -3684, -16659, -3624, -17243, -8584, -3813, -9568, -3837, -13002, -8983, -4193, -7514, -4636, -10462, -8864, -4036, -5969, -5485, -8704, -8689, -3081, -4683, -6535, -7310, -7888, -2436, -3996, -7866, -6560, -7437, -2539, -3992, -9937, -6985, -9075, -3531, -4695, -11614, -9521, -14498, -5769, -6377, -8750, -6250, -2388, -2382, -792, -3844, -5568, -4195, -2097, -1896, -4692, -3336, -7965, -2214, -4281, -6960, -2085, -4817, -2960, -4738, -14538, -2011, -4251, -4964, -4203, -9271, -2839, -6000, -9238, -3609, -8753, -4399, -4727, -9798, -2251, -8970, -7127, -2190, -7635, -1894, -5336, -4922, -1187, -6424, -3022, -3667, -2114, -1209, -5803, -5445, -3153, -1059, -1714, -5782, -6155, -2981, -1207, -1976, -6663, -6096, -2844, -2311, -2135, -7195, -8362, -2705, -4110, -3132, -3972, -14535, -2467, -5510, -5792, -1921, -7078, -2310, -4635, -4818, -1135, -5387, -2569, -3822, -2402, -1269, -4121, -3458, -4663, -1609, -2134, -2080, -5044, -10175, -1910, -3693, -420, -7921, -5837, -3250, -6267, 390, -11087, -2919, -5527, -11392, 354, -4261, -2479, -5466, -12193, -474, -1930, -3810, -4357, -7850, -1864, -1383, -4977, -4058, -6027, -2994, -2375, -3743, -3166, -5115, -2870, -4993, -4345, -2099, -4091, -1980, -7257, -8726, -2171, -3207, -1416, -4962, -7049, -4404, -3282, -1581, -2328, -4625, -11970, -4971, -2512, -957, -4192, -3732, -8884, -3966, -954, -4571, -2315, -4916, -3980, -2717, -4787, -2467, -2751, -2466, -10008, -4276, -3237, -1999, -1585, -3612, -3781, -3062, -2151, -1621, -1599, -3895, -2077, -3195, -2708, -1552, -4783, -1739, -5405, -5519, -2732, -5996, -2242, -6747, -8327, -4793, -6178, -3120, -5205, -4868, -6877, -5084, -3574, -4568, -3278, -8116, -4178, -3346, -3155, -2751, -9489, -3357, -2974, -1424, -3687, -8878, -2607, -3122, -724, -7232, -7028, -2531, -4177, -1287, -8077, -4775, -3380, -6154, -3483, -8296, -2786, -5279, -7446, -9742, -7717, -2005, -6688, -8091, -7778, -4203, -2509, -3835, -9854, -6041, -3579, -3402, -2103, -5315, -6127, -4537, -3127, -1887, -2927, -7252, -5946, -3274, -3282, -2280, -8381, -6652, -4967, -7575, -3073, -6001, -7409, -8732, -10256, -5786, -4500, -10375, -14838, -7218, -12124, -4221, -8848, -10338, -7181, -5745, -4837, -5972, -6104, -7131, -3726, -6107, -5315, -4291, -6432, -3057, -7145, -5953, -4118, -5286, -3563, -7131, -7803, -4913, -4846, -5573, -7630, -12685, -4135, -5862, -5860, -8251, -10917, -2629, -9106, -3478, -5686, -7278, -1934, -6210, -2447, -3660, -6232, -1807, -4019, -2351, -2685, -6934, -1713, -3831, -2811, -2361, -10394, -1327, -5543, -3893, -2399, -11271, -924, -12006, -6556, -2697, -8086, -980, -6260, -8052, -3147, -7675, -1867, -3905, -4646, -3523, -8270, -4120, -3468, -3723, -3978, -8272, -9603, -4622, -4360, -5092, -6699, -5698, -8289, -6575, -7691, -4966, -3395, -7250, -13723, -9388, -3800, -2684, -5014, -8438, -5655, -3298, -2890, -4606, -5398, -3834, -3409, -3617, -4354, -4354, -3106, -3951, -4212, -3430, -4542, -3071, -4575, -4677, -2538, -5841, -3489, -4923, -5681, -2124, -8023, -4274, -4900, -7264, -2333, -8982, -5708, -4813, -8796, -3313, -8289, -8689, -5138, -7854, -5175, -8156, -10859, -6117, -5752, -5528, -4471, -2652, -6196, -11727, -8669, -4997, -2925, -1220, -9177, -4889, -4601, -3001, 373, -6932, -2599, -2013, -2167, 571, -6367, -2479, -1175, -1324, -277, -4778, -3825, -2284, -1048, -2049, -2983, -3926, -5524, -1465, -4418, -2204, -2113, -3979, -2658, -6428, -2456, -1106, -2602, -4177, -8465, -3291, -1040, -2746, -4047, -10954, -3643, -1595, -3662, -3529, -5062, -3396, -2253, -5660, -4050, -2701, -3635, -3181, -7993, -5894, -1968, -5269, -5613, -4906, -11586, -2387, -6787, -19755, -3199, -7378, -3991, -3393, -7052, -2632, -4643, -7713, -1496, -6389, -2867, -3961, -5292, -933, -8342, -3994, -3450, -2399, -1669, -13083, -6695, -1822, -1225, -4265, -6013, -7647, -205, -1037, -6638, -3330, -5317, 707, -1597, -4335, -2858, -4621, 846, -2926, -4878, -4668, -4337, 262, -4596, -10910, -8174, -5034, -934, -3779, -6660, -4125, -9053, -2616, -2219, -4445, -2773, -8275, -4516, -1280, -4806, -2834, -5603, -5921, -916, -7097, -3696, -5307, -7555, -1364, -9936, -4798, -5744, -9207, -3079, -8646, -5690, -7252, -5003, -6585, -8770, -6410, -10935, -3488, -5610, -8659, -6744, -9245, -4543, -3736, -6559, -7362, -6667, -9999, -3573, -4302, -8965, -5489, -3734, -5494, -2963, -5703, -5456, -1880, -11408, -2594, -2907, -6858, -1770, -4699, -2890, -1549, -6535, -2640, -2857, -3453, -1154, -4094, -4328, -2189, -4074, -1541, -3391, -7130, -2055, -4605, -2792, -4375, -8446, -2633, -4459, -5634, -6677, -6922, -3739, -4190, -16075, -7423, -5863, -3600, -4931, -5658, -5893, -4679, -3076, -6630, -3613, -3718, -3507, -3927, -7514, -2568, -2615, -2837, -7290, -8002, -1719, -2934, -2845, -6953, -8216, -1143, -4435, -3538, -4074, -8730, -1125, -4456, -5120, -3464, -9807, -1668, -3324, -8996, -4488, -7542, -2334, -3513, -9803, -7113, -5666, -2808, -5626, -6177, -5883, -4286, -3672, -12648, -5514, -4407, -3453, -5572, -8244, -5411, -5150, -3455, -8737, -7283, -4425, -10922, -4379, -13654, -5561, -3741, -5647, -6222, -14264, -3558, -4234, -2762, -6842, -13732, -2974, -6441, -1961, -4929, -7858, -3630, -11656, -2401, -3825, -4479, -4823, -8689, -3994, -3620, -2891, -5125, -7594, -6922, -3746, -2095, -4262, -6938, -10203, -3831, -1822, -3487, -5721, -7810, -4420, -2297, -3764, -5273, -5157, -6377, -3705, -5866, -5856, -3896, -8346, -5827, -11724, -7327, -3817, -6118, -6657, -5614, -9996, -4462, -5188, -5069, -3567, -23608, -5227, -5446, -3785, -2982, -9908, -6383, -6470, -3373, -2828, -7664, -9051, -7122, -3856, -2319, -7283, -14350, -6048, -5148, -1901, -7891, -10559, -5218, -6995, -2190, -8009, -8803, -5223, -9427, -3309, -6301, -8108, -5472, -11170, -5393, -4919, -7391, -5316, -14433, -7828, -4693, -6097, -5145, -7918, -5216, -5792, -4923, -5350, -4639, -3623, -8660, -4158, -5483, -3482, -3677, -8145, -3554, -4932, -3589, -5313, -5483, -2925, -4456, -4440, -9515, -4467, -2589, -4890, 3118, 146, 1330, 6913, -8593, 2225, -2169, 4462, 6442, -5307, 12, -2240, 6211, 5121, -3754, 1312, 1078, 6366, 3616, -3143, 2963, 2155, 5076, 3021, -2276, 3466, 3005, 1414, 2465, -1894, 3025, 3214, -157, 740, -4887, 1293, 2110, 3189, -4219, -2132, -4556, -1005, 3860, -2021, 2117, -988, -6969, 3108, 306, 3776, 2001, -3941, 546, -137, 4468, 2875, -3603, -7925, -958, 4940, 2381, -2086, -131, 1799, 5298, -257, -19, 1104, 3233, 5130, -1436, 755, 202, 3141, 3946, 2103, -996, -1421, 1700, 660, 2879, -1924, -391, -73, -827, 1894, 2690, 319, 1207, 2394, -865, 4090, 511, 2256, 2674, -2225, 3748, 735, 2067, 1310, -805, 1920, 526, 1172, -336, 316, 162, -206, 561, -4199, 1989, 568, -1159, 654, 72, 3204, 150, -3201, 1390, 3714, 3505, -472, -9209, 1725, 4733, 2879, -171, -1469, 729, 4091, 1390, -691, 396, -2601, 1674, -810, -2626, 295, -7749, -4042, -3765, -4460, -1820, -3734, -3146, -8464, -6383, -8245, -1372, -2356, -3271, -5291, -2978, 733, -1947, -1560, -1302, -1978, 1491, -432, -2768, 154, -3479, 940, 126, -7540, 9, -7941, -284, -776, -2313, -1679, -4676, -294, -3182, -1244, -3582, -2537, -44, -2447, -1635, -2579, -1208, -961, -777, -1382, -3078, -74, -3733, -602, -943, -3659, 674, -12982, -1533, -1950, -926, 812, -5139, -3127, -3137, 55, 385, -4789, -4648, -987, -234, 565, -5526, -5624, -483, -47, 1504, -2684, -7560, -1628, 61, 1754, -738, -8574, -1004, -1997, 1217, 92, -2497, 756, -4957, 887, 251, -78, 1558, -1276, 1105, -37, 864, 1478, -1042, 1072, -963, 840, 515, -1753, 612, -3097, 141, -1088, -1256, -163, -5478, -1065, -2240, -1733, -901, -2319, -3035, -2699, -4870, -1569, -198, -5528, -3643, -3113, -3722, 748, -2815, -6049, -748, -8112, 813, -1249, -10768, -477, -1404, 223, -1639, -9965, -1843, 436, -587, -4400, -7743, -5307, 600, -1048, -9887, -4784, -6827, -371, -1397, -3433, -2408, -4764, -1549, -3179, -1722, -763, -4034, -1054, -5471, -2083, 41, -3624, 844, -613, -5535, -199, -3123, 2355, 787, -6442, -1793, -3035, 2846, 197, -1717, -5117, -4639, 2196, -2325, 310, -4472, -17536, 255, -7013, 1172, -1994, -3928, -3289, -9853, 1038, -379, -1702, -10583, -4825, 59, 694, -786, -4575, -2715, -1504, 1229, -290, -574, -2738, -2659, 1129, -455, 1086, -4577, -2561, 147, -1698, 1292, -6912, -2028, -2223, -3573, 147, -4034, -1176, -6949, -4009, -2647, -2021, -691, -7117, -1952, -4681, -1034, -173, -5394, 544, -2675, -487, 966, -1670, 2086, -1898, -583, 1526, 1029, 2718, -1984, -2698, 884, 2329, 2530, -2503, -3246, -933, 2231, 1490, -2589, 810, -2167, 188, -256, -1535, 1951, -1852, 4277, 8809, 8073, 8894, 6117, 3705, 8169, 7263, 8200, 5739, 2140, 6120, 4511, 5897, 4409, 220, 2412, -1604, 1340, 1445, 146, 481, -1372, 1083, -3380, 1598, 78, -303, 1172, -534, 1779, 437, 2339, -180, 102, -96, 3588, 3941, 1896, -338, -7107, 5326, 4951, 4069, -568, -1001, 5674, 5616, 4464, 116, 533, 4623, 5794, 2535, 2085, -90, 2337, 5337, -650, 3534, -2172, 3173, 4030, 3689, 3828, -2848, 4564, 1813, 4696, 3088, -83, 4455, 1995, 3875, 1675, 2758, 3043, 3189, 1410, 215, 4450, 479, 2920, -1555, -385, 4934, -2987, 1382, 245, 524, 4125, -3666, -1159, 1789, 2241, 2386, -582, -2739, 2611, 3599, 3106, 367, 503, 3170, 3851, 4087, -163, 2224, 3834, 2505, 3466, -1465, 2628, 4288, -600, 1277, -2497, 2187, 3945, 1691, 460, -1772, 1456, 2627, 3462, 1714, 507, 977, 1390, 4027, 1833, 2274, 325, 1221, 3987, 747, 3308, -1273, 328, 3319, -1813, 3771, -4158, -1971, 1860, -2041, 3738, -8238, -6137, 140, 549, 3185, -8916, -8056, -245, 1533, 1988, -3807, -2856, 8, 1112, 86, -2567, -1311, 257, -1158, -625, -4053, -884, 724, -8202, 204, -5880, -549, 1493, -3115, -338, -1423, -598, 2289, -2715, -2811, 211, -2133, 2723, -5070, -3071, 611, -8399, 2597, -3161, -2561, 692, -3892, 1767, -1189, -3756, 1144, -1831, -48, -728, -3358, 1838, -1321, -3653, -891, -2556, 2279, -818, -5325, -1002, -2309, 2273, -755, -1921, -970, -3974, 1745, -2182, -462, -1343, -6567, 595, -4975, -109, -2688, -712, 98, -2412, -786, -4322, 515, 930, -1467, -2608, -3287, -363, 881, -3112, -5276, -1939, -1794, -198, -6744, -6453, -1216, -868, -1136, -1844, -4225, -1144, -463, -2293, -40, -2040, -1808, -1214, -5789, 735, -1162, -4271, -3008, -8304, 1061, -1156, -6402, -4590, -6784, 835, -1738, -1396, -3877, -4845, -72, -3918, -375, -3647, -2302, -1608, -8159, -1533, -3457, -957, -3636, -2085, -3981, -2984, -393, -6563, -454, -4316, -2912, -391, -7770, -154, -8634, -3245, -852, -4968, -428, -2861, -3898, -1510, -4373, -1559, 310, -5401, -2226, -5840, -5442, 1388, -5982, -3498, -12001, -6296, 1478, -2471, -6107, -5912, -2775, 1040, -626, -5956, -2526, -2580, 37, -222, -3260, -729, -3968, -2029, -982, -2254, 52, -7660, -4143, -1877, -1721, 0, -9829, -3081, -1249, -993, -278, -7732, -3697, -1019, -611, -13, -9038, -9054, -2074, -485, 538, -3289, -6787, -3741, -897, 1122, -1718, -5178, -3493, -3183, 1177, -2659, -4875, -1197, -3555, -370, -7024, -2896, 359, -1109, -10480, -3403, -1167, 750, -742, -682, -1152, -273, 631, -359, 1694, -417, -631, 967, 650, 2436, -396, -3188, 1408, 1224, 2455, -890, -4362, 1385, 1311, 1974, -2045, 6241, 8127, 8154, 3329, 3450, 5414, 7353, 7504, 4539, 2359, 2893, 4853, 5406, 5810, 1415, -1407, 256, 1137, 6393, 2869, -4026, -1018, -3143, 6315, 2155, 1049, 1256, -932, 5055, -2328, 1888, 2348, -688, 522, 392, 1371, 1929, -161, 1861, -383, 1944, 436, 605, 4813, 1599, 2704, -665, 78, 5335, 4973, 2879, 316, -4132, 4860, 5703, 2508, 552, -2180, 3700, 5143, 1233, -840, 1420, 1344, 4776, -241, -3382, 2340, -973, 4692, 1402, -6939, 1903, 1856, 4098, 2648, -7534, 271, 2871, 3474, 2561, -2175, -3392, 2245, 3982, 1263, 431, -5024, -271, 5016, -803, 2239, -404, -4052, 5332, -1549, 3452, 1413, 285, 4676, -1912, 4399, 2200, 1950, 4041, -4243, 5284, 2722, 2343, 5254, -7932, 5851, 3446, 2058, 6540, -3096, 5792, 3984, 1509, 7012, -79, 5012, 3853, 851, 6625, 1757, 3676, 2829, -245, 5303, 2223, 2010, 665, -2602, 2883, 1032, -577, -3711, -5186, -375, -2619, -5703, -5238, -928, -593, -1219, -2876, -1840, 1076, 1431, 735, -2153, -756, 1646, 2671, 1002, -3381, -237, 951, 2829, 384, -4943, 284, -1173, 1765, -810, -2245, 794, -1385, -1118, -718, -879, 1043, 812, -1580, 712, -1844, 617, 1873, 391, 1316, -2229, -997, 2264, -60, 984, 724, -1524, 2405, -3089, 20, 2026, 1053, 2434, -4403, -739, 2167, 2422, 2259, -839, -659, 1578, 2632, 1650, 247, -828, 419, 1795, 319, -694, -1902, -798, -256, -1868, -4354, -3589, -864, -1973, -3668, -3444, -3657, -939, -447, -4164, -3165, -2500, -2023, 36, -5331, -7651, -2047, -2187, -969, -5920, -3386, -2484, -1053, -2807, -5063, -1625, -3744, -1227, -2107, -4562, -1828, -5324, -3535, -728, -5042, -2414, -4339, -4821, -435, -5803, -1451, -1994, -2642, -1112, -3598, 21, -334, -3353, -2078, -1599, 842, 223, -10118, -2764, -810, 845, -733, -5822, -4143, -1101, -5, -3691, -6578, -4775, -1730, -1606, -2260, -4415, -2597, -1198, -2413, -567, -414, -1047, -116, -1646, -993, 475, -162, 1059, -1526, -3779, -725, 354, 1978, -2684, -12033, -4345, 581, 2077, -5734, -6570, -7242, 245, 967, -9861, -2620, -13415, -1008, -2056, -3860, -341, -4412, -3183, -16484, -1046, 515, -1713, -3196, -5242, 290, 709, -847, -1213, -3672, 196, 859, -581, 130, -2007, -1415, 1056, -926, 842, -1128, -1339, 832, -1558, 1039, -1686, 429, -331, -120, 936, -4188, 662, -2454, 1262, 705, -4660, -622, -3390, 1469, -124, -3031, -3537, -1024, 687, -2587, -4361, -8373, 1268, -716, -3647, -8348, -7906, 2426, -1858, -1745, -2939, -3338, 2563, -1919, -2562, -1240, -1319, 1873, -1528, -8172, -740, -557, 537, -905, -5316, -928, -343, -1343, -382, -3196, -2312, -285, -3772, -710, -2727, -4046, -461, -2665, -536, -163, 1395, -2433, 1451, 700, 744, 289, -3430, 3049, 1103, 669, 769, -1953, 3410, 273, -1166, 1312, 104, 3125, -2569, -3797, 1211, 1460, 2553, -9160, 187, 970, 1832, 1920, -2243, 1512, 854, 1220, 1268, -1188, 946, 536, 262, 486, -2287, -1878, -373, -200, -702, -7091, -6246, -1769, -1183, -2357, -3416, -2110, -2397, -3818, -3072, -1011, -1305, -1881, -3042, -1255, -866, -1461, -1339, -1058, 828, -1576, -1817, -975, -769, 1895, -384, -1716, -768, -1761, 1759, 840, -483, -1031, -4489, 255, 635, 564, -2962, -4338, -2924, -1584, 561, -6641, -1145, -3653, -8057, -1020, -37, -382, -2246, -1516, -6472, 2152, -2088, -1904, 192, -4472, 2868, -3651, -1567, -85, -2669, 2764, 450, -990, -2113, -2535, 2310, 1626, -728, -874, -1695, 1779, 891, -1428, 971, -1296, 972, -2200, -4166, 1114, -1924, -589, -5780, -7825, 221, -2285, -3323, -1691, -3487, -433, -1145, -6073, -230, -2525, 154, -513, -7508, 585, -2832, 982, -1242, -6886, 1164, -3535, 1293, -3821, -2967, 1527, -2951, 1074, -3743, -1304, 1347, -1822, 720, -957, -1811, 494, -1426, 611, -92, -6989, -125, -2038, 500, -931, -3428, -303, -4554, -223, -4165, -768, -1666, -8290, -1602, -9042, -497, -5360, -2436, -1486, -5364, -1441, -9835, -372, -324, -4806, -3517, -7210, 429, -68, -4413, -9929, -2532, 63, -987, -4720, -4172, -1231, -2332, -2607, -7687, -1449, -1587, -10531, -2300, -6691, -997, -1616, -2487, -1538, -2714, -1635, -947, -2399, -1748, -1546, -1794, -870, -4803, -2651, -1760, -1825, -737, -1535, -4039, -2533, -1711, 154, -150, -5934, -2753, -484, 1019, -933, -7073, -2866, 5, 1070, -3637, -5680, -4080, -1145, -109, -2894, -3903, -7681, -5198, -2927, -1149, -3309, -13945, -4640, -7076, -712, -4112, -8977, -2381, -8465, -1063, -5929, -6661, -2103, -10346, -2170, -6951, -5306, -1922, -8416, -3844, -6126, -3923, -918, -6938, -3284, -5098, -1641, 232, -4789, -1976, -5542, -320, 584, -2403, -1930, -9068, -89, -478, -1271, -3167, -8062, -453, -3539, -1173, -4139, -5769, -675, -2442, -1128, -3323, -5757, -424, -655, -992, -3463, -5377, -141, -554, -1804, -4584, -4849, -221, -1415, -3947, -3942, -5664, -758, -2821, -5311, -2857, -7407, -1807, -4706, -4203, -2952, -7839, -3364, -7523, -2643, -4658, -7175, -4285, -10408, -1974, -8684, -5055, -3850, -10031, -3020, -4467, -3341, -3543, -10283, -8030, -2506, -2501, -3456, -9502, -4641, -2462, -2508, -3156, -8393, -1826, -4311, -3506, -2583, -6880, -1017, -10471, -5698, -1943, -5264, -1200, -6114, -8872, -1308, -3958, -2024, -3779, -9555, -714, -3006, -3196, -2756, -7642, -318, -2665, -4451, -2181, -7800, -232, -3248, -5932, -1995, -9862, -387, -5214, -7985, -2473, -5118, -634, -10596, -6671, -590, 828, 1140, 897, -4455, 836, -453, 1020, -805, -8201, 1240, -3314, 1013, -1857, -4285, 878, -10100, 575, -1714, -2248, -534, -4527, -1053, -2108, -1398, -3738, -3428, -5782, -2540, -1106, -8967, -1979, -7322, -2507, -1225, -4764, -375, -5824, -3301, -1909, -188, 210, -5874, -5913, -2966, 2004, 13, -2887, -11871, -3077, 2628, -182, -2256, -7499, -2382, 1941, -20, -2963, -6365, -2134, -214, 85, -3343, -6950, -2664, -5440, -97, -2891, -9609, -4111, -6051, -512, -1859, -6414, -4387, -2835, -991, -1289, -3253, -1811, -2261, -1819, -1961, -2581, -154, -3716, -3708, -4248, -2866, 428, -5957, -4586, -5717, -1388, 250, -1362, -2812, -4076, -46, -232, 202, -2495, -3994, 145, -473, -293, -2952, -5457, -607, -394, -2999, -2029, -5329, -1868, -402, -1902, -730, -2852, -2581, -860, 88, 94, -1471, -1763, -1976, 154, 599, -1287, -409, -3449, -1277, 655, -2383, 311, -2279, -4613, -296, -5104, -67, -199, -7294, -3867, -8220, -1944, 800, -3967, -4647, -7273, -3447, 759, -2999, -810, -6999, -836, -375, -3924, 91, -6887, 602, -3578, -9585, 263, -6229, 989, -4598, -5303, 443, -5622, 594, -814, -1778, 190, -5693, -602, 161, -20, -1138, -6369, -3280, -345, 693, -4110, -7452, -10517, -2039, 522, -6520, -10090, -1877, -3949, -111, -3046, -10215, 153, -3469, -1228, -858, -4303, 197, -3005, -4583, 20, -1881, -1980, -3873, -6635, -204, -969, -12129, -6634, -2248, -1165, -1067, -3411, -14424, -1216, -2162, -1806, -3472, -10512, -1015, -3433, -2713, -8785, -8797, -1523, -4765, -3220, -6674, -6629, -2753, -1521, -3010, -5032, -4341, -2046, 556, -2567, -5564, -2743, -961, 1157, -2728, -4715, -2157, -1369, 577, -3680, -2853, -2554, -3246, -935, -4763, -1830, -3949, -5571, -2846, -4939, -2357, -7216, -5189, -5632, -5028, -5879, -6176, -3218, -5355, -6656, -7252, -2515, -2071, -1519, -8773, -3268, -1159, -1901, 43, -6697, -2751, -1582, -2470, 251, -5832, -3593, -4347, -3784, -472, -4930, -4996, -2333, -5359, -1016, -3163, -5633, 387, -3609, -360, -1554, -4434, 1352, -1620, 357, -653, -2786, 1356, -955, 589, -304, -1947, 814, -1709, 232, -331, -2133, -95, -4579, -960, -981, -3216, -1523, -9511, -3151, -2752, -5009, -4028, -4287, -3325, -6326, -7580, -8835, -2825, -1915, -12577, -9888, -6154, -2438, -1518, -16095, -8728, -4523, -2806, -1754, -12740, -4331, -4205, -4441, -2262, -10771, -1767, -4063, -7782, -2945, -5524, -579, -3885, -4925, -3475, -2923, -415, -3872, -3641, -3227, -1621, -1265, -3880, -3911, -2963, -1030, -3607, -3291, -2867, -3751, -882, -10713, -2529, -1312, -6123, -944, -7948, -2416, -1050, -9084, -1181, -7284, -3032, -2472, -8240, -1961, -10394, -3808, -7257, -8586, -3656, -7317, -4037, -6884, -10044, -5869, -5150, -3836, -5947, -2580, -1817, -63, -1113, -9139, -3509, -732, 2203, -2243, -7660, -666, -399, 3078, -3463, -3819, 709, -1157, 2992, -3260, -3360, 978, -3220, 2087, -1007, -5895, 413, -6009, 198, 468, -7010, -938, -5300, -2032, 601, -3241, -3022, -4062, -1096, -266, -2400, -3961, -3889, -541, -976, -2954, -2619, -4510, -1088, -1482, -3296, -1694, -3411, -1747, -2278, -2002, -1510, -1566, -1565, -2514, -1351, -1842, -731, -667, -2777, -2532, -1939, -895, -195, -2897, -6893, -1062, -1717, -852, -4150, -2542, -28, -2440, -3422, -5473, -890, 332, -3761, -6847, -2396, -1703, -569, -8831, -1617, -2322, -6028, -4802, -1462, 155, -5542, -3449, -3114, 1202, 196, -3242, -1460, 157, 2223, -1741, -982, -1798, 999, 2258, -4027, -504, -2424, 1102, 1597, -309, -858, -1269, 835, 568, 1041, -1503, -573, 96, -538, 860, -2239, -1024, -476, -2009, -584, -3420, -2146, -1219, -4215, -3154, -5719, -2372, -4291, -5754, -5190, -10646, -2435, -8020, -6840, -4674, -10945, -3730, -3218, -7367, -2206, -6945, -6626, -2250, -5292, -295, -4357, -7260, -2140, -4918, 608, -2141, -4577, -3272, -6137, 700, -806, -4059, -8068, -7767, 67, -862, -2626, -6891, -9693, -1233, -2828, -190, -4005, -13823, -3004, -7741, 1078, -2999, -7404, -4510, -6447, 1406, -1940, -6131, -1874, -7410, 1286, -1144, -5664, 323, -9777, 931, -869, -4100, 1027, -5152, 3, -929, -3232, 550, -2988, -2172, -960, -3351, -688, -2065, -5764, -756, -3666, -2056, -1780, -2930, -674, -3646, -3854, -1655, -605, -1363, -3738, -5948, -1755, 749, -3931, -4082, -4189, -2218, 1260, -7893, -3659, -2275, -2730, 775, -2651, -2921, -1098, -2917, -955, -1833, -3719, -945, -3060, -4225, -3916, -10150, -1887, -3949, -4420, -7190, -3920, -2446, -6648, -3020, -2013, -1590, -1372, -9080, -3407, -786, -1784, -739, -6573, -5994, -1196, -4625, -954, -5556, -5302, -2991, -6013, -1596, -3238, -2435, -6571, -2527, -1443, -1401, -1446, -12956, -1688, -623, -692, -1449, -9256, -1925, -434, -936, -2392, -6646, -2804, -1317, -1929, -6513, -7742, -4992, -3521, -3534, -4806, -5703, -11473, -7166, -5587, -1267, -2751, -6370, -6135, -5950, -694, -2614, -5122, -3782, -4633, -1739, -4493, -4723, -2648, -3777, -4008, -2574, -3483, -2485, -3100, -5203, -825, -2691, -3275, -2515, -3061, -688, -2771, -4995, -2296, -1519, -1502, -3411, -4819, -2533, -989, -1955, -4571, -3057, -3199, -1354, -1337, -6963, -2599, -4289, -2705, -1162, -9032, -3603, -5197, -5798, -2242, -8257, -6241, -4827, -14563, -5396, -9561, -8319, -4668, -6812, -10119, -13471, -6541, -5009, -7422, -5365, -9996, -4516, -3651, -8204, -3802, -6835, -2656, -2308, -3295, -3198, -5994, -1602, -2187, -1432, -3289, -6904, -1313, -3172, -1048, -4012, -7904, -1301, -4601, -1706, -5041, -7724, -1318, -5221, 9893, 6950, 9734, 7998, -3265, 9282, 6868, 9246, 7306, -879, 7376, 6226, 7886, 5027, 487, 4021, 4447, 6120, 1103, 1111, 198, 1432, 4432, 1914, 1731, -41, 270, 2231, 2670, 2032, 765, 1266, -1073, 2285, 1999, 57, 2064, -1174, 1420, 1713, -4, 2528, 18, 208, 1011, 2531, 2550, -774, -987, 247, 4302, 2273, -1992, -512, 1069, 5292, 2765, 601, 259, 2656, 5511, 3997, 1922, 615, 3785, 4756, 4676, 1487, 1453, 4497, 2866, 4353, -1937, 1953, 5063, 1640, 2681, -406, 1008, 5555, 2238, -1792, 3028, -2156, 5709, 1660, -707, 4037, -1697, 5139, 1333, 1563, 3710, 144, 3461, 2740, 1301, 2213, 216, 279, 3573, -1012, -915, -575, -2572, 4101, -6155, -5955, -974, 776, 4613, -6417, -2489, -160, 3507, 4596, -3033, -2042, 376, 4807, 3740, -543, -3313, -291, 4973, 2331, 90, -4669, -1893, 4219, 1493, -1212, -3760, -962, 2868, 1060, -4321, -2394, 350, 1828, 136, -1545, -2829, 486, 1568, -150, 91, -6332, -233, 1223, 791, 955, -972, -1221, 404, 1432, 1927, 1262, -538, -576, 1452, 2499, 1585, 1448, -604, 990, 2197, 668, 2686, -106, 401, 527, -548, 2888, -561, 375, -5179, -647, 2015, -2836, 934, -1038, -715, -143, -6899, 1233, 1224, -2034, -4156, -4439, 707, 970, -5586, -6884, -3377, -790, -1534, -10400, -6638, -2846, -2670, -2224, -4720, -4488, -2764, -3121, -458, -2227, -2505, -3033, -2467, -895, -1393, -2155, -2927, -2708, -2651, -2073, -2826, -2188, -5623, -2440, -4684, -3015, -1380, -7691, -1396, -8090, -3008, -1330, -2732, -1107, -4133, -4632, -2552, -1529, -1286, -2098, -8551, -5014, -1830, -1746, -1218, -6037, -4872, -2835, -2461, -1528, -5820, -4374, -3178, -3227, -2825, -7996, -6427, -3596, -3601, -3179, -7516, -5452, -5289, -4098, -2506, -5674, -2494, -6585, -5832, -2239, -5129, -1965, -6739, -7895, -2245, -6075, -3593, -12704, -6431, -2473, -5989, -8011, -5722, -6393, -2616, -3421, -7615, -2983, -6584, -2418, -2383, -7676, -2490, -4175, -2544, -2873, -5523, -3387, -2302, -3566, -4987, -4964, -5383, -1518, -5393, -9860, -6669, -8023, -1758, -6861, -8351, -5303, -8833, -3061, -5485, -5551, -3952, -6464, -5607, -3324, -4449, -4393, -4230, -9981, -2401, -4229, -6714, -2955, -12310, -2517, -4169, -5225, -2739, -8967, -3045, -3946, -2176, -3315, -6666, -3395, -4325, -1027, -3142, -4725, -3617, -6432, -1090, -1997, -3373, -3991, -8417, -1858, -1347, -2983, -4736, -5653, -2642, -1435, -3830, -5918, -4329, -3166, -2324, -6439, -7517, -2801, -3681, -4403, -7189, -8238, -1590, -3374, -9389, -3213, -5115, -866, -2799, -9122, -880, -2473, -394, -3240, -5616, 298, -980, -554, -4377, -4575, 393, -443, -1834, -4171, -5295, -725, -757, -4530, -2532, -10057, -2845, -1725, -8647, -698, 3683, 4463, 1825, -124, 2917, 3531, 4227, 4240, 35, 2671, 2782, 3483, 5662, 524, 2710, 504, 2319, 5436, 1115, 3175, -3508, 963, 3424, 1254, 3130, 543, -871, -2756, 521, 2540, 1362, -2417, 1540, 422, 1314, 82, -1317, 3275, 2037, -1669, -2950, 414, 3145, 2608, -6893, -6719, 2433, 1962, 1679, -5415, -244, 4197, -253, -665, -1236, 3013, 5400, -2164, -3883, 1545, 4445, 5907, -791, -4302, 2164, 4659, 5654, -2012, -1539, 953, 4030, 4641, -1671, 1948, -2540, 3135, 2907, 2284, 4142, -1780, 2362, 508, 3697, 5003, -104, 1246, -2934, 3750, 4673, -57, -356, -7216, 2959, 2988, 324, -1990, -788, 1999, -1190, 1584, -6384, 1481, 1711, -875, 2793, -3376, 1938, 1773, 816, 3392, -910, 903, 1359, -1253, 2831, -1619, 1642, -188, -731, 255, -5239, 3956, -4493, 2828, -8619, -2533, 4856, -4998, 3833, -1001, -1084, 4393, -3073, 3923, 618, -1142, 2651, -4611, 4240, 1265, -881, 210, -5301, 4501, 1122, -499, 193, -4510, 3983, 262, -1048, 1801, -4984, 2540, -291, -2398, 2929, -4414, 757, 537, -2886, 3307, -4481, 103, 1723, -996, 2971, -4340, -56, 2378, 779, 1931, -1460, -617, 2165, 1457, 356, 324, -1165, 1014, 957, -219, 749, -1223, -80, -772, 268, -53, -1566, 7, -3643, 100, -2097, -3244, -380, -5296, -443, -5329, -3409, -1484, -4828, -764, -7308, -397, -2607, -4755, -1428, -5650, 1043, -4558, -3782, -2276, -4608, 1365, -4631, -3248, -2331, -4564, 937, -3603, -4689, -1848, -5570, -114, -4942, -6652, -1041, -8989, -1444, -4558, -4670, -768, -8841, -1623, -2698, -3964, -1574, -4905, -1545, -2709, -3772, -1889, -3496, -2481, -4800, -3080, -487, -3199, -2491, -6607, -2057, -99, -3860, -956, -4339, -1413, -1421, -5906, -119, -5179, -1661, -4126, -6756, -18, -9412, -2886, -3466, -4567, -490, -4385, -3190, -3539, -4647, -1720, -3269, -2601, -6575, -8530, -4143, -4104, -3705, -7531, -6789, -4666, -5399, -6984, -4920, -3645, -2381, -3745, -4689, -3534, -2175, -1047, -1526, -3752, -2596, -1387, -478, -439, -5222, -2893, -1772, -690, -638, -9504, -5060, -3742, -1752, -2606, -5450, -5338, -4699, -3223, -8253, -2526, -2665, -3154, -3203, -3882, -1171, -1418, -2852, -1799, -2719, -769, -956, -3830, -592, -3001, -893, -876, -6593, -122, -2411, -1366, -712, -6676, -453, -1599, -2241, -174, -5179, -1158, -1393, -3593, 190, -8457, -1606, -1738, -5732, -191, -5409, -1791, -2832, -8734, -1571, -1648, -1687, -4201, -8852, -4170, -527, -1602, -4051, -5823, -9139, -730, -1987, -3716, -3907, -11209, -1602, -2843, -3955, -3356, -8787, -2174, -3993, -4651, -3786, -10514, -2840, -4097, -4885, -5179, -7967, -4623, -2429, -3972, -9638, -4419, -2540, -1185, -3861, -8437, -2446, -244, -882, -5374, 2071, 5274, 358, 3097, 2901, 3087, 5290, 179, 2440, 4240, 4286, 5227, 2071, 2279, 5543, 4640, 4868, 3722, 3871, 5615, 4256, 4036, 3915, 4598, 4038, 3599, 2603, 2792, 4107, -820, 2694, 333, 669, 2386, 1352, 545, -2228, -1132, -297, 2616, -4617, 66, -478, 928, 1899, -3609, 2059, 1131, 3144, 3561, -2802, 2953, 1802, 4341, 5646, 176, 3275, 1193, 4703, 6660, 1689, 3389, -406, 4168, 6646, 1494, 3245, -202, 2362, 5312, 546, 2550, 672, -1315, 1314, 539, 1039, 99, -305, -1380, 537, -1736, -2001, 1107, 2170, -629, -4142, -3126, 824, 2788, -3120, -323, -1983, -1179, 3342, -5279, 1431, -1203, -15504, 3500, -8644, 1589, -289, -1264, 2896, -1443, 1085, 870, 683, 1977, 1646, 1753, 1766, 762, 1584, 2523, 2441, 2014, -410, 1828, 1733, 2143, 1665, -2458, 1779, -580, 1122, 1333, -2289, 443, -2330, -694, 1141, -851, -5301, -1406, -4307, 201, -240, -704, -1220, -1759, -349, -231, 1902, -3224, -1091, 1012, -494, 2122, -3760, -3942, 1430, -685, 606, -911, -2434, 572, -741, -1792, -827, 187, -959, -812, -1344, -3080, 1182, -2765, -1219, -396, -2854, 1454, -6097, -2278, 349, -346, 984, -5858, -1832, 586, 208, 185, -3048, -159, 35, -1482, 5, -482, 323, -1365, -9304, -245, 965, -492, -2805, -809, -578, 1008, -2378, -2286, 462, 348, 162, -3310, -1562, -1082, 1163, 61, -1521, -886, -10256, 1089, 201, -321, -304, -1749, 651, -802, -186, -472, -786, 487, -3197, -700, -1998, -2250, 30, -5741, -1330, -5332, -5894, -1304, -5224, -2301, -5321, -7508, -3500, -4848, -4435, -5400, -4138, -5353, -5387, -4648, -5943, -2636, -4929, -5749, -2260, -5960, -2548, -4522, -5910, -1570, -11322, -3391, -4287, -4582, -2262, -5475, -4224, -5056, -2469, -3304, -3208, -5285, -15497, -1671, -2481, -3233, -7761, -3302, -2240, -1290, -4304, -7305, -748, -3313, -959, -4685, -8587, -138, -2873, -1691, -5040, -9775, -750, -2175, -3745, -8771, -4605, -2461, -1900, -7811, -6671, -3613, -5205, -1659, -16669, -3382, -4566, -5873, -1742, -7431, -2962, -7979, -4609, -2757, -3770, -4067, -8369, -3708, -5023, -1628, -5470, -4799, -3005, -7284, -787, -4821, -3364, -3245, -8660, -1205, -3282, -2386, -5394, -21635, -2749, -3176, -1431, -9820, -6374, -4620, -5153, -994, -7799, -3404, -5608, -4621, -1549, -4089, -1986, -5269, -2318, -3083, -733, -1068, -3624, -1497, -3572, 905, -463, -2247, -1346, -2685, 1208, -663, -1894, -1327, -2314, 308, -1739, -2844, -1368, -2315, -1855, -2198, -5478, -1863, -2681, -4685, -2098, -9135, -3094, -4042, -6115, -3475, -7313, -4275, -7120, -11604, -4665, -5881, -3958, -4008, -5829, -2099, -5042, -3526, -1499, -3020, -955, -4614, -3889, -628, -2335, -978, -5090, -5198, -6693, -2397, -2436, -6940, 413, -3124, -1150, -1766, -4277, 569, -1716, -1089, -821, -3726, -133, -1335, -2118, -574, -4771, -1118, -1788, -4533, -1089, -6483, -1203, -3295, -7803, -1687, -7666, -782, -7035, -5120, -1532, -8367, -640, -8173, -3809, -1042, -5039, -758, -4992, -2834, -766, -2795, -1257, -4148, -1562, -1042, -1781, -2915, -3268, -924, -2126, -1678, -6465, -2094, -1358, -3889, -2569, -2978, -1369, -2705, -4702, -4670, -1376, -1192, -2399, -4298, -3541, -1823, -1405, -688, -4292, -1129, -4441, -1744, 165, -4909, -83, -8700, -2234, 64, -6111, -44, -5034, -3463, -1129, -8544, -933, -3916, -5216, -4297, -9496, -3055, -4060, -5058, -6889, -5530, -6880, -5043, -5511, -3563, -3947, -5509, -4620, -9826, -3077, -3703, -4110, -2473, -9109, -3073, -4321, -4340, -1237, -6172, -2252, -4721, -5560, -1206, -4919, -1714, -3427, -5315, -2540, -3081, -2010, -2043, -3547, -5688, -1806, -3034, -1653, -2336, -6185, -1448, -4324, -2606, -1612, -4627, -1750, -5049, -5608, -1617, -4301, -2017, -4837, -10434, -3121, -3926, -1761, -4320, -6408, -8827, -3809, -1742, -3933, -5517, -7753, -4951, -2753, -3445, -5975, -8179, -10358, -5800, -2992, -6739, -8190, -6338, -11959, -2968, -4780, -3609, -3461, -5121, -3250, -2908, -2881, -3423, -3601, -3812, -2465, -4197, -6068, -3341, -5352, -3239, -7876, -8982, -3038, -5348, -4535, -9111, -5954, -1789, -3284, -4922, -5043, -5908, -801, -2898, -4112, -2754, -6412, -731, -4210, -3444, -1365, -6418, -1557, -7601, -3078, -1010, -6761, -2828, -12376, -2903, -2004, -8207, -3801, -7601, -3812, -5223, -8936, -4466, -7246, -7516, -7407, -6897, -5080, -11590, -5389, -3402, -4261, -6361, -6756, -2689, -1936, -2229, -7673, -4149, -1919, -1751, -1495, -5312, -3567, -2082, -2883, -2053, -4058, -3840, -2715, -6105, -3758, -4086, -4213, -3681, -9655, -7278, -5025, -4966, -5049, -5135, -8523, -6913, -6019, -5251, -3028, -3299, -7882, -4942, -4176, -1766, -1731, -6423, -4198, -3960, -1243, -1617, -6221, -5419, -4669, -1382, -2249, -7777, -9966, -5818, -2018, -2800, -11253, -7221, -7299, -2961, -2481, -11771, -6067, -8673, -4298, -1633, -8038, -7159, -8733, -5798, -1147, -5952, -6394, -8592, -4579, -1465, -5627, -4546, -7981, -3215, -2877, -6026, -3884, -7634, -3317, -6058, -4868, -4166, -8562, -4982, -14775, -3836, -5090, -10727, -6290, -6773, -4127, -5961, -10665, -4646, -4232, -6169, -5847, -7353, -4010, -3031, -13470, -5311, -4702, -4576, -2828, -9168, -5029, -3332, -5408, -3340, -7328, -5208, -3058, -5153, -4181, -7644, -6256, -3696, -5304, -5532, -8713, -9250, -4765, -7600, -6878, -7966, -7504, -4952, -13402, -4994, -6511, -4579, -4783, -7267, -3893, -6276, -3691, -5962, -6824, -4245, -7964, -4287, -11713, -9145, -5564, -10924, -6544, -7722, -13292, -6756, -7277, -10999, -4536, -12303, -6903, -6011, -8762, -3384, -8783, -7266, -5094, -1758, 539, -1365, -4791, -4721, -2575, 280, -2241, -2165, -6321, -5738, -745, -3091, -1159, -8461, -5071, -2328, -3748, -1559, -5463, -2303, -4316, -4237, -2643, -4484, -1084, -7260, -4257, -2386, -5808, -502, -9351, -3275, -2278, -5282, -685, -5953, -2327, -4449, -2162, -2211, -4664, -2235, -11079, -874, -6058, -3890, -3257, -3600, -1054, -5523, -3336, -5205, -2252, -3012, -4600, -3611, -4839, -2429, -12304, -6370, -4213, -3251, -3541, -3974, -8535, -3213, -2980, -5442, -2141, -8424, -1759, -4405, -5868, -2593, -9943, -955, -5322, -4002, -5310, -10303, -894, -3296, -3313, -9276, -8628, -1514, -3113, -4392, -6355, -6785, -2784, -5316, -8109, -6109, -6047, -4949, -6070, -7465, -6936, -5086, -6889, -2832, -7369, -6030, -3774, -4208, -1253, -8404, -3820, -3682, -2389, -679, -3868, -2504, -5052, -2034, -1099, -1895, -2037, -4638, -3185, -3038, -868, -2173, -2866, -6430, -9804, -424, -2733, -2356, -7989, -5663, -811, -3507, -2854, -5952, -4975, -1880, -4178, -3808, -6414, -5351, -2707, -4521, -4528, -8718, -2235, -4135, -4597, -4677, -8254, -804, -6268, -4446, -3836, -9373, -640, -2699, -4008, -2669, -9369, -1061, -1315, -3832, -2167, -3958, -1699, -1593, -4476, -2625, -2028, -2486, -3115, -4525, -4117, -1429, -3197, -5245, -3167, -6147, -1533, -3729, -5266, -2557, -5763, -2090, -4646, -4320, -2833, -3939, -3538, -6731, -4405, -3527, -2938, -8177, -7466, -5799, -4107, -3175, -6661, -4212, -7763, -3838, -5107, -3701, -2595, -6778, -3437, -9132, -3471, -2411, -6444, -3854, -5967, -4620, -3650, -7721, -4753, -4224, -4841, -6932, -4576, -5572, -3361, -3391, -7439, -2177, -7651, -2442, -2727, -4821, -1431, -15264, -1812, -3167, -3935, -2009, -9428, -2125, -4544, -3858, -4016, -8822, -3363, -6455, -4417, -8595, -10716, -3291, -9719, -6556, -7831, -9129, -2689, -14961, -11897, -5334, -6140, -4082, -10302, -5638, -4772, -4843, -9858, -6458, -4837, -4478, -4410, -4187, -4183, -5874, -3020, -4188, -2493, -3906, -4757, -1700, -4013, -2692, -5375, -4042, -1573, -4192, -4489, -7997, -4416, -3228, -4402, -8039, -8710, -3564, -6046, -3384, -5108, -7259, -3197, -3036, -2377, -2994, -7188, -4405, -1827, -2444, -2195, -9858, -5077, -1842, -3757, -2257, -9107, -4206, -2181, -6015, -3182, -8494, -4305, -2950, -6589, -4508, -13431, -5429, -4654, -6104, -3609, -6191, -7352, -4738, -6426, -2113, -4235, -6788, -3346, -7461, -1490, -4282, -4553, -3139, -9259, -1646, -5598, -2930, -3924, -11458, -2406, -7733, -2064, -5018, -10187, -3546, -10919, -2177, -5494, -8587, -4725, -11695, -3399, -5475, -7729, -5695, -6528, -5951, -5992, -7138, -6525, -4372, -11951, -6613, -5776, -6964, -4011, -9602, -4965, -4208, -6534, -5737, -7235, -3685, -3411, -5973, -14497, -7473, -3750, -3294, -5934, -5699, -9083, -5165, -3318, -6469, -4112, -8797, -8091, -3206, -7289, -4758, -7385, -13164, -983, -2618, -1430, -6237, -6901, -2444, -3226, -1698, -4829, -7651, -3930, -3933, -2127, -4045, -9454, -3907, -4364, -3061, -5928, -9154, -4016, -4725, -3306, -10267, -6507, -4147, -6880, -2790, -3706, -5966, -4041, -8154, -2811, -1877, -6466, -3886, -4459, -2223, -1488, -7046, -3697, -2987, -1109, -2058, -7563, -3708, -2432, -971, -3695, -8193, -2804, -2787, -2060, -8280, -9323, -1595, -4177, -3683, -6437, -12501, -1280, -6059, -3919, -2800, -11453, -1949, -6527, -3085, -1425, -9891, -3501, -3659, -2804, -1343, -11028, -5985, -1959, -4378, -2792, -6076, -9615, -1845, -9014, -5251, -3560, -11352, -3228, -4238, -3017, -2309, -8728, -5041, -3193, -1803, -1228, -6368, -2893, -4937, -2003, -375, -5447, -749, -9557, -3031, -201, -5586, 505, -3438, -4368, -737, -5887, 1022, -1503, -5542, -1723, -6895, 933, -961, -7023, -2900, -11516, 625, -1297, -12475, -4248, -9750, 605, -2522, -7218, -5872, -6866, 534, -4454, -4463, -8378, -6013, -297, -4135, -4382, -14230, -4859, -2286, -2914, -7407, -9845, -3623, -4097, -2763, -5304, -9005, -3696, -2495, -3462, -2115, -8544, -5963, -1348, -3882, -987, -4457, -7470, -1439, -3310, -899, -2184, -5336, -2739, -3180, -1397, -1390, -5633, -3845, -4027, -2116, -1766, -6484, -3335, -5731, -2782, -2970, -5438, -3612, -7501, -3358, -3969, -4071, -5267, -6485, -3966, -4561, -2938, -8219, -4049, -4750, -6253, -2217, -9780, -2429, -5805, -7919, -1982, -7617, -1792, -7054, -5938, -2146, -6167, -1846, -8343, -5433, -2438, -5843, -1846, -9650, -6905, -2410, -7158, -1193, -9534, -10417, -2000, -12900, -399, -6743, -7047, -1744, -7605, -143, -4190, -4915, -2287, -4745, -836, -2500, -4223, -4594, -3315, -2877, -1744, -4608, -11793, -2157, -6722, -1960, -6021, -5013, -913, -6898, -3122, -7735, -3919, -49, -4869, -4548, -7977, -4797, 55, -4032, -4615, -6303, -6967, -623, -4596, -4538, -4574, -7977, -1834, -6415, -4690, -4360, -7051, -2900, -7709, -3442, -6105, -5977, -3239, -7452, -2039, -4954, -4467, -3367, -4470, -1369, -2568, -3856, -3578, -2824, -1408, -2082, -5095, -3258, -2876, -2106, -3241, -9538, -3047, -4457, -3370, -6342, -6241, -4427, -7243, -4289, -10023, -5125, -7772, -8947, -3484, -8418, -7120, -5262, -7066, -2664, -8736, -10187, -4987, -4961, -2399, -13039, -5705, -7055, -3659, -2047, -8617, -4646, -5492, -3211, -1724, -6067, -4670, -3438, -3741, -2229, -5475, -3997, -2771, -5357, -4129, -5380, -3021, -3085, -7386, -7047, -5142, -2896, -3938, -7699, -6699, -4483, -3973, -5248, -8577, -6873, -3673, -6820, -8722, -9155, -7596, -3153, -15415, -11084, -7236, -7217, -2845, -10475, -6924, -7289, -7188, -2861, -10334, -6502, -11166, -7858, -3324, -9201, -5974, -8784, -9039, -3723, -6916, -4568, -5916, -8996, -3705, -6047, -3705, -5480, -8428, -3879, -6029, -3437, -5810, -8973, -4596, -5666, -3464, -5546, -8858, -5801, -5238, 15165, 2220, 10293, 9886, 8359, 14767, 5638, 9599, 9189, 10163, 13535, 6920, 7288, 6853, 10144, 11358, 6285, 2129, 1303, 9299, 8385, 4271, 475, 1013, 8251, 7587, 1764, 688, 1984, 6512, 8553, 128, -249, -611, 3759, 8828, -867, 256, -6937, 5346, 8283, -328, -509, -264, 6056, 6842, 1506, 1386, 1412, 4279, 4689, 3435, 3697, 2469, -3939, 3292, 4896, 4869, 3037, 1643, 3547, 5663, 5200, 3137, 1847, 4912, 5548, 4834, 2720, -1288, 5655, 4299, 3914, 1229, -7067, 4971, 1763, 2803, -2426, -3092, 2336, 631, 1807, -2942, -2819, -836, 1185, 836, -1536, -5055, 1715, 493, 50, -1759, -1808, 2202, -1063, -527, -2432, -664, 1002, -2089, -1745, -6010, -296, -2271, -1179, -4133, -3901, 1201, -5958, -318, -3961, -898, 2363, -3331, -739, -3644, -745, 2815, -2835, -2475, -6246, -1696, 2777, -3418, -2199, -6704, -874, 2129, -6288, -653, -4689, -13, 121, -6716, -278, -5560, -415, -8130, -1474, -1032, -5326, -1839, -1879, 429, -3153, -3739, -3077, -201, 1026, -7811, -3606, -2202, -740, 728, -17050, -3349, -857, -1628, -260, -9764, -3061, -223, -1872, -1284, -5219, -3867, -554, -3348, -1211, -3364, -4911, -2136, -5185, -949, -3196, -6153, -3803, -4069, -1546, -4273, -11220, -2293, -5814, -3211, -5874, -9225, -1543, -7654, -4453, -6492, -8702, -2022, -3445, -3538, -5984, -11835, -3137, -2778, -3033, -5314, -7909, -4071, -3630, -3184, -5341, -5343, -5856, -4960, -3531, -6565, -3590, -10830, -5853, -3938, -7846, -2905, -4797, -4374, -4549, -6669, -3654, -3344, -2147, -5170, -6659, -4874, -3849, -841, -5242, -9633, -3131, -5622, -363, -4773, -11108, -1937, -7477, -427, -4271, -6912, -1979, -7271, -877, -4149, -5375, -2753, -6536, -2024, -4627, -4488, -3442, -6879, -4657, -5827, -4222, -3640, -8266, -9185, -7401, -4772, -4017, -8267, -7768, -7331, -6096, -5318, -6145, -7204, -6757, -7470, -8929, -4211, -6455, -7478, -7380, -8746, -2915, -6007, -11402, -6159, -5388, -2385, -5302, -10046, -4972, -4620, -2669, -4366, -5827, -4223, -5372, -3708, -4377, -4049, -3955, -7320, -5222, -5567, -3183, -4157, -10406, -6307, -7145, -2926, -4542, -15272, -5720, -7004, -3214, -4562, -9529, -5296, -6641, -4069, -4579, -8847, -6434, -8733, -5309, -5471, -11759, -9022, -9436, -6037, -8163, -10258, -7918, -3794, -5935, -12911, -7705, -6644, -1835, -5753, -8442, -7612, -6550, -1397, -5687, -7383, -8925, -7595, -2077, -5466, -7698, -9273, -9340, -3655, -5085, -7302, -8444, -9286, -6043, -5029, -5724, -8654, -9691, -11093, -5857, -4828, -10089, -13643, -10036, -7491, -4924, -11296, -12769, -6573, -5603, -5821, -10109, -9007, -5561, -4060, -7081, -9241, -7857, -5062, -4361, -8146, -8987, -7778, -4128, -6806, -9337, -8181, -8017, -3304, -13477, -9510, -6888, -7578, -3356, -8468, -7269, -6063, -7039, 8741, 3952, 6975, 8689, 7461, 7965, 4037, 6240, 8235, 7088, 5365, 3753, 3586, 6965, 5982, -709, 2291, -8624, 5319, 4748, -4470, -1068, 620, 4040, 4512, -2797, -1090, 558, 3121, 4183, -367, 1438, -3119, 1993, 3133, -592, 3228, -56, 84, 2502, -3397, 4205, 2057, -3665, 3187, -7182, 4323, 3214, -7878, 4075, 583, 4282, 4808, -2543, 4389, 3794, 4987, 6275, 193, 3820, 5394, 5719, 6925, 1546, 2253, 5734, 5810, 6541, 1361, -167, 4882, 5234, 4868, 613, -2154, 2816, 4206, 1450, 2241, -1280, 161, 2891, 1105, 3465, -94, -137, 982, 2355, 3369, -380, 154, -1515, 1786, 2095, -2752, -326, -166, -31, -185, -7063, -1308, 1459, -1995, -2564, -3374, -2490, 1997, -3375, -4284, -2141, -2608, 1926, -5535, -3928, -2394, -1395, 1648, -6430, -2423, -3605, -709, 1407, -5782, -3505, -4673, -1148, 1209, -7441, -5364, -4258, -3250, 862, -14465, -1560, -2896, -10573, 87, -6434, -360, -1859, -5823, -1257, -4715, -237, -1667, -3697, -2150, -4467, -520, -2329, -2695, -1664, -4289, -1902, -3308, -2223, -1493, -3401, -7242, -3745, -2694, -1736, -3402, -4590, -3741, -4302, -1632, -5902, -1390, -3761, -6770, -1434, -5788, -121, -3823, -8089, -1653, -3119, 547, -3750, -5731, -2427, -3391, 832, -4036, -3416, -3804, -6366, 572, -5602, -2191, -5673, -6006, -681, -10616, -1883, -7549, -4492, -4344, -8372, -2417, -7063, -5091, -6680, -6508, -3977, -5308, -5015, -2084, -6696, -7297, -4537, -3235, -970, -5048, -11384, -4676, -2338, -1043, -3625, -6729, -5139, -2746, -1931, -4086, -4856, -6156, -4940, -3320, -7477, -4850, -11532, -9552, -4050, -10210, -7748, -6825, -6017, -2984, -5601, -10312, -3707, -5121, -1871, -4374, -5851, -3115, -5930, -1696, -4228, -5661, -4027, -6161, -2534, -4901, -7737, -4717, -5627, -4341, -5874, -10902, -3761, -6915, -7455, -6447, -7895, -3654, -18720, -13483, -6889, -6565, -5180, -7222, -9348, -7138, -6865, -9112, -5547, -8639, -6701, -8530, -8968, -6065, -11853, -6201, -8321, -7126, -7279, -10446, -6732, -6220, -6626, -6673, -6152, -9638, -4512, -6631, -6094, -4599, -9879, -3458, -7760, -6785, -4192, -6707, -3481, -12012, -8925, -4470, -6211, -4762, -10526, -11451, -5108, -7719, -7049, -7306, -11076, -5739, -13789, -8367, -6461, -9835, -5993, -8478, -7185, -7141, -8315, -5675, -5652, -6084, -9976, -7564, -5021, -4584, -6254, -17176, -7346, -4589, -4718, -7559, -9942, -7128, -4647, -6373, -9423, -8840, -7063, -4976, -12287, -15035, -9816, -7145, -5328, -7967, -9515, -11203, -6917, -5561, -4906, -6676, -8212, -6556, -4962, -3648, -6157, -6806, -6157, -4169, -3571, -6516, -7052, -5704, -4041, -4950, -6261, -8524, -5911, -4554, -8975, -5784, -10226, -7143, -5486, -8860, -5819, -10541, -7835, -6689, -7483, -6120, -10127, -7749, -7490, -9826, -6313, -10173, -9714, -7104, -11192, 4458, 2870, 7118, 7575, -11243, 3348, 1685, 6636, 7254, -4944, -609, -1185, 5416, 6456, -1588, -1007, 1479, 4418, 5674, 1846, -1635, 2980, 4191, 5048, 4140, -5635, 3251, 3899, 4070, 5286, -975, 2726, 3097, 2906, 5483, -3298, 1238, 1617, 2440, 4715, -1532, -1686, -609, 1671, 2256, 3037, -3160, -3006, -1311, -3579, 5003, 1111, -937, -2107, 2997, 5863, 4373, 1221, 1334, 4453, 5773, 5938, 1434, 2093, 3956, 4642, 5925, -301, 2054, 2136, 2482, 4000, 794, 3022, 2635, 1047, -3405, 2476, 3858, 4138, 880, 467, 2019, 3438, 4503, -16, 1300, -669, 1587, 4082, -466, -1437, -4634, -1483, 3305, -533, -8420, -6667, -6500, 2350, -889, -2601, -5765, -5648, 864, -804, -2077, -1985, -2407, -1520, -198, -1745, -1615, -1994, -1470, 346, -1230, -3470, -2001, -12, 236, -1557, -10862, -1871, 353, -839, -2868, -6024, -2304, -86, -3463, -4276, -3767, -3760, -1369, -9859, -4134, -3319, -5611, -3591, -4525, -3073, -3684, -3931, -4325, -3927, -2727, -4850, -3074, -2305, -7892, -3983, -7513, -5005, -645, -4649, -6189, -13061, -6612, -176, -1450, -2832, -12060, -2315, -1227, -694, -1063, -7551, -1224, -4165, -1451, -781, -4934, -1604, -4534, -3464, -1419, -4606, -2728, -3025, -4085, -2318, -5605, -3903, -2358, -3239, -3209, -5515, -5165, -1846, -3741, -4852, -5936, -7169, -2057, -5461, -7091, -9465, -8962, -3333, -6245, -6562, -7129, -9671, -4477, -6273, -6751, -5552, -11221, -3905, -7579, -9701, -7571, -6112, -4143, -9314, -11239, -9671, -3291, -6937, -9167, -8239, -4276, -1935, -9456, -8446, -5746, -2875, -1615, -5504, -7196, -4037, -2975, -2231, -6170, -5945, -3717, -3918, -3490, -11158, -4926, -4759, -4549, -3561, -4858, -4167, -5523, -4314, -2564, -3533, -3755, -4182, -4855, -2477, -4788, -3605, -3583, -8525, -3652, -11478, -3554, -4205, -6096, -5556, -7369, -3680, -5724, -2706, -6369, -5545, -4411, -7552, -1721, -6916, -6312, -6501, -9040, -2130, -7502, -9788, -11790, -7529, -3799, -6730, -11512, -10105, -6241, -7233, -5022, -7393, -9046, -6171, -8237, -3758, -6358, -8040, -7227, -5758, -3342, -6662, -6714, -10113, -5566, -3729, -8050, -6617, -7486, -7133, -4795, -10028, -7793, -5152, -9578, -6239, -9313, -9877, -4713, -9609, -7260, -7252, -11532, -5531, -9312, -8461, -5703, -11067, -7127, -9298, -11221, -5150, -9746, -8573, -9261, -7140, -6157, -8772, -8980, -9628, -4919, -11494, -8258, -8132, -10059, -4307, -7427, -8265, -6819, -8427, -4611, -4321, -8843, -6113, -6823, -4983, -3504, -9175, -6057, -6212, -4853, -3996, -8911, -5606, -6328, -5217, -5402, -9312, -4622, -7036, -6732, -7241, -10592, -4093, -8669, -7196, -8304, -10786, -4047, -11327, -6214, -7631, -8903, -4054, -8959, -6600, -8118, -8014, -3898, -6536, -8753, -12148, -8668, -3674, -5627, -9694, -9457, -10135, -3660, -6112, -7095, -7659, -4829, -7102, -6498, -5768, -7102, -6936, -6734, -7755, -5765, -7561, -4010, -6378, -10869, -5938, -7981, -2349, -6027, -9615, -5920, -8148, -2201, -6023, -9381, -5366, -7391, -3445, -6148, -9821, -4920, -5938, -6092, -5824, -8314, -5159, -5012, -5167, -5281, -8243, -6280, -5023, -3392, -4739, -11745, -8310, -6182, -3030, -4111, -11193, -10530, -9371, -3623, -3622, -7625, -10460, -15111, -4370, -3745, -6713, -8825, -9433, -4118, -4924, -6975, -8062, -9147, -3587, -7154, -9096, -8549, -11286, -3679, -7569, -12180, -8767, -15624, -4455, -6400, -7286, -7822, -10345, -5084, -4614, -4905, -9334, -7582, -4162, -2134, -2845, -6630, -3609, -2167, -17, -740, -1735, -452, -502, 1187, 862, 480, 1284, 214, 1356, 1522, 1168, 1752, -121, 484, 1039, 556, 972, -1504, -1278, -845, -1431, -1274, -3916, -3357, -4865, -5202, -5812, -7535, -5205, -8171, -12697, -8842, -10191, -6426, -6474, -10853, -7187, -8928, -6003, -6521, -7274, -6582, -9937, -5139, -7692, -6007, -6221, -12284, -5021, -11105, -5926, -5930, -9419, -6087, -10641, -6514, -5528, -7850, -8223, -8236, -7463, -5493, -7054, -9559, -7551, -8722, -6216, -6346, -8339, -8193, -10419, -7790, -6011, -6303, -10805, -11837, -9272, -6640, -4770, -9711, -11618, -9646, -9355, -4113, -7521, -11748, -11232, -9333, -4237, -7380, -13581, -16033, -5474, -4666, -8751, -16529, -14081, -4155, -4990, -11089, -10811, -10738, -4401, -5478, -11609, -8690, -8725, -5911, -6111, -9299, -8324, -8702, -6955, -6697, -7727, -9391, -11741, -6187, -8326, -7471, -11304, -13708, -5902, -16418, -8593, -8898, -9336, -6526, -8725, -11389, -6642, -8172, -7757, -6779, -15746, -5817, -7703, -7228, -7294, -15452, -6349, -7830, -5863, -10127, -14359, -8933, -9199, -5960, -13144, -13676, -12484, -12232, -8559, -10365, -13134, -8452, -10297, -12472, -8164, -12280, -8102, -9018, -8343, -7143, -11929, -10335, -9879, -9266, -7373, -13421, -14360, -10807, -12668, -8397, -14255, -10952, -8965, -8240, -9241, -9871, -10460, -7929, -7171, -9145, -8414, -11568, -7746, -7378, -8297, -8713, -11369, -7947, -6951, -7257, -9695, -10045, -8383, -5811, -6687, -9494, -9430, -8879, -4912, -7073, -9061, -8905, -9013, -4489, -8822, -8683, -8541, -8780, -4744, -10384, -8191, -8858, -8695, -6062, -8407, -8082, -9874, -9036, -9017, -7240, -8356, -11460, -9588, -8399, -6772, -8776, -14374, -9760, -6181, -6490, -9244, -12994, -9444, -5628, -6383, -9540, -9428, -9244, -6381, -6598, -9933, -7944, -9549, -8644, -6929, -11073, -8064, -10229, -13556, -7220, -13279, -10255, -10962, -15329, -7872, -12613, -25624, -11789, -13159, -9007, -9435, -12071, -12529, -9989, -9948, -7981, -11921, -12561, -7856, -9965, -8073, -14185, -12093, -6894, -9528, -9832, -11276, -11549, -6884, -9140, -13116, -9690, -11024, -7704, -8890, -12101, -9682, -10647, -8939, -8893, -11875, -10968, -10730, -9519, -9104, -13947, -13496, -11562, -9776, -9449, -13752, -11391, -13395, -6389, -9624, -16465, -6442, -7466, -6840, -8839, -10579, -6320, -6329, -8537, -9431, -11509, -6801, -5775, -12776, -11379, -15505, -7008, -5151, -9260, -9727, -9754, -6292, -4510, -7001, -7445, -9310, -5955, -4042, -6402, -6402, -11807, -6881, -3903, -7043, -6345, -13333, -10060, -4227, -9048, -7133, -11438, -15372, -5080, -11930, -8676, -8836, -9456, -6219, -8870, -8569, -6909, -7821, -6827, -6598, -6804, -6603, -7425, -6689, -6119, -6132, -7994, -8306, -6495, -7395, -6363, -12395, -10567, -6375, -10852, -6267, -12735, -12963, -6237, -13169, -5422, -8806, -12784, -6011, -8836, -5921, -9344, -7571, -5404, -4695, -11035, -7611, -3635, -3964, -1767, -2650, -2313, -810, -1627, -153, 156, 10, 820, 120, 134, 1037, 737, 1271, 736, -1071, 492, 190, 517, 160, -4510, -1503, -1532, -1610, -1669, -11587, -5463, -4267, -5254, -4741, -8280, -15162, -7212, -6867, -7758, -8927, -12272, -8991, -6882, -7694, -6603, -11110, -9255, -7925, -6672, -4942, -10171, -7343, -9089, -6634, -4274, -9386, -6059, -9577, -6845, -4610, -9093, -6397, -9470, -6499, -6164, -9931, -8640, -9571, -6537, -7640, -13149, -9624, -10646, -7687, -7070, -15768, -7213, -14142, -10798, -7979, -13044, -6278, -11236, -14927, -12957, -15540, -6364, -7963, -10746, -7243, -13890, -7234, -6878, -9893, -5107, -9341, -8881, -7192, -11066, -4954, -7535, -11376, -8430, -12321, -6650, -6869, -15032, -9283, -9100, -14197, -6967, -15599, -7797, -8152, -8514, -7974, -11753, -5950, -9176, -6387, -10935, -9870, -5311, -10894, -6324, -16341, -9195, -6390, -11663, -7128, -10019, -9261, -11025, -11791, -7568, -9002, -9379, -8652, -9165, -7394, -9352, -8714, -6234, -8158, -7802, -9070, -7488, -5989, -9042, -9344, -8042, -6586, -6864, -12293, -10880, -7590, -6404, -8422, -10823, -10168, -7802, -6856, -9588, -7647, -9961, -8530, -7155, -9057, -6166, -11078, -9897, -6731, -8667, -5798, -14226, -12170, -6542, -9721, -6427, -16335, -13202, -7267, -13399, -7961, -11308, -11535, -9159, -17204, -9854, -9240, -10689, -11900, -12876, -11019, -8235, -11085, -12564, -9966, -10665, -7782, -13555, -11505, -8935, -8942, -7669, -14441, -11151, -10175, -7768, -7950, -10255, -12934, -12839, -7580, -8995, -8485, -17870, -11892, -7973, -12074, -7532, -11100, -16350, -7935, -14477, -6916, -9097, -11120, -7431, -9535, -6860, -8405, -8211, -7274, -8373, -7644, -8478, -8013, -7825, -8867, -8892, -9286, -9248, -9057, -10672, -9452, -11033, -9892, -10176, -13720, -10212, -14444, -9741, -10905, -15857, -11506, -18255, -10059, -11254, -11994, -10817, -13174, -10355, -11549, -10362, -10549, -10748, -10769, -14835, -10895, -11818, -9494, -11104, -12061, -14763, -13702, -9219, -11137, -9622, -10427, -15396, -9879, -11703, -9868, -7912, -13792, -11483, -13580, -11679, -7388, -10885, -13456, -23639, -12058, -8362, -9625, -13018, -12653, -11652, -11247, -9247, -11012, -10383, -11355, -17928, -9261, -9521, -10202, -11240, -15208, -9977, -9045, -11615, -12414, -10114, -3970, -8334, -5869, -8970, -9229, -4310, -13488, -5688, -9313, -7789, -4518, -13098, -6176, -6320, -6221, -4871, -11503, -6972, -5298, -5173, -5314, -10167, -8163, -5540, -4841, -5239, -10524, -10875, -6467, -5194, -4537, -9662, -12428, -7536, -6002, -3813, -6677, -8850, -8483, -6964, -3407, -5263, -6918, -9347, -8347, -3453, -4954, -5744, -10223, -10946, -4005, -5209, -5377, -11445, -14886, -4655, -5733, -5939, -11334, -14268, -4448, -6726, -7298, -9502, -10389, -4105, -8853, -8121, -8992, -8542, -4941, -11153, -8126, -9763, -8478, -7911, -8585, -8538, -12136, -8421, -9635, -5953, -6932, -11206, -5318, -5835, -3192, -3692, -4885, -2082, -2022, -652, -966, -1735, -91, 56, 997, 624, -174, 646, 569, 1520, 996, 80, 193, -421, 798, 70, -999, -1448, -3357, -1397, -2473, -3820, -4221, -12012, -4667, -7935, -10437, -7136, -8222, -5044, -15169, -7808, -7900, -8154, -6085, -15738, -6267, -7565, -9659, -9547, -10544, -5693, -7656, -8504, -8180, -8827, -5122, -9644, -6047, -7165, -7995, -4756, -13342, -4937, -8674, -7220, -4943, -8547, -5094, -16086, -6744, -5605, -7958, -6338, -8025, -6950, -6103, -10312, -8173, -6047, -7703, -6154, -11872, -9040, -5874, -8139, -6608, -7372, -8626, -6821, -8573, -7953, -5926, -8458, -8241, -10022, -9390, -6105, -9443, -8828, -12613, -9850, -7899, -11362, -8784, -12567, -12242, -10835, -9466, -9091, -9564, -11749, -9632, -7662, -9057, -7084, -8390, -8928, -7209, -7888, -5694, -8031, -9046, -7896, -7005, -5408, -10131, -8701, -9926, -7092, -6175, -15552, -8263, -14198, -8416, -7737, -10128, -7893, -19648, -12171, -8898, -8567, -6952, -12958, -14097, -9430, -8408, -5916, -8995, -10367, -11185, -9023, -5393, -7523, -10380, -13151, -10173, -5283, -8047, -13643, -9635, -11738, -5285, -10362, -15064, -7977, -12013, -5510, -7585, -10676, -7525, -10252, -6394, -5210, -9757, -7497, -9468, -8360, -4284, -10698, -7487, -10423, -11830, -4265, -12672, -7843, -14152, -16256, -4728, -11014, -8814, -10652, -14344, -5211, -9543, -10244, -8002, -10937, -5613, -8743, -13338, -7280, -9437, -6035, -8430, -14408, -8177, -8749, -6535, -8710, -9385, -11559, -7945, -7557, -9657, -7736, -17573, -7224, -8791, -12450, -7361, -12250, -7151, -7702, -15480, -7544, -10976, -7976, -6557, -10490, -7928, -9773, -9783, -6497, -9302, -9016, -9029, -12423, -7322, -9630, -11402, -8466, -14060, -8830, -10799, -12772, -8346, -11323, -11245, -10842, -13624, -9383, -9700, -15633, -10561, -14654, -11197, -9269, -11468, -10332, -10460, -10194, -8898, -9169, -8613, -8676, -9056, -8087, -8695, -7213, -8226, -8841, -7587, -9421, -6443, -8782, -9153, -8005, -10086, -6048, -10301, -9820, -9972, -9947, -6109, -12165, -10936, -15691, -10654, -6898, -12113, -13707, -12451, -12240, -8843, -11489, -16271, -10362, -10891, -13140, -11680, -10329, -9403, -9133, -14873, -12631, -8537, -8669, -8325, -13261, -13581, -8354, -8244, -8241, -15671, -13412, -9423, 8813, 10397, 10659, 8490, 6718, 8016, 9942, 10005, 7905, 6152, 5336, 8532, 7937, 6131, 4406, 2646, 6102, 4708, 3216, 1406, 3898, 3039, 3748, -79, -1617, 3079, 1561, 2902, -2100, -2952, 1341, 2545, 195, -3053, -11033, 2008, 3509, -1404, -1508, 91, 3027, 3571, -1222, 373, 2781, 2993, 2556, -2068, 1033, 3773, 1180, -249, -3393, 1549, 3892, -1764, -2551, -5508, 3372, 3544, -603, 2574, -5315, 4896, 2781, -1798, 4386, -3700, 5320, 1226, -148, 4572, -3826, 4542, -1227, 1932, 3323, -4813, 2329, 722, 1888, 248, -3533, -2016, 2718, -179, -2923, -978, -4124, 3098, -7186, -240, 829, -3245, 2120, -3145, 966, 1626, -3372, 108, -941, 1235, 1246, -2906, -3208, -446, 1013, -730, -2199, -3670, -1099, 775, -5065, -1910, 888, -3410, 562, -3306, -711, 1797, -3112, -131, -1919, 646, 210, -1290, -1860, -506, 648, -8568, -1965, -5820, 1012, -1470, -2090, -1702, -7525, 1603, -13126, -1030, -82, -2749, 1247, -2015, -1730, -1340, -1634, 414, -49, -693, -8504, -2743, -122, 377, 1062, -158, -7438, -409, -30, 1753, 991, -4883, -600, -115, 826, 387, -4172, -381, 605, -3979, -874, -6606, -627, 1205, -1725, -2647, -4240, -2689, 1415, 1168, -7682, -3140, -14648, 1137, 1515, -4479, -2758, -2630, 193, 427, -1744, -839, -862, -819, -2238, -1687, 103, -714, -218, -9737, -3465, -557, -1492, 439, -5712, -4673, -1832, -2782, 106, -4317, -3455, -177, -3986, -1112, -3988, -2608, 1099, -5197, -2516, -2516, -2493, 964, -5540, -3544, -1251, -3593, -604, -3070, -5482, -744, -7616, -3978, -1337, -12462, -1125, -7786, -8380, -742, -8535, -2774, -4063, -11811, -1018, -7103, -5773, -3582, -5192, -1771, -6211, -6737, -4687, -2416, -2447, -3962, -9365, -5494, -1557, -2921, -2362, -8857, -3950, -1830, -3256, -1536, -4470, -3112, -2783, -2844, -1492, -2905, -3625, -3987, -1998, -2360, -2419, -5022, -5214, -1659, -4169, -2912, -6536, -5247, -2094, -6068, -4404, -12883, -4173, -3040, -5744, -6282, -6009, -3920, -3782, -4821, -8265, -3423, -4906, -4196, -4536, -11284, -3433, -6995, -4462, -4385, -7178, -6038, -8637, -4578, -3974, -5469, -12730, -7578, -4933, -3589, -5236, -6031, -5920, -5391, -3457, -5734, -5707, -5407, -5162, -3782, -6514, -8844, -6256, -4151, -4442, -7372, -9864, -8398, -3579, -5075, -8072, -5520, -11035, -4064, -5974, -7418, -4383, -9173, -5413, -7400, -6295, -4422, -7142, -6321, -8876, -5980, -5285, -6607, -6100, -9986, -6726, -6866, -7026, -5898, -9719, -9170, -9123, -7579, -6793, -8407, -14646, -18011, -8116, -10370, -8259, -10472, -8183, -8928, -11228, -11437, -10430, -5390, -8883, -8491, -7834, -9696, -4587, -7441, -8322, -4980, -7794, -5017, -6123, -8598, -4332, -6821, -6314, -5720, -8598, -4967, -5271, -8158, -6420, -8336, -6520, -3875, -5633, 5939, 7498, 3816, -4110, -683, 4949, 6931, 3325, -2868, 505, 1173, 5324, 1999, -103, -833, 276, 3248, -27, 688, -4897, 2082, 1688, -1912, -381, -3131, 840, -120, -967, -2153, -1680, 262, -8665, -1243, -4695, -1078, 2055, 581, -249, -3880, -118, 2793, 3291, 1934, -1310, 732, 2875, 4391, 2177, -864, 1025, 2300, 4922, -22, 1560, 741, 209, 5020, 664, 3346, 174, -5471, 4348, 3231, 3735, -310, 664, 2497, 3428, 3167, -723, 2976, -596, 1225, 2238, -952, 3683, -853, -10966, 1769, -404, 3105, 129, 580, 2038, 690, 982, 575, 1900, 2110, 1487, -2467, 895, 1792, 1323, 1460, -1122, 695, 1478, -612, 98, -272, -430, 1702, -4604, -3266, -769, -1265, 2188, -9726, -3476, -2752, -435, 2395, -4439, -2936, -3515, -479, 2059, -3641, -4340, -1159, -2214, 1049, -3233, -5523, -933, -5408, -557, -1956, -6331, -3005, -3736, -2091, -1428, -5164, -7148, -1484, -2616, -2569, -6325, -3510, -129, -2039, -5926, -8524, -1105, 286, -1427, -4879, -3383, 539, -554, -1496, -3624, -1878, 1532, -3859, -1822, -4389, -1500, 1812, -6993, -1536, -6968, -1613, 1247, -2806, -1111, -12036, -2403, -315, -3363, -1365, -10198, -5101, -3183, -6179, -2557, -4521, -3642, -10706, -2277, -4067, -1316, -846, -6087, -392, -4254, 2, -513, -3761, -8, -2085, -262, -2486, -3954, -700, 279, -1985, -7065, -7600, -2532, 1410, -3414, -3956, -5137, -6374, 1188, -3260, -3883, -1687, -7568, -775, -4153, -3148, -403, -4011, -7901, -6251, -1121, 12, -2929, -3366, -9076, -538, -175, -3405, -1694, -10890, -1364, -1269, -5414, -2133, -11695, -3369, -3862, -4455, -3469, -13321, -5873, -5912, -2569, -4727, -12900, -7660, -4463, -2150, -5530, -10061, -6325, -4875, -2331, -6140, -8754, -5603, -6225, -2366, -6844, -9310, -7169, -6174, -2398, -8265, -8591, -9419, -5748, -2759, -11208, -6633, -8630, -4414, -3587, -6956, -6090, -11112, -3346, -4689, -5276, -6994, -12638, -3257, -5399, -6281, -8506, -7850, -3844, -4581, -12244, -8998, -5467, -4606, -3000, -7437, -11024, -3982, -5235, -2214, -5741, -14559, -3415, -5922, -2329, -5662, -8330, -3771, -7270, -2936, -5776, -6914, -5191, -9555, -3375, -5683, -7191, -8282, -11319, -2918, -5387, -8629, -11193, -14322, -1951, -4908, -10776, -7617, -10083, -1392, -4472, -11289, -6296, -7170, -1536, -4382, -8472, -6262, -6463, -2432, -4708, -6520, -7024, -7264, -4142, -5191, -5795, -7500, -9399, -6018, -5687, -6166, -6950, -11079, -5344, -6695, -7335, -6520, -9568, -4151, -9366, -7915, -6668, -7892, -3664, -11859, -7509, -7343, -6626, -3604, -8203, -7554, -8792, -5775, -3673, -7738, -8497, -8781, -5335, -3895, -10352, -12172, -6126, -5371, -4573, -10832, -11214, -4691, -5896, -6076, -7233, -7274, -4370, -6438, -8981, -6794, -6313, -4781, -6075, -13189, -8392, -6425, -2794, -5014, 2094, 4062, 775, 920, -1146, 2417, 2589, 4936, 3051, 1403, 3034, -10342, 6765, 3262, 2457, 3411, 2193, 6895, 1430, 2447, 3277, 3251, 5772, -1085, 1645, 2595, 1631, 3600, 407, 163, 1554, 580, 1491, 38, -2249, 561, 2839, 709, 1250, -4808, -409, 3087, 963, 3247, -3035, -3537, 1405, 2691, 3955, 288, -2711, 1159, 3357, 3626, 2891, 2046, 2533, 2067, 2343, 4115, 3543, 1477, 434, -88, 3895, 3370, -3691, 2722, -1088, 1912, 1934, 1207, 3667, 520, -1062, 770, 2300, 4338, 568, 928, 733, 877, 5272, -1201, 1467, -155, -3759, 5542, -4377, 614, -2033, -7205, 4832, -1541, -509, -3463, -4153, 3246, 619, -614, -4077, -3923, 1866, 1284, 58, -3159, -5763, 2323, 970, 376, -1191, -9738, 2746, 571, -167, 163, -2991, 2090, 518, -1675, 606, -1285, -9, -5, -3919, -66, -1182, -4671, -1455, -6022, -2343, -1636, -6281, -3871, -8176, -6628, -825, -2241, -6933, -6604, -3550, 737, -1412, -7588, -3941, -1937, 1675, -2996, -5979, -3184, -1677, 1721, -5206, -4511, -3779, -2436, 861, -2233, -3094, -4685, -4646, -1042, -1167, -1844, -4323, -12324, -5943, -1999, -1198, -3691, -5630, -4199, -7219, -1373, -3991, -2125, -623, -4238, -1845, -4512, 48, 499, -2786, -1957, -3037, 1229, 646, -6367, -2558, -2054, 1263, 280, -2470, -2945, -2372, -233, -556, -172, -2081, -3973, -2944, -1700, -275, -2455, -10596, -1288, -1024, -2207, -5302, -4313, -725, 450, -5139, -15950, -1506, -2403, 849, -4575, -11619, -1381, -5521, 241, -3617, -10848, -3952, -4205, -629, -2762, -9008, -10166, -4152, -1251, -2646, -13814, -3670, -7243, -2545, -4078, -6141, -2909, -7624, -5308, -7177, -4140, -3531, -3071, -7346, -6519, -4223, -4333, -1660, -7726, -5860, -5727, -4502, -1749, -7183, -6056, -7503, -4412, -3281, -4656, -5271, -6772, -4827, -7504, -3650, -3645, -5648, -5674, -9299, -3597, -2461, -5263, -5178, -6334, -3368, -2197, -5509, -3935, -7568, -2920, -2855, -6093, -3293, -11061, -3300, -3975, -6699, -3216, -6724, -5529, -4297, -7015, -3670, -5820, -8424, -3813, -6821, -5098, -6949, -4491, -3662, -6529, -8867, -9136, -3331, -4482, -6795, -12447, -9999, -3576, -6464, -8371, -8162, -10053, -4297, -6243, -11225, -7268, -8150, -4944, -5010, -7377, -7233, -6136, -5842, -5271, -5335, -8012, -5435, -6803, -6653, -4850, -9710, -6171, -6797, -8058, -5448, -11619, -7080, -5864, -8252, -6766, -11448, -5552, -5293, -7839, -8005, -9893, -4396, -5711, -7421, -8020, -8635, -4153, -7208, -6681, -7290, -7992, -4352, -8804, -5837, -7035, -7624, -4365, -8369, -5335, -7635, -7078, -3812, -8074, -5399, -9177, -6562, -2998, -8894, -6445, -13334, -6483, -2447, -9350, -9490, -11962, -6895, -2528, -7762, -14601, -8024, -7449, -3536, -6936, -11336, -7346, -8039, -5960, -7576, -12136, -9686, -7937, -8472, -9287, -3496, -7503, -8433, -8897, -10383, -4426, -5678, -6649, -7783, -6855, -7695, -4832, -4747, -6722, -5148, -7399, -4425, -3662, -6695, -4683, -4367, -4128, -3404, -7448, -5218, -3807, -3883, -3796, -8240, -6667, -4906, -3967, -4597, -8482, -9104, -7851, -4858, -5533, -8476, -10049, -10036, -6751, -6587, -8181, -7837, -7628, -6463, -8581, -7612, -7054, -7060, -4725, -11410, -7441, -7732, -8435, -4225, -7490, -8598, -9807, -9328, -5025, -5693, -12061, -14319, -6423, -7758, -5131, -9252, -16790, -5234, -17193, -4865, -7176, -12803, -5477, -7934, -4707, -6494, -11724, -6881, -6387, -5316, -6151, -11360, -9805, -6221, -7437, -5109, -10351, -13271, -7217, -9062, -3882, -9080, -7205, -10676, -7973, -3569, -9486, -5212, -11092, -9780, -4564, -12814, -4973, -8225, -13128, -7084, -12401, -6159, -7772, -7994, -9596, -10001, -8795, -7764, -6861, -9734, -8743, -13018, -8587, -6936, -10458, -7666, -16832, -13248, -7464, -11157, -6865, -13350, -8835, -8364, -12259, -6464, -10412, -6063, -9754, -10762, -6847, -8698, -5100, -11149, -9803, -8488, -7883, -4924, -10474, -11642, -13066, -7668, -5416, -8495, -11305, -13263, -8182, -6834, -8020, -8702, -9646, -9635, -7661, -9712, -8259, -8472, -10820, -6223, -12439, -8311, -7929, -10802, -5712, -8917, -8296, -8237, -10867, -6521, -6645, -9213, -9927, -9922, -7500, -5195, -10675, -10293, -8680, -6508, -4594, -9877, -8656, -7971, -5540, -4911, -7628, -8495, -7962, -5331, -6144, -6128, -9506, -8988, -5546, -8410, -5828, -10408, -12057, -5777, -11265, -6702, -9785, -14430, -5836, -8674, -8660, -8797, -10904, -5568, -6489, -10644, -8964, -10424, -4712, -5601, -9813, -11439, -11621, -3802, -5747, -8579, -11469, -11915, -3544, -6736, -8169, -8615, -9917, -4222, -7571, -8891, -7903, -9164, -5899, -7390, -11613, -8061, -9634, -7748, -7776, -12381, -8261, -10773, -7733, -10101, -9310, -8382, -11118, -7290, -13743, -8720, -8758, -9523, -7255, -9444, -9833, -9839, -8479, -7638, -8215, -11816, -11469, -8316, -8413, -8325, -11585, -11035, -8254, -8751, -9150, -11193, -9967, -8321, -8034, -10605, -11760, -9553, -9412, -7233, -14406, -11946, -9279, -11210, -6727, -12462, -12255, -8889, -10244, -6605, -8051, -15851, -8480, -9993, -7124, -6429, -14108, -8135, -12885, -8908, -6275, -11362, -7831, -14963, -12904, -7163, -12241, -7476, -10451, -9523, -8431, -23659, -7144, -9732, -8050, -9233, -10722, -6999, -10200, -8585, -9996, -8487, -7020, -11260, -9236, -11182, -8138, -7204, -13736, -8276, -10763, -9119, -7783, -18582, -7917, -9568, -11103, -9010, -14757, -8302, -9259, -14129, -10997, -14171, -8989, -9768, -14633, -13936, -12129, -11061, -10782, -10645, -20938, -10071, -19054, -11648, -9323, -16545, -9286, -10579, -11734, -9386, -14180, -9455, -9479, -11729, -10118, -13190, -10268, -10695, -11622, -11141, -12357, -11626, -14135, -9898, -12644, -12714, -13309, -18135, -8553, -14126, -16128, -13935, -11560, -8260, -13613, -15183, -13687, -5460, -5452, -11196, -9790, -6817, -6056, -5513, -9729, -8527, -7462, -6792, -6547, -8323, -8116, -7521, -7897, -8488, -7397, -7994, -6971, -9023, -9701, -7447, -8062, -7417, -9471, -8606, -8319, -8659, -8879, -9053, -7016, -9132, -9522, -9267, -8717, -5973, -9771, -9712, -8848, -8000, -5820, -10974, -9332, -8454, -7183, -6355, -9140, -9043, -8340, -7705, -7043, -6816, -7799, -9236, -11026, -8276, -5938, -6492, -11037, -13919, -12229, -6516, -6059, -12418, -10092, -11244, -9211, -6435, -12527, -10279, -8786, -16235, -7044, -12617, -10954, -8149, -9443, -7371, -12099, -10423, -6895, -7777, -8077, -10603, -10177, -5797, -6952, -9957, -11431, -8600, -5629, -6369, -10092, -13096, -6683, -6349, -5890, -7907, -8525, -5796, -7962, -5661, -7485, -7186, -5890, -10650, -5852, -9032, -7611, -6651, -9081, -6749, -12763, -8409, -7470, -7463, -9612, -12106, -7683, -7599, -8078, -13115, -12183, -6457, -7475, -9603, -7910, -17086, -5794, -8052, -7818, -7213, -14571, -6190, -9540, -7204, -8812, -11549, -7308, -10768, -8684, -14668, -10139, -7048, -10197, -12322, -13194, -9157, -6602, -9200, -12084, -10056, -8285, -7252, -8627, -12810, -7922, -7328, -8022, -8385, -11429, -6773, -6689, -7771, -8045, -8789, -7003, -6466, -7631, -7573, -8432, -8996, -6556, -8270, -7469, -10263, -11910, -7045, -9701, -8035, -15432, -10726, -7968, -9492, -8998, -12569, -11408, -8956, -7808, -9465, -9476, -11573, -9228, -7152, -8629, -7377, -9487, -8537, -7727, -7552, -6347, -7904, -7637, -10031, -7612, -6232, -6806, -7240, -15664, -9616, -6842, -6692, -7670, -9481, -10893, -8064, -7899, -9089, -7650, -7844, -10338, -9958, -11632, -7788, -6743, -15399, -9672, -14526, -9735, -6879, -9602, -9141, -14182, -9734, -7913, -7734, -9744, -13034, -7855, -10075, -7958, -10335, -12388, -7859, -12946, -10337, -9381, -12022, -9788, -8896, -15956, -8627, -11608, -12881, -7129, -11091, -9218, -11313, -10909, -7331, -9856, -12378, -10599, -9289, -8453, -10636, -14063, -9657, -8366, -7316, -14168, -9587, -9603, -7885, -6435, -12406, -8310, -10827, -7918, -6999, -9890, -8193, -13505, -8799, -8627, -9652, -8718, -16357, -10594, -10108, -11474, -9647, -11601, -9607, -9776, -16771, -10976, -8973, -7534, -8982, -12427, -12469, -7884, -6626, -9249, -10560, -12453, -7916, -6818, -11029, -9956, -11459, -8787, -8394, -14866, -10541, -11158, -10044, -12984, -16609, -13795, -11623, -11747, -11577, -15079, -15484, -11876, -18280, -9348, -13700, -10976, -11500, -12031, -9298, -12239, -9985, -10336, -9195, -9849, -11672, -10390, -9080, -8701, -9727, -10923, -11246, -8823, -9799, -8697, -8961, -9886, -9284, -12383, -7919, -7485, -7816, -9307, -15202, -8285, -6939, -6696, -9471, -12960, -10168, -7129, -6570, -10868, -10858, -11686, -7784, -7360, -12979, -9968, -10203, -8744, -8974, -13473, -9813, -9332, -10319, -11144, -14184, -10010, -8908, -14214, -12825, -16374, -10464, -8726, -12654, -12828, -21747, -11321, -8842, -9372, -12247, -13544, -12614, -9218, -9057, -9536, -11694, -10012, -10812, -9707, -14010, -13820, -12716, -10251, -6857, -14040, -13994, -9343, -12918, -5936, -9919, -10056, -7413, -13393, -6025, -8555, -6813, -6237, -9227, -5917, -9202, -5305, -5587, -7527, -5636, -14629, -4851, -5726, -6898, -6312, -9374, -5153, -6618, -7181, -8660, -6488, -5724, -7500, -8430, -12088, -5575, -6115, -7335, -8971, -12970, -5820, -6878, -5845, -7404, -11189, -7265, -9106, -4676, -6434, -8058, -11195, -11526, -4566, -6239, -6886, -12075, -9203, -5535, -6462, -6907, -8017, -8769, -7501, -6576, -7458, -6817, -9307, -10182, -6217, -8087, -7065, -9381, -14000, -5790, -9111, -7695, -9273, -14013, -5530, -9469, -6265, -7964, -8628, -5245, -7611, -5366, -6227, -6624, -4801, -6887, -6173, -5867, -6126, -4380, -8080, -8235, -7523, -6694, -4270, -12832, -8111, -10652, -7851, -4643, -11482, -8314, -8778, -9029, -5509, -8708, -8613, -9667, -9666, -6783, -7574, -6763, -15752, -8621, -8420, -6630, -5875, -10426, -7571, -11014, -5964, -6041, -8652, -7110, -16756, -6136, -6739, -7334, -7024, -8682, -7497, -7024, -6649, -7826, -6229, -9272, -6467, -6947, -10813, -5450, -9178, -6030, -7863, -13031, -5848, -9559, -6195, -8376, -10567, -7039, -11033, -7016, -8152, -13587, -8136, -12396, -8158, -7953, -11075, -9305, -14775, -8235, -8296, -6976, -9759, -12712, -8007, -9244, -5595, -7951, -10772, -9307, -8603, -5583, -7666, -10898, -11411, -6726, -6690, -9241, -12558, -9605, -5889, -8239, -9273, -16695, -9047, -6261, -8320, -8281, -12356, -8355, -7796, -8204, -9367, -9069, -6581, -10290, -9000, -12092, -7293, -5492, -12402, -10646, -11428, -6309, -5349, -13143, -13503, -11224, -5961, -5992, -12181, -11390, -11425, -6118, -6902, -10596, -9237, -9379, -6499, -6978, -10052, -9085, -7620, -6983, -6004, -9964, -10892, -6877, -7917, -4814, -9631, -13976, -6852, -9618, -4085, -10410, -10403, -7118, -11857, -4145, -16169, -9094, -7372, -14266, -5161, -10884, -9700, -7793, -11879, -7035, -8524, -12626, -8692, -9682, -7916, -8797, -15806, -9044, -8925, -7578, -11683, -11961, -8553, -8639, -8371, -13669, -11163, -8835, -8225, -10796, -11336, -10129, -9206, -7826, -11944, -11962, -8899, -9312, -7680, -11506, -13009, -8766, -11443, -7934, -14209, -11887, -9428, -15040, -8677, -16195, -10058, -9453, -9580, -9204, -11942, -8270, -9110, -7994, -8292, -11405, -7274, -9576, -7425, -7484, -11145, -7187, -10667, -7253, -7809, -10004, -7976, -10382, -7373, -9628, -9389, -9718, -9708, -8018, -13756, -9756, -13145, -10434, -10148, -25925, -11243, -16287, -13292, -19021, -16248, -14065, -11228, -23071, -9222, -13028, -12224, -9445, -14471, -7451, -13009, -9687, -8828, -11633, -7669, -19763, -8689, -8807, -10563, -9429, -13228, -8834, -9196, -10590, -11230, -10881, -9994, -9838, -10660, -10238, -10778, -11866, -10049, -10486, -9334, -11957, -12076, -9901, -10670, -9106, -15188, -10807, -10374, -11336, -9513, -16229, -10619, -11442, -12249, -10440, -12259, -12338, -11888, -11873, -11920, -8255, 8218, 8518, 4703, 137, -5140, 7753, 8166, 5106, 540, -3250, 6287, 7108, 5555, 791, -1631, 3470, 5348, 5428, 570, 1156, -2180, 2995, 4792, 899, 3233, -668, 588, 3980, 1142, 3964, 991, -1786, 3029, -304, 3094, 702, -8279, 1340, -3512, -478, -1112, -2044, -2134, 1037, -733, -2611, 604, -2068, 3033, 1683, -1222, 1844, 96, 3771, 1510, 67, 2656, 175, 4017, 111, 1671, 3035, -950, 3948, -1754, 2724, 2612, -511, 3152, -2003, 2721, 832, 1060, 745, -727, 1420, -4550, 1752, -1065, -971, -2190, -886, 1588, 2265, -2517, -4913, 1840, 1015, 3345, -3708, -1224, 2726, 1227, 2817, -8670, -906, 2485, 2340, 982, -2849, -1446, 1054, 3226, 62, 537, -684, -2201, 3490, -115, 1737, -56, -7898, 3096, -4738, 1778, -982, -6826, 2077, -1031, 828, -3160, -10160, 152, 2222, -1483, -1212, -4060, -4423, 3118, -5594, 248, -2787, -2026, 2878, -3903, 324, -3570, 406, 1755, -1324, -124, -2496, 719, -230, -71, 80, -720, 417, -1210, -232, 469, -854, 1272, 220, -1195, 159, -4591, 2291, 1101, -1698, -765, -3671, 2406, 1309, -821, -1862, -197, 1487, 1173, 791, -3180, 112, -262, 591, 1361, -5797, -1610, -1179, -998, 493, -6925, -5420, -742, -4666, -1194, -1936, -3467, -1125, -7554, -890, 178, -2146, -2983, -3930, -629, 876, -2217, -5998, -2068, -2152, 306, -2729, -7022, -1218, -7188, -2206, -3760, -5448, -1174, -7687, -10954, -4143, -3419, -1516, -5093, -3138, -2143, -1985, -2057, -4052, -2775, -1117, -1170, -2641, -2138, -5550, -995, -1224, -2670, -735, -9578, -567, -2007, -2219, -342, -7692, 524, -3086, -1683, -948, -7077, 1296, -5370, -1194, -2221, -3256, 1257, -4950, -1069, -3383, -1472, 233, -1693, -1771, -4892, -1180, -1980, -419, -3866, -6621, -2138, -5474, -156, -6157, -4795, -4213, -5127, -339, -4524, -3590, -6570, -3194, -780, -4325, -3557, -8074, -2608, -1703, -5544, -4800, -8634, -3328, -3206, -6749, -7973, -8729, -5125, -3443, -7786, -7871, -10310, -6026, -2155, -10906, -7845, -13434, -5541, -1414, -10743, -15660, -9978, -4354, -1374, -6485, -6403, -8967, -2751, -1939, -3752, -4951, -9769, -1632, -2963, -1807, -5986, -10566, -1131, -3689, -669, -9595, -13136, -1276, -3427, -415, -12170, -10248, -2242, -3000, -1194, -7320, -5671, -4156, -2917, -3317, -4703, -3638, -4702, -3214, -6274, -3608, -2845, -3237, -3756, -5799, -3894, -3093, -2684, -4211, -6050, -5378, -4583, -3074, -4323, -7715, -6447, -7930, -4186, -4257, -7771, -5940, -12505, -5731, -4563, -6867, -5028, -13601, -5859, -5985, -5732, -4149, -8554, -4586, -10478, -4734, -3890, -6391, -4026, -10602, -4790, -4268, -6069, -4167, -7309, -6658, -5053, -6613, -4131, -6262, -15018, -6338, -8256, -3866, -5088, -7044, -8316, -12071, -4221, -4230, -5000, 5922, 2877, -2652, 7225, -1942, 5515, 2353, 3865, 6686, 1766, 4165, 730, 5510, 4940, 3051, 1358, 904, 5010, 2671, 2092, -5564, 2646, 2289, 3628, -1862, -4151, 2909, 607, 4154, -5251, -1857, 1644, 3858, 3041, -1910, 10, -602, 4972, 1045, -3599, 1195, 605, 4873, 810, -9585, 1429, 2420, 3718, -155, -2336, 1055, 3117, 1407, -5780, -222, 808, 2803, 890, -817, 1013, 1218, 2085, 3289, 1366, 1234, 2027, 2761, 4672, 1799, 198, 3034, 3583, 5051, 1359, -1866, 4040, 3129, 4518, 319, -2769, 4706, 813, 3008, -854, -1545, 4699, -3603, 235, -113, -1184, 3630, -1158, -2969, 2063, -2284, 709, -774, -662, 3467, -4019, -992, -2120, 629, 3772, -6185, 1582, -4819, 128, 3272, -7246, 1865, -11520, -1190, 3004, -2061, 812, -2624, 278, 2945, -906, -60, -184, 1228, 1770, -859, 174, 294, 611, -203, 858, 249, -1086, -1130, 369, 2022, 241, -1940, -1573, 174, 1316, 853, 929, -1203, -2489, -2748, 1830, 2295, -2578, -11287, -3262, 2455, 2604, -3068, -6488, -1289, 2326, 2428, -89, -5309, -4264, 1290, 1918, 846, -5271, -4314, -320, 742, -190, -8586, -2029, -1024, -1542, -4638, -9557, -2594, -476, -4319, -4176, -6330, -1582, 565, -4829, -1713, -7113, 14, 1462, -5858, -2051, -10818, 631, 1639, -10144, -3800, -2388, 300, 683, -5406, -5103, 539, -1099, -2281, -2988, -3971, 1757, -3044, -12130, -3151, -2522, 1792, -3792, -3819, -4758, -1578, 714, -4145, -3659, -3347, -1303, -1851, -4225, -5126, -1984, -1914, -7118, -4073, -6039, -1921, -3745, -4571, -3449, -5360, -3066, -4057, -3408, -2754, -3995, -5962, -2056, -3713, -2999, -3494, -8482, -1508, -4204, -3874, -4233, -7004, -2412, -4300, -3411, -6686, -7724, -5074, -4663, -2566, -11435, -8951, -9769, -6523, -2522, -4694, -8805, -5417, -11164, -3203, -2571, -9365, -3728, -7995, -4366, -2390, -9768, -3197, -6963, -5469, -3829, -5474, -3229, -6954, -5628, -4607, -3508, -4104, -6926, -5201, -3017, -3258, -6781, -6688, -5292, -1676, -4259, -8702, -5994, -6273, -442, -6137, -8217, -5305, -7539, 275, -8081, -8464, -5335, -7354, 147, -8731, -3499, -5803, -6249, -888, -7789, -2032, -5607, -5626, -2776, -5259, -2924, -6184, -5689, -5352, -4394, -5429, -9887, -5982, -8624, -5787, -2827, -11662, -5790, -12709, -12312, -1539, -7007, -5155, -13300, -9568, -1918, -4272, -4926, -10232, -7642, -3585, -2757, -5668, -7063, -6153, -6748, -2676, -6399, -5254, -5138, -17375, -4308, -5488, -4550, -5500, -8419, -9177, -5281, -4523, -7549, -5931, -6620, -6823, -4509, -7848, -5396, -5237, -11409, -4001, -5616, -6506, -6804, -9460, -3360, -5102, -6861, -10260, -7357, -3247, -6051, -4702, -6499, -6841, -4070, -8027, -3936, -5306, -6850, -6079, -8982, -4609, -5490, -7067, -9131, -7701, -6456, -6575, -7263, 7862, 3577, -3578, 6519, 8233, 7387, 3047, -265, 6189, 8002, 5799, 1670, 1362, 5358, 7334, 2052, 840, 1291, 4485, 6244, -1155, 1285, -128, 3838, 4508, 3300, 1833, -1630, 2803, 2706, 4122, 2146, -633, 1071, 4250, 3709, 1664, 733, 1908, 5011, 3086, 48, 1542, 2952, 3427, 2686, -1076, 1275, 2652, -882, 1801, -599, -870, 1956, 3469, -227, -932, -10134, 1353, 4678, -4543, -2031, 84, 400, 4984, -3068, -3364, 2172, 945, 5524, 86, -5368, 2475, 1878, 5646, 1514, -4784, 1380, 1394, 5202, 1857, -1441, -806, -1002, 4984, 1045, 477, -635, -4379, 4954, -1648, 1641, 644, -2797, 4288, -3253, 2644, 972, -1322, 3020, 397, 3596, 687, -101, 2814, 1834, 4182, 349, 33, 3996, 2236, 4101, 852, -964, 4939, 1990, 3145, 1720, -2451, 5058, 1103, 1231, 1760, -3097, 3923, -603, -635, 322, -2722, 262, -3038, -1189, -4472, -2620, -1060, -2899, -2015, -3919, -3436, 2012, -984, -1798, -597, -2320, 1947, 383, -902, 216, 171, 124, 1242, -747, -309, 1428, -2713, 1657, -1183, -2483, 1433, -3601, 1756, -1977, -7766, 72, -2811, 1657, -2306, -10583, -3253, -2841, 1340, -2238, -6886, -4297, -3968, 519, -1825, -2592, -2136, -5200, -1223, -213, -715, -1543, -4770, -2527, 325, 291, -1608, -3019, -1503, -1502, 1062, -2140, -1168, -526, -6645, 1322, -3678, -154, -132, -1217, 627, -7430, -550, -1186, -480, -1285, -4158, -3529, -5876, -1895, -3438, -2063, -7058, -5493, -3733, -3336, -2027, -2192, -3358, -3342, -3693, -3797, -2182, -4358, -3690, -4396, -7597, -4956, -6387, -3553, -4124, -8527, -3015, -6323, -2577, -4534, -6396, -614, -4495, -3322, -6881, -3609, -8, -3697, -7313, -9857, -2506, -696, -4470, -5693, -9221, -3224, -2436, -6633, -4554, -7967, -5896, -3135, -4783, -6263, -6039, -5094, -2310, -2602, -6682, -6548, -3167, -2169, -1943, -6395, -13476, -2639, -2628, -2692, -6610, -7486, -2796, -3263, -5452, -3570, -5008, -3103, -4128, -14413, -2148, -4189, -2920, -5986, -6298, -2296, -3889, -2034, -9934, -5030, -3815, -3879, -1032, -9400, -5194, -6892, -3773, -352, -10041, -6318, -11567, -3246, -68, -11535, -8678, -11611, -2635, -19, -9312, -9926, -10994, -2358, -75, -16555, -8034, -10548, -2571, -458, -5942, -7471, -10320, -3233, -1499, -3288, -7675, -10172, -3883, -3313, -2820, -7216, -10202, -3874, -5729, -3540, -5958, -9375, -3945, -8679, -3976, -4982, -6867, -4869, -14072, -4032, -4766, -5660, -6485, -12797, -5370, -5521, -6325, -7500, -10770, -7950, -7705, -9406, -7495, -9962, -5439, -14339, -7057, -8173, -7902, -3887, -8710, -4512, -9782, -6912, -3828, -6140, -3589, -7110, -7707, -5054, -5275, -3751, -5350, -11512, -8205, -5413, -4861, -5301, -10081, -12683, -6424, -6305, -6681, -6900, -8432, -8580, -7125, -8259, -5725, -8012, -8535, -8108, -5274, -4485, -4669, -8641, -6926, -6248, -6259, -5340, -11387, -7950, -6505, -7441, -6765, -6574, -10861, -6476, -5437, -8423, -4254, -15479, -7169, -4629, -8620, -3606, -12207, -9201, -5047, -7602, -3747, -8709, -11083, -6616, -6982, -3893, -6456, -10302, -9628, -7076, -3962, -5050, -8471, -12842, -7508, -4693, -4689, -7345, -11734, -6814, -6884, -5827, -7439, -11003, -5609, -12702, -10190, -7761, -10101, -5059, -13157, -9423, -6792, -8744, -5142, -9739, -6426, -5961, -7578, -5798, -7210, -5659, -6137, -6867, -7190, -5969, -5808, -7719, -6570, -8674, -6533, -6466, -11384, -6787, -10674, -10207, -6446, -6049, -8001, -9156, -4805, -4379, -2756, -6357, -4016, -2200, -2543, -1038, -3515, -1868, -1601, -1907, -492, -2414, -1319, -2497, -2527, -1066, -2857, -2123, -4310, -4353, -2907, -4978, -4412, -4906, -5775, -6566, -9626, -8518, -5234, -5106, -10306, -12933, -10710, -6888, -5272, -8755, -11421, -11443, -8847, -6832, -9574, -10006, -14369, -8444, -8294, -12115, -10349, -17059, -8218, -6559, -12109, -12793, -14743, -8958, -5232, -10175, -11258, -13735, -8599, -5377, -8724, -9164, -15455, -7532, -7007, -8339, -8083, -13265, -7816, -9196, -8268, -7815, -11564, -9832, -9775, -6952, -7926, -13187, -13063, -10765, -5906, -7782, -15584, -12379, -10490, -6108, -8448, -12091, -9122, -7745, -7751, -11906, -13267, -7103, -6600, -10677, -10751, -17622, -6265, -7042, -12941, -9065, -14011, -6049, -8883, -9876, -10813, -20246, -5982, -9756, -7965, -14369, -10195, -5954, -8426, -8195, -13464, -7762, -6066, -7427, -10571, -16908, -7728, -6619, -6541, -17431, -10379, -10433, -8506, -5986, -12697, -9069, -11079, -12715, -6155, -8603, -9403, -7391, -8120, -7531, -6590, -9741, -6131, -6525, -10710, -5535, -10606, -5838, -6682, -8170, -4985, -13638, -6081, -7904, -6235, -4881, -13114, -6427, -9614, -6178, -5447, -11671, -6425, -10083, -7648, -6948, -11728, -6684, -8257, -10462, -9234, -10779, -8225, -6923, -12661, -10619, -9710, -13744, -6671, -16022, -11446, -9270, -10943, -7321, -12995, -13079, -9065, -8320, -8063, -9957, -11276, -9036, -7934, -8312, -9468, -8819, -9467, -8590, -8967, -10645, -7828, -10501, -9496, -10112, -11590, -8063, -11299, -8770, -10139, -10255, -8887, -10595, -7676, -9236, -9306, -8792, -9146, -7960, -8973, -8622, -8151, -7974, -10602, -10019, -8011, -7899, -7927, -14595, -12994, -7918, -8135, -9534, -10919, -13005, -8829, -9017, -14014, -12278, -11690, -11613, -9955, -15600, -15036, -12645, -19515, -9337, -14409, -10368, -12627, -13603, -8850, -15890, -9811, -10021, -14068, -9407, -16778, -11374, -8387, -13052, -10373, -14304, -14554, -8023, -11012, -10984, -11336, -16887, -9066, -10720, -12363, -9353, -14030, -11340, -11317, -15637, -8510, -12135, -12642, -11503, -16126, -8884, -12226, -13096, -11769, -12705, -10963, -14302, -13279, -13499, -9957, -19172, -16625, -12660, -15562, -8688, -13533, -15111, -11206, -13165, -8805, -11767, -13777, -10342, -11808, -10262, -11397, -12807, -10458, -6477, -8783, -9156, -7244, -9578, -6328, -9733, -13536, -7400, -7805, -7936, -9056, -8489, -8789, -6259, -11497, -8573, -7079, -7972, -5792, -7806, -8781, -7542, -4974, -6663, -6561, -8910, -10156, -3840, -9021, -7269, -8634, -12588, -4296, -11760, -9368, -8887, -8988, -6455, -9678, -11606, -9632, -8275, -8061, -6691, -10323, -9533, -9416, -6173, -4993, -7891, -9118, -12433, -5687, -4293, -6883, -9419, -16123, -6407, -4190, -7167, -9529, -14934, -8109, -4288, -8700, -7897, -9795, -12745, -4326, -12059, -6700, -7222, -10335, -4404, -16733, -6277, -6233, -6387, -5099, -11768, -5417, -6268, -5291, -8062, -6109, -3571, -5826, -6571, -8834, -2852, -1710, -3620, -8090, -3887, -1178, -580, -1986, -3856, -2366, -779, -430, -1643, -2432, -2403, -1609, -1343, -2671, -2818, -3680, -3795, -3377, -4520, -4806, -5870, -7664, -6535, -4420, -8343, -7916, -15536, -10653, -4084, -12695, -9889, -11828, -13098, -5003, -9736, -11340, -8721, -12170, -7176, -7383, -8885, -7056, -10148, -10846, -7232, -7236, -6012, -8370, -17930, -8908, -6677, -6057, -7995, -20861, -13738, -7012, -7767, -9371, -11406, -14260, -7883, -13412, -16421, -7421, -10815, -8644, -11246, -10137, -5665, -9564, -9488, -9443, -7578, -5485, -9463, -9239, -9567, -7295, -6693, -9922, -7080, -9377, -8432, -8617, -7936, -5892, -8845, -9031, -9569, -6097, -6073, -8837, -8300, -9826, -5514, -7909, -9189, -8287, -8081, -5938, -13439, -9856, -8392, -6871, -6969, -11578, -10508, -7797, -7008, -8090, -9814, -9997, -7225, -8278, -9567, -10223, -9397, -7195, -10334, -11868, -10981, -8329, -7907, -12488, -10352, -11151, -6826, -9507, -13503, -9198, -11249, -6094, -11238, -11431, -9771, -11613, -6580, -9476, -9627, -10380, -12747, -9020, -7275, -8856, -10247, -13736, -16003, -6086, -8414, -11570, -11831, -8566, -5962, -8008, -16748, -11574, -7193, -7054, -8048, -14475, -13484, -7650, -9263, -8539, -11817, -12244, -8730, -9245, -8822, -10515, -10283, -8339, -8075, -8612, -9537, -8883, -7938, -7841, -8409, -8677, -7755, -8264, -8050, -8787, -7793, -7192, -8081, -8359, -10367, -7308, -6991, -7332, -8931, -14232, -8007, -6797, -7132, -9800, -13835, -11501, -6596, -7893, -9831, -11601, -12887, -6679, -9853, -9139, -11078, -8894, -7338, -11703, -8684, -11386, -8556, -8925, -10719, -8095, -12223, -9890, -12600, -10678, -7601, -13352, -10997, -14219, -12580, -7914, -14900, -10834, -10587, -17160, -9606, -17509, -11831, -9792, -14535, -14620, -15935, -13545, -10180, -13387, -14109, -12626, -11733, -11259, -12852, -11649, -10359, -9112, -13805, -10874, -12114, -8940, -7478, -11162, -8905, -13014, -8389, -7070, -8300, -7873, -12301, -8759, -7897, -7516, -7945, -11441, -9479, -9758, -8260, -9257, -10055, -8912, -11370, -10436, -12243, -9002, -8078, -11958, -13352, -17471, -8733, -8008, -12959, -11729, -16054, -8775, -8649, -14557, -9828, -16015, -8934, -9793, -14432, -9459, -15591, -9838, -11052, -12957, -10547, -15496, -12015, -11458, -12524, -12694, -8230, -7691, -5468, -9481, -8670, -9001, -7408, -5868, -8990, -6591, -9581, -7771, -6956, -7195, -6580, -10393, -7327, -8931, -6473, -7471, -7970, -5549, -11685, -6128, -7159, -7631, -4150, -11748, -5513, -7929, -9741, -3795, -10485, -4303, -17918, -8069, -4614, -8971, -3127, -7586, -6064, -6814, -7951, -2698, -5489, -5580, -10569, -7771, -3189, -5469, -5785, -11898, -7226, -4466, -6865, -6114, -10132, -6694, -6073, -9733, -6129, -6873, -7455, -7364, -13436, -5859, -5163, -9935, -8014, -13410, -5672, -4931, -11197, -8088, -11952, -5759, -5908, -8516, -8227, -10857, -6700, -7381, -6294, -7948, -7578, -7593, -6226, -4093, -5630, -4017, -4501, -4020, -2154, -3361, -1993, -2598, -2742, -1072, -1949, -1330, -2120, -2586, -1063, -1517, -1931, -2742, -3767, -2267, -2219, -3885, -4222, -6305, -5003, -4359, -7515, -6275, -6329, -9340, -7607, -12642, -7451, -5676, -9219, -6602, -13829, -5922, -6883, -7370, -5890, -10794, -4729, -10218, -5433, -6630, -9067, -4538, -15278, -4265, -8349, -8557, -5277, -15622, -4066, -8880, -8228, -7025, -17999, -4908, -8895, -7876, -9730, -20204, -6995, -10528, -7947, -8986, -15609, -11480, -8558, -8529, -6973, -14060, -13132, -6336, -9480, -6072, -14891, -8563, -5576, -9787, -5940, -12477, -6978, -5672, -9075, -6201, -9322, -6417, -6451, -8859, -6523, -7573, -6467, -7443, -9016, -6973, -6791, -7238, -7352, -8515, -7959, -6689, -8750, -7373, -7939, -9814, -6907, -8398, -8020, -7907, -11790, -7184, -6899, -8017, -8015, -10770, -7572, -6198, -8602, -7580, -9305, -7928, -6155, -12835, -6869, -8482, -8451, -6730, -11413, -6489, -8152, -9575, -7862, -8206, -6709, -8087, -8522, -9050, -7654, -7533, -7890, -6803, -9935, -8072, -8451, -7253, -6535, -11353, -8295, -8740, -6322, -7893, -15348, -7725, -8988, -5476, -11460, -13262, -7221, -9483, -4995, -10780, -10224, -7251, -9437, -5058, -8963, -8837, -7649, -9570, -5841, -9093, -8473, -8169, -11427, -7607, -10154, -9463, -9020, -13397, -10596, -9380, -11766, -10451, -10172, -10965, -8168, -11446, -11564, -8940, -9038, -8329, -11145, -11019, -8637, -7810, -10112, -13124, -9888, -8452, -7159, -12460, -13661, -8969, -8120, -7365, -11740, -11131, -8617, -7994, -9199, -10800, -9901, -8864, -8338, -18405, -9328, -9597, -9573, -8683, -9092, -8348, -10440, -11231, -8532, -7338, -8315, -13288, -13336, -8470, -7996, -8943, -11069, -10472, -9040, -11538, -10138, -8492, -9458, -10575, -12131, -12718, -7794, -10389, -12879, -10330, -17404, -8374, -12979, -12355, -11566, -15374, -10212, -15777, -12279, -12726, -16126, -12892, -15051, -17251, -12160, -15098, -11206, -13405, -13200, -12773, -12624, -9967, -12677, -10384, -12458, -10770, -10191, -12112, -9969, -12304, -9488, -11298, -11629, -10552, -12837, -9005, -12997, -11904, -11543, -11254, -9555, -14936, -12024, -13036, -10176, -11863, -16570, -11122, -14227, -10661, -18824, -15736, -10527, -14187, -13092, -11981, -10996, -10305, -17064, -21464, -10450, -9195, -11056, 4273, -1175, 9553, 9450, 3052, 4463, 3879, 9185, 8848, 3751, 3691, 5671, 8199, 6996, 2976, -6, 5626, 6835, 3747, -666, 792, 4574, 5106, -1149, 3063, 2037, 4190, 3092, -4209, 3800, -358, 4688, 1661, -2811, 2384, 554, 4827, 2424, -2806, 1978, 2707, 4521, 3968, -690, 2707, 2711, 3757, 4130, 2386, 1913, 2064, 2494, 2508, 3667, 712, 2465, 1624, -715, 3416, 4000, 3141, 2531, -43, 2698, 6322, 3113, 4058, 1241, 3628, 7327, 2097, 4876, 2277, 4319, 7299, 1273, 4438, 3268, 3504, 6323, 1854, 3006, 3946, 376, 4314, 1023, 3672, 4062, -5035, 714, -3398, 4912, 3429, -584, -8156, -3245, 4998, 1886, 697, -982, 327, 4263, -1023, 1589, 1056, 3814, 3295, -5086, 2308, 1972, 5817, 2295, -2104, 3082, 2652, 6521, 377, -467, 3600, 3493, 6229, -3459, -114, 3379, 4039, 5186, 1078, -559, 2118, 3913, 3637, 3134, -594, -248, 2957, 1526, 3430, -111, -1222, 986, -1358, 2163, -472, 56, -2241, -835, -1865, -2532, 1237, -4694, -594, -748, -9471, 2363, -695, -6239, 2071, -3963, 3385, 1107, -315, 2712, -1725, 4066, 1139, 2838, 1943, -850, 4185, 385, 3798, -1034, -810, 3729, 409, 3633, -3631, -1834, 2835, 188, 2725, 946, -4437, 1381, -1223, 1115, 1704, -6992, -1534, -2586, -1552, 193, -4345, -4134, -2019, -2514, -5752, -3653, -1077, -1083, -444, -2084, -4006, -412, -207, 462, -456, -2819, -1217, 425, 537, -907, -1298, -3329, 342, 278, -2320, -650, -6489, -974, -53, -2929, -765, -4640, -4479, -814, -2364, -1373, -2710, -9811, -2690, -2639, -2160, -1708, -7460, -5063, -4249, -3165, -1116, -6249, -2842, -5023, -4942, -960, -3882, -1322, -3471, -8502, -1330, -3190, -894, -2532, -9041, -1644, -3392, -1071, -1851, -6633, -1087, -3902, -1602, -1002, -5609, -598, -5119, -2438, -522, -4698, -1066, -6220, -3522, -1088, -4180, -3025, -5845, -4633, -3574, -4309, -9354, -5815, -5317, -8883, -4318, -4059, -5763, -4295, -4753, -3956, -1188, -5059, -3028, -5161, -4196, -282, -4459, -2775, -9570, -4659, -623, -4394, -3602, -6541, -2769, -1731, -5262, -4933, -5054, -1102, -2424, -8236, -4875, -4457, -759, -1695, -5776, -4752, -4278, -1699, -657, -3225, -5190, -6168, -3979, -402, -2833, -3816, -9388, -7674, -1212, -3869, -2747, -4540, -11357, -3107, -5078, -3168, -3531, -8642, -5995, -4722, -5514, -4313, -5362, -8466, -3742, -12373, -6390, -3513, -7445, -3093, -5643, -8647, -2786, -5096, -3357, -3478, -8699, -3144, -3019, -4871, -3100, -8418, -4030, -1802, -7819, -4520, -8160, -3842, -1386, -9033, -9826, -8837, -3438, -1593, -5964, -4630, -9426, -3444, -2068, -3661, -1901, -7578, -3273, -2546, -2794, -963, -6642, -3195, -3431, -3491, -1447, -6127, -3465, -3316, -6683, -3872, -5921, -3687, -2004, -9602, 6954, 9472, -4937, 4408, 9914, 6202, 9072, -277, 4177, 9310, 3917, 7959, 2087, 3212, 7388, 683, 6428, 3014, 2072, 3868, 582, 4826, 3459, 2377, 1248, 2628, 3240, 3879, 2178, 2305, 3044, 2265, 4056, 802, 3017, 977, 2908, 4021, -218, 2782, -1481, 3752, 3866, 9, 1238, 1895, 3814, 3406, -734, -1246, 2452, 2890, 2862, -2419, -2154, 1980, 744, 2974, 458, -160, 2350, -3684, 3764, 1833, 1209, 2987, -188, 4442, 1831, 1820, 3272, 3009, 4590, 1979, 2915, 3663, 4306, 4297, 2743, 3739, 4182, 4135, 3864, 3231, 3347, 4460, 2066, 3431, 3057, 1366, 4330, -4188, 2732, 2029, -2450, 3903, 673, 1244, 597, -4712, 3501, 1868, -1737, 1065, -6321, 3025, 1724, -4798, 2014, -4691, 2115, 726, -4126, 2091, -2153, 873, -214, -4141, 2340, 833, -948, 3005, -788, 3695, 2866, -1217, 4662, 580, 4650, 3917, 1403, 4843, 599, 4670, 4315, 2157, 4046, 1278, 4078, 4281, 968, 2668, 1969, 3638, 3946, -3127, 868, 1315, 3439, 3449, -3484, -1794, -954, 2896, 2900, -913, -7509, -3831, 2195, 2366, -124, -8891, -3278, 2169, 1966, 447, -9929, -2773, 2353, 1726, 974, -7235, -4046, 1859, 1446, 1041, -4166, -4206, 167, 963, 362, -4972, -2035, -4366, 733, -1274, -4793, -1814, -2747, 1230, -3148, -1473, -3520, -65, 1452, -1912, -365, -4497, 161, 630, -1234, -1045, -2661, -1458, -1577, -2481, -4519, -1881, -2648, -5054, -7214, -6705, -1632, -918, -5935, -5615, -2820, -1622, -958, -7067, -2567, -3478, -2015, -3264, -8679, -1535, -8165, -2000, -5201, -6614, -1732, -1751, -1280, -3369, -6594, -3178, 554, -656, -3463, -5552, -6775, 1130, -171, -4938, -3561, -8282, 471, 41, -5423, -2609, -2999, -1300, -94, -3325, -2318, -1368, -3745, -379, -1975, -2221, -1283, -5095, -900, -1983, -2245, -2265, -4743, -2068, -3757, -2644, -3826, -3992, -4546, -8374, -3572, -5080, -4028, -10704, -6822, -3868, -5142, -5987, -4616, -6468, -2488, -4351, -9791, -2110, -7995, -1434, -3764, -4731, -1066, -5576, -1032, -3972, -3632, -1165, -2801, -647, -4636, -4538, -2905, -1633, -126, -4203, -4911, -9326, -1965, -14, -3423, -3255, -5919, -3705, -551, -3487, -2473, -5154, -6023, -1571, -4266, -2469, -9219, -7353, -2958, -4869, -2960, -9120, -8008, -5357, -5053, -3932, -6637, -6305, -7577, -4855, -5276, -6676, -3559, -5508, -3928, -8032, -5416, -1765, -4957, -3400, -7311, -3173, -977, -5631, -3807, -3876, -1883, -1052, -7343, -5107, -2784, -1889, -2034, -7426, -6933, -2888, -2758, -3039, -5105, -7268, -3435, -3180, -1892, -4394, -6583, -3779, -3925, -902, -5305, -7276, -4089, -6806, -1123, -7841, -8526, -5036, -5094, -2829, -12767, -7115, -6830, -3640, -4196, -6814, -6351, -5633, -5165, -2616, -4037, -7365, -3552, -12596, -2570, -3857, 5615, 3635, 5008, 8307, 8560, 5276, 3327, 4031, 7670, 8181, 4450, 2321, 1492, 5751, 7141, 3678, 319, 2251, 3453, 5936, 3177, -3642, 2484, 2769, 5359, 2469, -8211, 83, 1311, 5080, 1111, -4452, -710, -1942, 4119, -1054, -5164, 75, -988, 1760, -2503, -5947, -2624, 1559, 2341, -664, -399, -3492, 2666, 4350, 1598, 1249, -3523, 2324, 4896, 3228, 1656, -2654, -128, 5228, 4019, 2532, 406, -2052, 5724, 3668, 2788, -39, 2565, 5583, 1650, 1405, -870, 3978, 4515, -2496, 933, 2143, 3757, 2798, -1109, 2023, 2958, 2232, 2025, -625, 1457, 2016, 114, 2601, -1397, 894, 15, -1423, 2450, -2000, 2236, -1643, -11317, 1123, -1329, 2933, -2148, -170, -824, 557, 2647, -1452, 2212, -2245, 2466, 1557, -1140, 2175, -1229, 3422, -218, -1811, -164, 581, 3061, -2526, -3445, -5945, 1800, 1065, -5835, -5227, 176, 2800, -702, -8766, -4097, 2096, 3326, 706, -3323, -2528, 2868, 3305, 365, -1412, -980, 3057, 3440, -2261, -908, 566, 2721, 4059, -3183, -1116, 1551, 1749, 4440, -1772, -1045, 1894, 359, 4158, -2445, -643, 1789, -242, 3144, -4745, -967, 1530, -193, 1520, -4033, -2696, 1308, -892, 52, -2012, -5652, 978, -2084, 18, -1076, -4025, 301, -647, -37, -1324, -2462, -748, 993, -756, -4055, -1989, -1544, 1716, -216, -4336, -1713, -798, 1934, 646, -734, -585, 182, 1874, 632, -120, 181, 146, 1506, 245, -1036, -461, -1386, 874, 294, -1857, -2886, -4885, 226, 715, -1534, -4240, -3475, -156, 764, -1498, -4122, -2271, -228, 6, -1893, -7978, -2968, -98, -1350, -2696, -7527, -3951, 161, -2049, -4314, -4112, -2768, 377, -2023, -6945, -2920, -1353, 292, -2319, -8120, -2399, -663, -146, -3012, -6529, -2890, -708, -576, -3730, -5428, -5567, -1452, -537, -4195, -5525, -6484, -3160, -453, -4817, -7842, -2593, -7125, -1080, -5487, -7095, -1935, -11674, -2918, -3832, -3255, -3267, -7803, -5583, -1555, -1853, -3193, -4682, -4558, -248, -2116, -1765, -1967, -3151, 143, -4549, -2223, -635, -3122, -199, -11564, -4887, -375, -5590, -1244, -3692, -4172, -974, -6671, -3216, -1978, -1813, -2305, -2030, -4099, -1808, -942, -4570, -619, -1963, -2460, -1148, -8696, -699, -693, -2703, -2454, -6312, -2090, -404, -2307, -4238, -5549, -5742, -910, -2557, -4134, -8368, -6972, -1986, -3818, -4147, -5337, -2869, -2843, -5667, -5483, -2721, -1442, -2606, -6727, -5661, -2118, -1262, -2025, -6217, -4312, -2781, -2241, -1803, -5391, -4079, -3978, -4918, -2132, -5481, -4602, -4163, -8880, -3134, -7374, -4419, -3967, -5455, -4967, -8361, -3621, -3249, -4093, -6857, -4338, -2503, -1548, -3482, -6420, -2519, -1318, -657, -3514, -4889, -2151, -979, -1116, -5343, -2908, -3067, -2029, -3077, -8158, -1527, -6560, -5790, -3832, -2206, -4127, -3399, -4292, -4940, -4974, -2793, -2362, -2653, -10980, -5415, -3649, -2321, -1871, -4721, -2919, -4537, -2595, -2070, -2139, -2575, -1729, -2704, -3356, -1931, -3305, -753, -2510, -6063, -3729, -5163, -1706, -2349, -9383, -5256, -11377, -5034, -2566, -7340, -2712, -5787, -9046, -3593, -6261, -1699, -3302, -9886, -6186, -6696, -1792, -2738, -7512, -8622, -9946, -2511, -3281, -3572, -4661, -8071, -3873, -4912, -2319, -2313, -4209, -6451, -7637, -2129, -1412, -2828, -5466, -7336, -2281, -2182, -2979, -2911, -6517, -2539, -6309, -4981, -2174, -6412, -2590, -4489, -7737, -3255, -4516, -1907, -1229, -3607, -5026, -1662, -835, -276, -1725, -2208, 222, -152, -496, -1159, -920, 934, -298, -1543, -1731, -1278, 570, -1511, -3107, -3860, -2520, -665, -4148, -5063, -9601, -3563, -2338, -7677, -6647, -9347, -5738, -4128, -5612, -6055, -8722, -11473, -5027, -4799, -5335, -10194, -3950, -3216, -5976, -4666, -6511, -2263, -1858, -11547, -3776, -4016, -2056, -1812, -6608, -3305, -3151, -2510, -3001, -3221, -3992, -3655, -3160, -3823, -2022, -7049, -4559, -3915, -3231, -2280, -10880, -4556, -4119, -3716, -3862, -5402, -5662, -3493, -5324, -6761, -3992, -12154, -3430, -4389, -10854, -3634, -7926, -4819, -3306, -7653, -3998, -6180, -8424, -3646, -7246, -5270, -5766, -6096, -5140, -8179, -8096, -4530, -3860, -7042, -4222, -14070, -3643, -3048, -7790, -2448, -6400, -3436, -2945, -7516, -2289, -3818, -3584, -3237, -8134, -3080, -2611, -3866, -3720, -8361, -3900, -2253, -4413, -4300, -4948, -5062, -2574, -5451, -4891, -3104, -9966, -3473, -6412, -4902, -2675, -7509, -4489, -6146, -4202, -3286, -5122, -4607, -6019, -3941, -4588, -5910, -4538, -6926, -4744, -5937, -9521, -5491, -8071, -6459, -6309, -11466, -8106, -7592, -7168, -5891, -9960, -11277, -5992, -5987, -5797, -9214, -8528, -4722, -4286, -6720, -6405, -6920, -4206, -3205, -6913, -3869, -6418, -4041, -3431, -4272, -2550, -7061, -4052, -5496, -2653, -2424, -7305, -4873, -5290, -2181, -3493, -5061, -7351, -2919, -2649, -5876, -3521, -9266, -2294, -4077, -10095, -2802, -7212, -2773, -5907, -8717, -2538, -7541, -3682, -5534, -5626, -2788, -11674, -4209, -5122, -4904, -3801, -7671, -4054, -5863, -6040, -5899, -5640, -3933, -6746, -7308, -9937, -6103, -4673, -7159, -6200, -11302, -8101, -6783, -8030, -6107, -10018, -8576, -9051, -8822, -7101, -11354, -9780, -10360, -7996, -7714, -12917, -14236, -12235, -6338, -6552, -11621, -9197, -7458, -5166, -4849, -8419, -7984, -6006, -4844, -3899, -6185, -7370, -5861, -5552, -3962, -5079, -6536, -5921, -7571, -5142, -4988, -5869, -5594, -8610, -7533, -6242, -5003, -4945, -7103, -8357, -10606, -4213, -4411, -7081, -6808, -6725, -4030, -4417, -8126, -6290, -3779, -4559, -5224, -8156, -7091, -2724, -5747, -6887, -7593, -10336, -2890, -7675, -7564, -7008, -10528, -9120, -3096, -4727, -4287, -7491, -4825, -4498, -3189, -5400, -5052, -2316, -9808, -3096, -4647, -2070, -1095, -6897, -3549, -5188, -1297, -802, -4170, -4566, -6792, -1008, -1259, -3154, -7079, -7195, -699, -2081, -2734, -15953, -4835, -883, -3234, -2323, -6262, -3110, -1629, -6398, -2055, -4209, -3242, -2189, -8191, -2449, -3915, -5945, -2211, -3292, -3650, -4302, -8079, -2289, -1759, -5461, -3952, -6295, -2647, -1335, -7280, -3541, -8559, -3380, -1636, -6264, -3789, -13940, -5077, -2738, -4418, -4242, -9014, -9489, -4759, -3781, -4495, -5163, -5181, -6342, -4922, -5022, -3683, -2458, -8291, -7631, -6580, -4346, -1075, -8462, -2754, -4878, -3071, -243, -2870, -537, -1919, -316, 204, -1089, 0, -670, 949, 296, -995, -644, -856, 1038, -27, -2143, -1944, -2630, 177, -943, -3767, -2880, -7857, -1420, -2684, -4335, -3313, -6982, -3321, -5534, -4204, -3754, -4830, -5405, -9695, -4094, -4340, -5866, -8479, -13551, -3983, -5277, -8131, -10593, -13952, -3253, -5526, -5080, -10748, -15480, -2255, -3728, -3198, -8577, -12923, -1884, -2381, -2588, -6205, -8805, -2267, -2100, -3295, -5584, -7718, -2484, -2385, -6230, -5795, -5552, -1869, -2196, -8137, -4130, -3618, -1475, -1783, -4668, -2520, -3253, -1644, -2018, -3820, -2332, -4373, -2114, -3077, -3941, -3940, -5092, -2411, -4569, -4179, -8094, -3619, -2672, -4884, -4497, -4430, -2644, -4021, -3878, -5995, -2571, -2405, -8544, -3126, -13961, -2273, -2688, -7916, -2867, -5187, -2779, -3384, -6460, -2694, -2522, -3542, -4525, -8638, -2424, -1563, -4042, -6247, -15573, -2544, -1488, -4321, -7301, -10773, -3226, -1982, -4677, -5448, -7491, -3714, -2968, -4713, -3784, -4511, -3859, -4348, -4788, -3045, -2910, -4707, -5446, -6259, -3197, -2664, -6729, -5219, -8369, -4314, -3598, -10067, -4589, -5702, -6900, -4468, -14336, -4819, -4702, -15129, -3976, -12010, -5059, -4953, -8456, -3869, -11674, -3651, -5724, -6693, -4473, -12949, -2778, -7384, -6712, -4823, -12265, -3244, -8545, -6116, -4636, -12510, -5433, -7265, -4422, -4448, -10423, -12733, -7066, -3619, -3561, -7027, -7660, -6530, -3902, -2370, -5509, -5134, -6155, -4675, -1971, -5581, -4506, -7476, -5309, -2794, -7460, -5683, -10713, -6690, -5356, -12984, -11029, -9099, -8566, -9806, -12260, -7688, -7849, -6230, -7807, -9346, -5945, -8325, -4902, -7786, -6910, -7009, -8612, -5072, -9369, -5536, -10069, -6354, -6591, -10282, -5508, -8597, -4974, -9521, -9013, -7028, -7475, -4960, -12767, -7785, -11313, -6752, -6424, -12740, -7696, -11893, -5091, -9821, -12027, -8870, -7707, -3872, -8602, -12424, -10914, -5108, -3573, -6720, -12253, -11214, -3706, -4009, -6618, -10520, -8551, -3648, -4646, -8112, -8389, -6121, -5259, -4687, -12149, -7513, -4632, -10013, -3921, -11291, -8555, -4036, -8911, -3076, -9212, -12275, -4365, -7671, -2822, -8690, -8791, -5970, -9197, -3530, -8578, -6469, -5236, -4781, -6658, -2943, -1061, -7932, -4475, -8167, -934, -1390, -5860, -2757, -4476, -89, -2212, -2857, -2192, -2450, 167, -3011, -1371, -1832, -1663, -238, -3480, -972, -1294, -1547, -1734, -4059, -1244, -897, -1830, -3042, -5447, -1757, -863, -2291, -1205, -7176, -2443, -1068, -2025, -309, -6780, -3996, -1493, -1345, -773, -7187, -6478, -2689, -1326, -2301, -8534, -3977, -5782, -2000, -3862, -7084, -2219, -12366, -2773, -4157, -5134, -1684, -8569, -3243, -4514, -3676, -1609, -7788, -3766, -5119, -3547, -1606, -7236, -4041, -5522, -4209, -2205, -8857, -3681, -5065, -3096, -4882, -10267, -5416, -4456, -2720, -5063, -4605, -5564, -5785, -5154, -1789, -1874, -728, -5549, -5346, -1221, -874, 786, -2209, -2249, -2372, -1341, 650, -767, -1850, -3870, -3180, -695, -403, -3195, -3004, -5858, -2351, -602, -6531, -2624, -7577, -2869, -893, -7728, -3960, -8577, -3177, -1114, -5156, -6189, -9822, -3652, -1729, -4802, -4580, -9729, -3535, -3155, -6991, -3884, -9499, -3153, -4561, -8089, -3763, -8259, -3177, -3769, -5249, -3167, -6487, -3448, -2869, -6451, -2904, -5645, -3415, -2875, -6168, -3025, -5571, -2856, -3942, -2709, -3116, -6335, -2206, -6728, -1971, -2853, -8948, -2071, -11805, -3066, -1838, -12433, -2644, -6024, -5840, -967, -6445, -3627, -4214, -8153, -878, -4446, -4481, -3426, -6547, -1549, -3317, -5099, -2609, -5216, -2762, -2450, -5268, -1988, -4438, -4504, -1871, -4618, -2094, -3854, -7470, -1826, -3355, -2869, -3289, -17753, -2802, -2154, -3651, -2710, -7254, -5823, -1379, -3810, -2387, -4293, -7421, -1022, -3262, -2595, -2864, -4888, -984, -2695, -3096, -2603, -5210, -1266, -3076, -3220, -3347, -6868, -1982, -5280, -2894, -3896, -7007, -3145, -17998, -2759, -3266, -7738, -4097, -6380, -3554, -3183, -10779, -3979, -4415, -6024, -4240, -12735, -3976, -3511, -9161, -6071, -12265, -5311, -2484, -10379, -6941, -7090, -10284, -1505, -12420, -5684, -4708, -7921, -1099, -7151, -3929, -4140, -4845, -1423, -7725, -2906, -5352, -4079, -2415, -10884, -2767, -9575, -4751, -3868, -4996, -3267, -11989, -7115, -5006, -3391, -3812, -11979, -10810, -5188, -3586, -3784, -8891, -6382, -5441, -5553, -3438, -5727, -3479, -5894, -12436, -3191, -4619, -2024, -5517, -7064, -3122, -4018, -1711, -4483, -4948, -3381, -3236, -2307, -3707, -4471, -4159, -2468, -3365, -3586, -4439, -5249, -1958, -4202, -4446, -4159, -5909, -2016, -4686, -7049, -3815, -5830, -2881, -5316, -8985, -3897, -5727, -4315, -6894, -6111, -4099, -6446, -5802, -10967, -5680, -3778, -8126, -8852, -12693, -6969, -3660, -9269, -11311, -8799, -8984, -4230, -10135, -6885, -6827, -8416, -4706, -12410, -6134, -6142, -7269, -4802, -11045, -6734, -6913, -6875, -5306, -7901, -7838, -8307, -6747, -5268, -6268, -8514, -7424, -6007, -4627, -6013, -7963, -6595, -4887, -4943, -6881, -6893, -6953, -4348, -6424, 8312, 5887, 763, 6240, -363, 8294, 6155, 1032, 5545, -1258, 8007, 5877, 1907, 2928, -1251, 7048, 3746, 3572, -1938, 911, 5242, -371, 4533, 2396, 1978, 3126, 3069, 3923, 2713, 1787, 2172, 4094, 719, 14, 481, 3186, 4027, -121, -4285, 838, 4514, 3804, 2625, 180, 2550, 4919, 3657, 2521, 1067, 3483, 4582, 3362, 258, 2969, 3998, 4482, 2739, -6911, 4973, 4239, 4254, 3194, -2381, 5869, 4139, 2316, 4698, -612, 5539, 3654, -2238, 5395, -864, 3736, 2454, 913, 5114, -2219, 274, -5, 1216, 4154, -2132, 1318, -2522, -67, 2602, -1085, 2215, -2412, 131, -283, -886, 1268, -4026, 1186, -8097, -1710, -1149, -6953, 1561, -4291, -3347, -4797, -2354, 1522, -1303, -3727, -6138, -433, 1412, 133, -2083, -4125, -87, 815, -292, 172, -1455, -1082, -27, -3173, 1392, 845, -3508, 747, -2476, 1285, 1824, -1900, 1521, -1280, 820, 1686, 181, 1523, -4127, 1264, 491, 504, 1582, -1000, 1071, -3544, -907, 1450, 2030, -655, -2890, -3654, 3, 2817, -492, 659, -651, -4158, 2016, 1441, 818, 725, -10322, -840, 1979, -1194, -2, -8915, -5398, 1183, -1790, -2223, -6956, -2149, -1520, -56, -1105, -3460, -2442, -10631, 261, -303, -1559, -3357, -1627, -200, -1439, 167, -1243, -98, -570, -2185, 1208, 270, -178, -341, 51, 1412, 678, -1143, 5, 1425, 1216, -292, -1832, -159, 1825, 1256, -3538, -1494, -1115, 1555, 1587, -1977, -404, -2659, 1059, 1717, 80, 665, -3520, 841, 1159, 162, 792, -3107, 657, -448, -835, -464, -2113, 58, -3922, -1838, -3144, -1636, -806, -10528, -1556, -2638, -2444, -1534, -4173, -477, -1284, -3701, -2217, -3028, 311, -1290, -1968, -2833, -2955, 532, -2286, -406, -2998, -3034, 207, -3360, 179, -3012, -2639, -619, -2785, -62, -3928, -1952, -1977, -1827, -1392, -7686, -1681, -4262, -1592, -5592, -9053, -1987, -8758, -2354, -5422, -6045, -2718, -7035, -4539, -1752, -6965, -3828, -5662, -10232, -853, -7632, -5907, -6125, -6723, -855, -6549, -8259, -5978, -3467, -1133, -6529, -4785, -4562, -2279, -1386, -6847, -3401, -3669, -2823, -1427, -7821, -3833, -3606, -6032, -1374, -8088, -6000, -4148, -7704, -1368, -5769, -7785, -4977, -4936, -1565, -4181, -5556, -6132, -5997, -2140, -3599, -3794, -7335, -13081, -3091, -4133, -2413, -7218, -7692, -4501, -5860, -1528, -6840, -6739, -7249, -6578, -1438, -8422, -8001, -17811, -5284, -2387, -10105, -7352, -7847, -4947, -4342, -5643, -6214, -7228, -6386, -5210, -4781, -7105, -8778, -13916, -4956, -6509, -11004, -8787, -7620, -5986, -13650, -7198, -9389, -6170, -8564, -12574, -5441, -18478, -7578, -14813, -12988, -5656, -9929, -14786, -9762, -8635, -6950, -8535, -8450, -6373, -7771, -7891, -9058, -5077, -5412, -8878, -7258, -9097, -3639, 1446, 4870, 5496, 3432, 778, 2169, 4055, 4926, 2644, 1374, 2487, 1165, 2583, 1077, 1593, 1238, -9366, -4050, 2166, 1722, -1745, -4241, 2422, 3098, 2608, -1709, -11737, 3101, 2365, 2776, -656, -3138, 698, 90, 1600, -336, -1552, 42, 1775, 821, 87, -2168, 3276, 3289, 2542, -194, -1324, 4464, 2620, 4013, -3154, 646, 5129, 658, 5289, -802, 2092, 5542, 3390, 6094, 2705, 3242, 5233, 4793, 6071, 3909, 3952, 3664, 4131, 5190, 3726, 4040, -489, 463, 3738, 2159, 3503, -3730, 867, 2626, -1511, 2218, -177, 3882, 2668, -891, -258, -454, 4726, 2825, 821, -1874, 271, 4810, 2074, 230, -1089, 2122, 4593, -88, -2783, -2625, 2683, 4179, -4117, -7287, -3032, 1897, 3611, -3947, -3767, -1114, 377, 3060, -3057, -3805, -1994, 650, 2579, -4042, -6118, -6273, 1787, 1891, -5161, -6898, -5117, 1980, 863, -4271, -2408, -6868, 696, -89, -3863, -556, -3126, -4108, -359, -1906, 282, -431, -1615, -145, 439, 855, 479, 930, -166, 1445, 1122, 957, 828, -616, 1130, 775, 1433, -1303, -1174, -415, -162, 1415, -1521, -1711, -2517, -798, 37, -129, -1913, -2753, -848, -5232, -1012, -1887, -1764, -1762, -2590, -3901, -2498, -512, -2482, -429, -2118, -3514, 660, -1072, -597, -614, -4241, 1327, -790, -1868, -22, -3086, 1275, -2170, -2804, 433, -738, 732, -5131, -1557, 660, 408, 493, -6968, -83, 401, 317, 544, -3263, 920, -609, -882, 79, -592, 1584, -2882, -2961, -889, 747, 1898, -6333, -3936, -1213, 1066, 1671, -4477, -3040, -1196, 501, 605, -3687, -2741, -2076, -948, -1863, -3725, -3608, -3615, -3514, -8203, -2846, -5675, -4626, -7676, -5780, -2051, -5646, -4864, -7906, -4712, -1879, -4707, -4460, -8375, -6614, -2083, -5367, -4632, -16250, -14775, -2613, -7158, -5467, -7373, -10453, -3500, -9096, -6113, -6672, -12921, -4584, -8025, -7107, -9112, -8602, -5586, -6671, -8545, -6273, -4569, -6001, -6944, -6493, -3572, -3106, -5768, -6814, -5466, -2070, -2986, -5942, -6051, -6991, -1191, -3900, -7742, -5497, -10539, -980, -5624, -12196, -4103, -5565, -1540, -7062, -9523, -2878, -3827, -2988, -7111, -10643, -2372, -3418, -5831, -7249, -6598, -2449, -3770, -9218, -7702, -3064, -2873, -4524, -5252, -7390, -1470, -3361, -5234, -3699, -6322, -1108, -3863, -5805, -3796, -5425, -1798, -4517, -5806, -5718, -5233, -3353, -5104, -5088, -8064, -5966, -4350, -5365, -4661, -4926, -7452, -3960, -5678, -4644, -3868, -8402, -3993, -6276, -4768, -4497, -7430, -4679, -6686, -5100, -6680, -6008, -5367, -6348, -5765, -9584, -5354, -5330, -5759, -6800, -8074, -5635, -5118, -5631, -8313, -6312, -6572, -5525, -6352, -9706, -5356, -8122, -6676, -8115, -9754, -5232, -11807, -8113, -11082, -8604, -5830, -12132, -9036, -11127, -6709, 6577, 2520, 4753, 4151, -6277, 5589, 1368, 4321, 3621, 3271, 1874, 1192, 3362, 3087, 5773, -3867, 3437, 3263, 3753, 6554, 33, 4131, 3884, 3777, 6045, 1716, 3607, 3956, 2241, 4189, 2850, 2007, 3377, 1367, 1161, 1951, -1589, 2473, 3501, -395, 715, -2136, 1248, 4026, 2129, 3597, 349, -3343, 2390, 4017, 5389, -34, 904, 1934, 3345, 6038, 2492, 4607, 4228, -325, 5722, 4891, 5595, 3828, 4094, 4293, 5306, 4624, -1214, 5181, 1633, 3550, 792, 2721, 3531, 821, -5316, 717, 4457, 1230, 1080, 1384, 2685, 3550, 4020, -580, 2553, 2205, 205, 4954, -2816, 1369, 590, -8658, 4742, -1698, -1211, -629, -6616, 3828, -646, -3831, -237, -7037, 2574, -273, -4698, 467, -3754, 2042, -103, -5349, 849, -1731, 1984, 182, -8257, 951, -381, 1267, -129, -15880, 728, 94, 47, -1664, -9613, -14, -844, -405, -4780, -6293, -1484, -3930, -408, -5712, -3936, -4110, -1411, -383, -5165, -3535, -12188, 935, -295, -5321, -4553, -5474, 1539, -921, -1715, -3578, -2731, 969, -1541, 604, -1873, -1981, -490, -371, 1661, -1224, -2605, -2349, 191, 1867, -915, -4072, -4724, -641, 1362, -614, -5444, -7437, -1715, 46, -997, -7221, -4130, -770, -2305, -2440, -4308, -2677, -259, -4370, -3465, -1358, -2415, -715, -2586, -2698, -199, -2647, -834, -516, -1834, -588, -2857, -569, 258, -1793, -2251, -2194, -1192, -898, -1937, -2191, -852, -2583, -7152, 351, -1356, 102, -3698, -2950, 1852, -1932, 359, -6144, -1220, 1854, -2172, 55, -6653, -2009, 546, -1185, -340, -2419, -4113, -1290, -1150, -478, -1239, -6890, -2098, -2300, -959, -1842, -9870, -3081, -3299, -2614, -4334, -6524, -5286, -2315, -6323, -8689, -6324, -7051, -1389, -9340, -7912, -11485, -6039, -1331, -5992, -8125, -7089, -4737, -2125, -3981, -10595, -4020, -4177, -3806, -3357, -10943, -3272, -5259, -6807, -3837, -5883, -3671, -7274, -11253, -4242, -4281, -4544, -3604, -11765, -3483, -4209, -5169, -1853, -10870, -3008, -4896, -5876, -1572, -6055, -3923, -5510, -7833, -2223, -4625, -8226, -5841, -12540, -3583, -5274, -6509, -6567, -8375, -5407, -8003, -3287, -8715, -6207, -7424, -13138, -2446, -9753, -5663, -9630, -15199, -2672, -7218, -6661, -6037, -12704, -3539, -6174, -10491, -3939, -8698, -4719, -5061, -8431, -3339, -7629, -5801, -3775, -6080, -3854, -8518, -6103, -3128, -5811, -5276, -7916, -5332, -3191, -6563, -6015, -7152, -4632, -3752, -7412, -5063, -9671, -4680, -4701, -7650, -4302, -9953, -5723, -6167, -7995, -4104, -6363, -8287, -8535, -10190, -4399, -5858, -9631, -15346, -16341, -5128, -6659, -6771, -9534, -9119, -6612, -7005, -5858, -6761, -7614, -10632, -5834, -6800, -5861, -5931, -9280, -4667, -11591, -5616, -4315, -6135, -4309, -8330, -5613, -3928, -5865, -4985, -5460, -6193, -6200, -8553, -6508, -7937, -3343, -9220, -7479, -7092, -7098, -3815, -7377, -7211, -10560, -7407, -4573, -4819, -7566, -10829, -9354, -4967, -4005, -9157, -7836, -11251, -4939, -4060, -12517, -7841, -9124, -5106, -4032, -9702, -9763, -8266, -5876, -3708, -8169, -12969, -8955, -7321, -4019, -8001, -13153, -12277, -7778, -5533, -8327, -10652, -9170, -6266, -8421, -8485, -7668, -6262, -5238, -12272, -9176, -5981, -5445, -4819, -11447, -10176, -5855, -6189, -5005, -9051, -7100, -7117, -8724, -5961, -11311, -5790, -8166, -15544, -6816, -9360, -5149, -8190, -8935, -5866, -9914, -6606, -9288, -12789, -10198, -444, -785, 22, -512, -111, 3825, 3700, 4011, 3732, 4105, 5934, 5876, 6050, 5867, 6151, 6562, 6530, 6678, 6554, 6749, 5860, 5810, 6005, 5934, 6042, 3714, 3491, 3871, 3867, 3881, -362, -1720, -451, -332, -462, -8244, -5334, -9966, -11060, -13928, -14965, -3825, -7231, -7838, -7538, -14237, -5644, -11454, -9635, -12447, -11333, -7218, -10735, -7740, -14281, -7785, -7484, -7030, -8134, -10768, -7984, -8501, -5343, -10237, -8640, -10149, -11186, -5127, -16213, -8201, -9637, -11594, -6077, -11188, -8957, -7394, -11445, -8346, -8459, -9894, -6577, -12171, -11157, -7507, -9402, -7244, -8254, -10331, -7807, -8790, -9451, -6069, -11115, -9174, -9743, -15000, -5165, -15623, -9049, -13810, -14946, -4951, -14153, -7619, -17394, -12244, -5271, -10076, -7398, -15090, -10956, -6246, -8342, -8767, -16558, -10643, -7892, -8455, -11276, -11013, -12434, -9863, -11098, -10564, -8306, -14245, -11683, -14496, -10210, -7352, -10358, -11766, -9902, -11844, -7797, -8521, -9587, -9240, -12672, -9598, -7539, -8180, -10056, -9348, -11558, -6969, -8082, -10771, -7471, -10510, -7045, -8843, -10586, -6675, -9127, -8457, -8768, -9414, -6932, -8309, -12611, -7940, -7554, -8612, -8127, -10569, -7552, -6501, -11995, -8345, -8661, -7566, -6721, -11127, -8660, -8710, -7776, -8403, -9893, -9024, -10124, -8184, -9859, -9545, -8899, -13021, -8806, -8623, -9544, -8291, -12631, -9539, -8508, -10086, -8184, -10718, -11079, -9891, -10988, -8798, -9846, -15501, -12770, -12005, -9506, -9090, -11859, -16988, -13076, -9577, -8205, -10545, -15281, -12434, -9458, -7601, -10825, -15101, -10698, -9846, -7697, -9290, -15813, -9752, -11370, -8616, -8167, -14591, -9649, -15588, -9597, -8495, -15462, -9906, -14673, -9892, -9926, -20536, -9793, -11426, -11057, -10986, -12734, -9231, -10131, -14054, -10780, -10743, -8703, -9892, -13703, -10864, -10543, -8545, -10911, -13096, -11370, -11418, -9104, -13976, -11827, -11626, -12918, -11025, -13271, -9958, -11491, -14768, -15232, -11312, -9615, -11615, -13200, -12779, -11637, -10649, -12531, -11272, -11775, -13881, -10788, -13604, -10618, -12568, -17230, -9775, -13103, -10832, -13373, -17598, -9893, -12065, -11959, -13262, -15866, -11391, -11454, -14518, -13114, -14350, -13728, -11407, -14804, -13246, -14622, -13285, -11845, -13064, -12030, -18307, -11760, -12159, -12305, -10412, -15123, -6324, -9477, -9400, -7057, -5710, -6352, -8487, -9278, -5078, -6096, -6298, -7707, -8482, -4442, -8448, -5661, -7246, -8358, -4752, -12692, -5302, -6206, -10007, -5788, -7182, -6166, -4983, -13270, -7494, -5273, -8510, -4454, -10594, -9438, -4780, -10193, -4690, -8615, -10919, -5125, -11052, -5489, -7798, -13036, -5854, -12236, -6499, -7745, -7401, -6635, -10632, -7170, -7794, -4840, -7557, -11145, -7431, -7733, -3910, -8096, -11765, -8948, -8494, -4135, -6962, -9891, -12542, -10049, -5225, -5766, -10963, -10163, -8393, -7226, -7008, -9025, -7379, -6072, -8597, -9535, -13454, -7980, -10483, -10619, -10454, -524, -357, -673, -521, -913, 3774, 3850, 3806, 3801, 3726, 5896, 5951, 5941, 5949, 5967, 6539, 6579, 6562, 6618, 6666, 5850, 5857, 5818, 5968, 6006, 3680, 3600, 3535, 3900, 3852, -704, -1039, -1074, -41, -442, -20425, -13137, -8880, -7008, -7180, -7676, -7249, -9812, -10616, -7360, -10279, -5481, -10821, -11285, -6744, -11031, -5069, -9065, -12055, -6518, -9991, -6225, -8756, -16333, -8667, -10592, -8419, -8312, -11250, -10011, -12191, -13430, -7967, -10377, -10608, -12739, -13080, -6812, -11457, -12300, -13509, -10314, -6313, -16158, -13876, -18989, -8759, -6995, -16806, -12813, -11600, -7944, -8763, -18811, -7810, -8523, -8087, -8626, -13671, -5455, -7530, -9310, -6986, -10603, -4667, -7855, -10926, -6627, -10213, -5114, -9406, -10426, -7630, -10276, -6652, -10178, -9082, -9365, -9640, -9105, -8955, -8049, -10069, -9361, -12141, -8768, -8044, -10018, -10155, -15871, -8742, -9890, -9962, -13161, -22128, -8200, -13833, -10789, -16792, -13824, -8273, -10713, -12965, -14624, -10183, -8548, -10172, -10605, -20387, -7962, -7851, -11897, -8350, -13740, -6838, -7172, -13924, -7292, -11677, -6817, -7315, -12211, -6859, -11522, -8153, -8547, -10846, -6858, -11643, -11284, -10893, -10119, -7332, -10993, -11217, -11394, -10115, -8360, -10006, -9632, -11033, -10993, -9848, -9822, -9397, -11758, -12169, -11656, -11314, -9647, -10253, -11377, -15028, -17323, -9926, -8792, -9976, -15320, -14192, -10389, -8646, -9355, -11446, -12505, -11423, -9549, -9778, -10204, -13602, -12870, -11143, -11814, -10021, -18248, -12820, -12849, -14717, -10517, -16157, -11201, -13626, -10610, -12078, -13136, -9927, -13163, -8579, -14304, -11833, -9257, -12540, -7856, -12246, -10955, -9144, -12407, -8209, -10861, -10350, -9797, -13195, -9967, -10891, -10379, -11896, -15556, -14905, -11801, -11591, -19418, -16477, -13344, -11845, -15351, -14372, -14073, -11411, -10850, -18659, -12416, -13199, -12060, -10790, -15823, -12264, -12718, -14280, -12046, -18986, -12902, -11598, -15084, -12664, -17066, -13984, -10396, -15153, -11569, -16303, -14781, -9857, -17401, -11389, -22830, -13452, -10185, -27068, -12151, -13558, -11746, -11330, -16623, -13653, -11224, -11074, -13063, -14198, -16091, -10707, -11621, -15303, -13355, -14189, -11493, -13829, -17195, -14040, -11965, -13852, -18027, -14642, -17286, -11045, -17219, -15206, -12429, -22284, -10583, -15085, -14255, -5111, -8181, -6549, -4897, -8234, -8490, -18312, -7810, -5765, -17195, -9800, -10653, -8301, -7841, -9189, -8646, -14834, -8803, -9710, -7281, -9213, -10024, -8625, -9340, -7338, -8926, -7689, -7824, -9330, -9147, -8812, -8023, -6553, -11359, -13026, -9700, -9056, -5691, -13529, -8406, -8745, -9062, -5610, -9201, -6813, -7212, -9078, -5853, -7526, -6881, -7424, -9496, -6434, -7064, -7710, -9464, -9887, -8019, -8062, -9180, -11192, -8688, -9004, -14243, -11558, -10074, -6315, -7134, -10315, -9984, -10918, -5924, -6393, -10145, -11123, -9806, -6673, -6775, -7294, -7563, -10028, -6767, -6627, -6054, -8211, -673, -269, -153, -410, -462, 3658, 3899, 3790, 3794, 3863, 5808, 6013, 5839, 5920, 5990, 6444, 6660, 6471, 6571, 6643, 5689, 5989, 5790, 5895, 5987, 3325, 3884, 3647, 3761, 3929, -1754, -187, -639, -440, 50, -8211, -8616, -11834, -10163, -5789, -7590, -10466, -8996, -13313, -6715, -11943, -10600, -9727, -8406, -6591, -9097, -9376, -8364, -7190, -6668, -9015, -8462, -8907, -8539, -6303, -8460, -7343, -9806, -10953, -6011, -7663, -6472, -10571, -9496, -6413, -6880, -6655, -11790, -8082, -7031, -6522, -8223, -11268, -8737, -7692, -7118, -10117, -11663, -12041, -8448, -9533, -9593, -15313, -12392, -9478, -18602, -8816, -11429, -8895, -12054, -11179, -8822, -9217, -7784, -14643, -9564, -9603, -8496, -7855, -9020, -8861, -10482, -8191, -8705, -7733, -9082, -10202, -8062, -11167, -8627, -11604, -8907, -8473, -16546, -10658, -11858, -7812, -9627, -9355, -8890, -8190, -7538, -10633, -7706, -7730, -6849, -8080, -9108, -7559, -8057, -6720, -9112, -7655, -8306, -9830, -7647, -9889, -7064, -9763, -12763, -10007, -9471, -7045, -11985, -12538, -15469, -8243, -7479, -13782, -13003, -15736, -7151, -8434, -12474, -20353, -12992, -6507, -9800, -11537, -12301, -10376, -6345, -10815, -11652, -9995, -9366, -6590, -10528, -12500, -9541, -10271, -7098, -9549, -13197, -9750, -10632, -7794, -8985, -12956, -10146, -8248, -8486, -9275, -12169, -11215, -7216, -8669, -10398, -11343, -13727, -7454, -8569, -11756, -11006, -18229, -8521, -8946, -12224, -11114, -19315, -9737, -10248, -12077, -11015, -19702, -10458, -12370, -12977, -10475, -14351, -10803, -11973, -16841, -9938, -11685, -11222, -10314, -13740, -9705, -10829, -11841, -9569, -11818, -10113, -11856, -11386, -9666, -11946, -12096, -16134, -10401, -10214, -12794, -20737, -13145, -10467, -10065, -13294, -10923, -11149, -11854, -9264, -13455, -8919, -11022, -12777, -9041, -13589, -8787, -12370, -11861, -9846, -15421, -10085, -14716, -11869, -11867, -17826, -12719, -11822, -12688, -15281, -12752, -15662, -10433, -12735, -18034, -11246, -19506, -10818, -12305, -15670, -11170, -13583, -11790, -12741, -14857, -11642, -11180, -10749, -14781, -16906, -11816, -10866, -9400, -21844, -15369, -11386, -12020, -8669, -18289, -11859, -10840, -13480, -8294, -17206, -10414, -10607, -13398, -8217, -16096, -10103, -10802, -13232, -8573, -14197, -10582, -11426, -13681, -9469, 13787, 14482, 4978, 9252, 11837, 13142, 13944, 4781, 8623, 11115, 11041, 12305, 4122, 6636, 8769, 6500, 9549, 4653, 3113, 4014, 364, 6117, 5897, 1273, -1449, 4622, 4026, 5912, 1807, -4079, 4377, 4233, 4397, 762, -2972, 2131, 4306, 2088, -94, -1821, 731, 3764, 2965, 2827, 2767, 3262, 3394, 4029, 4634, 4859, 3406, 3613, 4412, 5302, 5672, 1375, 4227, 4558, 5029, 6061, -3400, 4918, 4488, 3616, 6377, -5761, 5197, 3982, 355, 6282, -1053, 4744, 2957, 363, 5315, 1144, 3424, 2115, 2646, 3131, 1395, 1044, 2637, 3056, 656, 956, -3300, 3401, 2110, 1208, 105, -6609, 3508, 681, 1312, -4040, -3827, 2964, 2051, 978, 1360, -3994, 2019, 3680, 1426, 4160, -4790, 653, 4368, 1589, 4987, -2691, -1786, 4311, 977, 4326, -936, -2880, 3675, -26, 1433, -152, -260, 2708, -1196, -3895, -336, 944, 2077, -1140, 1532, -1804, 1016, 2018, -230, 1660, -1298, -2, 1662, -783, -759, 725, -2655, 492, -2131, -5217, 1363, -4750, -1417, 88, -5661, 1034, -2778, -3746, 1317, -4242, 311, -3574, -8503, 817, -373, -340, -2916, -7619, -68, 2394, -443, 58, -4328, 1397, 3818, -149, 1292, -2863, 2312, 3943, -590, 1294, -1452, 1738, 2645, -2903, 176, -1242, -587, -913, -3009, -2557, -3482, -6100, -3543, -97, -9954, -8191, -6916, 150, 820, -8630, -3025, -6507, 1377, 444, -7535, -2068, -5282, 1773, -1119, -5293, -1568, -3256, 1565, -4468, -4636, -860, -2027, 631, -6159, -6005, -239, -1157, -1430, -4037, -5551, 152, -397, -5342, -3689, -2472, 10, 41, -3431, -3131, -596, -819, -40, -1561, -2261, 413, -2281, -549, -1152, -1936, 780, -3916, -1306, -1405, -1886, 549, -3835, -2180, -1917, -1818, -387, -2792, -3422, -2357, -2055, -2215, -2501, -6241, -2373, -2782, -4704, -3033, -8393, -2033, -4217, -6929, -4108, -6246, -1681, -8068, -11620, -5597, -7465, -1732, -6024, -6720, -8259, -13971, -2807, -3209, -4535, -10705, -11232, -6537, -2961, -4340, -6189, -8549, -6525, -4973, -5306, -4475, -6917, -3450, -8409, -6693, -4114, -8079, -3555, -4950, -7082, -4463, -11262, -6691, -4196, -5694, -5222, -4124, -9836, -4855, -3625, -6954, -1699, -5164, -4765, -1928, -14286, -663, -4169, -4080, -956, -6668, -472, -3927, -4223, -808, -4050, -927, -4054, -4659, -1518, -3273, -2043, -4659, -4806, -2857, -3485, -4026, -5012, -5753, -3289, -4506, -7114, -4157, -8458, -2383, -6814, -8776, -3046, -10124, -1919, -9729, -8006, -2438, -8481, -2476, -7223, -8942, -2651, -8119, -4495, -6713, -10699, -3729, -9751, -9391, -8462, -9084, -4869, -12085, -14189, -11420, -7217, -4537, -9290, -6958, -10445, -5602, -3890, -8713, -2884, -7885, -5075, -4081, -6824, -993, -5433, -6297, -5445, -6813, -581, -4298, -11537, -8013, -10279, -1352, -4068, -9035, 8985, 6518, 7563, 8877, 9046, 8234, 6594, 7027, 8347, 8532, 6331, 5677, 5772, 6952, 6924, 5024, 981, 5111, 5260, 4061, 3806, 2037, 5742, 3558, 440, 967, 4386, 6629, 2409, -783, -883, 3656, 7114, 1283, -349, 2952, 2413, 7141, -2137, -67, 5129, 3158, 6509, -1857, 1100, 5734, 3958, 4491, -2596, 2334, 5404, 4255, -814, -4981, 2856, 5080, 4016, 3871, 763, 3031, 5362, 3360, 5969, 2332, 2827, 5563, 3133, 6510, 2666, 2052, 5428, 3497, 6210, 2579, 1018, 5290, 3136, 5414, 2374, 388, 5181, 962, 4383, 1588, 226, 4666, -8481, 3193, -1021, -410, 3159, -2200, 1715, -119, -2705, -842, -2369, 539, 2781, -10846, -1682, -8065, 649, 3237, -2652, 2167, -6821, 272, 1411, -187, 3126, -4139, -1393, -1419, 809, 2593, -188, -2666, 1660, 526, 549, 1751, -2642, 2880, -2175, -3542, 2355, -1774, 3630, -3843, -7162, 2117, -33, 4132, 594, -10058, 1187, 935, 3783, 1152, -5997, -1100, 903, 2279, -742, -2986, -9530, -343, -685, -1943, -1738, -800, -4534, -5764, -203, -1451, 1532, -3386, -6807, -385, -1934, 2482, 154, -5475, -748, -492, 2676, 1176, -4795, -405, 1741, 2257, 901, -4046, -832, 3050, 1426, -528, -2648, -2209, 3695, 768, -3119, -495, -2869, 3888, 478, -7138, 1492, -1466, 3557, -528, -7174, 2892, -1106, 2438, -2650, -3884, 3745, -2364, -20, -2147, -2024, 4007, -3977, -5755, -2340, -122, 3501, -3717, -2271, -6275, 838, 1949, -2174, -28, -2191, 445, -1442, -698, 540, -615, -1399, -6006, -537, -92, -1203, -4365, -1382, -2154, -1656, -2113, -3715, -389, -7872, -2267, -1547, -2291, -928, -3354, -1762, -1495, -2020, -2464, -599, -1845, -2575, -2336, -4021, 372, -2314, -4497, -2622, -4010, 282, -2952, -6128, -2952, -3405, -535, -3805, -5759, -4534, -3411, -1497, -3776, -4343, -9672, -3453, -2263, -3392, -3115, -3355, -2792, -3364, -4273, -2577, -1414, -2260, -5289, -5577, -3117, -1496, -2341, -8298, -4319, -5022, -3242, -2912, -10586, -3495, -6735, -4189, -3526, -8272, -2519, -5886, -3111, -3694, -6397, -1252, -4882, -4093, -3443, -5273, -804, -4317, -8079, -3204, -5308, -1356, -5169, -5436, -3218, -6950, -2610, -7845, -5021, -3555, -7503, -3948, -7689, -5972, -4387, -6617, -5066, -6911, -3284, -5760, -8977, -5918, -6541, -1693, -5689, -10069, -5800, -5469, -1504, -3599, -6215, -5202, -4553, -2416, -2353, -5588, -4994, -3747, -4273, -2588, -5373, -5430, -3370, -6208, -5044, -4717, -6317, -4029, -6065, -5950, -4743, -6737, -6835, -5706, -3061, -5988, -6782, -8754, -7073, -2705, -8530, -6424, -4552, -7345, -4113, -12075, -5777, -3244, -3463, -6001, -15697, -6055, -2947, -1629, -6014, -9874, -7633, -2862, -1191, -6825, -7375, -9082, -2771, -1903, -6828, -6079, -12057, -3123, -3750, -5684, -5858, 7254, 3780, 5352, 8324, 7066, 7171, 3086, 5094, 7895, 6213, 6727, 851, 4354, 6526, 3843, 5390, -2087, 3193, 4117, 3207, 2262, -2314, 1654, 2565, 3126, 2013, 745, -46, 3361, 1325, 4042, 3062, -104, 3836, 2767, 4176, 3288, 1227, 4010, 3783, 3360, 1017, 1727, 3485, 2176, 2138, -2184, 1294, 1347, -6664, 531, 1541, -80, -1763, 1195, -1041, 2582, -3103, -380, 1419, -1732, 2633, 1146, -1351, 1509, -3214, 1956, 3383, 707, 3109, -4593, 393, 3552, 2910, 2673, 1140, -2294, 1842, 3182, 2083, 3269, -1350, -478, 1649, 4232, 3696, 858, 1509, -3165, 5058, 2523, 1699, 2458, -4177, 4411, -2484, 2717, 2408, -2617, 2814, 58, 3860, 2037, -6038, 2143, 3316, 4150, 1901, -3622, 2863, 4118, 3282, 2190, -1326, 3523, 3616, 979, 2192, -1138, 3638, 1956, -3769, 1246, -1925, 2589, -1005, -4772, -664, -3082, 144, -4808, -5487, -1236, -3921, 1631, -3920, -4314, -289, -1963, 3125, -997, -878, 536, 568, 3125, 1100, -87, 1132, 2375, 2481, 2173, -588, 916, 3384, 1815, 2460, -1252, -670, 3538, 1108, 2340, -1871, -4154, 2703, 850, 1950, -2672, -4339, 499, 1269, 1169, -3861, -2132, -4124, 1562, 169, -6132, -261, -2596, 1437, -843, -2396, 722, -781, 871, -1632, -1151, 484, -292, -168, -807, -2771, -188, -270, -1242, 784, -14377, 384, -752, -1214, 1457, -2334, 652, -2146, -1095, 669, -88, -423, -4151, -2159, -1953, 663, -2218, -4541, -2894, -2170, 348, -3093, -5154, -892, -404, -488, -3708, -4906, 109, -283, -802, -2311, -3105, -386, -1719, -713, -1343, -2995, -2943, -6075, -972, -1948, -5119, -4035, -6812, -2209, -3295, -11489, -1136, -4506, -5033, -2868, -7918, -847, -5278, -7842, -2304, -3639, -2461, -4408, -11924, -2104, -1206, -4600, -2108, -7483, -1639, -277, -4610, -1091, -4659, -1884, -464, -3838, -1260, -5409, -3828, -1361, -2961, -2613, -11108, -7331, -2289, -3521, -5412, -5253, -5834, -2362, -7268, -7961, -3699, -5927, -1680, -7667, -6690, -4054, -7101, -1061, -4319, -6204, -4494, -5229, -805, -4567, -6323, -4150, -3547, -893, -8945, -6568, -4867, -2577, -1066, -7158, -7404, -8847, -2021, -890, -4696, -10328, -8292, -2006, -644, -5885, -7639, -5119, -2603, -1086, -10119, -4971, -4890, -3480, -2684, -5412, -4289, -6038, -4012, -5439, -4182, -4826, -6486, -4081, -6591, -4286, -6108, -5920, -4195, -6369, -4245, -8101, -5814, -4660, -6888, -4094, -8298, -5812, -5539, -7734, -4961, -5751, -5919, -6810, -8659, -8082, -4912, -6634, -7885, -10439, -10783, -5265, -8314, -7614, -11534, -7287, -5005, -10458, -6328, -7728, -6504, -3880, -9864, -5156, -6502, -6430, -3550, -9472, -4517, -7652, -6597, -4643, -8696, -4595, -11083, -7127, -7788, -6724, -5271, -8046, -8521, -10178, -5892, -5092, -6057, -10780, -9513, -5852, -2958, -4130, -5138, -9591, -4239, -4771, -4595, -3537, -7593, -4988, -6791, -6457, -3617, -5186, -9184, -8984, -9752, -5332, -3757, -9695, -8023, -9904, -8192, -3567, -7496, -5663, -6636, -10251, -4988, -10139, -4265, -5209, -8259, -7312, -10026, -4064, -4842, -5919, -6798, -9178, -5491, -4279, -5506, -4718, -6877, -7453, -4436, -4938, -5641, -10793, -7051, -8165, -5146, -6237, -5783, -3706, -5657, -6567, -6163, -7552, -5332, -4544, -7934, -4428, -7473, -7132, -2816, -3669, -7263, -5272, -6182, -5161, -8287, 1297, 1380, 382, 427, 1207, -5695, -8279, -4121, -8316, -6680, 8561, 8618, 8700, 8553, 8437, 13004, 13007, 12983, 12916, 12893, 15159, 15134, 15101, 15057, 15049, 15814, 15765, 15745, 15709, 15700, 15123, 15045, 15056, 15018, 15001, 12934, 12800, 12884, 12824, 12786, 8481, 8155, 8507, 8337, 8234, -6212, -3159, -3672, -8783, -6067, 355, 1573, 140, 692, 704, -6870, -5118, -3656, -13381, -7976, -3363, -8489, -2432, -4041, -3085, -13187, -6128, -4945, -14447, -7311, -7663, -3928, -4995, -7782, -6564, -11356, -5002, -6850, -10812, -11615, -6916, -5388, -8674, -8337, -12006, -7994, -4573, -8011, -5441, -11762, -8180, -4139, -6462, -4421, -16667, -10089, -4886, -7481, -4405, -7607, -13750, -5921, -8591, -4365, -5118, -9873, -7548, -9934, -5196, -5328, -8781, -10656, -14920, -6792, -7727, -9037, -11447, -11389, -8594, -14847, -9884, -10947, -8958, -9617, -6934, -9289, -10973, -8780, -9326, -5223, -7221, -8742, -8512, -9119, -5599, -6083, -6824, -7067, -9787, -7035, -6014, -5755, -6035, -12388, -7980, -7264, -5557, -6080, -13525, -8373, -10795, -6081, -7427, -10104, -7020, -11727, -7375, -11093, -7431, -5927, -8775, -8995, -13316, -5955, -5824, -8544, -9358, -9168, -5567, -6647, -11194, -9332, -7582, -5880, -8291, -12999, -10338, -6506, -6668, -9652, -8827, -10795, -6129, -8010, -10285, -7865, -9139, -6920, -9528, -11676, -7471, -8425, -8858, -9571, -11366, -7427, -8712, -10255, -9618, -10512, -8751, -8954, -9471, -11316, -11523, -14983, -9112, -8722, -16038, -13343, -10452, -10208, -9099, -11641, -9484, -7683, -10772, -11344, -9792, -7278, -7034, -11116, -15446, -10288, -6693, -7359, -16187, -12218, -11828, -7788, -7894, -9483, -11724, -10789, -12571, -8252, -6930, -13333, -10655, -11221, -8965, -6238, -12123, -12075, -8249, -10092, -6645, -9684, -12421, -8088, -9963, -7965, -8294, -11999, -9632, -8837, -10239, -7443, -12000, -13315, -8706, -11505, -7439, -12416, -14043, -10646, -10071, -8528, -13571, -10865, -15017, -8877, -10497, -11921, -8804, -11247, -7730, -13069, -10791, -7478, -11828, -6398, -15423, -12001, -7192, -20448, -5201, -16101, -13201, -8376, -13641, -4585, -14289, -9748, -13001, -13041, -4645, -11616, -8328, -11523, -14627, -5170, -11110, -8451, -8356, -13502, -5950, -12049, -9883, -7761, -10373, -7152, -12526, -12659, -8455, -8713, -9156, -11939, -16142, -9589, -8459, -12138, -11687, -14965, -9961, -10498, -4366, -6670, -6268, -6777, -7229, -6131, -9281, -8240, -7699, -8929, -7196, -10164, -9029, -7444, -11207, -7603, -9629, -8669, -5848, -6033, -7414, -11634, -7184, -5213, -4398, -8612, -8062, -6308, -5370, -3304, -13810, -6177, -7408, -4579, -2825, -7811, -5579, -7973, -3825, -3546, -6430, -4992, -8108, -3809, -4781, -4527, -4429, -6506, -4269, -4491, -4848, -3487, -4891, -7768, -3571, -7588, -2584, -3465, -8846, -7026, -5220, -5205, -4060, -11604, -5445, -2622, -4630, -3540, -3661, -13629, -16253, -13092, -4810, -7932, 231, 618, -82, 543, 843, -6248, -7054, -4917, -3788, -8231, 8605, 8622, 8675, 8654, 8498, 12929, 12970, 12956, 12954, 12918, 15061, 15099, 15067, 15070, 15063, 15710, 15741, 15699, 15705, 15706, 15022, 15042, 14988, 14999, 15003, 12839, 12842, 12761, 12787, 12794, 8398, 8357, 8181, 8271, 8320, -6355, -9827, -5114, -8031, -11445, 742, 449, 897, 548, -492, -6196, -9566, -10589, -7494, -5073, -8525, -3144, -3699, -3026, -2223, -5070, -7672, -10938, -5874, -3889, -3862, -8293, -8123, -6864, -3393, -7232, -5562, -14238, -6677, -5029, -8078, -4318, -11472, -7169, -5990, -6359, -5438, -12955, -9248, -7282, -4699, -6061, -8298, -7138, -7975, -4437, -5255, -4977, -7199, -7408, -4404, -5040, -4346, -6498, -8164, -4424, -5932, -5922, -6287, -13094, -5022, -6947, -8673, -7353, -11799, -6385, -7265, -8889, -6892, -9465, -7244, -8190, -8641, -5854, -8326, -7533, -11441, -8925, -6478, -7704, -8121, -12430, -8424, -8580, -8303, -8555, -9459, -7952, -11706, -10874, -8801, -7781, -7932, -11601, -11746, -9392, -6681, -8702, -9492, -10771, -8897, -6269, -11134, -7989, -10751, -7531, -6453, -13250, -7211, -8926, -7404, -7610, -10312, -7486, -7607, -8600, -12793, -8181, -8674, -7479, -10202, -9162, -6921, -8904, -7697, -11286, -6098, -6608, -7722, -7804, -11937, -5398, -6998, -6592, -8510, -11931, -6006, -7656, -5732, -10168, -11643, -7700, -7865, -5153, -9670, -11404, -9945, -7621, -4734, -7718, -11938, -10592, -7930, -4469, -6955, -14370, -10031, -9183, -4556, -7329, -15667, -10284, -10498, -5050, -8892, -12373, -11084, -10118, -5802, -11839, -10744, -9393, -8932, -6557, -10599, -9939, -8174, -8555, -6929, -8379, -9147, -8371, -9724, -6772, -7539, -8646, -9213, -12563, -6454, -7698, -9055, -8331, -11230, -6225, -8717, -10672, -6809, -10830, -6241, -10608, -14785, -6331, -14765, -6812, -12383, -14279, -7241, -12980, -8388, -10530, -11516, -10115, -9969, -11681, -8633, -11517, -17696, -8967, -17098, -7730, -9999, -15671, -8469, -13164, -7734, -8058, -16219, -8806, -10957, -8309, -7622, -12298, -10108, -10766, -8402, -8250, -10221, -11010, -13232, -7994, -8410, -9360, -11065, -14546, -7912, -7768, -9280, -10873, -10923, -7989, -7800, -10287, -9905, -10087, -8439, -9129, -12060, -9325, -10332, -10265, -12743, -9949, -9270, -9962, -11686, -19639, -8180, -9033, -9152, -9150, -14519, -7532, -8746, -9194, -8408, -10822, -6541, -4087, -5366, -7217, -12242, -8318, -3539, -5595, -5565, -10054, -10115, -3416, -6678, -5715, -9487, -10487, -3463, -9138, -5286, -11194, -7805, -3598, -8649, -4087, -14458, -5912, -3513, -5294, -3330, -15491, -5595, -2995, -4509, -2842, -9703, -5078, -2744, -5044, -2878, -6441, -4684, -3510, -5504, -3700, -5324, -5093, -4428, -5770, -3850, -7746, -5534, -4368, -9431, -3672, -6965, -5120, -3532, -8148, -3980, -5835, -12972, -4140, -6914, -7836, -3209, -4326, -4421, -2653, -4978, -4388, -5867, -4333, -6509, -8827, 759, 1307, 1420, -92, 441, -7569, -6729, -8428, -3816, -5727, 8547, 8521, 8509, 8797, 8689, 12911, 12937, 12918, 13017, 12962, 15045, 15072, 15054, 15101, 15063, 15687, 15707, 15695, 15716, 15688, 14985, 14996, 14991, 14996, 14973, 12773, 12778, 12783, 12769, 12751, 8257, 8274, 8289, 8231, 8207, -5729, -13222, -9847, -7725, -6606, 365, -216, 347, 366, 774, -5794, -4154, -13970, -10100, -11214, -3024, -1610, -5056, -3311, -4302, -8556, -5486, -9925, -10494, -10449, -8816, -15377, -7035, -9377, -10897, -9692, -6966, -10351, -7962, -7623, -6415, -5614, -6263, -6224, -6176, -8085, -6004, -8928, -7974, -8482, -8961, -6683, -15713, -8733, -11044, -8909, -9524, -9595, -6530, -10027, -9220, -16761, -7156, -6052, -9278, -8183, -10191, -6519, -8056, -10499, -7503, -8314, -6524, -9726, -8568, -7912, -7454, -6168, -7788, -6564, -8006, -7323, -6360, -6623, -5660, -7513, -8958, -7956, -6270, -5558, -7624, -12761, -8830, -6275, -5664, -9072, -13250, -8080, -6211, -5807, -11441, -10268, -8066, -6481, -6255, -11688, -8512, -8791, -7602, -6731, -9345, -7804, -8950, -9074, -6544, -7603, -7631, -7568, -9252, -6544, -6215, -7159, -6531, -8562, -7341, -5194, -6266, -6163, -8140, -8458, -4865, -5520, -6092, -7987, -7760, -5326, -5329, -6243, -7926, -6852, -6405, -5870, -6721, -8345, -7595, -7663, -7234, -7119, -10125, -10775, -8350, -8534, -7286, -16410, -8787, -7965, -7840, -7968, -12117, -7281, -7110, -7247, -9360, -9899, -8670, -6584, -7114, -10510, -9248, -13548, -6732, -6288, -10753, -9136, -8383, -7539, -5229, -10635, -9847, -7519, -8798, -4756, -9004, -10133, -9215, -10716, -5047, -7250, -7926, -15045, -11737, -6079, -6478, -6366, -13869, -9279, -7261, -6801, -6041, -12884, -8079, -7599, -8272, -7054, -12862, -8067, -7855, -10268, -10148, -11724, -8568, -8570, -10879, -14031, -10273, -8699, -9357, -11814, -9495, -8848, -8366, -10098, -12661, -8400, -7876, -8351, -10997, -11791, -8652, -7701, -8922, -10359, -10201, -9356, -8575, -9593, -9505, -8288, -9822, -11194, -10080, -11126, -7323, -10529, -21742, -10828, -10949, -7205, -11905, -11172, -12073, -7210, -7450, -13675, -9491, -14562, -6110, -8045, -13884, -9622, -13397, -6723, -9438, -11220, -11368, -11545, -9052, -12156, -10030, -16389, -12288, -12561, -18890, -10493, -15268, -16791, -11629, -15410, -12913, -14502, -14921, -11217, -12042, -19888, -28647, 13098, 8550, 12481, 11510, 6595, 12477, 8828, 11738, 10975, 6030, 10405, 8846, 9290, 9300, 4418, 5407, 8596, 4699, 6340, 3498, 4144, 8868, 3899, 2446, 4495, 6787, 8970, 2932, 1036, 4904, 6608, 8465, 1355, 3923, 4740, 4907, 7665, 1149, 4657, 4591, 551, 6910, 744, 2513, 4346, 634, 6196, 1842, -279, 3940, 3736, 5306, 2460, 4698, 3741, 4214, 4093, 2261, 6028, 3943, 2999, 3252, 2051, 5861, 4558, -1126, 3221, 2513, 4490, 5250, -2272, 2371, 2501, 2731, 5767, 1238, 375, 1447, 3380, 5850, 1900, 2377, 1045, 3946, 5011, 2334, 3950, 2051, 3233, 2580, 3282, 3982, 2613, 1159, 159, 3710, 2869, 2481, 487, 1210, 3661, 1243, 1716, 2588, -657, 4677, 1926, -421, 3542, -546, 5690, 3141, -7300, 3727, 2018, 5486, 2751, 1503, 3443, 2021, 4042, 1177, 3537, 2839, 305, 2858, 2208, 3935, 2313, -2395, 2622, 2907, 3506, 1766, -2201, 820, 1286, 2877, 816, -25, -2138, -2230, 2460, -253, 1158, -185, 2089, 2181, -948, 1834, -429, 3619, 1837, -1815, 2181, -2963, 3555, 1253, -3382, 1436, -7497, 2318, -221, -1989, -2519, -3937, 466, -5658, -553, -383, 130, 109, -2147, -554, 2605, 1478, 993, 944, -327, 2950, 1038, 1962, 1665, 621, 1470, -1293, 2675, 1147, 637, -1902, -6527, 2557, -113, -766, -2756, -2414, 1072, -1280, -3066, -1732, 176, -407, -1687, -1358, -1275, 1793, 1532, -1903, 714, -738, 2727, 2283, -2128, 1424, -1013, 2830, 1480, -1826, 1085, -2187, 1872, -748, -1223, 504, -1724, -540, -3577, -1331, 302, -372, -3290, -3077, -2456, -212, 453, -1665, -2179, -2590, -1244, 769, -958, -2758, -1194, -2220, 646, -1298, -5466, -206, -3085, 298, -2484, -13396, 244, -3976, -448, -5072, -6577, 67, -3844, -1491, -15234, -3075, -866, -2785, -1116, -7562, -1541, -2665, -2528, -294, -7910, -1687, -5553, -3298, -160, -10161, -3578, -10016, -3192, -472, -3439, -5625, -9486, -2319, -951, -1201, -4550, -9342, -2459, -1431, -458, -4420, -6978, -3757, -1541, -854, -3911, -4840, -6298, -1450, -2480, -2853, -3829, -7433, -2031, -5517, -2518, -2354, -5552, -3672, -8558, -2856, -980, -3831, -4039, -6818, -3270, -177, -2357, -3496, -4436, -2980, 111, -1947, -5155, -3473, -2306, -187, -2633, -5752, -3380, -2078, -1182, -3664, -3089, -3429, -2692, -2826, -3918, -2817, -3812, -4573, -4250, -3465, -4590, -5220, -9117, -4231, -3124, -8516, -7993, -11830, -4338, -3576, -11939, -7717, -7077, -4823, -4840, -12315, -4104, -4608, -4103, -4752, -7408, -1875, -3730, -3127, -3489, -5600, -790, -4849, -3237, -3361, -3940, -662, -9472, -4932, -4740, -2668, -1493, -4366, -5298, -7908, -2498, -3603, -2126, -3150, -9119, -3642, -8609, -1767, -2772, -5899, -6106, -6767, -2754, -4208, -3280, -5059, 6690, -8153, 10131, 7048, -919, 6500, -1237, 9535, 7554, 1466, 5763, 2689, 7584, 8134, 2435, 4781, 4620, 3350, 8012, 1830, 5661, 5048, 658, 7105, 778, 6783, 4105, 3704, 5783, -74, 6618, 2593, 4285, 5187, 720, 5186, 2589, 3617, 5421, 1199, 4084, 2423, 1579, 5335, -518, 3879, 2804, -894, 4502, 692, 1989, 4329, 1791, 2961, 3354, 1889, 5035, 3692, 1175, 4608, 4214, 4861, 3955, 476, 5123, 4452, 4207, 2604, 1752, 4949, 2423, 3388, 1864, 3468, 3937, -2942, 2577, 4006, 4407, 2053, 2979, 2078, 5120, 4232, -451, 4465, 1539, 5069, 2721, -2834, 4398, -366, 4056, -1059, -4394, 3825, -1555, 2553, -3650, -4648, 3783, 984, 1518, 220, -2108, 4223, 1564, 1432, 1126, -416, 4287, 927, 1765, 985, -266, 3353, 180, 1171, 1319, -1422, 700, 323, -1087, 2497, -1730, -3577, 986, -4078, 3156, -379, -145, 804, -5633, 3189, 347, 692, -838, -2836, 3184, 591, 372, -3742, -1062, 3175, 815, 775, -4880, -1859, 2491, 1139, 1429, -2167, -6691, 487, 1412, 1693, -494, -3217, -4289, 1377, 2490, -297, -193, -6386, 972, 3451, -977, 1287, -4593, 571, 3687, -1970, 2053, -4635, 521, 3061, -3478, 2249, -3130, 572, 2009, -2216, 1942, -2060, 642, 1428, 431, 1191, -2079, 677, 1189, 1781, 15, -3089, 122, 430, 2063, -996, -816, -1523, -2164, 1360, -575, 1708, -3664, -6231, -374, 368, 2832, -4666, -355, -2308, 889, 2960, -3159, 1093, -1614, 588, 2495, -820, 1216, -287, -1047, 1888, -233, 463, 180, -5792, 1396, -1210, -1699, -456, -5831, 827, -1932, -4360, -1542, -3116, -181, -1081, -1611, -1293, -2754, -1835, -1012, -752, -892, -3009, -3416, -1665, -1331, -1022, -3744, -2976, -2081, -3307, -1008, -5304, -1919, -2296, -6978, -599, -9515, -1543, -2617, -2689, -324, -5503, -2134, -2837, -849, -552, -2105, -4034, -2991, -641, -1427, -987, -9344, -3313, -1334, -3026, -1507, -5572, -3958, -2143, -3900, -4232, -2728, -4591, -2131, -2097, -11497, -1606, -4683, -1188, -635, -4314, -772, -4588, -392, -95, -3143, 504, -5553, -420, -401, -3153, 1642, -12972, -1425, -1560, -3376, 2085, -5530, -3346, -3278, -3476, 1682, -3339, -6006, -4696, -2954, 318, -3931, -8714, -4326, -1709, -2490, -3776, -10887, -1777, -777, -10400, -1479, -12866, -745, -686, -5189, -826, -8513, -1537, -1478, -4025, -1742, -7835, -3353, -2888, -5665, -3837, -6347, -2788, -3952, -17953, -6267, -4056, -2692, -4012, -4997, -8544, -3186, -4337, -4604, -2943, -5270, -3660, -6473, -9815, -2948, -2994, -3978, -7759, -4141, -4830, -1837, -2409, -9588, -365, -8098, -1245, -1044, -7724, 1152, -7450, -1150, -518, -3907, 1373, -5088, -1650, -941, -1635, 501, -2392, -2714, -2385, -835, -1466, -920, -3973, 8763, 8553, -1506, 9043, 5045, 8329, 7818, 4856, 8679, 5189, 7124, 5235, 6475, 7547, 4899, 5539, -2724, 5978, 5518, 3051, 4243, 1960, 3948, 2257, -764, 3257, 2827, 3653, -4867, 3192, 1750, 1546, 4642, -1789, 4821, -503, -1688, 4092, 759, 4430, -877, -10154, 1867, 814, 540, 675, -6481, 292, -964, 1989, 2501, -5274, 1801, -2428, 5702, 3249, 984, 1939, -1699, 6847, 2841, 3143, 325, -4114, 7089, 2120, 3203, -449, -1716, 7005, 1932, 879, 1514, 1679, 6616, 1470, -1494, 1524, 2209, 5686, 383, 1209, -1306, 129, 4051, -917, 274, -2145, -4903, 1958, -3227, -10316, 421, -2018, 2525, -6570, 1371, 165, -7468, 4230, -1425, 3275, -1489, 652, 4741, 506, 3377, -3377, 3027, 3845, 1603, 2098, -3518, 3347, 845, 2379, -1130, -505, 2476, -1302, 2437, -2395, 1055, 832, 1731, 1313, -13, 1424, -1240, 1930, -1705, 66, 1181, -2536, -493, -10492, -1451, 1033, -3839, -1341, -10204, -4003, 1254, -2854, 2599, -4882, -4488, 1321, 1188, 3988, -429, -2851, 976, 3064, 4135, 1534, -2062, 521, 3641, 3510, 2383, -2765, 362, 3398, 2477, 2512, -4557, 551, 2803, 1501, 1934, -2537, 731, 2299, 1677, 334, -1009, 638, 1833, 3102, -2805, -1109, 447, 969, 4139, -2513, -2382, 332, 160, 4254, -556, -4855, 342, 1225, 3384, 230, -9011, 901, 2469, 1469, 344, -1342, 1682, 2800, -1616, -299, 1071, 1871, 2211, -4908, -1796, 1832, 1146, 841, -4058, -3723, 1510, -467, -884, -1918, -4119, 501, -1711, -2314, -531, -2890, -225, -1369, -3129, -539, -2156, -60, -1479, -3522, -2704, -2097, -308, -2167, -4943, -4489, -2310, -2024, -1823, -6980, -1326, -2668, -4405, -951, -3549, -759, -3620, -2580, -708, -1778, -1286, -4578, -2603, -1275, -1417, -1385, -4056, -6586, -2563, -2143, -1543, -3927, -5338, -3925, -3430, -2858, -3746, -2880, -4848, -3057, -6455, -3291, -3926, -5108, -1669, -7064, -3807, -11714, -3433, -786, -2551, -3780, -5750, -2579, -553, -530, -2358, -3964, -3609, -1075, 313, -1908, -4017, -7855, -2455, 274, -2862, -4266, -6328, -4246, -274, -4876, -3763, -3283, -5502, -747, -4153, -2845, -1491, -8382, -1394, -2877, -2209, -403, -9169, -2948, -2452, -2235, -95, -4587, -3623, -1834, -3028, -594, -2742, -2108, -1247, -4172, -2123, -1891, -1002, -1352, -4534, -5646, -1920, -289, -2096, -4388, -7798, -3139, -214, -3092, -5273, -5865, -6345, -1249, -3905, -8090, -9013, -7257, -4051, -3610, -4638, -7809, -5399, -7985, -2443, -2722, -4250, -5762, -4407, -1562, -2710, -3316, -6933, -2448, -1343, -3403, -2966, -9019, -1554, -1776, -3475, -3180, -8528, -1840, -2636, -4344, -4117, -2747, -3535, -3723, -9379, -4126, -312, -3640, -5202, -6598, -3572, 711, -1680, -6312, -3807, -3978, 831, -1188, -4245, -4310, -7584, -1936, -2416, -3598, -3759, -6397, -1902, -1112, -4363, -2385, -4368, -2542, -971, -7739, -1412, -4526, -2295, -1956, -5969, -909, -9751, -1952, -3951, -3203, -1013, -5079, -2482, -5007, -2823, -1841, -2115, -3485, -3893, -4508, -3042, -1813, -3944, -2476, -8390, -3065, -3524, -3411, -1102, -5568, -2684, -5474, -2825, -289, -5226, -3652, -2696, -2998, -310, -5345, -8172, -1250, -4284, -1246, -3334, -6708, -857, -7354, -2712, -2274, -3151, -1019, -9777, -2957, -2140, -2087, -1432, -5676, -2471, -2637, -2178, -2087, -3877, -2453, -4159, -3341, -3348, -3197, -2388, -7626, -5980, -5700, -3484, -2026, -4123, -5319, -5244, -4475, -1800, -1513, -2944, -2875, -4371, -1973, -696, -2443, -2122, -3853, -2977, -1062, -3546, -2808, -4503, -5683, -1769, -6391, -4870, -4615, -6658, -1760, -9873, -6902, -2950, -4382, -1757, -8724, -7033, -1944, -4151, -2451, -6731, -8317, -1880, -5179, -3833, -5847, -8860, -2768, -5707, -5330, -5913, -6610, -4725, -4401, -5875, -6154, -6022, -5516, -3292, -6049, -6410, -6349, -4202, -2875, -6326, -6422, -5028, -3904, -2945, -6690, -5428, -4164, -4081, -3296, -7285, -3982, -5411, -4086, -4066, -7589, -3160, -9155, -4876, -6195, -8635, -3481, -6154, -7075, -13717, -17795, -5003, -5407, -6101, -4434, -6576, -5973, -6237, -4436, -2085, -3952, -5654, -5689, -4266, -1523, -3278, -7182, -4895, -5054, -2485, -4046, -8509, -5342, -6065, -5898, -5987, -3994, -6742, -6265, -7377, -5848, -2032, -6876, -4901, -3902, -4456, -1474, -5497, -3380, -3330, -4201, -2127, -4147, -2510, -4583, -4967, -4416, -3244, -1952, -8653, -6811, -11506, -3228, -1339, -6706, -10673, -7462, -4530, -996, -4300, -9813, -5660, -7329, -1301, -3779, -7764, -4954, -5833, -2200, -4394, -8093, -4546, -4186, -3206, -5595, -9355, -4807, -4028, -4239, -6176, -8076, -5462, -4511, -6117, -5945, -6543, -5732, -4528, -9712, -5220, -5844, -5094, -4086, -9797, -4710, -5940, -3813, -4005, -6182, -4521, -7039, -3016, -4075, -4228, -3924, -8014, -2996, -3576, -3577, -3383, -6866, -3434, -3182, -3886, -3540, -6838, -3964, -3752, -4418, -4241, -8312, -4467, -5897, -4328, -4970, -7845, -4810, -10414, -4067, -5665, -7341, -5217, -8887, -4270, -6873, -8852, -6348, -9758, -5437, -10058, -9898, -8191, -11707, -8987, -10901, -9673, -6973, -7642, -9459, -6637, -15261, -6045, -7429, -5868, -5225, -6272, -7219, -10226, -4687, -5036, -3421, -10001, -13849, -4330, -5559, -2544, -8478, -12205, -4389, -6394, -3113, -7046, -11090, -4939, -7445, -5228, -6198, -9975, -6280, -9031, -9711, -5579, -11368, -6788, -10330, -11091, -5669, -10241, -4890, -8679, -8822, -6936, -7734, -3785, -6695, -7786, -7611, -6787, -3772, -5455, -7664, -6296, -6440, -4766, -5136, -8690, -6163, -5953, -6939, -6212, -9519, -7597, -5168, -8792, -10846, -8362, -11220, -4762, -7115, -7982, -8059, -14884, -5349, -6460, -5340, -4174, -1237, -4037, -530, -4954, -4174, -2522, -3614, -994, -6100, -2920, -3954, -2632, -2247, -9287, -1616, -4426, -2914, -4583, -5939, -845, -4044, -3528, -6908, -2561, -797, -4028, -2921, -4638, -1136, -1577, -4795, -2614, -3579, -1038, -3496, -5431, -3322, -3708, -2270, -7766, -4628, -3843, -4251, -5138, -7506, -3381, -3110, -4437, -7679, -4581, -2569, -2639, -4356, -7414, -3575, -2247, -2931, -4870, -6583, -3313, -2108, -3925, -6622, -4064, -3390, -1943, -5490, -7479, -2462, -3729, -1799, -7472, -5139, -1960, -4159, -1785, -11648, -3484, -2290, -4479, -1986, -10230, -2910, -2944, -5338, -2099, -6642, -4165, -4211, -8715, -1448, -5782, -8041, -8232, -8483, -722, -5205, -3221, -5106, -4944, -913, -4297, -1544, -3085, -3364, -2204, -3838, -1820, -3118, -1824, -2690, -3507, -4098, -3537, -968, -1757, -2774, -21301, -3335, -1385, -1588, -1829, -4718, -2810, -3704, -1814, -1186, -3376, -2211, -21827, -1887, -1290, -4445, -2342, -4557, -2236, -2360, -8339, -3652, -3064, -2763, -3372, -6379, -6009, -3624, -2998, -2490, -4106, -8994, -6324, -3087, -2093, -4128, -13751, -9152, -2466, -3083, -7281, -11801, -4567, -1805, -4833, -8001, -10322, -3041, -2281, -3630, -4067, -9236, -3017, -4560, -1911, -3684, -8263, -4517, -10479, -1119, -5675, -6364, -10327, -20358, -1023, -10732, -4767, -6247, -8368, -1528, -4746, -4216, -2983, -4246, -2913, -2574, -4841, -1884, -2734, -6145, -1727, -7198, -2100, -2697, -11135, -1772, -7530, -3580, -3827, -7508, -2708, -4040, -6147, -6024, -7296, -4290, -2445, -7961, -8740, -5872, -4995, -2092, -7900, -10261, -4057, -5117, -2828, -5617, -9008, -3259, -6224, -4583, -4048, -7363, -3309, -7746, -6672, -3700, -7212, -4105, -7622, -9777, -3554, -8676, -6131, -6578, -5873, -2582, -10892, -12501, -5608, -2886, -1768, -7949, -6930, -5185, -2165, -1734, -4853, -4810, -5409, -3225, -2563, -3271, -4393, -6393, -6190, -4328, -2921, -4492, -5464, -6662, -6721, -3605, -4504, -2806, -5473, -7027, -5113, -4566, -1484, -5975, -6032, -6411, -5262, -1418, -7516, -5429, -5497, -7180, -2201, -8448, -5025, -4215, -8562, -2727, -7362, -4902, -3800, -7443, -2685, -6053, -5415, -4525, -7229, -3456, -5082, -6395, -6904, -6703, -5888, -4365, -6522, -9974, -5301, -7193, -3975, -5716, -6555, -4081, -6234, -4262, -4815, -4722, -3544, -8030, -5932, -4538, -3835, -4174, -10042, -12196, -5802, -3681, -7210, -5852, -8365, -11229, -4208, -10922, -4575, -6589, -6415, -5101, -5875, -4948, -7750, -4057, -6052, -5357, -6997, -11230, -3570, -7159, -6148, -12133, -7698, -3994, -8878, -6703, -11760, -4551, -4813, -13831, -7419, -7405, -2793, -5913, -12081, -9096, -5796, -2280, -7953, -9445, -8924, -5801, -2982, -14337, -9974, -7061, -6966, -4944, -8875, -10837, -5828, -7896, -8018, -6489, -8304, -5412, -7048, -8014, -6504, -6799, -5686, -6278, -6303, -8279, -6485, -6170, -6540, -5936, -5547, -3390, -4884, 313, -2275, -5205, -3825, -4419, -712, -6002, -6433, -4252, -3189, -2211, -7314, -9619, -4710, -2507, -3601, -3322, -6767, -6094, -2362, -3490, -2405, -4586, -10020, -2379, -3266, -2906, -3675, -10631, -2392, -4206, -4625, -3173, -8286, -2611, -5431, -5448, -2849, -8566, -3250, -4016, -2558, -2961, -7528, -4419, -2752, -883, -4098, -5385, -6192, -2356, -731, -8262, -3910, -8129, -2542, -2219, -5083, -2952, -5691, -3190, -5673, -1978, -2423, -2901, -4317, -4986, -924, -2528, -1423, -5413, -3747, -850, -3729, -1128, -4775, -3680, -1003, -7519, -2264, -3471, -3324, -746, -8795, -6607, -2657, -2284, -461, -4480, -6069, -2310, -1272, -796, -3395, -3008, -2363, -836, -1808, -3736, -3082, -2986, -1026, -2795, -5576, -5211, -4724, -1269, -3337, -11530, -5590, -9675, -898, -3985, -7161, -3814, -7127, -399, -4453, -4459, -3717, -4424, -272, -4145, -3612, -4997, -3564, -698, -3620, -3438, -7013, -3593, -2199, -3800, -3317, -8395, -4469, -7607, -5528, -3399, -7366, -5659, -4618, -14263, -3532, -5910, -5974, -1672, -5954, -2692, -4889, -4994, -1074, -3646, -1954, -3507, -3351, -1526, -3297, -2598, -2770, -2700, -2589, -3889, -6451, -3521, -3070, -4159, -4155, -5944, -6990, -3590, -6149, -3818, -2166, -9168, -4215, -7917, -3963, -1372, -4878, -6426, -7147, -4834, -2278, -3570, -10798, -4734, -5753, -5726, -2839, -6221, -3579, -5617, -9161, -2446, -4039, -3903, -4882, -4570, -2575, -2848, -5119, -4334, -4000, -2973, -2471, -5503, -4278, -4478, -2937, -2861, -6736, -4598, -5032, -2978, -4320, -9367, -4628, -6017, -4192, -10281, -4014, -4672, -8068, -5377, -5145, -1725, -5761, -10937, -3245, -2092, -688, -4328, -10058, -1908, -1239, -363, -1743, -6145, -1607, -1582, -580, -715, -4074, -2175, -2512, -1221, -956, -3665, -3863, -3144, -2089, -1971, -5056, -4436, -3419, -2881, -2545, -9684, -2025, -3608, -3396, -2396, -12097, -994, -3362, -3588, -2442, -10976, -1438, -2872, -3295, -3008, -11353, -3386, -2753, -2876, -4564, -8431, -7063, -3675, -2700, -9427, -7128, -8582, -6544, -2614, -7480, -6192, -8026, -6297, -2497, -4253, -4874, -8420, -3969, -2731, -3707, -3623, -8860, -3467, -4105, -4764, -2854, -8585, -3975, -7415, -5983, -2595, -7169, -4972, -5572, -5020, -2861, -5735, -6013, -3911, -4773, -3655, -5287, -7482, -3890, -5173, -4776, -6153, -10354, -4815, -4027, -5856, -7702, -8618, -6613, -2938, -6685, -6564, -6505, -8551, -3061, -7454, -5335, -5890, -6235, -4488, -8389, -5273, -6417, -4250, -6685, -7292, -6254, -8490, -3528, -7534, -5091, -8071, -16270, -3670, -8866, -3933, -8751, -10555, -4230, -13174, -3898, -7635, -7917, -5234, -11510, -4896, -6785, -6733, -6968, -9992, -6789, -6312, -6186, -6140, -10876, -9400, -6279, -6354, -4174, -14447, -13489, -6691, -7307, -3387, -9865, -9254, -7337, -6874, -3650, -8955, -6250, -8217, -5054, -4855, 6703, 3204, 1586, 6835, -3668, 6345, 2720, 1801, 6394, -1134, 5365, 1177, 1741, 5107, 1061, 4119, -2197, 898, 3222, 2289, 3167, -8615, 284, 1169, 2993, 2409, -2027, 1073, -2036, 3106, 1086, -1293, 1938, -5374, 2331, 547, -1753, 2523, 5, 797, 1067, -24, 2946, 1931, 656, -1071, 1855, 2833, 2952, 2201, 1457, 3108, 1416, 3439, 3749, 4705, 4256, -32, 3213, 5112, 5749, 5414, 2752, 1872, 5989, 5477, 6280, 3819, -160, 6105, 4546, 6504, 2810, 1047, 5312, 3980, 5820, -433, 1945, 3821, 3567, 3844, 2125, 1419, 2976, 2419, -320, 3857, 176, 2403, 1613, 164, 3877, -1456, -24, 2528, 1172, 2732, -3532, -1812, 2889, -517, 1047, -144, -435, 2003, -408, 292, 1904, -883, -362, 1147, -1093, 2728, 1437, -5296, -94, -8915, 2993, 2659, -7021, -10282, 1091, 2931, 1639, -4613, 811, 3232, 2468, -3024, -2828, 2863, 3548, 1460, 1274, 126, 3568, 2711, -394, 3262, 1813, 3683, 1363, -4406, 3223, 2242, 3312, 403, -1225, 1673, 1474, 2497, 23, 1854, -1056, -1611, 1466, 825, 3183, -2861, -3901, 473, 1839, 3504, -5223, 1113, -398, 1868, 3128, -6163, 2229, -1538, 795, 2285, -3406, 1855, -2338, -252, 1237, -3807, 544, -276, -252, 395, -4846, -970, 948, -1082, -25, -2043, -860, 533, -2352, -229, 9, 484, -1634, -993, -505, 1165, 1547, -3511, -590, -974, 1707, 2050, -2970, -2518, -1589, 1697, 2108, -5249, -2631, -2542, 1152, 1867, -7052, -177, -3760, 137, 1291, -3246, -75, -3836, -1175, 229, -3124, -2183, -2316, -2709, -1316, -3948, -6511, -993, -4539, -3187, -2271, -6249, -588, -4778, -5457, -695, -10341, -1169, -3864, -4383, 156, -7273, -2097, -4081, -2309, 567, -4283, -1895, -5611, -1484, 490, -3179, -1638, -6577, -1538, -352, -2336, -2480, -5376, -2014, -2253, -1795, -4154, -4983, -2025, -3769, -2038, -3711, -5141, -1714, -2523, -3799, -2234, -4715, -2128, -1522, -9073, -1593, -3986, -4264, -1285, -7244, -1632, -3726, -5375, -2149, -8677, -1852, -4676, -1688, -4917, -7194, -1826, -8096, -492, -12282, -2964, -1637, -7885, -1091, -6994, -2175, -1556, -5414, -3828, -5926, -3777, -1687, -4540, -20328, -5444, -8621, -1951, -4144, -6359, -4912, -3849, -2310, -4653, -5526, -4968, -2186, -2929, -6903, -5798, -5746, -2091, -4192, -8093, -5356, -6310, -2948, -6581, -5592, -4002, -6308, -4391, -7763, -5412, -2773, -7445, -5002, -6596, -8029, -2051, -14411, -4477, -7266, -10649, -1923, -8147, -4639, -10554, -7352, -2289, -6031, -5873, -13132, -8828, -3032, -6298, -7359, -9153, -7857, -4502, -7934, -7195, -6047, -4379, -7915, -9677, -5741, -4285, -3318, -9178, -9480, -4826, -3693, -3636, -5388, -7589, -5189, -4258, -4850, -4741, -5690, -7230, -6325, -6145, -6763, -4460, -9858, -11254, -6214, 1293, 6143, 1369, 3002, -6919, 2589, 5625, 2395, 2359, 1396, 3514, 3919, 3497, -60, 4035, 2884, 548, 3781, -7328, 5095, 458, -776, 3353, -198, 5134, 590, 749, 2328, 1795, 4407, 3217, 1141, 412, 2568, 3058, 4693, 983, -4580, 2762, 858, 5438, 119, -3118, 2391, -2306, 5534, 1281, -1659, 1589, -3437, 5182, 4135, -72, 1068, -106, 5599, 5719, 3958, 1330, 2715, 6580, 6093, 5937, 1590, 3934, 6784, 5487, 6334, 1391, 3827, 6024, 4268, 5213, 2532, 2476, 4725, 2996, 1936, 4331, -143, 3626, 1903, -1202, 5311, -3511, 2869, 75, 1116, 5583, -4604, 1661, -5912, 358, 5407, -3736, -1659, -312, -3236, 4889, -4575, -6926, 993, -10314, 4077, -4774, -2910, -919, -8073, 3183, -3574, -2594, -1749, -4815, 2386, -4578, -223, 2025, -402, 1379, -3131, 1151, 3552, 1653, -307, -1652, 1588, 4067, 2550, -1863, -2704, 1634, 3913, 2716, 128, -4038, 1601, 3233, 2298, 1743, -976, 1691, 2509, 1212, 2014, 106, 1861, 2459, -545, 910, -530, 1893, 2695, -1881, -2392, -3240, 1653, 2586, -1497, -7493, -4522, 1314, 1810, -577, -1369, -554, 1343, -279, -149, -17, 1383, 1717, -1704, -736, -337, 2342, 1784, 1357, -2468, -1523, 2672, 1083, 2579, -4590, 301, 2526, -625, 2299, -4465, 2389, 1926, -3639, 566, -2154, 3378, 857, -5484, -3344, -534, 3636, -375, -2516, -12965, 58, 3478, -860, -379, -4807, -35, 3069, -38, 1062, -567, -587, 2468, 1059, 1903, 1600, -1397, 1548, 1590, 2101, 2320, -1832, -55, 1443, 1640, 1993, -2134, -1309, 726, 561, 1127, -3168, -521, -312, -1202, 354, -4864, -373, -945, -4005, -663, -6055, -1355, -869, -4117, -2990, -5865, -3041, -902, -2457, -8170, -5027, -4746, -1442, -2935, -10249, -4432, -5016, -2340, -7190, -6067, -4864, -4258, -3037, -6829, -2751, -6363, -3300, -3169, -4239, -1698, -5350, -2072, -3388, -5548, -2701, -3534, -1137, -4792, -7117, -7722, -2995, -814, -8137, -3626, -6399, -3808, -1096, -7043, -2003, -4058, -6258, -1518, -6399, -1569, -4900, -9322, -1486, -6839, -2077, -8802, -7117, -1405, -5116, -3519, -8928, -5047, -1596, -3431, -5787, -5447, -4194, -1928, -2840, -6319, -3920, -4545, -2079, -3631, -4603, -3377, -5533, -1722, -6507, -3148, -3755, -5508, -1590, -10105, -2108, -5016, -5074, -2436, -9812, -1715, -6540, -5372, -4575, -11719, -2270, -6622, -6098, -6740, -5126, -4204, -5991, -7256, -5343, -3221, -8612, -5590, -9812, -4101, -3040, -8594, -5369, -9472, -3783, -4275, -6415, -5323, -8459, -4783, -6485, -5315, -5352, -9788, -9495, -5953, -4822, -5571, -10721, -6150, -5775, -5135, -6381, -10666, -3189, -8294, -6049, -7777, -12603, -2586, -7554, -6878, -8223, -10970, -3410, -5760, -6977, -5866, -9642, -5563, -6499, -6528, -4094, -9282, -9337, -8436, -6019, 6460, 8585, 6506, -1671, 2320, 6263, 7904, 6607, 4638, 4738, 5687, 6070, 6838, 6771, 5155, 4927, 4654, 6804, 7110, 3835, 3991, 3955, 5957, 5941, 436, 2319, 1879, 3752, 2813, -1564, 1025, -2462, 1189, 481, -1290, 1768, -6966, 2144, 1278, -4873, 1698, -2827, 2060, 2646, -3446, 695, -839, 2309, 5169, 1280, 485, -121, 3583, 6523, 3448, 1856, 216, 3940, 6911, 4334, 2638, 242, 2952, 6260, 4036, 2291, -887, -240, 3493, 2322, 858, -4898, -6552, 1023, -1619, -2154, -1399, -694, 5282, -1276, -6278, 670, -750, 6114, 394, -1566, 783, -2170, 5681, -62, -1027, -185, -2775, 5170, -2306, -3586, -1760, -3144, 4729, -7322, -3833, -3287, -1245, 3711, -19766, -589, -3358, -222, 2242, -8093, 27, -3191, -970, 1022, -4243, -1122, -3548, -3359, 209, -3298, -4685, -2986, -5363, -298, -4225, -7646, -1347, -5386, -964, -8173, -6611, -132, -5248, -1823, -6344, -5415, 315, -4457, -999, -2598, -2179, 144, -3868, 105, -1560, -1501, -509, -3549, 279, -2197, -2952, -1794, -3053, -246, -3620, -5376, -3607, -2577, -1222, -2705, -4183, -4144, -3278, -3791, -1762, -2836, -2395, -6206, -5145, -1087, -2115, -305, -1526, -1274, 104, -2627, 818, 929, -498, 781, -4614, 704, 1460, -1142, 253, -4524, -603, 434, -2681, -2192, -2584, -777, -2499, -5398, -5049, -1574, 712, -11590, -2509, -2376, -1586, 1435, -3710, -250, -3423, -1846, 1829, -1418, 701, -2715, -487, 2131, -1248, 1073, 867, 716, 1818, -3331, 1106, 2047, 902, 523, -12523, 682, 1608, 253, -1466, -6181, -499, -528, -912, -1687, -5199, -2605, -6409, -2194, -639, -4671, -4952, -5239, -3145, -138, -4332, -7433, -3721, -3566, -337, -4663, -12593, -5254, -3552, -1391, -4762, -7195, -8644, -3370, -3758, -4647, -6089, -5053, -3458, -6957, -4791, -6491, -3648, -4299, -5356, -4950, -5986, -4012, -6366, -4894, -5337, -4762, -5765, -9859, -5770, -6680, -4250, -7849, -8077, -6539, -8993, -4049, -7880, -5595, -7021, -7878, -3440, -7817, -4289, -9246, -6359, -2550, -7828, -3690, -14931, -5444, -2002, -6701, -3536, -8096, -4238, -2251, -5883, -3852, -7104, -3132, -3703, -6021, -5128, -8187, -2707, -7868, -6281, -9567, -9829, -3158, -8433, -6121, -7803, -9826, -4530, -4120, -6513, -4211, -8745, -6605, -2590, -7734, -3280, -8554, -8064, -2129, -8656, -3965, -8337, -8232, -2411, -7856, -6265, -5359, -8473, -3191, -6319, -7133, -3973, -8603, -3961, -5119, -5602, -4297, -8081, -4038, -4657, -4597, -5804, -7912, -3391, -5386, -4008, -6926, -8704, -2602, -7435, -4229, -8161, -11275, -2156, -7266, -5466, -9710, -14398, -2307, -7574, -7933, -7565, -8732, -3190, -11110, -10776, -7046, -7437, -4874, -5258, -8394, -8759, -8230, -6787, -3350, -6713, -15560, -10338, -6749, -3291, -6291, -10373, -10250, -6686, -8081, -3861, -7544, -12242, -5296, -4990, -3638, -6283, -9534, -4842, -4384, -3611, -6077, -7659, -5782, -4796, -3644, -6173, -6376, -8535, -5620, -3851, -5851, -6373, -7229, -7298, -4720, -5509, -7419, -6000, -7694, -6763, -5797, -6459, -6692, -5630, -10988, -6929, -4902, -7763, -4236, -14770, -8883, -4496, -7651, -3452, -10059, -11134, -5015, -7245, -3129, -8703, -10550, -5908, -5993, -3172, -8592, -8335, -6287, -4910, -3536, -8320, -7303, -6516, -4655, -4341, -7341, -6919, -7810, -5046, -6037, -7272, -6556, -9608, -5551, -10399, -8040, -6681, -8608, -5595, -11077, -7942, -7533, -8245, -5352, -7727, -7381, -8621, -9242, -5506, -7582, -6260, -8946, -12264, -6541, -9181, -4954, -6697, -9602, -8278, -11606, -4501, -5073, -6425, -8221, -10750, -5169, -4816, -5116, -7345, -8677, -7055, -5554, -4801, -7546, -6583, -8102, -6044, -5165, -9019, -5398, -6459, -5659, -6100, -11315, -5408, -5590, -5940, -7048, -10794, -6623, -5433, -7994, -6872, -9456, -8768, -5395, -11278, -6691, -8343, -10468, -5121, -8059, -7592, -7063, -9210, -4766, -7158, -9540, -5863, -7060, -4729, -7870, -9096, -5170, -6140, -5375, -10321, -6839, -5354, -6402, -6812, -17832, -5637, -6724, -7307, -7519, -9106, -5496, -8705, -7919, -6604, -7291, -6224, -7896, -8120, -6267, -7301, -7367, -7235, -7994, -6827, -8576, -7996, -7929, -7577, -8062, -10179, -7451, -9083, -7175, -9730, -10866, -6625, -8186, -7108, -10845, -10002, -6490, -6085, -7891, -10350, -8082, -6925, -4784, -9322, -9988, -7385, -7246, -4706, -9306, -9214, -8374, -7127, -6081, -8930, -7544, -11900, -6299, -9353, -8191, -6706, -12636, -5464, -8912, -7071, -7185, -9948, -5367, -7078, -7114, -8801, -8905, -6146, -6768, -9244, -9259, -7689, -7835, -6756, -14682, -8430, -6448, -10286, -6334, -9283, -8936, -5805, -10398, -6232, -8215, -11595, -5907, -8780, -6925, -9266, -12734, -6654, -8245, -8377, -13011, -10854, -7601, -9180, -10070, -16819, -9726, -8044, -13164, -10194, -12386, -8277, -8308, -11393, -8966, -11102, -7739, -9389, -8107, -7966, -9149, -8758, -12630, -7110, -7712, -7642, -12974, -16843, -7381, -8716, -7506, -12816, -12094, -8807, -12294, -9444, -9445, -12427, -11430, -13088, -13175, -9000, -11861, -13592, -11056, -8018, -9609, -8138, -13507, -13650, -6437, -9416, -6223, -13215, -10254, -6645, -8461, -5572, -11994, -7187, -8797, -8068, -5900, -11103, -6167, -12028, -8353, -7192, -10938, -6353, -8272, -9002, -9690, -9898, -7507, -7329, -9624, -12416, -8870, -9500, -8506, -10184, -12048, -9132, -11676, -11289, -10610, -13399, -10614, -12017, -9963, -10329, -17632, -12277, -10225, -9342, -10059, -11794, -12810, -8551, -11024, -11152, -9739, -10594, -7666, -13738, -16279, -9015, -8973, -7541, -10362, -14029, -8803, -8840, -8188, -8717, -11141, -8518, -10270, -9868, -8657, -10411, -8097, -13847, -13647, -9581, -10752, -7837, -17834, -19148, -9836, -12529, -7931, -20091, -13792, -9977, -11735, -8497, -13887, -12597, -5991, -3744, -8902, -11410, -8909, -5391, -4875, -9033, -8824, -11574, -4686, -7483, -10082, -6786, -9772, -4221, -8386, -11713, -5534, -7215, -4427, -7160, -11370, -5162, -6295, -5663, -6160, -9608, -5567, -4910, -8094, -5465, -8462, -6479, -3906, -10248, -5571, -7955, -7540, -4028, -12081, -6664, -7881, -8728, -5443, -11211, -8168, -8236, -8905, -8792, -8369, -8285, -8463, -7148, -12392, -7433, -7569, -6835, -6183, -8421, -7292, -7064, -5297, -6863, -7661, -6998, -7198, -5058, -10533, -8750, -6326, -8437, -5922, -10417, -12173, -5678, -11215, -5797, -7091, -13441, -5301, -12537, -4946, -6199, -9546, -5184, -10470, -5456, -6234, -8400, -5204, -9073, -7572, -6855, -8838, -5254, -8304, -8123, -8270, -9406, -5340, -6641, -7515, -10446, -8337, -5466, -4801, -9911, -9273, -7318, -5471, -4036, -10924, -7826, -6955, -5336, -4542, -5788, -7617, -7424, -5559, -6493, -4346, -7735, -8804, -6796, -10525, -4645, -7064, -9692, -8022, -24960, -6532, -6083, -8804, -5864, -12193, -8419, -5556, -7612, -4576, -9891, -7835, -5563, -6365, -4740, -9331, -8463, -5905, -5533, -6383, -9772, -10027, -6335, -5503, -10656, -11335, -8994, -6706, -6632, -12304, -14695, -8003, -7338, -10125, -8839, -10698, -8142, -9166, -11785, -8201, -8931, -8256, -12605, -7731, -8399, -9187, -7673, -13029, -6747, -8740, -10575, -6812, -18001, -7123, -9667, -10123, -6003, -8773, -8340, -10541, -9335, -6346, -6194, -9319, -7978, -8672, -9434, -5109, -9667, -6188, -7126, -11739, -4909, -10658, -5687, -6117, -7850, -5786, -12360, -6263, -6042, -7688, -7843, -10842, -7874, -6553, -7756, -7997, -9353, -10055, -7000, -6986, -6754, -9075, -10057, -6836, -6558, -6460, -9185, -8933, -6373, -6269, -6889, -9051, -8414, -6409, -6204, -7961, -9056, -8596, -7465, -7027, -9355, -10020, -9444, -9167, -9397, -10302, -13686, -10432, -8710, -12956, -12171, -13586, -10825, -7945, -10608, -20602, -9473, -11381, -8347, -9115, -11084, -8096, -11883, -9886, -8625, -9771, -8113, -11845, -12840, -9157, -11089, -9648, -13506, -17357, -11322, -15611, -10725, -12426, -12935, -11703, -15018, -8182, -9198, -11329, -8610, -14320, -6861, -8047, -12005, -7322, -9497, -6595, -8139, -16254, -7258, -7208, -7013, -8970, -11442, -7916, -6760, -8093, -10028, -9065, -8420, -7990, -10361, -10859, -9035, -7877, -11779, -17250, -11230, -11400, -7004, -17858, -11925, -11498, -11424, -6944, -12917, -9719, -12969, -8998, -8374, -11280, -9195, -13799, -8777, -12118, -10145, -9121, -10062, -10183, -12353, -10403, -9174, -8311, -11381, -11711, -11370, -9726, -7643, -9668, -11575, -10860, -10616, -7382, -8398, -9651, -10141, -9582, -7492, -7666, -8988, -10232, -7922, -8451, -7308, -10074, -11430, -7321, -10715, -7654, -12915, -12854, -7852, -10677, -9120, -11435, -11781, -9380, -8932, -12507, -9987, -11731, -11085, -9085, -16788, -10218, -12420, -11560, -12065, -13337, -11069, -11049, -11568, -15013, -12380, -10784, -10065, -11213, -10293, -11080, -10060, -10459, -10470, -4645, -7279, -8322, -10262, -8200, -7235, -10412, -8067, -11503, -7272, -7172, -11788, -8851, -12891, -5541, -5762, -10109, -10237, -24390, -5888, -5896, -11184, -11610, -11714, -8864, -8080, -13501, -12644, -10258, -8987, -10534, -9757, -11648, -13154, -6682, -6602, -7124, -11465, -13310, -6786, -5208, -5621, -14978, -9388, -9169, -5411, -4955, -14351, -8002, -12895, -7435, -4944, -10748, -6909, -8310, -12699, -5243, -9682, -6661, -7229, -8543, -5389, -9297, -7954, -7459, -6961, -5349, -9556, -11466, -8024, -6584, -5736, -11375, -10080, -9118, -6553, -7427, -10460, -7665, -10338, -6999, -11786, -7307, -6465, -8590, -8550, -13963, -5895, -6046, -7109, -10132, -14164, -4839, -6536, -6678, -7674, -8115, -3733, -8272, -7110, -6862, -6329, -3312, -11836, -8294, -7997, -6689, -3960, -10943, -9089, -9066, -8144, -5551, -8517, -7720, -8118, -8383, -6593, -7131, -6316, -8435, -8351, -6436, -6196, -5747, -9933, -9374, -7091, -5701, -5978, -9258, -11383, -10144, -5677, -6655, -7256, -11110, -12618, -5888, -6986, -5780, -10439, -7687, -5980, -6480, -4776, -8935, -6403, -6059, -5546, -4204, -6751, -6283, -6454, -4842, -4038, -5731, -6589, -7155, -4825, -4279, -5682, -6878, -7933, -5746, -5162, -6189, -7117, -9120, -7767, -7193, -6874, -7464, -11775, -10395, -9418, -7089, -8237, -10760, -10105, -8380, -6914, -10549, -8362, -8312, -8602, -7812, -14282, -7759, -7345, -11042, -11655, -9857, -8144, -7312, -13243, -12635, -9634, -8513, -7797, -12732, -10126, -12235, -8198, -8174, -13280, -8696, -11478, -8139, -8563, -13062, -7110, -10727, -9314, -9222, -17312, -6665, -13161, -12697, -10077, -11454, -7278, -14893, -13504, -12326, -7911, -8250, -8763, -11000, -13215, -6521, -8694, -6221, -10134, -9276, -6203, -8828, -5189, -10501, -7422, -6533, -9168, -5264, -13122, -6549, -7343, -9686, -6382, -14479, -6508, -8844, -10154, -9085, -10108, -7377, -10863, -10607, -17692, -8197, -9145, -10507, -11689, -9599, -7331, -11922, -10398, -11527, -8239, -7226, -16751, -13203, -9232, -9399, -7455, -11164, -13717, -8828, -13202, -7527, -8539, -11117, -11690, -10044, -7620, -6948, -11590, -12705, -8974, -7925, -6103, -12496, -8686, -10038, -8381, -6360, -10878, -8348, -12467, -8828, -8132, -9960, -9718, -13730, -8801, -11835, -9764, -10661, -11965, -8838, -14391, -9139, -10330, -10710, -9810, -12038, -7957, -10940, -10779, -11834, -8383, -7025, -12421, -11755, -13472, -6596, -6669, -12898, -13153, -14344, -6041, -6955, -12086, -15793, -14101, -6451, -7941, -11562, -21332, -10627, -8039, -9853, -12192, -22607, -8947, -11731, -13727, -15488, -17383, -8963, -12440, -17614, -16423, -13197, -10609, -11382, -13433, -12505, -11141, -13491, -14398, -12776, -11681, -10186, -13165, -16676, -12033, -11957, -10227, -11562, -13239, -11000, -11789, -11349, -10535, -13464, -10916, -10743, -12834, -10362, -12974, -11947, -10160, -12579, -11610, -13058, -12664, -10771, -12170, -16505, -12734, -11097, -13525, -11957, -12217, -10174, -9629, -13331, -11881, -9968, -8909, }; diff --git a/sw/applications/trans_versasense/dense_layerC.c b/sw/applications/trans_versasense/dense_layerC.c new file mode 100644 index 00000000..37d06f02 --- /dev/null +++ b/sw/applications/trans_versasense/dense_layerC.c @@ -0,0 +1,73 @@ +// +// Created by alireza on 10/6/23. +// + +#include "dense_layerC.h" +#include + +void createDense(Dense* dense, size_t input_dim, size_t output_dim, quant_bit_width *weight, quant_bit_width* bias) { + dense->input_size_ = input_dim; + dense->output_size_ = output_dim; + dense->weight = weight; + dense->bias = bias; +} + +void destroyDense(Dense* dense) { + // Free the memory allocated for the Dense struct + free(dense); +} + +void multiplyweight(Dense* dense, size_t seq_len, int32_t* input, int32_t* output) { + for (int length = 0; length < seq_len; length++) { + for (int out_idx = 0; out_idx < dense->output_size_; out_idx++) { + int32_t* weight_ptr = dense->weight + out_idx; + int32_t* output_ptr = output + (length * dense->output_size_) + out_idx; + int32_t* input_ptr = input + (length * dense->input_size_); + int32_t sum = 0; + for (int i = 0; i < dense->input_size_; i++) { + sum += MUL_HQ(*weight_ptr, *input_ptr); // MUL_HQ macro + input_ptr++; + weight_ptr += dense->output_size_; + } + *(output_ptr) = (int32_t) (sum >> NUM_FRACTION_BITS); // NUM_FRACTION_BITS macro + } + } +} + +void addbias(Dense* dense, size_t seq_len, int32_t* output) { + for (size_t idx = 0; idx < seq_len; idx++) { + for (size_t feature_idx = 0; feature_idx < dense->output_size_; feature_idx++) { + output[idx * dense->output_size_ + feature_idx] += dense->bias[feature_idx]; + } + } +} + +void computeDenseOneRow(Dense* dense, size_t seq_len, int32_t* input, int32_t* output){ // 1x16x16 + multiplyweight(dense, seq_len, input, output); +} + +void computeDense(Dense* dense, size_t seq_len, int32_t* input, int32_t* output) { + //multiplyweight(dense, seq_len, input, output); + //printf("\rMul %dx%dx%d\n", seq_len, dense->input_size_, dense->output_size_); + multiply_cgra(input, seq_len, dense->input_size_, dense->weight, dense->output_size_, output); + if (dense->bias != NULL) { + addbias(dense, seq_len, output); + } +} + +void activation(Dense* dense, size_t length, int32_t* input, int32_t* output) { + float in_float, in_tanh; + int32_t x3, in_tanh_fxp; + for (int i = 0; i < length; i++) { + x3 = MUL(MUL(input[i], input[i]), input[i]); + x3 = MUL(x3, 183); // 183 = 0.044715 in fixed-point 12 bit + x3 += input[i]; + x3 = MUL(x3, 3268); // 3268 = sqrt(2/PI) in fixed-point 12 bit + in_float = (float) x3 / (float) (1 << NUM_FRACTION_BITS); + in_tanh = tanhf(in_float); + in_tanh_fxp = (int32_t) (in_tanh * (1 << NUM_FRACTION_BITS)); + in_tanh_fxp += (1 << NUM_FRACTION_BITS); + output[i] = MUL(in_tanh_fxp, input[i] >> 1); + } +} + diff --git a/sw/applications/trans_versasense/dense_layerC.h b/sw/applications/trans_versasense/dense_layerC.h new file mode 100644 index 00000000..e0438f8d --- /dev/null +++ b/sw/applications/trans_versasense/dense_layerC.h @@ -0,0 +1,31 @@ +// +// Created by alireza on 10/5/23. +// + +#ifndef FVLLMONTITRANSFORMER_DENSE_LAYERC_H +#define FVLLMONTITRANSFORMER_DENSE_LAYERC_H + + +#include +#include +#include +#include "param.h" +#include "cgra.h" + +// Define the struct +typedef struct { + size_t input_size_; + size_t output_size_; + int32_t* weight; // quant_bit_width is a typedef for int32_t + int32_t* bias; // quant_bit_width is a typedef for int32_t +} Dense; + +void createDense(Dense* dense, size_t input_dim, size_t output_dim, quant_bit_width *weight, quant_bit_width* bias); +void destroyDense(Dense* dense); +void multiplyweight(Dense* dense, size_t seq_len, int32_t* input, int32_t* output); +void addbias(Dense* dense, size_t seq_len, int32_t* output); +void computeDense(Dense* dense, size_t seq_len, int32_t* input, int32_t* output); +void computeDenseOneRow(Dense* dense, size_t seq_len, int32_t* input, int32_t* output); +void activation(Dense* dense, size_t length, int32_t* input, int32_t* output); + +#endif //FVLLMONTITRANSFORMER_DENSE_LAYERC_H diff --git a/sw/applications/trans_versasense/main.c b/sw/applications/trans_versasense/main.c new file mode 100644 index 00000000..6a26f77e --- /dev/null +++ b/sw/applications/trans_versasense/main.c @@ -0,0 +1,143 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include +#include "main.h" +//#include "data_cpp/signal.cpp" +//#include "data_cpp/signal_fft.cpp" +#include "SYLT-FFT/fft.h" +#include "weightsAndBiasesC.h" +#include "transformerBlockC.h" + +// For the cgra +#include "multiply_cgra.h" + +// FFT +//#include "stftVec.h" +#include "data_cpp/array_output.h" + + +float error_check(const quant_bit_width* groundTruth, const quant_bit_width* output, size_t length){ + long error = 0; + for (int i=0; i> NUM_FRACTION_BITS); + return (float) error/ (float) length; +} + +void prototype_distances(quant_bit_width* prototypeVec, const quant_bit_width* modelOutput, int32_t* distVec, size_t prototypeLength, int prototypeNums){ + for (int p=0; p< prototypeNums; p++){ + long dist = 0; + quant_bit_width * prototypePtr = prototypeVec + (p * prototypeLength); + for (int i=0; i> NUM_FRACTION_BITS); + distVec[p] = (int32_t) dist; + } +} + +void transformerInference(quant_bit_width * transformerInput, quant_bit_width * transformerOutput, quant_bit_width* input_normalized, quant_bit_width* qkv, quant_bit_width* intermediate, quant_bit_width * aux_padding, void* kperf){ + quant_bit_width * weightVec[NUM_LAYERS*(3*NUM_HEAD+5)+5]; + quant_bit_width * biasVec[NUM_LAYERS*(3*NUM_HEAD+5)+5]; + getWeights(weightVec); + getBiases(biasVec); + quant_bit_width * clsTokenVector = getClassToken(); + quant_bit_width * posMatrix = getPosEmbedding(); + TransformerBlock* selfatten = createTransformerBlock(D_SEQ, D_MODEL, D_Q, NUM_HEAD, D_FF, weightVec, biasVec, clsTokenVector, posMatrix); + computeFixedPoint(selfatten, D_SEQ, transformerInput, input_normalized, transformerOutput, intermediate, qkv, aux_padding, kperf); +} + +quant_bit_width compute_log_amp(int32_t real, int32_t imag){ + real = MUL_HQ(real, 25) >> (NUM_FRACTION_BITS - 9); + imag = MUL_HQ(imag, 25) >> (NUM_FRACTION_BITS - 9); + int32_t real2 = MUL_LONG(real, real) >> NUM_FRACTION_BITS; + int32_t imag2 = MUL_LONG(imag, imag) >> NUM_FRACTION_BITS; + float pow2 = (float)(real2 + imag2) / (float) (1<< NUM_FRACTION_BITS); + float amp = sqrtf(pow2); + float stft = logf(amp+ 1e-10f); + quant_bit_width stft_int = (quant_bit_width) (stft * (1< +#include +#include "param.h" + +float error_check(const quant_bit_width* groundTruth, const quant_bit_width* output, size_t length); +void prototype_distances(quant_bit_width* prototypeVec, const quant_bit_width* modelOutput, int32_t* distVec, size_t prototypeLength, int prototypeNums); +void transformerInference(quant_bit_width * transformerInput, quant_bit_width * transformerOutput, quant_bit_width* input_normalized, quant_bit_width* qkv, quant_bit_width* intermediate, quant_bit_width* aux_padding, void * kperf); +quant_bit_width compute_log_amp(int32_t real, int32_t imag); + +#endif //FVLLMONTITRANSFORMER_TRANSFORMER_H diff --git a/sw/applications/trans_versasense/matMulC.c b/sw/applications/trans_versasense/matMulC.c new file mode 100644 index 00000000..0212afe3 --- /dev/null +++ b/sw/applications/trans_versasense/matMulC.c @@ -0,0 +1,22 @@ +// +// Created by alireza on 10/6/23. +// + +#include "matMulC.h" +#include + + +void MatMul_multiply(size_t seq_len, quant_bit_width* input, quant_bit_width* weight, + quant_bit_width* output, size_t input_size, size_t output_size) { + //printf("\rMul %dx%dx%d\n", seq_len, input_size, output_size); + multiply_cgra(input, seq_len, input_size, weight, output_size, output); +} + +void MatMul_scale(quant_bit_width* input, int shift_scale, size_t mat_size) { + + for (size_t i = 0; i < mat_size; i++) { + *input = (*input) >> shift_scale; + input++; + } +} + diff --git a/sw/applications/trans_versasense/matMulC.h b/sw/applications/trans_versasense/matMulC.h new file mode 100644 index 00000000..9844b787 --- /dev/null +++ b/sw/applications/trans_versasense/matMulC.h @@ -0,0 +1,21 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_MATMULC_H +#define FVLLMONTITRANSFORMER_MATMULC_H + + +#include +#include "param.h" +#include "cgra.h" + +#define BLOCK_SIZE 4 + +typedef struct { +} MatMul; + +void MatMul_multiply(size_t seq_len, quant_bit_width* input, quant_bit_width* weight, quant_bit_width* output, size_t input_size, size_t output_size); +void MatMul_scale(quant_bit_width* input, int shift_scale, size_t mat_size); + +#endif //FVLLMONTITRANSFORMER_MATMULC_H diff --git a/sw/applications/trans_versasense/multiply_cgra.c b/sw/applications/trans_versasense/multiply_cgra.c new file mode 100644 index 00000000..1222d3f2 --- /dev/null +++ b/sw/applications/trans_versasense/multiply_cgra.c @@ -0,0 +1,178 @@ +/* + ******************* +******************************* C SOURCE FILE ******************************* +** ******************* ** +** ** +** project : HEEPsilon ** +** filename : main.c ** +** version : 1 ** +** date : 01/10/23 ** +** ** +***************************************************************************** +** ** +** Copyright (c) EPFL ** +** All rights reserved. ** +** ** +***************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ + +/** +* @file main.c +* @date 01/10/23 +* @brief An application to run a matrix multiplication. +* +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "cgra_x_heep.h" +#include "cgra_bitstream.h" +#include "multiply_cgra.h" + +// For interrupt handling +#include "csr.h" +#include "handler.h" +#include "rv_plic.h" +#include "rv_plic_regs.h" +#include "hart.h" +#include "cgra.h" + + +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +// Size of the input buffer for the CGRA +#define CGRA_COL_INPUT_SIZE 4 + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + + +// Handler for the CGRA interruption +void handler_irq_cgra(uint32_t id); + + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +// Plic controller variables +volatile bool cgra_intr_flag; + +// CGRA variables +static cgra_t cgra; +static uint8_t cgra_slot; + +// CGRA input and output buffers +static int32_t cgra_input[CGRA_N_COLS][CGRA_COL_INPUT_SIZE] __attribute__ ((aligned (4))); + + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +// Output needs to be multiple of 4 by 4, ex 12x16 +void multiply_cgra(int * matrixA, int ROWS_A, int COLS_A, int * matrixB, int COLS_B, int * matrixC) +{ + int ROWS_B = COLS_A; + int ROWS_C = ROWS_A; + int COLS_C = COLS_B; + // Prepare the input vector for the CGRA + // Col 0: &B[0][0], nItLoopColsC, &A[0][0], &C[0][3] + cgra_input[0][0] = &matrixB[0]; + cgra_input[0][1] = COLS_C/CGRA_N_ROWS; + cgra_input[0][2] = &matrixA[0]; + cgra_input[0][3] = &matrixC[3]; + // Col 1: &C[1][0], &B[0][1], nItLoopsColsA, &A[1][0] + cgra_input[1][0] = &matrixC[COLS_C]; + cgra_input[1][1] = &matrixB[1]; + cgra_input[1][2] = COLS_A; + cgra_input[1][3] = &matrixA[COLS_A]; + // Col 2: &A[2][0], &C[2][1], &B[0][2], nItLoopColsC + cgra_input[2][0] = &matrixA[2*COLS_A]; + cgra_input[2][1] = &matrixC[2*COLS_C+1]; + cgra_input[2][2] = &matrixB[2]; + cgra_input[2][3] = COLS_C/CGRA_N_ROWS; + // Col 3: nItLoopRowsC, &A[3][0], &C[3][2], &B[0][3], + cgra_input[3][0] = ROWS_C/CGRA_N_COLS; + cgra_input[3][1] = &matrixA[3*COLS_A]; + cgra_input[3][2] = &matrixC[3*COLS_C+2]; + cgra_input[3][3] = &matrixB[3]; + + // Set CGRA kernel L/S pointers + for(int col_idx = 0 ; col_idx < CGRA_N_COLS ; col_idx++){ + cgra_set_read_ptr ( &cgra, cgra_slot, (uint32_t) cgra_input[col_idx], col_idx ); + } + + // CGRA Execution + cgra_intr_flag = 0; + cgra_set_kernel( &cgra, cgra_slot, 1 ); + // Wait until CGRA is done + while(cgra_intr_flag==0) { + wait_for_interrupt(); + } +} + +// Initialize the CGRA +void initCGRA(){ + // Init the PLIC + plic_Init(); + plic_irq_set_priority(CGRA_INTR, 1); + plic_irq_set_enabled(CGRA_INTR, kPlicToggleEnabled); + plic_assign_external_irq_handler( CGRA_INTR, (void *) &handler_irq_cgra); + + // Enable interrupt on processor side + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level external interrupts + const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; + CSR_SET_BITS(CSR_REG_MIE, mask); + cgra_intr_flag = 0; + + // Load kernel + cgra_cmem_init(cgra_imem_bitstream, cgra_kmem_bitstream); + + cgra.base_addr = mmio_region_from_addr((uintptr_t)CGRA_PERIPH_START_ADDRESS); + // Select request slot of CGRA + cgra_slot = cgra_get_slot(&cgra); +} + +// Interrupt controller variables +void handler_irq_cgra(uint32_t id) { + cgra_intr_flag = 1; +} + +void countersInit(){ + // Enable and reset the CGRA performance counters + cgra_perf_cnt_enable(&cgra, 1); + cgra_perf_cnt_reset( &cgra ); +} + +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ diff --git a/sw/applications/trans_versasense/multiply_cgra.h b/sw/applications/trans_versasense/multiply_cgra.h new file mode 100644 index 00000000..d43ba4fd --- /dev/null +++ b/sw/applications/trans_versasense/multiply_cgra.h @@ -0,0 +1,6 @@ +#include "performance.h" + +// Multiply the matrix in the cgra +void multiply_cgra(int * matrixA, int rowsA, int colsA, int * matrixB, int colsB, int * matrixC); +void countersInit(); +void initCGRA(); \ No newline at end of file diff --git a/sw/applications/trans_versasense/param.h b/sw/applications/trans_versasense/param.h new file mode 100644 index 00000000..a48ed700 --- /dev/null +++ b/sw/applications/trans_versasense/param.h @@ -0,0 +1,26 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_PARAM_H +#define FVLLMONTITRANSFORMER_PARAM_H +#include "stdint.h" + +#define D_Q 4 +#define D_SEQ 12 +#define D_MODEL 16 +#define NUM_HEAD 4 +#define NUM_LAYERS 4 +#define D_FF 4 +#define D_EMBEDDING 400 + + +#define NUM_FRACTION_BITS 12 +#define MUL(x, y) (int32_t) (((int32_t)(x) * (int32_t)(y)) >> NUM_FRACTION_BITS) +#define MUL_LONG(x, y) (int64_t) (((int64_t)(x) * (int64_t)(y))) +#define MUL_HQ(x, y) (int32_t) (((int32_t)(x) * (int32_t)(y))) +#define SHIFT(x) ((x) >> NUM_FRACTION_BITS) + + +typedef int32_t quant_bit_width; +#endif //FVLLMONTITRANSFORMER_PARAM_H diff --git a/sw/applications/trans_versasense/performance.c b/sw/applications/trans_versasense/performance.c new file mode 100644 index 00000000..421d39be --- /dev/null +++ b/sw/applications/trans_versasense/performance.c @@ -0,0 +1,62 @@ +#include "performance.h" + +// For the timer +#include "rv_timer.h" +#include "soc_ctrl.h" +#include "core_v_mini_mcu.h" + +// Timer +static rv_timer_t timer; + +void kcom_perfRecordStart( kcom_time_diff_t *perf ) +{ + timeStart( perf ); +} + +void kcom_perfRecordStop( kcom_time_diff_t *perf ) +{ + timeStop( perf ); +} + +void timeStart( kcom_time_diff_t *perf ) +{ + perf->start_cy = getTime_cy(); +} + +void timeStop( kcom_time_diff_t *perf ) +{ + perf->end_cy = getTime_cy(); + perf->spent_cy += perf->end_cy - perf->start_cy; +} + +uint64_t getTime_cy( ) +{ + static uint64_t out; + rv_timer_counter_read( &timer, HART_ID, &out ); + return out; +} + +//Initialize the timer +void timerInit() +{ + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + mmio_region_t timer_0_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); + + rv_timer_init( timer_0_reg, (rv_timer_config_t) { .hart_count = 2, .comparator_count = 1 }, &timer ); + + rv_timer_tick_params_t tick_params; + + // The same frequency is provaided to get one tick per cycle. + rv_timer_approximate_tick_params( freq_hz, freq_hz, &tick_params ); + rv_timer_set_tick_params(&timer, HART_ID, tick_params); + + // Juan: see if i cannot remove this! + rv_timer_irq_enable(&timer, HART_ID, 0, kRvTimerEnabled); + rv_timer_arm(&timer, HART_ID, 0, 1); + + rv_timer_counter_set_enabled(&timer, HART_ID, kRvTimerEnabled); + +} \ No newline at end of file diff --git a/sw/applications/trans_versasense/performance.h b/sw/applications/trans_versasense/performance.h new file mode 100644 index 00000000..9324381e --- /dev/null +++ b/sw/applications/trans_versasense/performance.h @@ -0,0 +1,64 @@ +#include +#include "cgra.h" + +typedef long int kcom_time_t; +typedef kcom_time_t kcom_param_t; + +typedef struct kcom_col_perf +{ + uint32_t cyc_act; + uint32_t cyc_stl; +} kcom_col_perf_t; + +typedef struct kcom_time_diff +{ + kcom_time_t start_cy; + kcom_time_t end_cy; + kcom_time_t spent_cy; +} kcom_time_diff_t; + +typedef struct kcom_timing +{ + kcom_time_diff_t sw; + kcom_time_diff_t cgra; + kcom_time_diff_t load; + kcom_time_diff_t input; + kcom_time_diff_t output; + kcom_time_diff_t reprogramCols; + kcom_time_diff_t bitstream; + kcom_time_diff_t infer; + kcom_time_diff_t proto; +} kcom_timing_t; + +typedef struct kcom_perf +{ + kcom_col_perf_t cols[CGRA_N_COLS]; + kcom_col_perf_t cols_max; + uint32_t cyc_ratio; // Stored *CGRA_STAT_PERCENT_MULTIPLIER + kcom_timing_t time; +} kcom_perf_t; + +typedef struct kcom_run +{ + kcom_param_t sw; + kcom_param_t conf; + kcom_param_t cgra; + kcom_param_t repo; +} kcom_run_t; + +typedef struct kcom_stats +{ + kcom_run_t avg; + uint32_t n; + uint32_t errors; + uint8_t *name; +} kcom_stats_t; + +#define HART_ID 0 + +void timerInit(); +uint64_t getTime_cy( ); +void timeStop( kcom_time_diff_t *perf ); +void timeStart( kcom_time_diff_t *perf ); +void kcom_perfRecordStop( kcom_time_diff_t *perf ); +void kcom_perfRecordStart( kcom_time_diff_t *perf ); \ No newline at end of file diff --git a/sw/applications/trans_versasense/selfattentionC.c b/sw/applications/trans_versasense/selfattentionC.c new file mode 100644 index 00000000..7edfff50 --- /dev/null +++ b/sw/applications/trans_versasense/selfattentionC.c @@ -0,0 +1,99 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include "selfattentionC.h" + + +void create_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, int32_t** weightVector) { + self_attn->pre_seq_len = pre_seq_len; + self_attn->head_hidden_size = head_hidden_size; + createDense(self_attn->query_layer, input_dim, head_hidden_size, weightVector[0], NULL); + createDense(self_attn->key_layer, input_dim, head_hidden_size, weightVector[1], NULL); + createDense(self_attn->value_layer, input_dim, head_hidden_size, weightVector[2], NULL); +} + +void destroy_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn) { + free(self_attn->query_layer_out); + free(self_attn->key_layer_out); + free(self_attn->key_transposed_layer_out); + free(self_attn->value_layer_out); + free(self_attn->attention_scores); + + destroyDense(self_attn->query_layer); + destroyDense(self_attn->key_layer); + destroyDense(self_attn->value_layer); + + free(self_attn); +} + +void removeExtraCols(int32_t* input, size_t rows, int cols) { + int nElems = 3; + for(int r = 1; r < rows; r++, nElems+=3){ + for(int c = 0; c < cols -3; c++){ + input[r*cols+c -nElems] = input[r*cols+c]; + } + } +} + +void add_padding(int32_t *input, int32_t *output, int rows, int columns, int padding_width) { + // Calcular el nuevo ancho de la matriz con el relleno + int new_columns = columns + padding_width; + + // Crear una nueva matriz con el nuevo ancho y copiar los elementos de la matriz original + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + output[i * new_columns + j] = input[i * columns + j]; + } + // Rellenar las nuevas columnas con ceros + for (int j = columns; j < new_columns; j++) { + output[i * new_columns + j] = 0; // O cualquier otro valor de relleno que desees + } + } +} + +void remove_padding(int *matrix, int rows, int columns, int padding_width) { + // Calculate the new width of the matrix after removing padding + int new_columns = columns - padding_width; + + // Shift the elements of each row to remove the padding + for (int i = 0; i < rows; i++) { + for (int j = 0; j < new_columns; j++) { + matrix[i * new_columns + j] = matrix[i * columns + j]; + } + } +} + + +void compute_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, int32_t* input, int32_t* output, int32_t* qkv, int32_t* intermediate, int32_t* aux_padding) { + self_attn->query_layer_out = qkv; + self_attn->key_layer_out = qkv + self_attn->pre_seq_len * self_attn->head_hidden_size; + self_attn->value_layer_out = qkv + 2 * self_attn->pre_seq_len * self_attn->head_hidden_size; + self_attn->key_transposed_layer_out = qkv + 3 * self_attn->pre_seq_len * self_attn->head_hidden_size; + + // This 3 mmul need to think they have 16 rows instead of 13 + int padding = 3; + // TODO: Check that the outputs have enough space for the extra padding rows and cols + computeDense(self_attn->query_layer, self_attn->pre_seq_len + padding, input, self_attn->query_layer_out); // 13x16x4 (16x16x4) + computeDense(self_attn->key_layer, self_attn->pre_seq_len + padding, input, self_attn->key_layer_out); // 13x16x4 (16x16x4) + computeDense(self_attn->value_layer, self_attn->pre_seq_len + padding, input, self_attn->value_layer_out); // 13x16x4 (16x16x4) + + transpose_quant(self_attn->key_layer_out, self_attn->key_transposed_layer_out, self_attn->pre_seq_len +3, self_attn->head_hidden_size); // 4x13 + MatMul_scale(self_attn->key_transposed_layer_out, 1, self_attn->pre_seq_len * self_attn->head_hidden_size); //4x13 + + // Add padding 4x13 -> 4x16 + add_padding(self_attn->key_transposed_layer_out, aux_padding, self_attn->pre_seq_len, self_attn->head_hidden_size, padding); // 4x16 + + // 13x4x13 (16x4x16) + MatMul_multiply(self_attn->pre_seq_len + padding, self_attn->query_layer_out, aux_padding, intermediate, self_attn->head_hidden_size, self_attn->pre_seq_len + padding); + + // 13x16 -> 13x13 + remove_padding(intermediate, self_attn->pre_seq_len, self_attn->pre_seq_len, padding); + + //printf("\rSoftmax\n"); + computeSoftmax(intermediate, self_attn->pre_seq_len); + + // 13x13x4 + MatMul_multiply(self_attn->pre_seq_len + padding, intermediate, self_attn->value_layer_out, output, self_attn->pre_seq_len, self_attn->head_hidden_size); +} diff --git a/sw/applications/trans_versasense/selfattentionC.h b/sw/applications/trans_versasense/selfattentionC.h new file mode 100644 index 00000000..9206418b --- /dev/null +++ b/sw/applications/trans_versasense/selfattentionC.h @@ -0,0 +1,35 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_SELFATTENTIONC_H +#define FVLLMONTITRANSFORMER_SELFATTENTIONC_H + +#include +#include +#include +#include "dense_layerC.h" +#include "softmaxC.h" +#include "transposeC.h" +#include "matMulC.h" +#include "param.h" +#include "cgra.h" + +typedef struct { + Dense* query_layer; + Dense* key_layer; + Dense* value_layer; + int32_t* query_layer_out; + int32_t* key_layer_out; + int32_t* key_transposed_layer_out; + int32_t* value_layer_out; + int32_t* attention_scores; + size_t pre_seq_len; + size_t head_hidden_size; +} SingleHeadSelfAttn; + +void create_SingleHeadSelfAttn(SingleHeadSelfAttn*, size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, int32_t** weightVector); +void destroy_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn); +void compute_SingleHeadSelfAttn(SingleHeadSelfAttn* self_attn, int32_t* input, int32_t* output, int32_t* qkv, int32_t* intermediate, int32_t* aux_padding); + +#endif //FVLLMONTITRANSFORMER_SELFATTENTIONC_H diff --git a/sw/applications/trans_versasense/softmaxC.c b/sw/applications/trans_versasense/softmaxC.c new file mode 100644 index 00000000..f9f8bd2b --- /dev/null +++ b/sw/applications/trans_versasense/softmaxC.c @@ -0,0 +1,38 @@ +// +// Created by alireza on 10/6/23. +// + +#include "softmaxC.h" + + +void computeSoftmax(int32_t* input, size_t seq_len) { + size_t width = seq_len; + float input_float = 0.0f; + for (int i = 0; i < seq_len; i++) { + // Look for the biggest value of the row + int32_t max_val = input[i * seq_len]; + for (int j = 1; j < width; j++) { // Assuming its squared (width = seq_len) + if (input[i * seq_len + j] > max_val) { + max_val = input[i * seq_len + j]; + } + } + for (int j = 0; j < width; j++) { + input[i * seq_len + j] = (int32_t) fmax(input[i * seq_len + j] - max_val, -32767); + } + // Sum all values on the row + int32_t sum = 0; + for (int j = 0; j < width; j++) { + input_float = (float) input[i * seq_len + j] / (float) (1 << NUM_FRACTION_BITS); + input_float = expf(input_float); + input[i * seq_len + j] = (int32_t) (input_float * (1 << NUM_FRACTION_BITS)); + sum += input[i * seq_len + j]; + } + float sum_float = (float) sum / (float) (1 << NUM_FRACTION_BITS); + float sum_inv = (float) (1 / (sum_float + 0.00001)); // prevent zero divide! + int32_t sum_inv_int = (int32_t) (sum_inv * (1 << NUM_FRACTION_BITS)); + for (int j = 0; j < width; j++) { + input[i * seq_len + j] = (int32_t) MUL(input[i * seq_len + j], sum_inv_int); + } + } +} + diff --git a/sw/applications/trans_versasense/softmaxC.h b/sw/applications/trans_versasense/softmaxC.h new file mode 100644 index 00000000..fa47176f --- /dev/null +++ b/sw/applications/trans_versasense/softmaxC.h @@ -0,0 +1,17 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_SOFTMAXC_H +#define FVLLMONTITRANSFORMER_SOFTMAXC_H + +#include +#include +#include +#include +#include "param.h" + +void computeSoftmax(int32_t* input, size_t seq_len); + + +#endif //FVLLMONTITRANSFORMER_SOFTMAXC_H diff --git a/sw/applications/trans_versasense/stftVec.h b/sw/applications/trans_versasense/stftVec.h new file mode 100644 index 00000000..62243064 --- /dev/null +++ b/sw/applications/trans_versasense/stftVec.h @@ -0,0 +1,3 @@ +#include + +int32_t stftVec[49920] = {14912, 16305, 15424, 7300, 9641, 14329, 15823, 14833, 8710, 8912, 12488, 14281, 12956, 9398, 6336, 9702, 11379, 9458, 8448, -1345, 9383, 7575, 5905, 6193, 3111, 9534, 6388, 5963, 4307, 3857, 8353, 3661, 5646, 4840, 2974, 7109, 3348, 5522, 5048, 3034, 7513, 5345, 5058, 3058, 4169, 7233, 5680, 3618, -1939, 4739, 5392, 5531, 33, 3007, 4967, 5296, 5527, 2470, 3793, 5821, 6674, 5596, 4762, 3355, 6805, 6530, 6062, 5061, 3296, 7232, 4892, 6914, 3984, 3459, 7001, 1128, 7354, 1476, 3216, 6049, -4246, 7120, -809, 2509, 4113, 1815, 6269, 1109, 1261, 649, 3559, 4808, 1742, -1118, -2260, 4541, 2638, 1333, -3683, -2573, 5324, 1096, -41, -624, -6914, 5797, 1474, -749, 1036, -1670, 5676, 1178, 1827, 1675, -136, 4838, -524, 2920, 1334, -531, 3606, -5997, 2613, -295, 48, 2645, -2879, 1699, -2664, 1454, 969, -350, 1126, -2504, 1496, -4513, 428, 343, -2119, -288, -2229, 1388, -1021, -1983, -3119, -993, 1492, -842, -2102, -953, -1, -371, 77, -3653, -82, 1169, -1377, 613, -13738, -824, 674, 323, 1161, -3526, -3042, -2042, -359, 1511, -495, -3982, -2008, -5367, 1620, 1015, -2366, 202, -646, 1594, 1724, -2351, 739, 1997, 1015, 1845, -2589, 177, 2716, -743, 1526, -470, -1415, 2187, -4764, 870, 808, -3751, 227, -6828, -105, 405, -2589, -2027, -4123, -1632, -2546, -762, -542, -3523, -4738, -7353, -263, -416, -3632, -11115, -1954, -1127, -2297, -2954, -4223, -1644, -3840, -5020, -878, -3430, -2904, -10526, -3978, 912, -4403, -3360, -6759, -4464, 1940, -4478, -2115, -5273, -6310, 2291, -4053, -1078, -4874, -7426, 2178, -5158, -729, -4946, -5026, 1817, -7019, -795, -4583, -3242, 1282, -4693, -973, -3386, -2762, 493, -3012, -1475, -2270, -2920, -526, -3119, -2724, -2058, -3040, -1411, -4985, -5214, -3154, -2122, -1653, -5183, -11004, -4021, -1058, -1492, -3140, -6113, -1651, -856, -1647, -2264, -3441, -398, -1874, -2567, -2166, -2328, -798, -4980, -4395, -2596, -2396, -3644, -6692, -6640, -3482, -3798, -7317, -2442, -9695, -4718, -7081, -2114, -1099, -12776, -6194, -10210, -933, -1213, -7281, -6705, -7503, -1230, -2569, -5561, -6399, -4361, -2941, -5049, -4606, -5694, -2735, -8393, -7371, -3951, -4559, -2440, -6246, -6732, -3286, -3792, -3112, -4097, -4957, -3010, -3817, -4315, -5844, -3629, -3569, -5020, -5387, -6388, -2664, -5189, -8333, -6113, -2933, -3172, -7335, -9106, -7623, -2443, -5793, -6899, -6885, -8790, -3850, -8549, -6246, -6705, -6422, -6173, -5584, -6214, -8112, -5561, -6842, -3056, -5853, -11115, -5960, -6204, -2619, -5710, -8982, -6899, -5422, -3612, -6354, -6516, -7562, -5662, -4805, -6666, -5380, -5988, -8942, -4464, -5836, -6103, -4564, -7665, -3820, -5569, -8363, -3404, 10828, 5093, 9764, -637, -1552, 10180, 2996, 9296, 6157, -1414, 7937, 1593, 7768, 8228, -1236, 3042, 5579, 4561, 8634, -1291, 5745, 5866, -6705, 8019, 155, 7198, 3995, 2562, 6854, 2672, 6888, 2944, 4211, 6122, 4286, 5550, 4832, 4819, 6019, 4892, 5059, 5588, 5210, 5793, 4758, 5333, 5427, 5537, 5286, 4384, 4038, 4426, 5806, 4500, 4318, 2973, 2464, 5976, 4362, 4433, 5399, 2003, 5762, 5286, 4124, 6167, 3180, 4809, 5521, 2925, 5501, 3242, 2970, 4332, 1057, 4220, 2436, 677, 1175, 673, 3549, 1524, -996, -167, 1419, 3283, 855, -620, 1349, 1891, 3126, 21, 330, 1025, 1342, 3396, -364, 327, -259, -1672, 3904, 71, -113, -1710, -6133, 4303, -450, 51, -3479, -1414, 4283, -3264, 810, -3551, -2265, 3610, -6553, 1101, -15, -3014, 2068, -975, 654, 2445, -489, -830, 960, -122, 3656, 93, -5306, 1371, -1404, 3822, -1012, -2156, 480, -2754, 3166, -4172, -672, -1771, -874, 2085, -8220, -826, -4369, 125, 855, -4587, -2741, -5810, -768, -817, -3047, -6434, -8304, -5387, -1710, -1638, -3329, -2813, -2703, -143, -570, -1822, -1158, 622, 1100, -62, -1450, -1265, 1921, 1670, -287, -1317, -885, 2352, 1712, -1175, -749, 658, 2223, 1136, -476, 383, 1404, 1729, -347, 1100, 1501, 1061, 1107, -1263, 1494, 2095, -436, 523, 769, 671, 1946, -3210, -247, 1958, -288, 949, -4718, -1497, 1982, 172, -953, -3906, -2817, 1200, 314, -3714, -2514, -3680, 118, -902, -5827, -757, -4795, -515, -4974, -5055, -82, -5592, -101, -5554, -3961, -884, -5933, 355, -1759, -3638, -3811, -7708, -148, -1153, -4611, -11004, -9064, -1975, -2050, -6628, -7066, -5638, -3629, -3916, -6914, -10138, -3680, -2139, -5897, -8982, -6516, -2553, -1392, -8304, -9106, -3362, -1838, -1752, -14784, -4184, -2143, -1250, -3007, -9936, -2855, -1925, -717, -3695, -7644, -3151, -2452, -369, -2181, -5988, -4708, -3049, -406, -1225, -4564, -6602, -2813, -792, -1364, -3741, -5897, -2208, -1155, -2590, -3824, -4028, -1736, -1501, -5768, -5031, -2655, -1393, -2299, -7426, -5979, -2328, -1391, -3447, -2811, -5085, -3314, -2265, -3927, -1129, -4344, -5091, -4821, -3474, -589, -3947, -4532, -5623, -2869, -734, -4086, -4238, -3644, -2960, -1232, -4991, -6388, -3824, -4195, -1711, -5189, -11115, -5121, -4853, -2061, -3415, -5208, -4620, -2935, -2325, -1779, -3653, -3518, -1713, -2205, -884, -3294, -2666, -1488, -1954, -786, -3284, -1922, -2323, -2517, -1617, -3324, -1739, -4929, -5037, -4168, -3501, -2587, -9479, -5646, -10613, -4234, -5299, -4821, -2382, -2999, -6504, -7066, -3704, -1370, -1359, -28777, -4180, -3334, -1195, -1571, -6457, -2863, -2720, -882, -3203, -4974, -1921, -2339, -720, -4649, -4918, -1642, -2490, -1214, -4693, 8017, 5947, 8461, -2751, 9815, 7223, 6127, 8022, 2956, 9154, 4829, 5941, 7036, 5360, 7050, 4691, 5145, 5777, 5602, 3055, 6247, 4556, 3163, 3280, 1784, 6437, 3659, 2851, -3773, 4380, 5688, 1593, 5111, 3385, 4920, 4215, -50, 5408, 4045, 2722, 2053, -1742, 5027, 3237, 1031, 686, -10526, 5369, 2846, 5125, 2484, -1146, 6142, 3540, 5804, 4808, 926, 6608, 4504, 5018, 5994, 2364, 6477, 4881, 5104, 5893, 3248, 5468, 4141, 5982, 4460, 3000, 3115, 1903, 6320, 1467, 1021, -374, -2309, 6455, -3121, -5933, 1092, -3853, 6291, -4226, -2543, 1916, -3034, 5247, -2984, -312, 1637, -1636, 2669, -1564, 1060, 993, 444, -5085, -348, 2313, 309, 2137, -1156, 752, 2779, -235, 3077, 440, 1579, 2012, 269, 3224, 1158, 1843, -941, 1646, 2635, 2681, 1328, -8165, 2411, 1417, 3713, -223, -1668, 2049, 42, 3602, -2294, -1941, 537, -310, 2031, -1652, -2813, -577, 669, 624, -1099, -1117, 2, 1906, 2465, -1414, -852, -10, 2704, 3213, -1290, -2107, -628, 2970, 2815, -1178, -3975, -987, 2822, 2019, -1959, -4119, -1014, 2387, 1699, -3856, -2022, -896, 1673, 1995, -4500, -99, -984, 548, 2192, -1913, 1011, -757, -1355, 1698, -643, 1138, 883, -4408, 100, -1165, 162, 2147, -2661, -3259, -1635, -1216, 2327, -155, -10284, 1244, -206, 1579, 1159, -5793, 2667, 1028, 571, 1620, -2739, 2356, 869, 144, 1279, -1083, 29, -1014, -14, 96, -609, -8754, -1797, -161, -2169, -1144, -3281, -350, -385, -5554, -1973, -2571, -1009, -768, -4274, -1250, -3947, -4929, -1129, -3638, -687, -5509, -7464, -1615, -4331, -1858, -6204, -5584, -2211, -2430, -3557, -5531, -10001, -2042, -703, -856, -3471, -4115, -1611, -507, 467, -2635, -2046, -1894, -2326, 329, -3692, -1847, -2990, -6007, -1055, -9479, -2388, -5020, -991, -3992, -4559, -2541, -9936, 756, -8718, -2172, -2325, -5115, 971, -5266, -1954, -2102, -2722, 152, -3879, -3031, -2394, -2316, -1551, -4837, -4810, -3609, -3436, -3927, -12123, -5960, -3615, -4980, -4319, -4003, -5380, -2853, -3299, -3027, -1630, -4795, -4064, -1941, -2835, -1077, -4963, -9238, -1576, -4226, -1491, -5836, -5735, -1713, -9873, -2353, -7484, -4478, -1912, -6666, -3025, -11629, -5509, -2004, -3923, -3124, -14195, -7503, -2003, -3735, -2847, -9238, -6928, -2170, -4550, -2569, -5020, -4597, -2973, -3876, -2259, -2514, -3147, -5360, -2971, -1992, -1383, -2703, -12319, -3367, -2531, -1215, -2447, -5524, -4674, -5043, -1759, -1943, -4270, -3930, -6719, -2637, -1755, -4555, -2320, -4064, -2416, -1813, -4743, -1622, -4659, -1259, -1760, -5422, -1971, -7774, -641, -2088, -9479, -3574, -5638, -733, -3194, -6943, -7034, -5465, -1246, -4307, -4230, -12319, -8942, -1642, -3947, -3735, -8220, -7464, -4545, -4420, -4100, -4527, -2182, -4157, -5654, -1990, -2831, -1894, -4089, -5888, -1433, -2648, -3083, -3365, -4659, -2673, -3172, -6225, -3215, -3261, -5988, -3647, -8333, -3191, -2580, -17034, -2939, -6928, -2590, -2912, -6553, -2438, -6759, -2232, -4230, -3594, -3465, -5718, -2718, -5988, -3135, -5599, -4219, -4365, -10069, -4274, -3331, -3748, -9022, -6842, -6225, -1217, -4238, -7408, -4980, -8304, -146, -4067, -4145, -5906, -8683, 89, -3286, -3362, -5638, -5031, -634, -3577, -3580, -4491, -3430, -2642, -5726, -3621, -6173, -3378, -6246, -11356, -3455, -7445, -4523, -5793, -7644, -3968, -5710, -6640, -4858, -7066, -4805, -5429, -7004, -5906, -10899, -4968, -3444, -4923, -7752, -8165, -5576, -3114, -3680, -4319, -4242, -7464, -4991, -2851, -2485, -2437, -6615, -8165, -1779, -2273, -1313, -5662, -7523, -1053, -3326, -705, -6870, -4858, -1173, -4831, -749, -9064, -3311, -2031, -5415, -1427, -10069, -2891, -3342, -4951, -2348, -6103, -2977, -4957, -4532, -2809, -3076, -2952, -5444, -4826, -2731, -1731, -2861, -4093, -5810, -2825, -1404, -2952, -3801, -6492, -3680, -1752, -3650, -5759, -6553, -5444, -2937, -5726, -8942, -6958, -7623, -5638, -10526, -5906, -7865, -9429, -6828, -12534, -6434, -8903, -8086, -4597, -10442, -11004, -8363, -4935, -4299, -7687, -5554, -6516, -3232, -5743, -5374, -3609, -4754, -3067, -8276, -4270, -3554, -3560, -4713, -6045, -4278, -4847, -3149, -8942, -4550, -4946, -6354, -3537, -14784, -4759, -5970, -5202, -4319, -8549, -6759, -7050, -4035, -4390, -3710, -6885, -6540, -3653, -3415, -1844, -3763, -5531, -3883, -2969, -1482, -2312, -4912, -4184, -4003, -2247, -2188, -4399, -3309, -7752, -3923, -3301, -3820, -2055, -7503, -5615, -5227, -3609, -1579, -5279, -5694, -5879, -4555, -2116, -5607, -4698, -5145, -7842, -3476, -7960, -3543, -4082, -8138, -4592, -15615, -2543, -3187, -5260, -5227, -10442, -1836, -3163, -4455, -6007, -9585, -1480, -4130, -3920, -5997, -12319, -1490, -4219, -2982, -4688, -13365, -1631, -2859, -2295, -3259, -9238, -1475, -2268, -2720, -2843, -7019, -1047, -2589, -5592, -3754, -5670, -787, -3692, -9238, -6321, -4211, -1091, -5776, -4779, -13738, -2752, -2452, -8247, -4616, -9936, -2111, -6016, -6856, -5170, -7644, -2749, -13365, -5951, -5170, -7623, -5115, -7936, -5646, -5458, -9238, -8393, -8192, -5480, -6153, -9193, -6214, -6143, -6354, -7464, -7912, -5862, -4718, -9380, -9238, -8517, -8304, -4523, -8165, -6800, -8304, -10799, -5183, -6504, -5380, -5437, -5630, -6133, -7796, -5026, -3741, -4028, -6153, -28777, -4455, -3261, -3717, -5844, -8582, -4258, -3707, -4254, -5836, -7113, -5020, -4464, -5554, -6163, -7179, -6679, -4842, -7130, -8009, -7353, -8718, -5266, -7960, -13049, -7503, -9585, -6214, -8034, -11945, -6973, -9106, -8192, -9284, -10284, -6267, -6899, -13738, -10613, -5487, -6246, -5408, -12776, -6007, -3717, -4555, -2540, -3259, -2526, -6814, -5214, -5014, -4513, -4361, -7665, -12123, -6914, -5266, -3850, -3689, -4858, -4176, -5827, -2472, -2419, -2973, -2615, -6773, -2116, -2401, -3982, -2319, -5759, -2344, -3165, -6540, -3404, -4683, -2664, -4759, -4100, -6299, -4611, -2778, -8683, -3279, -6528, -4625, -2470, -7623, -4097, -4718, -4555, -2247, -3804, -5801, -3741, -6143, -2831, -2311, -7623, -2743, -13365, -4674, -2091, -9429, -1872, -4946, -8165, -3203, -7603, -1785, -3001, -10284, -6516, -5208, -2929, -2557, -8942, -6288, -4315, -5924, -2735, -6528, -3817, -4093, -12534, -3441, -5592, -3449, -3399, -5333, -5897, -7523, -4003, -2567, -3135, -9639, -9753, -4518, -2483, -2655, -3329, -5121, -4509, -3479, -3701, -1581, -4810, -4541, -5599, -6173, -1304, -5743, -5768, -5480, -5319, -1830, -3889, -8333, -3281, -4104, -2596, -2847, -4564, -2084, -3893, -3220, -2945, -1420, -1892, -3641, -4003, -3096, 102, -2587, -3659, -5487, -3447, 272, -3763, -4395, -8086, -4784, -888, -4620, -4880, -10526, -5234, -3698, -5374, -4365, -7730, -3863, -8192, -6516, -4149, -5091, -3463, -3504, -8192, -3656, -3490, -4416, -1397, -10138, -2937, -2999, -7213, -731, -8982, -3296, -3635, -5221, -890, -6376, -5694, -4923, -2714, -1481, -3723, -12319, -4874, -2390, -2344, -1961, -5702, -3717, -4592, -3653, -1198, -4086, -2877, -9022, -6204, -1377, -3788, -2650, -2819, -13738, -2488, -4149, -3184, -1308, -7464, -4654, -5221, -4282, -1307, -6016, -8009, -8549, -5480, -2356, -6692, -11781, -8485, -7019, -4486, -7644, -6732, -3779, -8393, -8304, -5960, -3269, -1903, -5654, -17034, -4644, -1553, -1214, -3482, -13738, -4352, -1036, -1380, -2472, -8009, -4743, -1560, -2359, -2308, -6288, -5133, -3135, -4307, -2809, -7213, -4743, -5494, -7503, -3603, -5784, -4509, -5615, -10001, -4127, -2594, -5333, -4513, -9022, -4149, -1202, -7162, -4199, -7984, -3883, -1068, -8009, -4373, -6640, -3795, -2002, -6332, -4573, -5694, -4336, -4024, -4759, -4518, -5718, -5997, -7644, -4369, -4274, -7644, -9022, -9064, -5429, -4344, -10526, -7019, -6422, -8192, -4800, -5061, -4578, -6173, -9873, -4578, -3417, -3196, -8165, -8276, -3589, -3656, -2383, -12319, -6516, -3309, -5260, -2084, -11356, -4469, -4274, -6083, -2228, -10799, -3010, -7623, -6123, -2733, -12319, -2455, -10526, -7281, -3827, -28777, -2960, -5480, -5670, -5524, -10799, -4743, -4635, -3903, -6388, -6928, -4698, -5702, -3324, -6007, -4810, -2557, -7264, -3592, -5465, -3603, -1878, -6480, -4486, -5183, -3126, -2516, -6267, -5569, -5008, -3509, -3985, -7389, -5960, -4644, -5319, -5394, -8683, -5387, -4469, -9936, -6310, -8138, -4874, -4874, -8683, -5638, -6943, -5247, -5694, -7603, -4800, -5862, -6577, -6842, -8982, -5339, -4858, -7687, -8060, -12534, -7408, -4583, -7066, -8615, -17034, -6434, -5924, -6173, -8276, -8827, -5253, -12319, -6007, -7687, -5646, -6553, -1616, -3168, -4523, -6016, -3795, -1521, -2644, -7130, -5091, -1944, -1469, -2478, -11115, -4863, -1434, -1404, -2879, -4795, -4006, -2223, -1601, -3860, -2770, -1831, -3982, -2524, -5458, -2497, -198, -5026, -4698, -9064, -3600, 328, -4013, -9380, -8754, -4429, -321, -2904, -11004, -5844, -3707, -2216, -2825, -12123, -5630, -3964, -5827, -3476, -12319, -6773, -4853, -12776, -3989, -7445, -7752, -4569, -4837, -4644, -6093, -7066, -4597, -2904, -5524, -5654, -6054, -5170, -2916, -5401, -5569, -4455, -3735, -4420, -4344, -5451, -2621, -1704, -5630, -3493, -4674, -1621, -745, -5472, -2865, -2960, -1343, -1158, -7353, -1661, -1247, -1313, -3352, -12319, -744, -222, -1299, -7247, -7936, -858, 81, -1263, -4896, -10613, -2191, -231, -1343, -3261, -7644, -4482, -1159, -1726, -2947, -4679, -3474, -2504, -2605, -4142, -4053, -1219, -3286, -3913, -6183, -4010, 40, -3726, -3574, -4795, -3732, 355, -4880, -1321, -3883, -3208, -275, -7299, 124, -4630, -3463, -1966, -13049, 606, -6988, -6007, -3563, -5906, 326, -8942, -8865, -2741, -4278, -326, -8247, -5465, -2248, -4491, -836, -5292, -4601, -1898, -4635, -1391, -3729, -3827, -1090, -3551, -2791, -3971, -3175, -619, -2560, -5133, -6016, -2642, -662, -2094, -5008, -10704, -2646, -816, -2348, -4266, -11115, -3352, -1060, -3471, -4688, -6246, -2737, -1822, -5451, -4912, -4203, -1507, -3085, -6899, -3671, -3304, -1426, -4262, -5319, -2751, -2895, -2861, -5360, -4203, -2811, -2619, -6928, -7196, -3982, -3580, -2599, -10138, -9812, -4523, -3944, -3227, -6376, -6528, -5686, -3430, -4991, -4299, -4149, -5333, -3161, -7984, -2364, -3189, -3923, -3476, -6958, -1409, -3163, -3412, -3999, -5109, -1477, -3961, -3606, -3957, -4601, -2559, -6299, -4348, -3653, -5751, -4130, -11356, -5670, -4086, -10704, -4504, -7050, -5915, -5897, -10526, -4601, -8009, -4254, -7196, -8827, -4211, -6870, -2685, -5662, -8582, -2813, -2803, -1836, -5906, -5516, -2305, -1349, -1816, -9380, -4447, -3247, -1220, -2386, -10799, -5240, -6422, -1849, -3294, -5735, -8363, -8582, -2821, -4644, -3833, -17034, -5546, -3795, -4703, -3045, -15615, -5067, -4250, -3535, -2887, -8582, -5718, -4331, -3644, -2931, -4929, -7130, -5014, -5531, -3147, -3476, -7503, -6343, -7066, -3482, -3554, -4805, -6354, -5394, -3889, -5607, -2731, -5531, -5686, -4550, -28777, -1501, -6133, -9429, -5592, -6719, -926, -12534, -9331, -7130, -5988, -990, -6214, -6640, -9238, -9331, -1743, -3326, -7353, -11945, -8220, -3261, -2889, -9106, -17034, -5776, -4991, -4226, -8086, -13738, -5253, -5195, -8165, -7960, -11488, -3695, -4559, -9284, -6856, -10799, -2517, -4336, -6928, -4640, -11629, -2720, -4923, -6615, -3447, -13365, -4513, -6640, -6786, -3314, -13049, -8333, -9064, -6692, -3916, -28777, -9022, -8333, -6133, -4500, -9429, -7213, -7034, -6064, -4258, -7264, -6434, -6705, -6666, 932, 7831, 7734, 5628, 2792, 5612, 7584, 7412, 5643, 3008, 7135, 6918, 6604, 5495, 2765, 6849, 6058, 5777, 4981, 1614, 6250, 5237, 5093, 4168, 1506, 6575, 4429, 4081, 3167, 2167, 6332, 3603, 2703, 2383, 1879, 4534, 3082, 2056, 3001, 993, 3610, 3376, 2564, 4093, 389, 5459, 4085, 3280, 4615, 372, 6118, 4222, 3667, 4530, 2164, 5969, 3504, 3511, 3670, 4618, 5289, 2286, 2860, 1070, 6124, 3514, 1379, 2043, -2992, 6525, -1364, 1278, 1404, 1455, 5802, -978, 1386, 1268, 2186, 3730, 1196, 584, 1598, 1340, -866, 922, -1921, 1457, 769, -4713, -145, -4564, 368, 1357, -1004, -636, -1618, -1302, 1839, -702, -80, -725, -2412, 2166, -1106, 443, -2079, -3261, 2277, -1727, 577, -3618, -6365, 1796, -2718, 249, -744, -6045, 720, -4863, -707, 556, -2038, -108, -10799, -2226, 1149, -860, -359, -9193, -3430, 1821, -474, -807, -6528, -4184, 2401, -299, -1386, -4168, -5853, 2410, -639, -2007, -2487, -6786, 1465, -1693, -3311, -1512, -4365, -930, -3110, -6628, -773, -3529, -2578, -3985, -10526, -262, -4290, -251, -4918, -5121, -291, -6492, 561, -6153, -3378, -1169, -9064, -98, -4918, -1758, -3326, -5516, -2714, -3444, -714, -7796, -3103, -3788, -2713, -804, -6988, -1880, -81, -2328, -1839, -3184, -1669, 1150, -2536, -2733, -1206, -2677, 582, -4258, -2391, -935, -5333, -2257, -9753, -1548, -2621, -5702, -2871, -9936, -1141, -1943, -4082, -887, -5353, -1427, 350, -3735, -1374, -2737, -1841, 835, -3507, -2276, -2207, -1448, 107, -2900, -716, -4191, -453, -520, -2289, 295, -6045, 217, -106, -1898, 182, -2333, 101, 222, -2008, -1052, -1240, -1064, -119, -2873, -3853, -1394, -4017, -1567, -4482, -8865, -2108, -7842, -3399, -5710, -7984, -2900, -2879, -1551, -4290, -5960, -4082, -1188, -263, -2294, -2567, -4242, -932, -254, -1130, -479, -2597, -2079, -1087, -1029, 454, -2294, -5339, -1921, -1894, 557, -4003, -4779, -2204, -1987, 202, -8827, -2457, -2797, -806, -339, -6376, -2121, -4527, -431, -1240, -4416, -3027, -7464, -1214, -2699, -2728, -3126, -5879, -3220, -4743, -864, -1900, -3940, -7842, -7665, 373, -2057, -3213, -8247, -6016, 477, -5055, -3386, -4923, -2300, -848, -6354, -3683, -4738, -13, -3650, -2904, -2813, -5002, 1256, -4523, -3051, -1623, -5227, 1543, -4611, -6093, -971, -6958, 712, -6256, -9812, -884, -4713, -1903, -7066, -6288, -1225, -2655, -15615, -5686, -6225, -1772, -1821, -3577, -5422, -7317, -2079, -1233, -2217, -7247, -7445, -1820, -1109, -2010, -4940, -5494, -1430, -2050, -2150, -2705, -3873, -1524, -4513, -3163, -2322, -3577, -2619, -7019, -5031, -3140, -5279, -5718, -5026, -4885, -4991, -7842, -12534, -4254, -3726, -10362, -4728, -6204, -4262, -2906, -6565, -3512, -5678, 4316, 6840, 4580, 3259, 2961, 3196, 6302, 4364, 4515, 4850, -2189, 4595, 3767, 5579, 6678, -8, 1191, 3113, 5479, 7398, 1764, -3457, 3130, 4156, 7223, -72, 553, 3813, 980, 6468, -7371, 2078, 4266, -23, 5328, -2265, 2586, 4023, 2669, 3707, -2463, 2829, 3190, 2994, 2463, -102, 3540, 2562, 2035, 2297, 2715, 4283, 2588, 2467, 1653, 4380, 4206, 2668, 3759, 2099, 4951, 3010, 2580, 4152, 3622, 4324, 1384, 2176, 3648, 4382, 2404, 1373, 1205, 2377, 4348, 941, 1380, -7, 487, 3747, 2119, 362, -75, -1494, 2973, 2771, -1351, 64, -2320, 2439, 2497, -1677, -1025, -2226, 1842, 1102, 224, -3422, -1604, 663, -1923, 1872, -5061, -679, -443, -1422, 2804, -5139, -1046, 330, -8, 3132, -1012, -4578, 1123, -743, 3080, 1385, -1940, 966, -3101, 2873, 2456, 533, 283, -2601, 2558, 2671, 941, -133, -1694, 1944, 2146, 846, -549, -2331, 805, 739, 952, -1741, -3735, -908, -1928, 513, -3463, -3203, -3018, -6256, -680, -3647, -1755, -5115, -8034, -1650, -4564, -1343, -5266, -6856, -1319, -2139, -1374, -4611, -3732, -501, 441, -37, -5494, -1592, -474, 1434, 1374, -7162, -797, -1931, 1590, 1724, -5924, -1475, -7162, 1209, 792, -6732, -3999, -4774, 4, -1714, -3957, -7019, -1597, -2432, -4399, -515, -7004, -533, -4433, -3830, 886, -7213, -678, -3360, -2885, 914, -6469, -2046, -2772, -823, -221, -12123, -2254, -3201, 351, -2128, -5020, -269, -5043, 406, -3049, -2102, 720, -8247, -453, -2027, -1515, 723, -9429, -1477, -926, -1857, -35, -6288, -644, -118, -1424, -1418, -5121, 610, 332, -336, -3010, -7130, 1036, 334, 407, -3726, -5509, 532, -84, 788, -3266, -3337, -942, -752, 896, -2929, -4046, -3027, -1414, 705, -3738, -4258, -3944, -2129, 86, -6064, -2058, -3638, -3543, -1160, -5387, -1560, -3501, -6914, -3441, -3671, -2279, -3978, -5561, -7146, -2516, -2531, -5202, -2555, -7213, -1473, -1336, -7179, -1366, -5509, -786, -174, -6958, -1460, -4743, -383, 263, -4089, -2606, -4890, -250, -23, -2473, -3457, -5818, -641, -581, -2185, -2791, -4957, -1481, -1194, -3626, -2176, -3158, -1772, -2403, -12776, -1952, -2175, -1504, -4482, -3018, -2062, -1852, -1760, -9331, -537, -2648, -1958, -2752, -4946, 15, -3985, -1967, -4592, -1143, -841, -6267, -1828, -9429, 148, -3334, -8485, -2964, -6856, -115, -8827, -7796, -11004, -4234, -1987, -10069, -6469, -3603, -3989, -4429, -28777, -4774, -1689, -2833, -1841, -7196, -3425, -2690, -1066, -410, -4980, -3259, -7162, -712, -360, -4816, -4733, -3135, -2079, -1277, -5546, -5415, -506, -4842, -1949, -6411, -3717, 630, -3686, -1086, -6679, -3085, 724, -2351, -227, -5539, -1996, -194, -1837, -24, -4536, -775, -2095, -1846, -600, 4204, 4660, 8026, 4595, 10348, 5216, 6364, 7879, 6734, 10114, 6388, 7902, 7603, 8184, 9483, 6672, 8301, 7352, 8347, 8510, 6065, 7650, 6789, 7585, 6985, 4981, 5876, 5470, 5887, 4510, 4088, 2554, 3362, 2625, 913, 3100, -926, 1407, -2228, -1682, 1032, 1499, 500, 1081, -984, -5374, 2541, -499, 1444, 74, -63, 2881, -21, -1083, 380, 2868, 3249, 2361, -2468, 2511, 3658, 3656, 3250, 2448, 4665, 2668, 3597, 2784, 4143, 5772, -546, 3238, 2202, 4779, 6199, 1526, 3364, 2774, 4899, 6270, 3139, 3512, 3183, 4641, 5958, 2564, 2909, 2858, 4004, 5026, -600, 1562, 1949, 2914, 3245, -4270, 109, 896, 1058, 679, 400, -274, 447, -2273, 42, 1204, 271, 808, -1407, 771, 785, 102, 1315, 1105, 385, 659, -2121, 1218, 2230, -1169, 1082, -6705, -6, 2556, -2267, 537, -1325, -2918, 2243, -1235, -1197, -490, -2675, 1355, -1544, -853, -1973, -450, 731, -2145, -220, -5415, 436, 1433, 489, -1404, -5630, 824, 2053, 1834, -3647, -3933, 1111, 1895, 1760, -3840, -1071, 1164, 1358, 889, -5561, 379, 857, 1312, 299, -6332, 591, 524, 1344, 648, -3080, 239, 679, 365, 1063, -1778, 463, 1396, -2128, 683, -575, 1417, 2220, -1558, -613, -261, 1921, 2688, -201, -1114, -2478, 1256, 2491, -850, -483, -5234, -1437, 1384, -2399, -648, -747, -3603, -914, -1382, -941, -779, -244, -2722, -688, 270, -3504, 390, -1014, -1146, 1486, -1465, -367, 121, -2292, 1870, -288, -1530, 429, -3773, 1307, -1486, -2531, 51, -4728, -401, -5480, -4028, -988, -4352, -3476, -12123, -5531, -2524, -3031, -7912, -7213, -5569, -4536, -1974, -28777, -4620, -5085, -4674, -2094, -10210, -3367, -5170, -1721, -3471, -8304, -3213, -5561, -277, -4826, -6256, -3444, -4784, -27, -4951, -4164, -4286, -4907, -532, -2670, -2130, -7796, -8192, -1419, -372, -1249, -6640, -4365, -2580, 615, -1821, -2967, -1713, -4282, 474, -3883, -1777, -1338, -6705, -574, -6958, -1553, -2962, -7050, -1909, -6083, -1713, -7644, -5979, -2574, -4601, -2608, -5319, -6133, -3795, -5234, -6194, -2805, -7299, -9064, -9238, -6692, -1369, -7281, -3161, -8517, -3201, -1020, -3444, -403, -6773, -2432, -1950, -828, 488, -7819, -1538, -3638, 235, 262, -4816, -647, -3883, -250, -765, -1513, -668, -3428, -2956, -2107, 221, -1687, -3294, -5240, -2637, 845, -3227, -3321, -2197, -2455, 567, -4211, -2766, -1743, -3438, -578, -4429, -1332, -2407, -10362, -2926, -4923, -359, -3801, -3609, -7842, -7603, -317, -4810, -877, -4469, -6143, -1126, -2950, -247, -2541, -1842, -2576, -1837, -697, -2922, -164, -5480, -1197, -1926, -7004, 63, -9531, -408, -5319, -5942, -1040, -2975, -67, -5183, -2497, -3692, -1281, -558, -960, -1859, -3840, -2176, -4053, -3080, -4795, -4290, -1389, -3754, -2438, -2566, -7335, -483, -3187, -1656, -1071, -4769, 227, -2231, -1377, -274, -2779, 499, -2701, -1962, 11, -2603, 361, -5465, -3194, -105, -2339, 37, -4569, -3883, -603, -1494, -218, -2971, -3071, -1480, -1470, -339, -4112, -1980, -2726, -2605, -705, -6814, -1701, -3227, -2447, -1825, -4382, -2442, -1534, -464, -3982, -3964, -3574, 24, 504, -4017, -4219, -3662, 867, 149, -2107, -2889, -2908, 1201, -1943, -1336, -2090, -2165, 1240, -6093, -1559, -2105, -2086, 1110, -4968, -2231, -1734, -3692, 520, -5049, -2076, 39, -10526, -1695, -603, -447, 2042, -1748, -2943, 1814, 1402, 3282, 518, 1279, 2560, 2470, 3513, 1056, 2696, 2051, 2503, 2648, 589, 2458, 359, 1399, 535, -181, 801, -2617, -1019, -3023, -357, -1397, -6343, -3801, -5654, -84, -1883, -7562, -2964, -5743, -332, -2805, -5584, -1599, -7687, -1928, -4464, -3846, -705, -12776, -6123, -4013, -3334, -459, -6045, -5784, -3062, -3769, -902, -3975, -4278, -2322, -4764, -2051, -3680, -4644, -1726, -5906, -3795, -5726, -5646, -1544, -6577, -5299, -7408, -5576, -2053, -6399, -4968, -2601, -4390, -4042, -6553, -3650, -1226, -4191, -14195, -7445, -2893, -1850, -4968, -2821, -6528, -3083, -5319, -3546, -393, -4718, -3373, -5951, -1532, 218, -3704, -2361, -3401, -735, -517, -3306, -1231, -4067, -1150, -2356, -2257, -607, -7445, -2686, -3257, -765, -349, -8485, -5127, -3430, -172, -510, -5599, -7523, -5472, -1054, -1458, -3213, -7389, -6422, -3496, -3814, -2080, -5951, -4587, -2158, -7503, -2356, -4315, -4504, -671, -4880, -4168, -3005, -3814, -1130, -3843, -9585, -2867, -2065, -4028, -3833, -8165, -4142, -1002, -9106, -3319, -5554, -6732, -713, -3850, -2398, -5853, -11945, -1125, -2774, -1831, -7842, -8034, -2292, -2248, -1784, -6958, -4191, -4311, -2020, -2216, -5079, -2853, -7371, -2562, -3237, -4242, -2608, -6842, -3612, -5227, -3618, -2962, -4606, -4223, -7050, -2762, -4053, -3415, -4708, -5524, -2214, -6133, -2776, -5026, -5415, -2317, -5836, -2592, -5374, -7752, -3060, -4172, -3025, -8112, -10138, -4500, -4013, -4046, -6565, -6988, -4885, -5592, -4901, -3311, -4654, -2900, -10799, -5152, -2507, -3420, -1932, -8718, -6214, -3187, -3580, -2276, -6745, -7408, -4918, -4968, -3626, -7730, -5055, -5997, -5743, -5152, -14784, -3206, -5827, -4282, -5924, -8034, -2182, -6422, -2920, -6528, -5387, -1613, -7936, -2179, -7408, -4386, -1411, -8718, -2104, -9238, -4138, -1513, -9639, -2728, -8942, -4842, -1716, -8683, -4226, -7842, -7335, -1868, -6288, -6288, -10526, -12123, -2152, -5888, -5933, -9753, -9380, -2941, -7708, -5067, -5458, -10799, -4442, -10284, -5195, -4587, -10001, -6035, -8649, -5494, -5888, -7774, -7081, -10799, -5306, -10442, -8009, -8304, -11356, -5055, -5988, -9812, -8615, -3900, -553, -5221, -2473, -2213, -3140, -1576, -5247, -3701, -4282, -2123, -3837, -3425, -6026, -2889, -1109, -3563, -4412, -11629, -1478, -291, -1218, -8333, -4157, -894, 217, 97, -3012, -1869, -830, 310, 567, -1073, -1373, -1528, -156, 288, -260, -2328, -3626, -1521, -787, 241, -4698, -8165, -5253, -2875, 333, -5026, -8060, -6054, -6565, -417, -3383, -6214, -2006, -7213, -2264, -3049, -3509, -1206, -3723, -3184, -3906, -1796, -2219, -2139, -2108, -3659, -1083, -5662, -1870, -1939, -1976, -998, -10001, -2316, -2718, -1005, -1446, -3650, -2795, -3978, -562, -2661, -972, -2877, -3735, -168, -4985, 1098, -740, -1271, 673, -3735, 2599, 1206, 435, 1678, -1448, 3280, 1886, 935, 1957, -1076, 2983, 1328, 255, 1045, -2863, 1566, -630, -1661, -1194, -6422, -1276, -4564, -4630, -2668, -2473, -5988, -3824, -4078, -2334, -1148, -6469, -1571, -2292, -2235, -1289, -5561, -511, -1786, -1513, -1826, -5710, -14, -3038, -1143, -1943, -6828, 6, -9380, -1432, -2883, -7408, -558, -2845, -1815, -8192, -5871, -1991, -925, -2204, -3817, -4482, -4858, -1420, -2675, -1124, -4006, -7389, -4784, -2574, -812, -3650, -5472, -7912, -2470, -1980, -1889, -5067, -3479, -3441, -3903, -280, -5509, -2686, -5576, -4723, 199, -4550, -2943, -4654, -4348, -712, -2378, -3554, -2825, -3597, -3244, -867, -4142, -2356, -3092, -2935, -259, -4315, -3455, -3172, -1121, -393, -3763, -7445, -4038, -624, -1052, -2999, -8649, -5312, -716, -2066, -2893, -6163, -3686, -813, -3447, -3247, -5970, -2030, -804, -3866, -3203, -5465, -1772, -1001, -3182, -2877, -4578, -2606, -1740, -3638, -2863, -3094, -3701, -3378, -4195, -3417, -1825, -3735, -6310, -2845, -5531, -1286, -2517, -4606, -2580, -6492, -1435, -1390, -2545, -4089, -3215, -2314, -1072, -2380, -5394, -2340, -4071, -1687, -3900, -3863, -3151, -5988, -3208, -5360, -3098, -5630, -4597, -4795, -3817, -2967, -12319, -2807, -5638, -3137, -3140, -9585, -1914, -7371, -3344, -3683, -5879, -2235, -6225, -4242, -4901, -2847, -4478, -5299, -6814, -7426, -826, -6310, -7445, -7603, -8220, 71, -3704, -4896, -4254, -5942, 63, -3269, -2205, -3373, -5319, -536, -3954, -1660, -3665, -5002, -1393, -4800, -2724, -3232, -3665, -2205, -5970, -5176, -2031, -2599, -2107, -8393, -5444, -1426, -2375, -1440, -8086, -4149, -1504, -2529, -1431, -5768, -3788, -2152, -2610, -2323, -5091, -4327, -3485, -2952, -3671, -5871, -5127, -5906, -3843, -4340, -8615, -4207, -8363, -5214, -3827, -28777, -3175, -6928, -6745, -3289, -10442, -3254, -6480, -6719, -3471, -8827, -4442, -6204, -6800, -3954, -7523, -6173, -4784, -9284, -3893, -6590, -6870, -4226, -10138, -3785, -6376, -6773, -5158, -8220, -4134, -6640, -6732, -7819, -9149, -4733, -6653, -6899, -10069, -12319, -5139, -5942, -7484, -7865, -13738, -5273, -5353, -8247, -4115, -1217, -1712, 369, -2442, -2083, -1941, -2851, 474, -4053, -1533, -2184, -3225, -137, -6163, -1936, -2447, -3096, -1098, -4438, -2583, -5008, -3352, -1674, -2681, -2956, -7371, -4386, -1320, -1531, -3135, -2855, -5979, -676, -577, -3817, -2679, -7196, -238, -143, -6026, -5561, -7644, -40, -688, -6565, -4266, -6988, -80, -2787, -6399, -1821, -5592, -539, -5312, -15615, -1349, -5415, -1734, -2429, -5494, -2051, -8304, -4578, -805, -3615, -3213, -3609, -10704, -387, -2097, -2969, -955, -3321, -1073, -650, -1614, -438, -1816, -2465, -1057, -992, -1442, -1947, -2954, -9022, -2679, -3498, -1970, -2764, -199, -5924, -2047, -73, -560, 2556, 351, 586, 1562, 1676, 2931, 1882, 1790, 2018, 2694, 1170, 1523, 1804, 1111, 2643, -8086, -394, 860, -1328, 1838, -705, -2546, -795, -2574, 862, 729, -1582, -2835, -1761, -163, 56, -617, -4748, -2222, -2720, -1583, -416, -6045, -2931, -5569, -3592, -790, -6045, -2737, -1166, -6958, -1225, -5319, -2470, -295, -8865, -1251, -3964, -2666, -1258, -7912, -1126, -2514, -3563, -3571, -4532, -1563, -1660, -5202, -4847, -1441, -2992, -1781, -4774, -4611, -322, -4997, -3198, -2952, -5942, -603, -5394, -6214, -2440, -6411, -1917, -4901, -5584, -3543, -5793, -3729, -4390, -3415, -7264, -8582, -5234, -5014, -2235, -8942, -4395, -6310, -8549, -1569, -6054, -2170, -7603, -5002, -1463, -5195, -2267, -9149, -2964, -1978, -3792, -4644, -9022, -3714, -2735, -2034, -13365, -7146, -6480, -2779, -635, -5444, -6256, -2807, -2774, 63, -3879, -7247, -1273, -4226, -70, -3677, -11781, -1544, -8138, -1093, -4003, -6590, -2997, -3151, -3254, -4810, -3279, -4555, -983, -7247, -5014, -1831, -5227, -463, -7984, -4195, -1944, -6565, -1102, -6828, -4395, -3334, -12319, -2986, -7146, -5784, -3218, -7936, -6246, -4250, -7371, -2606, -6074, -4935, -1803, -10526, -3769, -6045, -3198, -607, -6256, -6565, -4455, -3161, -278, -4082, -6692, -3105, -4649, -535, -4199, -6045, -3027, -7842, -1292, -5279, -7264, -3944, -13049, -2367, -5202, -6457, -5299, -13738, -2007, -6445, -3586, -6828, -13365, -764, -10704, -2758, -8549, -6988, -510, -3187, -3717, -10704, -3529, -1626, -918, -6365, -9695, -1779, -4504, -310, -7819, -7050, -1367, -7264, -937, -7179, -7583, -2398, -5516, -2448, -7050, -12776, -5827, -4523, -3203, -6565, -5415, -8517, -4331, -3549, -6376, -3776, -5097, -5888, -4764, -6615, -4748, -4816, -28777, -2793, -6988, -10362, -5862, -6469, -875, -7796, -4006, -6035, -4331, -367, -10001, -1756, -4693, -3635, -1064, -8903, -1414, -3436, -3360, -3012, -6422, -2417, -2677, -3375, -6973, -6225, -4344, -2743, -3863, -14195, -7484, -5836, -3795, -4578, -7213, -5546, -6016, -5374, -4935, -4896, -3975, -5380, -5759, -4842, -3415, -4010, -5374, -5437, -4980, -2817, -5221, -6928, -5844, -5037, -3156, 12134, 7964, 12326, 10783, 8293, 11562, 8697, 11639, 10187, 7721, 9797, 9075, 9413, 8177, 5757, 6745, 8684, 5434, 3553, 1036, 2902, 8678, 4881, 1333, -516, 1823, 8693, 5646, 2537, 403, 3576, 7805, 5197, 2556, -1100, 5226, 5757, 2662, 4307, 2672, 6239, 1909, -1969, 4505, 4656, 6247, -1849, 2392, 2524, 5823, 5138, 2186, 1376, -1860, 6818, 4252, 3845, 103, 2758, 7621, 4605, 5084, 4192, 4503, 8004, 3809, 5968, 5470, 4831, 7712, 622, 6074, 5073, 4209, 6425, -6679, 4972, 2877, 2824, 3429, -5164, 2167, -4142, 1406, -8549, -254, 641, -189, 942, 154, 1927, 1996, 1319, 726, 1413, 2212, 1668, 1070, 265, 2423, 1716, 12, 453, -417, 3108, 2143, -2306, -3, -1206, 2777, 3224, -3244, -712, -1927, 1433, 3625, -1742, -2493, -1672, -996, 2959, 346, -6504, -480, -8304, 997, 1689, -1503, -141, -2200, -1954, 1909, 1933, -1517, 408, -2375, 799, 3496, -6666, 976, -2447, -1733, 3721, -3311, 504, -1611, -2677, 2714, -318, -471, 66, -2573, 362, 1279, -1383, 1364, -3261, -2514, 2050, -1263, 2640, -1199, -1031, 1912, -97, 3743, 202, 656, 674, 932, 4287, 22, 1240, -1732, 1284, 4099, -1622, 768, -1030, 436, 3021, -3128, -625, 1057, -2791, 1251, -2083, -3056, 2130, -644, 832, -490, -7230, 2697, 1892, 1129, 612, -2488, 2826, 2021, 417, 637, -804, 2143, -284, -901, -111, -1250, 718, -1130, -1436, -548, -2861, 1279, 1877, -849, -1431, -3532, 2499, 2692, -522, -2977, -6074, 2475, 2350, -1123, -951, -3923, 1304, 1465, -2312, -112, -1156, -249, 583, -3003, -787, -954, -804, 120, -3309, -1418, -2543, -593, 238, -3344, -2008, -5960, 15, 460, -2340, -5049, -6759, 779, 33, -949, -6469, -4242, 1171, -1478, -87, -2747, -2863, 889, -3827, -225, -1086, -2411, 233, -4278, -1848, 671, -3433, -26, -2569, -4119, 1954, -8549, -109, -1791, -2231, 2352, -4382, -702, -3220, -2050, 1745, -2109, -1562, -7050, -6343, -110, -2562, -2239, -2225, -3133, -2871, -2801, -4003, -1242, 602, -1289, 430, -6064, -2657, 1996, -53, 2403, -2204, -5879, 2294, -654, 3164, -1335, -5465, 1706, -2933, 2983, -3291, -4184, 44, -1375, 2118, -8138, -1631, -2612, 607, 1069, -3158, 0, -1480, 1163, 425, -3184, 521, 27, 762, 102, -6705, 352, 610, -302, -556, -12534, -36, 795, -1710, -2253, -10899, -454, 87, -2580, -6133, -5702, -1070, -2807, -3187, -15615, -3076, -1921, -5208, -5487, -11004, -2322, -2148, -2003, -4743, -9812, -2473, -1118, -1889, -4003, -4620, -1991, 36, -3135, -4230, -2651, -848, 485, -2877, -1197, -2191, -399, -140, -1445, 146, -2805, -40, -2277, -1081, 335, -3644, 906, -6885, -1855, 568, -3094, 1723, -2910, -586, -256, 7955, 9431, 7065, 269, 75, 7232, 8576, 6787, 1631, -256, 4806, 5686, 5683, 2868, -1796, 3336, 5812, 3812, 3894, -1495, 5162, 7834, 4017, 4552, 1094, 4830, 7956, 4750, 4861, 3850, 1106, 6837, 4338, 4962, 5514, 800, 5479, 3551, 4794, 5981, 3929, 4838, 3787, 3849, 5465, 3666, 3666, 4655, 627, 4800, 720, 1166, 5579, -280, 4901, 572, 944, 6224, 4326, 4821, 3216, 2376, 6230, 5673, 3729, 3832, 2642, 5575, 5501, 1086, 3499, 1583, 4508, 4214, -2672, 2922, -1994, 3126, 3119, 8, 2423, -5915, 1204, 3471, 1033, 1761, -1943, -24, 3162, 631, 1150, -714, 851, 1134, -949, 1902, 1243, 1468, 1570, -4369, 3274, 1994, 1620, 3885, -9479, 3924, 1147, 1842, 4298, -4270, 3576, 129, 2110, 3005, -2621, 2410, 1788, 2122, 1103, -1865, 1274, 2796, 2517, 2250, -1522, 116, 2496, 3813, 2815, -591, -3668, 1378, 4765, 2004, 1073, -4718, 1297, 4694, 198, 2431, -1400, 2068, 3266, -1733, 3082, -1815, 2156, -550, -1699, 2937, -4331, 1401, -6093, -469, 2000, -4669, -324, -1580, 643, 947, -1557, -3957, -2226, 1428, 1061, 608, -3518, -5509, 1763, 1542, 2110, -519, -4974, 1758, 1922, 3083, 211, -1113, 1653, 1831, 3528, -551, 1174, 1511, -43, 3505, -2153, 2361, 1082, -3671, 3210, -2075, 2579, 86, 1497, 2916, 341, 2010, 1027, 2721, 2776, 2116, 1060, 3151, 1887, 2684, 2497, 299, 3847, -784, 2382, 1115, -347, 2894, -1433, 1655, -4779, -1533, 159, -313, 523, -1456, -2114, 157, -871, -383, 966, -1124, 1575, -2049, -438, 1143, -1455, 1545, -898, -255, 324, -5465, 849, 421, -349, -858, -3003, 1005, 757, -693, -2019, 380, 1884, 276, -930, -2885, 1472, 2254, -768, -871, -3412, 1381, 2043, -2011, -793, -4635, 364, 1345, -2132, -786, -7752, -1583, -157, -411, -743, -5607, -5208, -3289, 990, -759, -3560, -8790, -5827, 1501, -1095, -2847, -4348, -2801, 1092, -2051, -2086, -4412, -1752, -335, -3856, -1374, -6577, -2093, -3007, -5654, -554, -1904, -3978, -5960, -4611, 637, 121, -8942, -5569, -3087, 1370, 16, -7542, -4541, -1814, 1094, -2973, -3982, -3354, -391, -429, -6016, -2182, -2138, 1014, -2211, -1538, -1358, -1084, 2016, -374, -1303, -1492, -436, 2426, 943, -672, -2139, -757, 2059, 875, 559, -1998, -2170, 494, -265, 449, -1837, -1204, -2453, -1385, -1280, -2470, 446, -954, -3457, -2635, -3062, 911, 1, -3814, -233, -2333, 724, -1087, 166, 1384, -1346, -17, -3606, 818, 2076, -1003, -1745, -3692, -859, 2164, -1148, -4644, 820, -1743, 1766, -1029, -9639, 3229, 533, 1085, -708, -874, 4011, 1923, 925, -1191, 2077, 3458, 2779, 1197, -3196, 3238, 1601, 2975, 871, 8368, 8649, 11217, 9089, 2759, 7908, 8822, 10713, 8645, 4004, 6361, 8682, 9264, 7484, 3829, 3050, 7720, 7245, 6263, 2746, 4369, 6465, 6179, 5962, 5013, 7078, 5942, 6877, 6620, 5809, 7743, 5666, 7310, 7571, 4972, 6510, 4500, 6983, 8385, 3025, 2319, 222, 6253, 8565, 1389, 4631, 1123, 5188, 7790, 1940, 6545, 3968, 3206, 6076, 1376, 6721, 4951, 2413, 3870, -2165, 6022, 5664, 4337, -24, 72, 4580, 5524, 4530, -49, 1007, 2039, 4130, 2161, 3787, 149, -2783, 2257, -2276, 4606, 1418, -10284, 1590, 2613, 4302, 3173, -8363, 838, 3291, 3659, 4100, -7708, -81, 2399, 2572, 4251, -4191, -1082, 909, -69, 4001, -3121, -2404, 161, -2764, 3990, -2610, -1734, 696, 1203, 4170, -2382, -1397, 1343, 2686, 4120, -2219, -3580, 1245, 2895, 3752, -1654, -9479, -172, 2030, 3066, -842, -2916, -4509, -654, 1982, -244, -1865, -5253, -6800, 166, -472, -228, -2414, 789, -2945, -2887, 1391, -1107, 2896, -760, -4669, 1701, 112, 3687, 2489, 765, 1401, 839, 3641, 4129, 2694, 2037, 1305, 2869, 4570, 3362, 2311, 1486, 1344, 3977, 3261, 1359, 1306, -1243, 2830, 2727, 1584, 920, -8220, 2106, 2319, 2777, -212, -2982, 993, 2216, 2533, -28, 17, -3172, 1340, 677, 3016, 933, -1860, -2178, -2514, 4559, 302, 906, -1548, -3811, 4762, -2580, 1320, 453, -1516, 3905, -2883, 544, -1645, -2470, 2311, 152, -1839, -1755, -2768, 859, 1208, -2805, 1956, 2011, 659, 1685, 626, 2727, 3104, 1089, 2186, 1663, 1896, 1687, 889, 2434, 1138, -647, -5097, -473, 2128, -377, -8192, 684, -2125, 1721, -1707, -3170, 1992, -1529, 2441, -2756, -1328, 978, -908, 3470, -2191, -883, -1999, -1055, 3681, -430, -1117, -3741, -1670, 2816, -52, -2023, -705, -2356, 1098, -1448, -3433, 1467, -2311, 187, -4980, -5067, 2617, -1736, -55, -3577, -6469, 2823, -1540, -1337, -2260, -5810, 2055, -1671, -2555, -1247, -3549, -59, -1492, -1813, 482, -2118, -5422, -679, -877, 1674, -2066, -6928, 259, -607, 2092, -3903, -6590, 744, -2232, 1816, -8615, -3498, 622, -5260, 741, -5951, -43, 421, 526, -1446, -8517, 1176, 1159, 2573, -5702, -4821, 908, 2032, 3070, -8903, -768, -686, 2148, 2411, -3515, 585, -3067, 1365, 545, -609, 695, -5202, 537, -3163, 1236, 374, -7113, 1267, -11115, 2140, 292, -1455, 1836, -3683, 2020, 391, 1074, 1342, -1850, 595, 377, 2525, 211, -986, -2414, 302, 3370, -620, -451, -1466, 393, 3637, -941, -732, -7, 729, 3411, -223, -2720, -287, 1064, 2898, 603, -6732, -1899, 1126, 2168, 1134, -4234, -3701, 909, 1051, 1792, -4837, -2735, 567, -326, 2142, -5208, -1141, -38, -755, 1773, -1419, -35, -2401, 1021, -1310, 2214, -734, -1046, 1163, 74, 2339, -108, 464, 995, 557, 1910, 256, 1384, 727, 460, 861, 786, 1638, 420, -148, -433, 848, 1214, -147, -2297, -672, 503, 272, -1359, -3692, -1173, 571, -866, -2984, -1435, -2510, 1166, -2139, -1773, -2351, 640, 1466, -3843, -179, -2956, 2624, 940, -2248, 163, 338, 3240, 331, 359, -603, 1445, 3055, 1130, 1453, -1188, 1111, 2416, 1872, 1213, -124, -178, 1485, 1970, -125, 468, -1385, 265, 1849, -1076, -142, -824, -1423, 1800, -827, -1193, 336, -4258, 1409, -1427, -650, 1351, -2988, -710, -1215, 416, 2394, 176, -5670, 1344, 1570, 3240, 1391, 1708, 2979, 2617, 3518, 1122, 3488, 3494, 2930, 3063, -448, 3412, 3022, 2164, 1990, -2592, 1725, 1634, 104, 907, -2585, -1732, -379, -2039, 152, -460, -2986, -2271, -920, -1273, 602, -3189, -2933, 222, -4464, 280, -6745, -1325, 733, -7603, -761, -6204, -55, 617, -7819, -1402, -2612, 224, -39, -6026, -2046, -805, -556, -965, -3798, -2642, 364, -2829, -2007, -3232, -2904, 971, -3247, -2889, -3337, -2813, 791, -1196, -3291, -3029, -1963, -700, -923, -3744, -2615, -2053, -4455, -1889, -2841, -3417, -4923, -636, -3083, -1414, -6153, -3876, 1858, -3523, -1351, -3177, -231, 2562, -3971, -2929, -1513, 890, 1812, -4997, -1550, -2245, 528, -386, -6225, 776, -7623, -1071, -1521, -7819, 1657, -4082, -3128, -616, -8903, 1601, -1009, -3269, -108, -4153, 939, 41, -1668, 287, -778, -379, 368, -191, 91, 964, -2500, 350, 587, -994, 1328, -3215, 340, 657, -3062, 306, -1489, 529, 10, -6299, -2411, -92, 619, -1182, -6928, -7371, 616, 356, -2316, -6565, -15615, 762, -194, -4331, -8220, -5043, 724, -1022, -9753, -3471, -1832, 663, -2186, -2314, -533, -711, 320, -2711, -301, 909, -782, -392, -2819, 108, 1408, -1240, -881, -3863, -496, 1299, -1441, -1028, -5145, -1819, 965, -2118, -1966, -4464, -4215, 864, -4266, -5139, -3843, -10799, 1222, -9812, -11945, -4180, -2918, 1641, -5979, -6365, -5615, -599, 1531, -3311, -7984, -5793, -119, 402, -2430, -8276, -3853, -1016, -2244, -2673, -5127, -2871, -2861, -5380, -2668, -4573, -3003, -3344, -4805, -1763, -6204, -3795, -2265, -4985, -1516, -9812, -4348, -1511, -4723, -2566, -3632, -5026, -1407, -3471, -5662, -1293, -6504, -2102, -2140, -6842, -448, -4774, -3944, -1350, -3906, -475, -2825, -7819, -1278, -2950, -890, -2205, -6093, -1735, -2419, -1524, -2390, -3866, -2319, -2043, -2599, -2626, -3546, -2411, -2305, -4172, -2416, -4688, -1973, -3526, -4826, -2057, -7542, -1689, -5002, -4274, -2111, -10210, -2322, -4486, -4311, -3189, -7752, -4748, -4097, -5531, -6504, -5670, -6143, -4929, -8485, -11356, -3801, -3299, -9238, 3235, -1902, 2421, -281, -4365, 2278, -5073, 1347, -2247, 385, 134, -2239, 163, -5871, 2801, -5576, -2430, -974, -1976, 3776, -934, -9812, -1749, 750, 3595, 1489, -2077, -1443, 1740, 2481, 1780, 87, -1497, 1524, 992, 272, 130, -2540, 224, -483, -4923, -157, -2887, -2162, -2630, -4108, 423, -2018, -5569, -3779, -1699, 562, -1319, -7113, -2305, -1973, -482, -1226, -4340, -2170, -1603, -2545, -2254, -1782, -4486, -334, -3671, -4089, 69, -8138, -297, -3876, -3735, 1142, -3133, -1600, -4378, -2064, 1357, -1610, -2348, -5103, -598, 705, -423, -2036, -6064, 479, -488, 1160, -3695, -2672, 1635, -1005, 2546, -3362, -512, 2897, -660, 3138, 23, -3, 3646, -692, 2680, 1304, -940, 3516, -2080, 1062, 1287, -2497, 2303, -9284, -1376, 345, -1213, -399, -787, -3074, -334, 340, -6235, 2101, -4532, 731, 1017, -3665, 3170, -6054, 1665, 884, -1263, 3003, -5670, 1733, -465, -434, 1425, -3479, 1125, -5853, 66, -3594, -2391, 197, -2545, 872, -2211, -2926, -792, 240, 1239, 624, -5195, -1469, 345, 758, 845, -4564, -1862, -1661, -366, -134, -1559, -2641, -6256, -1721, -965, 75, -2863, -1780, -2279, -163, 570, -2445, 247, -1578, 870, -191, -1463, 1078, -1081, 1164, -1765, 586, 1244, -565, 472, -182, 2058, 841, 456, -1163, 1455, 2495, 43, 1297, -2098, 1862, 1844, -686, 1570, -1537, 1555, -361, -1224, 1274, -1375, 1274, -10362, -1018, 535, -955, 1616, -1261, 475, -446, -188, 2302, 1276, 1669, -1429, -372, 2583, 2101, 2073, -2245, -2432, 2063, 1842, 1812, -2569, -9531, 558, 522, 1053, -1720, -9149, -2040, -2024, -170, -332, -6828, -3370, -3900, -1635, 590, -1777, -2311, -1914, -1857, 782, -68, -2460, -760, -1298, 254, -149, -4569, -642, -1302, -681, -1680, -8454, -1348, -2018, -824, -4723, -3782, -2827, -3261, 206, -10613, -2435, -5002, -3378, 828, -8086, -2610, -4968, -2524, 239, -4172, -2967, -2427, -2184, -1878, -3108, -2229, -861, -1519, -2374, -3521, -867, -620, -313, -913, -2350, 98, -2163, 597, -901, -191, 355, -5836, 905, -1969, 892, -116, -2500, 510, -3485, 959, -1134, -1562, -630, -4587, 113, -1826, -3038, -1367, -4199, -1613, -1599, -1941, -333, -3213, -4323, -1772, 531, 251, -2314, -9238, -3264, 1372, -247, -1668, -9238, -5678, 1039, -1707, -1516, -6640, -4219, -130, -4071, -1967, -6814, -2912, -1719, -8247, -3304, -7281, -2829, -3089, -8060, -5202, -5915, -3779, -3615, -6173, -4067, -3944, -4968, -3665, -5897, -2977, -2437, -3391, -4093, -5133, -2817, -1864, -1847, -4907, -3723, -2681, -2473, -1310, -5836, -2555, -2420, -4541, -1505, -6759, -2175, -2599, -5888, -2142, -7299, -2673, -2969, -4382, -2797, -6528, -3883, -2191, -4573, -1230, -335, 645, 429, 357, -3038, -152, -1412, 1329, -229, -4348, -47, -6083, 1594, -1982, -3309, 23, -4635, 1187, -3170, -1646, -1013, -1054, 323, -2394, -1340, -5879, 314, -334, -1773, -3301, -3720, 584, -752, -361, -3698, -1733, 174, -1032, 678, -538, -2670, -549, -864, 491, 78, -2460, -1508, -953, -411, -1808, -976, -2973, -2054, -21, -5844, -672, -4075, -4093, 532, -251, -1414, -1376, -2827, 120, 1505, -3189, 1322, -685, -1286, 2352, -4664, 2820, 588, -7162, 2829, -2247, 3202, 1410, -1640, 2225, -732, 2496, 1687, 1589, -426, -1668, 523, 713, 2413, 912, -3003, -1305, -3247, 1645, 2977, 1544, 1310, -897, -313, 2760, 3205, 2988, 1433, 430, 603, 3140, 3446, 1385, 2077, 454, 1813, 2967, -406, 2819, 1991, 766, 1707, -4138, 3058, 1834, 1570, -371, -9149, 2707, 181, 2282, -3537, -4693, 1413, -2916, 2590, -5810, -1620, -276, -6732, 2826, -6988, -743, -284, -6786, 2924, -9193, -1535, -798, -4013, 2843, -7865, -2470, -2460, -1686, 3096, -2430, -1810, -1476, 143, 3503, 435, -1444, -855, 1322, 3261, 1347, -1227, -1814, 1695, 1779, 552, -487, -3208, 1165, -2364, -2550, 436, -2545, -395, -3334, -6528, 641, -1313, -2999, -573, -3005, -353, -1292, -3947, -842, -2326, -2500, -3001, -2988, -2835, -2207, -2135, -5127, -2670, -4433, -2040, -279, -4683, -2328, -3615, -1618, 769, -6732, -1543, -3242, -848, 1473, -5429, -742, -2061, -292, 1818, -2673, -499, -46, -804, 1349, -1369, -1100, 1304, -3738, -24, -104, -2344, 1780, -2843, -290, 1044, -4759, 1564, 381, 749, 1582, -6256, 1045, 1368, 939, 1323, -1788, 626, 1164, 359, 375, -843, 32, 220, -337, -773, -1428, -1186, -939, -1168, -2023, -988, -1232, -1241, -2205, -3378, 86, -133, -473, -340, -2383, 686, -380, 89, 1460, -1666, 1007, -2470, -263, 1945, -2977, 793, -6093, -1781, 1250, -6973, -227, -5599, -4211, -789, -2994, -2270, -3792, -6528, -5031, -938, -6376, -3144, -7371, -3498, -517, -12534, -4211, -7034, -1516, -1733, -7445, -4654, -13365, -1254, -8112, -6469, -3769, -3266, -1563, -3103, -5879, -4369, -751, -1213, -395, -6183, -5718, -361, -640, 288, -7371, -6332, -1802, -691, 277, -10704, -5260, -7523, -1131, -162, -10362, -3227, -4997, -1278, -1484, -5662, -2720, -2657, -1381, -2382, -4164, -4688, -2956, -2107, -587, -4153, -9238, -4738, -4078, 349, -5139, -2992, -6310, -8247, -127, -6504, -1722, -7213, -5103, -2330, -6565, -2236, -12534, -3509, -4890, -5164, -3886, -7081, -3656, -2385, -4123, -6492, -4258, -4416, -1680, -4295, -13365, -3482, -4455, -2478, -5599, -7562, -3662, -3656, -4215, -3866, -6153, -4078, -2550, -6504, -1831, -7113, -4361, -1401, -10526, -1369, -9064, -4327, -696, -12776, 10974, 5133, 12179, 10614, -15615, 10339, 6509, 11570, 10083, -5710, 8267, 7039, 9596, 8403, -3137, 3870, 5751, 5533, 5286, -2242, 966, 3967, -1683, 389, -1745, 3039, 4025, 615, -2125, -725, 3074, 3004, -787, 404, -66, 2859, 647, -159, 1152, 251, 3039, 1753, -97, -867, 1275, 3871, 2657, 291, -122, 2316, 4697, 2636, 1038, 3007, 2920, 4654, 3017, 300, 4325, 3402, 3192, 3945, -3589, 4568, 3727, -441, 4302, -1647, 3895, 3687, 164, 3558, -93, 2359, 3268, 1703, 1790, -2194, 715, 2426, 1429, 682, -1157, 245, 689, 605, 508, 1833, 125, -4669, 152, -366, 2668, 92, -1704, -620, -1566, 2372, 146, 1236, -1799, -3266, 1346, 211, 1634, -1900, -5942, -366, 469, 661, -1627, -4021, -2935, 903, -746, -1696, -2648, -3751, 1215, -1950, -1262, -2507, -3151, 1423, -4901, -391, -1911, -4644, 1646, -2849, -174, -1012, -8423, 1633, -298, -1270, -1283, -7389, 1189, 127, -3923, -3889, -4728, 492, -991, -6256, -5726, -2366, 48, -3744, -9585, -2028, -1419, 43, -9064, -8485, -1286, -1956, 16, -12534, -5214, -2153, -4774, -291, -6800, -5599, -4464, -7984, -796, -3540, -8165, -7752, -2726, -1325, -1898, -5380, -5988, -1576, -1583, -1682, -2815, -3597, -2080, -1550, -3076, -1475, -1975, -3441, -1987, -4743, -1014, -1593, -4500, -3850, -2366, -1427, -3124, -5561, -9585, -850, -2361, -12123, -8165, -5554, -393, -2359, -3707, -28777, -3741, -652, -1657, -2057, -10284, -4142, -1452, -1378, -3018, -11629, -6800, -2621, -1553, -6354, -12123, -7562, -3580, -2061, -3975, -8138, -4816, -3641, -2711, -2571, -7264, -4378, -3311, -3114, -3018, -6445, -5374, -3189, -3012, -4601, -4550, -7960, -3349, -2900, -6590, -2473, -17034, -3729, -3422, -8086, -1169, -5862, -4258, -4679, -8304, -848, -2760, -5067, -5422, -7066, -1276, -1302, -5997, -5444, -5465, -2008, -968, -6173, -6376, -4134, -2722, -1477, -5576, -7774, -3142, -3490, -2425, -4611, -6354, -2621, -4759, -3401, -3695, -4748, -2914, -7081, -4038, -3577, -4331, -4486, -7097, -3618, -4769, -5176, -7335, -5768, -2735, -6759, -5607, -7542, -5906, -2531, -5176, -4395, -6365, -6842, -3375, -3425, -4168, -5176, -7603, -4985, -2557, -5353, -4447, -7912, -5702, -2040, -6007, -4191, -6469, -6870, -1432, -4842, -2811, -4688, -10799, -782, -3656, -1336, -4203, -7389, -400, -2703, -899, -5312, -6692, -471, -2238, -1490, -5638, -8220, -1081, -2448, -2841, -3632, -9064, -1976, -3158, -4847, -3301, -7050, -2688, -3677, -8903, -5401, -4311, -3615, -3452, -6246, -6692, -2340, -4504, -3056, -3455, -3665, -1210, -3301, -3276, -2726, -3362, -831, -2499, -4957, -3393, -5339, -1122, -3126, -10613, -5103, -6590, -1967, -5487, -9380, -6666, -4278, -3686, -9753, -8220, -7034, -3373, -8138, -10704, -11004, -6235, -2895, -8034, -5374, 1449, 3197, 8375, 3840, -7960, 766, 2347, 7777, 4367, -4940, -1927, -133, 5842, 4880, -1305, -1580, 693, 2403, 4831, 1131, 2049, 2339, 1975, 4742, 2473, 3660, 2578, 2608, 5005, 2976, 4273, 2325, 1635, 5258, 2788, 4387, 1910, 339, 5076, 1996, 4280, 63, 1772, 4314, 901, 3961, -3168, 3391, 3087, -510, 3944, 1918, 4603, 1415, -3362, 4884, 3749, 5577, -1033, 0, 5577, 4087, 5888, -1456, 2902, 5178, 3504, 5074, -1015, 4127, 3391, 2664, 2516, -2295, 4236, 613, 2383, 76, -3089, 3453, 332, 2188, 2452, -3065, 1995, 160, 1504, 2824, -3989, 165, -862, 661, 1778, -4319, -1510, -815, 798, 159, -3383, -2204, 245, 1772, -533, -3182, -1799, 1191, 2324, -12, -5408, -1462, 1702, 2092, 276, -9812, -1961, 1717, 1328, -549, -6321, -2754, 1152, 741, -1920, -2046, -3163, 25, 663, -727, 677, -3247, -632, 751, 513, 1750, -1624, 202, 608, 711, 1575, -453, 946, -73, 120, 269, -470, 832, -861, -948, -2514, -1427, -582, -556, -1909, -5183, -3452, -5221, -79, -2022, -2472, -8718, -3471, -247, -1626, -1334, -4918, -1045, -310, -1642, -1216, -1966, -1503, 105, -2305, -1482, -828, -4853, -154, -3242, -1581, -565, -7113, -1817, -3720, -1001, -713, -5020, -4810, -3606, -92, -903, -4223, -4625, -3444, 437, -1189, -2597, -3393, -3474, 438, -1976, -1954, -2776, -3592, 166, -3103, -2003, -3360, -3532, -40, -1821, -2192, -6445, -3184, -114, -146, -2861, -4361, -3352, -154, 150, -4352, -1705, -4874, 68, -1157, -5183, -974, -8827, 680, -5139, -4847, -1104, -7484, 1084, -6745, -5735, -1184, -4311, 786, -4790, -7542, -1326, -2522, -276, -7097, -5702, -2488, -1661, -1495, -6194, -4985, -4523, -1326, -2377, -3401, -6492, -3203, -922, -4282, -3286, -8333, -2480, -599, -5037, -4869, -5121, -4142, -968, -2825, -3961, -3695, -6719, -2038, -2608, -2208, -3889, -3701, -2312, -4112, -1963, -5333, -3388, -1825, -5960, -2990, -4464, -4348, -2090, -6640, -5067, -2737, -3632, -3326, -5164, -7130, -2590, -3025, -4869, -3225, -5897, -4238, -3603, -6299, -3054, -4336, -7687, -4748, -10442, -4425, -3624, -4885, -4769, -7752, -4769, -3391, -3457, -3632, -5509, -4513, -3853, -3773, -3074, -6083, -6163, -6225, -5599, -3151, -8165, -5260, -8942, -7644, -2745, -5380, -3471, -4013, -5480, -2030, -2992, -2743, -2835, -3820, -1931, -1673, -1823, -3580, -3549, -2599, -1216, -1275, -6973, -4733, -3964, -1741, -1987, -6528, -7281, -5422, -3054, -4659, -3083, -5853, -4138, -3222, -4649, -1944, -3999, -2292, -2743, -2148, -1918, -3523, -1709, -3362, -1462, -2440, -3837, -2587, -4790, -2038, -3140, -4348, -5569, -6194, -3999, -3274, -4800, -8865, -9936, -6354, -2197, -5008, -5183, -8903, -3866, -1736, -4885, -3671, -5183, -2751, -2791, 3552, 2546, 6803, 2428, -607, 2619, 2288, 6397, 3673, 1962, 1236, 1293, 5440, 4737, 2974, 2997, -807, 4409, 4499, 1728, 3993, -904, 2855, 2610, -2696, 3693, 1618, 148, -2758, -1072, 2198, 2870, -14, -1298, 672, -1000, 2921, 490, -235, 318, -5979, 1866, 38, -1825, -2166, -2345, -23, 446, -2661, -3222, -109, -1863, 1191, -1836, 1712, 1648, -2407, 1575, -1586, 3739, 2695, -1357, 1647, -262, 4435, 2996, -539, 1369, 1681, 4231, 2582, 322, 530, 2755, 3487, 1325, 1291, -1313, 2575, 2805, -1219, 1520, -3701, 933, 2599, -6679, 799, -839, -231, 2571, -11781, -520, 673, 1176, 2401, -6399, -1760, 423, 1187, 1965, -3137, -2926, -1317, -990, 1329, -3036, -4361, -3415, -15615, 606, -4282, -2655, -4123, -2158, 219, -583, -251, -4382, -323, 477, 922, 934, -3846, 267, 371, 410, 1118, -3665, 532, -796, -2006, 247, -3266, 866, -2875, -3342, -2342, -1843, 1332, -3798, -2236, -7865, -941, 1451, -1651, -2768, -3757, -1011, 825, 1, -4250, -2979, -1875, -568, 486, -4278, -3927, -2897, -2071, 45, -3409, -5836, -3360, -2050, -1226, -3067, -7819, -3554, -848, -4138, -2843, -7230, -4180, -67, -7264, -2155, -5592, -4885, -265, -2637, -1579, -5103, -3501, -1388, -1746, -2314, -5480, -1786, -1016, -3496, -6026, -5853, -1022, 890, -7687, -3031, -4523, -960, 1892, -1701, -917, -2473, -996, 1951, 293, -1295, -1526, -839, 1363, 995, -3788, -1756, -767, 320, 890, -4698, -3094, -832, -1592, -26, -3615, -5292, -838, -4963, -1790, -4130, -3957, -792, -3010, -3010, -4550, -1954, -1098, -1471, -2610, -4082, -1511, -2256, -771, -2268, -3947, -2411, -5109, 87, -1683, -4270, -3957, -8393, 608, -1141, -4890, -4049, -2707, 521, -784, -5710, -3754, -679, -22, -643, -7179, -4112, -211, -1247, -1275, -10613, -4207, -1117, -4455, -3201, -7464, -2971, -3900, -6045, -3479, -3840, -1497, -6163, -2075, -1089, -2219, -770, -3083, -1019, 77, -2185, -1022, -1958, -1396, 53, -4093, -2083, -1809, -2891, -1158, -8423, -3108, -2282, -4509, -3430, -4433, -3665, -3463, -4142, -3695, -3512, -4303, -6093, -3259, -2548, -5208, -4378, -9812, -2316, -2468, -14195, -4003, -5818, -1296, -3237, -4021, -4180, -5279, -531, -4097, -1752, -4901, -8333, -295, -3866, -1062, -5970, -9695, -686, -3284, -1441, -7542, -5776, -1918, -3031, -2626, -10442, -5031, -4874, -3140, -3804, -7708, -4017, -5561, -3961, -4774, -4779, -3117, -2331, -5853, -7603, -3964, -3577, -1508, -8393, -11945, -5170, -6565, -2225, -9380, -6343, -6602, -7066, -4161, -7819, -4447, -4266, -4303, -6773, -7247, -3220, -3618, -4831, -12123, -6480, -2613, -3441, -5784, -7623, -4723, -2512, -2097, -3242, -3937, -4482, -2564, -1195, -2500, -3137, -5374, -2617, -1416, -3597, -4442, -4203, -10362, -6153, -2210, -5827, -2538, -8304, -8549, -1947, -7034, -1447, -7389, -10704, -2833, -9812, -1377, -6310, -6225, -5702, -8086, -1451, -5247, -4853, -11629, -4754, -1137, -4654, -4559, -9064, -2745, -972, -4644, -5008, -5592, -2411, -985, -5387, -6759, -2653, -4199, -622, -7484, -12534, -1134, -28777, -234, -10210, -8192, -774, -5031, -609, -7146, -6958, -1491, -3698, -2265, -5516, -9106, -3367, -4723, -6653, -4046, -12776, -6480, -8454, -5694, -3119, -7960, -10284, -6958, -2222, -3635, -7019, -11488, -4006, -849, -5067, -8165, -10210, -2893, -477, -4698, -10704, -9479, -3051, -798, -5451, -28777, -9936, -4980, -1666, -17034, -6759, -10284, -11629, -3163, -5067, -3126, -4918, -5615, -4991, -2438, -2012, -2438, -4303, -4211, -1262, -2540, -1617, -5273, -2624, -861, -4532, -1962, -7317, -2075, -1135, -7687, -3441, -7484, -2468, -1991, -7097, -7644, -5662, -3618, -3324, -6064, -7583, -3220, -5145, -4858, -5451, -3795, -1769, -6745, -5810, -3701, -2984, -1371, -10362, -6602, -2211, -3644, -1822, -7353, -8333, -1469, -5509, -3040, -4523, -7583, -1289, -7708, -4985, -3804, -5735, -1540, -9936, -7562, -4064, -5195, -2403, -8192, -10362, -4042, -5933, -4550, -4592, -10899, -3367, -8393, -9193, -3259, -8165, -3020, -8790, -5502, -3438, -5502, -3766, -5960, -3674, -4795, -3496, -6786, -5183, -3007, -6540, -2176, -10613, -6422, -2895, -7426, -1522, -5279, -6988, -3689, -7389, -1313, -4348, -3391, -6074, -7774, -1412, -4442, -1439, -7034, -9429, -1988, -3968, -693, -4880, -9064, -3375, -3668, -825, -4093, -8942, -5599, -4733, -1587, -4323, -11356, -7281, -5694, -2637, -5592, -5145, -7774, -3218, -3923, -7687, -2138, -9284, -1734, -6445, -8683, -714, -15615, -1277, -10362, -8060, -463, -10210, -1379, -7130, -7213, -1375, -7687, -1668, -7888, -8304, -3415, -6640, -1912, -12534, -11356, -6016, -4997, -2139, -6800, -7113, -6928, -3096, -2752, -5234, -5401, -4555, -2047, -3903, -4504, -4616, -3409, -2040, -4541, -4168, -4191, -3543, -2809, -4270, -5569, -4460, -3306, -3992, -4211, -9284, -6163, -2253, -4826, -5394, -4640, -13049, -1625, -3801, -8086, -2997, -8942, -1742, -2637, -4067, -2887, -7081, -2728, -2027, -2256, -3463, -6705, -4929, -1902, -2330, -4238, -7004, -9873, -2606, -3978, -4951, -10138, -9064, -4606, -7912, -5055, -11945, -5979, -8192, -12776, -4606, -7774, -5026, -14784, -9022, -4583, -7335, -4853, -10799, -10138, -5576, -7842, -4754, -9331, -9873, -6653, -7842, -4703, -17034, -7179, -5862, -6399, -4929, -8138, -5988, -5422, -5306, -5170, -5472, -6026, -6214, -4997, -5360, -5422, -8615, -8615, -4583, -5726, -7687, -8009, -12534, -3744, -5933, -11115, -4157, -9331, -3092, -5546, -9380, -2975, -7912, -2829, -4974, -10284, -3168, -8192, -2883, -5097, -7752, -4357, -8485, -3020, -6745, -6035, -6445, -6958, -3182, -7687, -6163, -8982, -6103, -3644, -5531, -7464, -9331, -5678, -2807, -4495, -3326, -5183, -10362, -2509, -5554, -5646, -3329, -4527, -2958, -7888, -10069, -1869, -1568, -4486, -9873, -10799, -2146, -470, -8615, -11781, -8754, -3540, -470, -6054, -10138, -5569, -3001, -1149, -2688, -6422, -3101, -2306, -2075, -1407, -3671, -1899, -3344, -3337, -1431, -2316, -2138, -4473, -6133, -2612, -2375, -4035, -3259, -6376, -4486, -3996, -6267, -3085, -3264, -5115, -8138, -5189, -4545, -2274, -5049, -13365, -4262, -8276, -2774, -6434, -8276, -3449, -7034, -4569, -5776, -6288, -2651, -4315, -4630, -3281, -4134, -2014, -3490, -2548, -2696, -2383, -1828, -3452, -1414, -3920, -1431, -2363, -2319, -1207, -7066, -1259, -3863, -895, -1834, -8683, -1945, -6267, -589, -3151, -7687, -3889, -5524, -1604, -4980, -7644, -7299, -3401, -2783, -7583, -8112, -5494, -2427, -1750, -14784, -6602, -3896, -2526, -1144, -9531, -4795, -3417, -3707, -1616, -5888, -4495, -3798, -5546, -2303, -4149, -5718, -5784, -5615, -2473, -3662, -7562, -8865, -4805, -3242, -4408, -6256, -5353, -4532, -5810, -6469, -5189, -4060, -4433, -13738, -10899, -5286, -3893, -4180, -15615, -9812, -6035, -3609, -4024, -8549, -5292, -6173, -2653, -4541, -4644, -3644, -5073, -1612, -5801, -3404, -3471, -3978, -1255, -6123, -3798, -4149, -3833, -2344, -4100, -5339, -4980, -5121, -7445, -2521, -6376, -5531, -7264, -4723, -2119, -5539, -6183, -6376, -2442, -2383, -4145, -7408, -5085, -3147, -1805, -2809, -5073, -3957, -7445, -888, -1777, -2801, -3827, -7464, -804, -1374, -1879, -5933, -4738, -1888, -1745, -1844, -9380, -4774, -4853, -2701, -2369, -5103, -5678, -11004, -3465, -3476, -4234, -6640, -4946, -3512, -5862, -4620, -10362, -3062, -3476, -9284, -4997, -8615, -2197, -3540, -4416, -4573, -4963, -2325, -3686, -1999, -3474, -4518, -3896, -4149, -665, -2825, -6343, -6732, -5266, -92, -3147, -14195, -4831, -7774, -307, -4532, -8942, -3543, -11781, -1481, -6528, -6064, -3741, -8304, -4311, -8086, -4295, -5026, -4968, -8363, -10442, -3383, -6988, -3089, -4153, -10899, -3507, -9531, -2644, -2912, -8942, -5020, -9149, -3689, -2510, -9331, -9193, -5735, -6528, -1839, -10526, -6332, -4918, -6958, -1345, -7004, -4282, -6083, -5097, -1682, -4918, -4425, -8582, -4408, -3094, -4010, -6800, -7912, -3433, -5915, -3615, -28777, -8247, -2378, -10526, -3163, -6988, -13738, -2036, -7912, -2605, -5458, -5776, -2507, -5227, -2369, -5374, -3249, -3433, -3388, -2819, -6267, -2448, -4067, -2142, -4127, -8754, -2724, -4180, -1590, -5266, -13049, -3937, -4017, -1875, -5339, -6928, -6516, -3723, -3239, -6745, -4874, -13049, -3487, -6553, -13738, -4149, -10613, -3824, -12534, -7066, -4180, -8790, -5408, -5718, -5853, -4532, -8165, -9873, -3612, -7819, -4940, -8086, -9753, -2531, -14195, -5353, -9479, -8827, -2228, -6288, -5915, -13738, -13738, -2887, -4669, -6856, -11629, -9193, -4659, -4569, -8683, -9812, -7445, -2651, -2851, -5401, -4168, -3496, -2574, -6246, -5429, -1510, -4963, -2764, -11781, -5710, -402, -8165, -3218, -5827, -5292, -525, -4708, -2366, -3776, -3498, -1852, -3714, -1358, -2694, -2216, -4578, -5067, -1531, -2730, -1665, -4728, -12123, -3014, -4082, -1831, -3025, -6310, -5827, -5494, -2228, -2522, -4555, -9193, -4997, -1787, -2619, -5422, -7644, -5333, -1144, -2908, -7730, -5662, -6565, -1139, -3618, -6026, -3940, -6365, -1816, -6480, -4532, -2347, -5768, -3299, -7299, -3493, -1326, -5480, -5951, -2170, -2601, -1012, -5208, -5924, -677, -2071, -1429, -5726, -4545, -934, -1721, -2573, -9022, -4669, -3047, -1401, -4395, -10284, -4331, -9284, -1276, -5818, -6321, -3365, -5170, -1650, -5208, -6842, -3549, -3194, -2776, -4352, -14784, -4078, -2419, -3840, -4527, -7708, -2091, -1914, -2960, -6870, -6800, -401, -1620, -1995, -11781, -9639, 142, -1557, -1474, -4527, -5827, -284, -1511, -1121, -2282, -3726, -1313, -1456, -1343, -1242, -3735, -1643, -1672, -2497, -1083, -5031, -950, -2163, -2130, -2026, -4703, -581, -2521, -537, -4713, -3244, -871, -2573, -167, -8683, -2751, -2004, -2424, -558, -6016, -3027, -4654, -2225, -245, -6256, -3261, -7665, -2297, 176, -9284, -3184, -4161, -2778, -287, -5437, -3723, -2962, -3656, -1282, -2713, -6123, -3054, -5312, -1651, -1511, -8304, -4172, -8165, -1834, -1285, -3677, -7752, -8827, -2931, -1833, -1797, -8423, -7484, -4748, -3051, -1197, -3785, -6759, -3360, -4408, -1485, -2270, -6422, -1912, -4509, -1774, -1575, -6173, -2083, -4344, -549, -1022, -4180, -3971, -5091, 589, -576, -2121, -7408, -6074, 661, -530, -1054, -7562, -5576, -424, -1143, -1001, -9479, -5584, -2398, -2606, -1882, -11488, -8086, -3455, -4951, -3135, -6666, -12776, -2883, -6133, -3863, -5638, -8304, -1753, -4455, -4518, -5091, -11004, -903, -3900, -4219, -4625, -10069, -860, -5494, -2472, -4669, -7562, -1756, -12534, -1041, -4145, -11945, -3763, -4541, -302, -3560, -6692, -6773, -2211, -329, -4583, -3577, -8517, -1398, -1249, -8549, -2731, -10362, -1701, -3254, -4674, -2941, -9753, -3074, -5494, -2747, -3436, -8138, -4679, -4365, -2937, -3526, -7281, -5862, -3992, -5247, -3201, -3893, -6653, -6183, -8517, -2817, -2072, -4215, -11781, -4683, -2528, -1878, -2902, -4311, -3447, -2253, -2690, -2971, -2300, -3665, -2051, -2855, -4021, -1583, -5026, -2118, -2545, -5576, -1572, -7371, -2589, -2406, -6278, -1963, -8363, -3465, -2069, -6246, -2642, -5374, -4226, -2273, -7542, -3876, -2853, -4842, -3306, -13365, -6153, -1499, -6973, -3985, -7523, -10613, -1173, -14195, -4698, -5879, -9531, -1611, -6103, -8485, -6577, -6113, -2189, -4611, -7097, -9193, -4601, -2317, -4821, -3999, -8034, -4429, -2361, -6256, -3476, -5970, -5387, -2823, -9585, -4460, -5793, -7196, -4157, -10362, -6800, -7353, -8615, -7687, -5592, -8683, -11629, -7865, -7665, 11108, 15036, 9902, 5969, 8435, 10914, 14606, 9535, 5610, 7636, 10259, 13280, 8492, 4280, 4800, 9422, 10943, 6856, 1240, -2483, 9204, 7308, 4388, -3235, 1828, 8919, 3366, 1632, -1922, 1982, 7442, 5799, 2713, -651, 980, 5082, 7154, 2829, 935, 942, 6232, 7188, 1098, 1365, 1948, 7247, 6255, 1483, 1173, 2999, 6938, 5352, 3522, 1440, 3995, 5610, 5482, 4188, 2033, 4887, 3614, 5927, 3668, 2194, 5521, 584, 6675, 1852, 1440, 5831, -8423, 7046, -2606, -424, 5716, -1380, 6420, -4464, -2599, 5131, -1733, 4583, -901, -2407, 4112, -1003, 1460, -264, -729, 2474, 691, 817, -635, -73, -609, 1211, 2572, -1883, -1241, -9936, 1423, 3290, -1665, -5759, -5026, 1054, 3031, 860, -7389, -6113, -782, 1510, 2398, -6299, -6828, -5353, -1940, 2896, -10442, -4161, -1883, 801, 2600, -5380, -4071, -463, 3135, 1766, -4195, -6516, -1500, 3716, 680, -4149, -13365, -3989, 2859, -453, -3299, -7819, -3741, 332, -1673, -2477, -8034, -13365, -2952, -3846, -2815, -5897, -589, -1263, -8138, -5776, -3362, 2448, 594, -3504, -7146, -2363, 3450, 1412, -1259, -2282, -1884, 3247, 756, -2, -934, -848, 2118, -2114, 877, -981, -23, 214, -5988, 1408, -1870, -234, -2158, -1113, 1581, -3126, -1725, -4013, 441, 1466, -3629, -3014, -5208, 718, 1164, -2359, -1782, -7081, 44, 663, -1002, -1315, -7912, -1241, -240, -489, -2153, -4885, -2417, -1843, -955, -4250, -2749, -3383, -4390, -2438, -6653, -1816, -4049, -7523, -4831, -5678, -2068, -3551, -7162, -7335, -4180, -3393, -3331, -4664, -7842, -3417, -5472, -4042, -3049, -4907, -3252, -6143, -4980, -2152, -3254, -3449, -4104, -6354, -1642, -2969, -3523, -2670, -11115, -1391, -3680, -3133, -2073, -7888, -1386, -4935, -2653, -2008, -4331, -1605, -6411, -2569, -2317, -3225, -1934, -7371, -3098, -3040, -3999, -2350, -6194, -4112, -4215, -7708, -2956, -5176, -5279, -6310, -8754, -4093, -5253, -6928, -11629, -5646, -6246, -6388, -10284, -6321, -4890, -10526, -7464, -12776, -4703, -4616, -8942, -6973, -13365, -4784, -4601, -6123, -6666, -10799, -3365, -4901, -4890, -7066, -6842, -1870, -5615, -4578, -8304, -5694, -1904, -6399, -5227, -11356, -6035, -3769, -5997, -7281, -9936, -5654, -9639, -5299, -8942, -7281, -4278, -8454, -6133, -8165, -7371, -4130, -7665, -7912, -9479, -10069, -5844, -10210, -6399, -9479, -8790, -12123, -4429, -6204, -7445, -6732, -9639, -1990, -7603, -7146, -6469, -8517, -1330, -7665, -7936, -6719, -9936, -2139, -5367, -8903, -6615, -9479, -4683, -4164, -9753, -6602, -7888, -9284, -4195, -11781, -7542, -6365, -5915, -4532, -17034, -8517, -5170, -3999, -4331, -8517, -6434, -5091, -4108, -4184, -6299, -4573, -6422, -5623, -5260, -5662, -3557, -9284, -6278, -9873, -6064, -3254, -11945, -5979, -8982, -7146, -3795, -11356, 7346, 1030, 4464, -12776, 6407, 6665, -1088, 3741, 2106, 6164, 4364, 1993, 1345, 3857, 5496, 1284, 4528, -2681, 3721, 4783, 3733, 4839, -1622, 2856, 4553, 5041, 3469, -864, 2763, 4348, 5302, 546, -810, 3205, 3649, 5070, 1732, -354, 3293, 2757, 4538, 4194, 1158, 3094, 2563, 3228, 5489, 3174, 2986, 3516, 2562, 5913, 4779, 3166, 5004, 5725, 5512, 5750, 3532, 6105, 7544, 4199, 6060, 3726, 6505, 7944, 1810, 5627, 3153, 6212, 7105, -1287, 4297, 784, 5368, 4947, -2125, 1953, -4997, 4230, 1269, -2118, -881, 1771, 3053, -1202, -3259, -2867, 3564, 1792, -908, -2815, -4997, 3953, -231, -569, -514, -6973, 3645, -4728, 873, 382, -5429, 3074, -1582, 1973, 239, -1874, 2533, 100, 2028, 55, 79, 1891, -702, 1148, 898, 817, 513, -4230, -68, 2067, 650, -1868, -3409, -704, 2675, -138, -1249, -2279, -801, 2473, -1144, 212, -4278, -1384, 1477, -1967, 688, -8865, -3850, 209, -2587, 414, -5319, -3801, 34, -3170, -1018, -6814, -1080, 633, -3594, -5240, -5630, -1246, 1007, -3227, -2851, -2353, -5906, 1011, -1982, -62, -1427, -2010, 733, -754, 838, -1663, 798, 344, -266, 609, -2386, 1455, -24, -885, -784, -3168, 1090, -282, -3023, -3883, -3051, 228, -322, -7603, -4810, -2347, -897, -449, -15615, -2098, -2375, -2336, -1301, -8517, -621, -3301, -3659, -3203, -4997, 351, -3430, -3551, -4853, -3920, 980, -2036, -2698, -3232, -3870, 1142, -1050, -2136, -1216, -3168, 779, -988, -1918, -419, -2175, -38, -1907, -1711, -1141, -1970, -1097, -3574, -1369, -3999, -2659, -2160, -4311, -1197, -6958, -3920, -3331, -3744, -1381, -4703, -5145, -4968, -3717, -2034, -5662, -6299, -6054, -4774, -3597, -7281, -8192, -4500, -7066, -7445, -4901, -10526, -3324, -8683, -8009, -4601, -8165, -3189, -8086, -5319, -6035, -6899, -3515, -7665, -4816, -4587, -7730, -3314, -7708, -5299, -2776, -13738, -2440, -9284, -6653, -2396, -8363, -1484, -15615, -5862, -2859, -6214, -724, -6842, -3989, -3378, -6565, -286, -4912, -3808, -3923, -8942, -328, -5818, -6173, -5346, -9106, -998, -8865, -10001, -8304, -7665, -2295, -3635, -4659, -7687, -8138, -3501, -1721, -3485, -5367, -9149, -3900, -1484, -3373, -4790, -8582, -4625, -2366, -3062, -6235, -8485, -6800, -3748, -2465, -12776, -8247, -11232, -4545, -2345, -6225, -6332, -8718, -4713, -3249, -4412, -4555, -6679, -4495, -5776, -4616, -3683, -5319, -4307, -10704, -5979, -3554, -4184, -5031, -8393, -6103, -3951, -3490, -7865, -6786, -5408, -4625, -3551, -13738, -6083, -6354, -5266, -4486, -6958, -6267, -8582, -5988, -5531, -5387, -6973, -6016, -7523, -4616, -4713, -7066, -4940, -10069, -3532, -4578, -7097, -5784, -9380, -3301, -5662, -8138, -8363, -9479, -3933, -10704, -8754, -8790, -10526, -5279, -7960, 1875, 1724, 3700, 3654, 5666, -1330, 1474, 4377, 5065, 5505, 1877, 1044, 5653, 6627, 5593, 4579, 1016, 6246, 7116, 5737, 4478, 542, 5706, 6436, 4948, 2431, -1265, 3984, 4567, 2879, 1205, -512, 1353, 1792, 371, 2124, 888, -1480, -779, 830, 1858, 794, -2540, -2176, 3201, 2063, 23, 1239, -2311, 4719, 3801, -450, 3452, 1213, 5149, 5054, 1528, 4350, 3267, 5136, 5319, 3439, 3872, 3312, 5286, 4516, 3922, 1105, 1387, 5024, 2733, 2864, -738, -414, 3647, 1405, -5, 2700, 306, 816, 1501, -937, 3033, -975, -1782, 1262, 335, 1386, -4223, -699, 548, 18, -3023, -9284, -965, -222, -907, -6814, -1691, -4412, -163, -1271, -2443, 1211, -400, 546, -1384, -898, 2188, 1882, 979, -1953, 214, 2303, 2226, 905, -2548, 940, 2185, 1392, 268, -2336, 1093, 1793, 107, -954, -2075, 442, 810, -690, -2947, -2019, -1257, -802, -1338, -6016, -2049, -2764, -2194, -1307, -5654, -2447, -1529, -1536, -550, -3827, -3535, -967, -178, -353, -2626, -5133, -1504, 415, -710, -1543, -8333, -2259, 45, -1111, -1052, -5879, -1926, -1219, -310, -1749, -1318, -795, -3119, 721, -4184, 411, -32, -2720, 632, -3054, 525, -70, -1071, -512, -956, -748, -454, -1151, -1681, -1015, -3396, 0, -3930, -3299, -3788, -9284, 946, -4469, -9479, -4907, -6045, 1387, -1624, -5164, -1598, -2766, 1209, -843, -3723, -1680, -2244, 870, -495, -4282, -5103, -2902, 655, -458, -6103, -5346, -2322, 90, -1083, -12319, -2809, -1287, -1212, -1908, -7484, -3692, -1202, -2933, -2319, -4723, -9193, -2071, -3811, -3428, -4060, -7196, -3748, -3509, -7299, -5451, -4912, -5970, -3119, -7247, -9873, -5299, -7623, -3393, -4425, -5702, -7774, -7371, -4748, -4674, -4365, -17034, -6343, -7708, -7130, -4853, -11356, -6457, -9479, -7730, -4616, -10613, -8615, -6411, -4104, -3067, -9380, -7752, -4373, -1994, -2516, -9193, -4946, -2906, -1286, -3194, -12319, -4086, -2028, -1984, -4821, -12534, -4703, -2011, -4119, -6943, -9695, -6800, -3098, -5286, -8649, -9479, -8276, -4946, -4230, -7353, -13365, -5286, -5139, -3944, -6732, -9106, -2881, -4842, -4187, -7888, -4532, -1735, -4957, -4842, -7542, -2574, -1898, -4659, -5988, -6225, -1827, -3471, -4764, -6928, -7281, -1880, -5942, -5524, -6565, -28777, -2460, -6163, -5924, -5879, -6133, -3537, -5942, -5103, -5509, -4097, -5531, -6411, -4536, -5097, -4119, -9531, -7113, -5286, -4810, -5686, -7603, -7984, -8220, -5170, -8615, -5607, -9812, -9812, -6411, -10001, -5487, -12776, -8615, -7936, -9064, -6653, -11781, -10799, -8060, -10704, -7623, -11356, -9238, -6814, -15615, -6035, -8615, -6411, -5694, -10001, -4935, -6528, -5516, -4946, -9022, -5103, -5735, -6045, -4242, -8393, -6504, -5546, -9106, -3569, -8247, -9064, -5164, -10899, -3299, -9936, -5979, -5292, -8582, -5480, -9429, -7230, -3843, -10442, -8454, -8247, -9429, -3194, -15615, -9193, -8060, -5979, -3540, -13049, -9022, -8192, -4357, -5139, -9064, -8009, -7665, -4669, -5793, -8165, -6332, -6732, -7523, -4940, -8165, -6016, -6278, -12319, -4038, -7179, -6943, -7281, -8333, -3130, -6899, -8393, -10442, -7984, -2920, -9064, -10138, -7299, -9106, -3218, -9149, -15615, -5247, -8827, -3846, -5702, -13049, -4901, -5670, -4659, -4578, -11488, -5227, -4344, -5152, -4774, -12319, -5145, -4340, -5260, -5630, -8192, -4630, -4649, -5871, -5451, -6035, -4764, -4587, -6842, -4853, -5429, -6914, -5079, -5702, -5152, -6026, -11781, -6299, -3438, -5247, -7484, -4616, -6679, -1875, -4369, -8112, -2758, -5273, -1447, -3689, -6914, -2505, -3916, -1950, -3512, -5979, -3441, -3319, -2772, -3989, -6163, -5554, -3444, -3130, -5380, -7353, -8363, -4060, -3020, -6577, -7389, -7842, -4826, -2945, -5951, -6246, -7034, -6332, -3023, -6422, -5871, -6870, -9479, -3271, -10362, -6553, -6492, -7774, -3717, -7066, -8517, -5933, -6143, -4112, -4654, -11781, -5662, -5924, -4469, -4541, -9936, -5710, -6705, -5451, -6113, -7603, -5915, -8220, -7774, -9873, -5951, -5827, -7819, -11232, -28777, -4606, -5576, -6204, -13365, -13738, -3760, -5401, -5465, -9380, -12534, -3512, -5333, -6007, -7408, -13365, -3900, -5516, -8034, -7264, -28777, -4863, -6123, -8165, -7503, -28777, -6434, -6759, -5924, -7247, -11945, -8549, -6666, -4985, -7247, -8582, -10526, -6007, -5103, -7623, -6640, -10899, -5240, -5960, -7936, -5662, -11004, -4447, -7464, -7583, -5367, -13049, -3903, -10526, -6928, -5623, -13049, -3923, -11232, -6565, -6480, -7865, -4592, -6267, -6914, -8138, -5710, -5615, -4295, -7865, -11356, -5085, -6540, -3732, -8754, -17034, -5844, -7623, -4207, -10442, -9479, -8517, -8982, -5546, -28777, -6988, -13365, -9064, -7687, -8790, -6163, -9064, -7464, -10442, -6786, -6602, -8165, -6083, -13738, -7230, -8304, -9331, -5670, -28777, -10362, -10210, -13738, -6214, -14784, -15615, -9064, -12534, -7213, -10069, -28777, -8754, -8276, -7888, -7247, -14195, -10362, -6590, -8718, -5836, -13738, -11004, -5960, -10442, -5444, -12319, -9331, -5759, -13738, -5710, -8086, -8363, -5380, -15615, -6278, -6653, -7644, -5020, -10442, -6870, -6321, -7247, -5176, -9064, -7050, -6800, -7623, -5979, -9585, -6973, -8112, -8790, -7426, -12776, -6759, -9695, -8903, -9429, -14195, -6732, -10613, -7542, -10799, -9193, -7426, -10899, -7335, -10069, -7299, -9936, -11115, -9064, -9812, -6399, -28777, -12776, -13365, -10799, -6365, -11945, -28777, -11232, -12776, -6988, -14784, -11232, -13049, -9753, -7644, -11781, -9873, -11115, -7523, -7562, -8865, -12319, -8615, -6590, -7004, -9193, -15615, -9936, -6615, -6814, -10362, -10362, -10210, -7665, -7562, -8718, -8903, -6516, -10001, -8865, -7752, -7865, -5387, -13365, -8454, -8393, -6653, -5599, -11629, -7842, -10526, -5970, -6666, -8827, -8138, -7317, -7179, -9936, -6870, -4800, -6388, -6828, -8982, -7708, -4207, -6153, -7912, -6988, -7644, -5176, -5810, -8683, -5718, -7842, -7623, -5208, -6083, -5793, -9429, -7819, -4896, -4550, -7603, -14784, -7019, -5008, -4361, -10001, -14195, -8454, -5451, -5158, -7623, -11004, -7281, -5979, -5458, -6899, -7196, -4935, -6365, -4592, -7730, -4784, -4532, -6973, -4319, -8423, -3801, -6007, -8423, -4951, -7888, -3886, -9639, -9064, -6299, -8304, -4896, -8485, -7960, -8192, -10704, -6719, -8086, -8754, -11115, -10069, -8582, -11629, -8790, -28777, -7819, -9064, -7097, -5759, -10362, -7644, -7936, -4112, -4442, -6445, -7389, -5576, -2668, -4266, -4100, -4495, -4042, -1848, -4698, -2920, -2499, -3773, -1382, -5415, -2851, -1803, -4907, -1347, -6388, -4035, -2419, -8220, -2045, -7912, -6310, -4555, -12776, -4142, -9639, -5906, -6399, -8718, -10704, -7984, -4654, -4606, -8192, -7179, -5933, -4500, -3978, -8754, -5279, -4980, -4748, -4365, -9479, -5554, -5115, -4386, -5145, -10442, -6759, -6504, -3920, -5546, -13365, -8363, -9429, -4438, -5247, -12319, -11004, -13738, -6870, -4733, -7687, -10899, -14784, -12123, -4569, -5844, -7542, -11004, -5638, -5055, -5472, -6814, -7464, -3583, -6045, -6376, -8649, -5531, -2871, -6745, -8754, -28777, -4790, -3025, -6376, -14195, -7774, -5189, -3840, -5494, -28777, -5726, -6565, -5152, -5139, -28777, -5286, -8454, -7034, -5743, -14195, -6123, -10001, -7603, -6988, -11781, -9106, -9695, -6016, -6492, -17034, -10362, -8615, -5367, -5319, -9380, -5942, -8276, -5924, -5247, -6045, -4097, -8615, -7665, -6299, -5240, -3417, -9479, -10799, -7842, -6299, -3493, -11781, -13738, -8423, -9753, -4028, -28777, -11488, -8903, -13738, -4912, -13365, -10704, -9812, -8942, -5988, -10069, -11629, -10284, -7623, -6288, -8112, -15615, -9380, -7730, -6256, -7281, -10704, -8112, -8485, -7389, -7523, -9429, -7912, -7464, -8982, -8683, -11115, -8754, -5768, -8138, -8982, -28777, -10069, -4951, -7445, -8549, -13049, -12319, -5494, -7335, -9331, -9429, -13049, -8333, -6628, -12319, -7299, -8138, -14784, -5862, -17034, -6365, -5862, -8982, -5561, -9639, -7097, -5085, -9936, -5360, -7984, -11004, -5319, -9284, -5286, -8220, -10001, -6113, -7050, -5784, -10284, -6885, -7687, -7335, -6692, -15615, -6943, -13049, -8304, -7113, -12319, -10138, -7752, -7162, -6973, -11629, -13738, -5539, -7484, -6885, -12534, -9106, -5374, -10899, -6602, -10799, -8582, -6399, -9479, -5743, -10442, -9639, -8276, -7247, -5247, -11115, -14784, -9238, -7389, -5759, -10210, -11781, -7842, -9106, -7665, -9429, -9936, -6842, -10526, -10799, -9639, -11115, -6773, -10069, -9812, -9812, -9585, -7317, -10613, -8827, -9064, -8393, -7774, -13738, -9193, -7842, -9812, -7335, -28777, -10210, -7113, -17034, -6759, -12776, -10799, -7503, -11232, -6540, -9873, -10284, -9149, -9149, -6800, -8454, -9585, -13365, -8827, -7542, -8192, -9585, -28777, -9585, -8982, -9238, -10442, -10799, -4473, -6516, -3817, -7464, -9936, -4089, -5979, -5458, -4907, -9429, -4357, -7484, -8034, -4344, -10138, -5299, -8942, -7665, -5615, -13049, -6457, -8517, -7842, -10362, -12123, -7146, -10362, -11356, -10362, -10526, -8060, -13738, -7888, -7130, -9479, -10001, -9238, -5061, -6469, -7034, -11629, -7708, -3873, -6007, -6026, -10799, -7196, -3656, -5422, -7213, -10001, -7130, -4369, -5360, -9429, -8754, -7888, -5260, -5997, -6235, -7317, -10704, -4896, -7113, -5133, -6225, -11629, -4219, -8363, -5871, -5401, -9753, -3230, -9284, -7162, -4733, -6256, -2040, -8517, -6457, -4640, -4082, -1359, -6376, -5247, -5776, -3707, -1356, -4592, -3710, -6332, -4532, -1954, -3589, -2300, -4215, -5002, -3110, -2768, -1620, -3354, -4545, -4805, -1815, -1807, -3992, -4447, -6434, -1261, -2851, -6163, -4683, -5871, -1434, -4688, -9106, -4659, -4980, -2270, -6943, -8754, -4172, -4918, -3600, -8582, -8304, -3560, -5465, -4826, -8423, -7819, -3108, -6988, -5139, -8086, -6553, -3085, -11356, -6074, -9193, -5266, -3808, -6093, -7644, -11781, -4597, -5487, -3798, -5924, -9479, -4918, -6943, -3306, -5202, -8649, -6045, -6411, -3751, -6516, -8790, -6354, -6492, -4161, -8034, -8683, -5951, -7389, -4215, -5465, -8333, -6343, -7708, -4968, -3900, -6480, -6705, -7146, -8247, -3393, -4532, -6411, -6343, -10704, -3444, -3507, -6666, -5253, -6083, -3624, -3407, -7562, -4112, -5170, -3801, -4299, -8138, -3415, -5401, -4250, -6332, -8942, -3370, -6256, -5214, -8942, -11488, -3876, -7960, -6943, -9149, -9639, -4713, -10613, -11004, -9479, -7503, -5924, -13365, -11781, -11115, -7464, -7796, -10704, -7960, -11629, -9753, -10210, -7644, -7960, -10899, -13365, -17034, -6457, -11488, -10284, -9238, -10362, -7644, -12534, -8982, -7687, -6565, -8903, -11781, -8034, -7623, -5422, -5014, -15615, -7912, -8517, -5879, -3535, -7936, -8333, -9331, -7774, -3357, -6434, -9022, -10069, -9639, -3594, -6828, -9812, -10799, -10442, -3910, -8485, -11115, -10001, -10899, -4708, -8304, -13738, -8549, -8454, -5751, -6457, -12123, -6565, -7503, -5202, -5942, -8754, -5097, -8549, -4583, -6163, -7066, -4564, -9022, -5214, -6163, -6074, -4912, -7213, -6480, -6943, -5584, -5862, -7317, -6388, -9639, -5630, -6153, -10069, -6445, -7484, -6246, -5472, -17034, -7097, -5319, -6773, -5049, -11488, -6469, -4826, -6602, -5253, -12123, -5871, -5569, -6615, -6183, -13365, -6422, -7842, -6653, -7865, -13049, -8304, -9695, -6074, -9022, -12776, -13049, -6705, -5970, -8220, -10069, -13365, -5049, -7146, -8034, -8454, -10138, -4303, -9695, -9585, -7484, -9812, -4399, -10799, -13738, -6026, -13738, -5759, -9639, -10001, -4640, -9812, -10138, -8034, -8582, -4149, -5646, -7752, -7034, -9284, -4559, -4112, -4837, -7264, -10899, -5718, -3856, -3817, -8423, -9531, -7426, -4569, -3720, -9639, -7004, -9753, -6045, -4238, -9380, -5531, -13365, -7984, -5189, -8423, -4826, -17034, -8827, -6204, 10085, 11221, 8963, 11018, 8334, 9316, 10859, 8285, 10493, 7927, 7109, 9776, 6180, 8944, 6627, 6461, 8059, 4071, 6596, 4456, 7327, 6182, 4924, 4416, 3687, 6875, 5014, 5059, 3515, 4214, 4988, 4298, 3876, 2967, 3293, 2754, 3230, 899, 2199, 122, 5608, 1801, -3779, 2184, -2036, 6931, 770, 1667, 1695, 1483, 6717, 487, 2971, -1433, 3730, 6108, 9, 2941, -490, 5580, 5814, 1001, 3414, 3220, 6865, 4438, 3648, 4125, 4494, 7290, -670, 4812, 3796, 4447, 6636, 531, 4412, 2070, 3617, 4561, 2454, 2450, -1029, 2858, -167, 1760, -304, -2020, 2464, -1854, 314, -278, -1401, 1950, -249, 50, -185, -1652, 1419, -1168, 992, -816, -1865, 1288, -1944, 1695, -1462, -1035, 1282, -1156, 1557, -1074, -138, 745, -301, 145, 338, -193, -773, -409, -1961, 1326, -1428, -4545, -1606, 840, 1391, -2253, -3656, -2188, 2628, 590, -206, 146, -1766, 3111, -645, 1245, 1269, -2146, 2745, -1472, 1586, 646, -1205, 1636, -1472, 912, -2046, 621, 718, -1254, -677, -3996, 1552, 1851, -1340, -2597, -2210, 1793, 2748, -1003, -2853, -3837, 1757, 2764, -220, -1321, -6528, 1499, 2660, -245, 117, -692, 697, 2803, -2121, 1046, 881, -893, 2547, -5599, 1485, 710, -3420, 1743, -892, 1465, -765, -9695, 847, 294, 1035, -1621, -3744, 60, -765, 367, -1573, -816, -704, -3252, -262, -4336, 410, -996, -1746, -635, -2386, 1060, -803, -526, -674, 787, 1419, -916, -433, -969, 1473, 1277, -2055, -1387, -2391, 458, 445, -5031, -3714, -5827, -2699, -1258, -8454, -4991, -10704, -5516, -4816, -5630, -3177, -5002, -2000, -8192, -5487, -1236, -1732, -415, -3034, -7583, -54, -280, 585, -1935, -10442, -31, -159, 1112, -2766, -5970, -1386, -1286, 969, -5561, -3653, -5061, -4115, 9, -4890, -2635, -8060, -6540, -2042, -2758, -2328, -5176, -4573, -6194, -1894, -2409, -4779, -4754, -6365, -1980, -2873, -3457, -6321, -3600, -3294, -4258, -2686, -6870, -2791, -7708, -6653, -3498, -5292, -2637, -7213, -2648, -4774, -2666, -2345, -4728, -148, -3404, -991, -1798, -5942, 881, -2534, -497, -1494, -7984, 964, -3080, -1008, -1873, -5480, 294, -4723, -1962, -3080, -6035, -1210, -4311, -2273, -3951, -7644, -4149, -3563, -1740, -3286, -4184, -6870, -4278, -1111, -2703, -2793, -3827, -6267, -1123, -2571, -2918, -2766, -9149, -1928, -2541, -4127, -2485, -8034, -2679, -2534, -5784, -2323, -6399, -2679, -3054, -6553, -2873, -7162, -2289, -4451, -6899, -3729, -13365, -1483, -5951, -7665, -1936, -8304, -1236, -5451, -6163, -606, -8138, -2143, -4649, -3626, -686, -8718, -4191, -4890, -2596, -2069, -3843, -4946, -6577, -3386, -4408, -2314, -3720, -8333, -7353, -5554, -2406, -2975, -6214, -9585, -4800, -3147, -2778, -3468, -7464, 5303, 7699, 9187, 7182, 4567, 4998, 6945, 8808, 6800, 6044, 4016, 4641, 7734, 5870, 7372, 2124, 2279, 6223, 5179, 7694, -1627, 1455, 4947, 4994, 7330, -6590, -3557, 4399, 4182, 6588, -993, -433, 3796, 1087, 5559, 501, 2203, 3461, -3198, 4384, 1062, 2649, 4003, 1569, 4012, 14, 2320, 3825, 506, 4519, -168, 2061, 2599, 225, 5207, 4308, 2727, 2718, 4269, 5699, 6329, 3881, 3698, 5604, 5512, 6863, 4638, 3582, 5193, 4359, 6259, 4768, 2425, 2746, 2310, 4553, 4327, 1066, -8363, 817, 1687, 3442, 421, 985, 1515, 656, 2389, -848, 2451, 2318, 1567, 1285, -1548, 2667, 2153, 802, -781, 1189, 2677, 623, -3449, -1863, 2437, 2450, -3399, -2374, 653, 2143, 1299, -4115, 1206, 1239, 557, -672, -877, 2275, 137, -340, 442, -147, 2466, -2253, 976, 1057, -322, 2106, -3583, 1713, -346, -583, 853, -3846, 1280, -1516, -992, -2467, -5002, -1289, -382, -1966, -6786, -5561, -2173, -867, -2024, -953, -3735, 1651, -3235, -468, 821, -1702, 2434, -3665, -100, 1454, -754, 1052, -2165, -2054, 1425, -1578, -2705, -1941, -10442, 1399, -6332, -615, -2427, -1236, 1845, -3179, 545, -2807, 660, 2260, -1174, 79, -3618, 1333, 2397, -1057, -1225, -4486, 1769, 2385, -526, -2787, -3879, 2168, 2090, 369, -2082, -2198, 2192, 1022, 839, -326, 302, 1657, -1595, 736, 328, 1621, 759, -3808, -205, -284, 1520, -113, -2126, -1482, -2129, 10, -749, -3329, -886, -5020, -2924, -1653, -9936, -6, -9695, -5793, -4149, -4564, 217, -10210, -6113, -14195, -3114, 243, -5539, -5020, -4754, -1482, 361, -3546, -3906, -3354, -311, 278, -2435, -2505, -3291, -413, -266, -1920, -1134, -3698, -1820, -953, -1626, -478, -4573, -4831, -901, -1300, -715, -5726, -14195, -316, -1038, -1913, -6457, -7523, 226, -1105, -4336, -7888, -4733, 698, -1600, -5654, -28777, -3191, 860, -2720, -3798, -7730, -2130, 313, -5408, -3354, -5306, -1169, -1352, -7665, -4157, -4842, -298, -4491, -4093, -4869, -5202, 100, -4500, -3846, -4270, -5339, -226, -2999, -6299, -3101, -4847, -1356, -2743, -8333, -2342, -4601, -3360, -3094, -10613, -2462, -6026, -6163, -3680, -5906, -3580, -10001, -7503, -4270, -1680, -6143, -6310, -5615, -3910, -100, -7371, -4303, -4086, -2900, 241, -4226, -2191, -3665, -2779, -208, -2799, -864, -4564, -3529, -1405, -2465, -897, -6828, -3137, -3961, -3156, -2231, -8865, -2653, -28777, -5221, -3689, -6885, -3580, -5014, -4885, -3007, -4433, -5638, -3444, -3326, -2057, -3362, -6235, -4703, -3735, -1624, -3071, -4195, -9812, -6679, -1640, -2300, -3220, -2326, -17034, -1880, -1144, -4837, -67, -7146, -2072, -453, -7299, 484, -3294, -2210, -548, -1998, -191, -911, -2596, -1527, -374, -1921, 206, -2990, 9559, 7043, -6183, 6970, 8473, 9287, 7540, 4242, 7206, 8535, 8438, 8037, 6533, 7465, 8612, 6931, 7830, 7230, 7288, 8385, 5091, 6974, 6978, 6565, 7458, 4710, 5715, 6004, 5247, 5457, 4882, 4077, 4551, 3744, 2095, 3670, 937, 3061, 3880, -710, -698, -4254, 1885, 4317, 484, 1705, 1691, -752, 3453, 1833, 4786, 2420, -2163, 2260, 608, 6022, 3268, 3204, 3217, -7179, 6134, 4795, 4331, 3255, 1001, 4940, 4841, 2835, 2286, 1770, 1232, 2483, -8247, 3633, 3913, -1412, -585, 2881, 4654, 6081, 1930, 2905, 4320, 4163, 6732, 1310, 3242, 3768, 2312, 6124, -2728, 1981, 2061, -740, 4500, -4089, 265, 512, -6411, 2225, -305, -331, 978, -3114, 1372, 487, 6, 2036, 32, 2416, -278, -552, 2470, 1348, 3030, -3526, -3490, 2160, 1784, 3221, -5638, -5702, 1329, 1637, 3304, -1798, -2912, 588, 965, 3035, -994, -4031, 389, -566, 1631, -1134, -8683, 247, -2347, -3194, -1934, -4176, -10, 254, -1407, -3054, -3482, 306, 2206, 1354, -2420, -2764, 1077, 2902, 1785, -1372, -919, 1499, 2692, 1317, -777, -231, 1376, 1797, 150, -448, -109, 870, 348, -3137, -437, 418, 109, -1810, -1811, -833, 539, -1189, -5662, 1290, -1392, -226, -2524, -10001, 1924, -1753, -1592, -15, -4869, 653, -828, -5380, 1940, -3172, -3674, 944, -4226, 2535, -2639, -3151, 1641, -765, 2104, -3507, -800, 766, -1104, 1027, -5654, -257, -2217, -4654, -283, -2302, -188, -4858, -967, -2071, -43, -587, -3860, 476, -4021, 818, -1277, -5592, -405, -3913, 852, -1505, -9695, -3526, -4207, 227, -1956, -12319, -7353, -6143, -1072, -3947, -7004, -9238, -9936, -2320, -10526, -4800, -4311, -10001, -1716, -6870, -4021, -2198, -8060, -1390, -4373, -3600, -2490, -7484, -2427, -2781, -3124, -5367, -7523, -4119, -1721, -3012, -6103, -8582, -4968, -1534, -3698, -3365, -13049, -6885, -2672, -5768, -2490, -8615, -7960, -7247, -11629, -2020, -6590, -5380, -5326, -5768, -1643, -8454, -3360, -1516, -3089, -1556, -9149, -1952, -158, -2075, -1707, -3692, -1761, 150, -2348, -1825, -1774, -3549, -32, -4053, -1852, -1175, -7113, -372, -7623, -2175, -1237, -2192, -1107, -13365, -3586, -1344, -520, -2596, -10799, -7542, -1507, -454, -3444, -6705, -4583, -2282, -1439, -2034, -5164, -2522, -3876, -3124, -815, -4303, -2545, -5319, -5718, -198, -3944, -3846, -5401, -6288, -160, -4307, -4230, -6183, -3179, -900, -4764, -2032, -9695, -2094, -2779, -4223, -257, -8454, -2651, -5561, -3108, 589, -5960, -5312, -5091, -2297, 614, -4266, -10210, -2999, -1944, 83, -2891, -4963, -1704, -1814, -748, -2793, -4361, -1597, -1838, -1921, -3738, -5487, -2557, -2182, -3551, -2916, -2722, -3717, -2988, -4344, -1685, -503, -3521, -4299, -3785, -1759, 237, -2698, -4161, -2540, -3201, -1264, -6492, -4254, -1427, -4442, -132, -3196, -3729, -1206, -5437, 23, -1994, -1991, -2014, -4348, -570, -2107, -1103, -3635, -4323, -1759, -2247, -1505, -5408, -6773, -3220, -1610, -2956, -6434, -6163, -3933, -984, -3367, -4425, -4307, -3515, -668, -2754, -2282, -6457, -2435, -517, -3058, -1276, -5170, -1661, -564, -3474, -1444, -986, -1564, -981, -2311, -2924, 375, -1932, -1674, -1232, -4369, 301, -2655, -1935, -1002, -2731, -760, -3930, -1590, -1680, -1602, -2168, -6256, -1473, -3795, -1616, -2827, -8192, -1865, -8683, -3029, -3194, -5776, -2040, -3016, -8138, -4764, -4541, -1183, -594, -4853, -2869, -4620, -291, 217, -2458, -436, -4997, -117, -229, -2540, 269, -4748, -985, -1822, -4420, -393, -5073, -3347, -2914, -7888, -2388, -5299, -7774, -2262, -8304, -5031, -3732, -6225, -2130, -5584, -5387, -2650, -5037, -2815, -4478, -6103, -2445, -4451, -4550, -5079, -8304, -2979, -3726, -8220, -5394, -7774, -4550, -2956, -6540, -3811, -5049, -6759, -2213, -4963, -3198, -3314, -5915, -1666, -5394, -3438, -2984, -4896, -1567, -7819, -3680, -4172, -4108, -2055, -8454, -3589, -6602, -3621, -3225, -6628, -4093, -6054, -4157, -5279, -7034, -6828, -4625, -6745, -8942, -8582, -7665, -4795, -15615, -4611, -8423, -3989, -7335, -6628, -1768, -7464, -3386, -7445, -5516, -681, -6988, -4912, -4382, -6246, -1021, -7819, -6943, -4176, -7842, -3005, -10526, -3833, -6666, -8754, -6422, -11629, -1928, -6628, -7162, -4545, -9873, -1080, -3096, -4880, -3121, -8165, -1126, -1561, -3080, -2785, -7004, -2165, -931, -1746, -3016, -6540, -4290, -949, -991, -3264, -6388, -7960, -1656, -944, -3360, -6516, -9238, -2843, -1525, -3526, -7299, -5607, -3049, -2195, -3978, -7162, -4315, -2562, -2458, -4545, -5678, -4573, -2952, -3154, -4242, -5061, -6183, -4826, -4923, -3569, -5103, -8220, -9106, -5524, -3074, -5079, -7299, -6842, -4340, -2672, -5061, -4442, -4816, -3811, -2339, -5584, -2774, -4064, -3820, -1939, -7623, -2497, -3650, -4219, -1680, -11232, -3415, -3498, -4837, -1778, -6800, -4929, -3801, -5079, -1995, -5623, -5702, -4545, -5214, -2173, -6422, -5266, -5049, -5793, -2785, -9022, -4597, -5286, -7196, -4532, -10138, -4315, -6376, -10442, -9284, -8790, -3748, -7936, -7819, -7865, -10069, -3175, -6653, -4640, -4974, -9193, -3615, -5960, -3126, -4223, -4923, -5879, -7213, -2540, -4399, -3331, -11232, -9149, -2585, -4779, -3438, -6528, -8060, -3121, -4935, -5387, -4708, -8454, -4180, -5260, -11781, -3971, -12319, -5638, -6445, -10001, -3674, -9429, -6113, -8683, -7317, -3704, -7281, -5234, -10001, -5979, -4142, -7196, -4929, -8304, -5638, -5240, -7842, -5599, -6332, -6800, -7247, -7371, -7264, -5014, -10362, -8982, -5942, -10210, -5002, -8865, -9022, -5055, -17034, -7335, -6434, -10442, -5422, -7752, -12123, -6035, -11004, -8060, -5516, -5793, -3130, -236, -4142, 321, -2964, -3846, -1086, -4779, -411, -3373, -2334, -2833, -4307, -1961, -5546, -639, -5569, -4578, -4559, -10704, 158, -5374, -4550, -9331, -3751, -90, -3321, -3213, -8086, -1527, -1549, -2776, -2756, -6732, -836, -4826, -3913, -3837, -7503, -1241, -6054, -8549, -5279, -6332, -2613, -3401, -7213, -4184, -4274, -4885, -2507, -4266, -3695, -3257, -7730, -2594, -3618, -4223, -3331, -10069, -3479, -3476, -5067, -4743, -8333, -4805, -3140, -6153, -8903, -5121, -5139, -2735, -7281, -10284, -2910, -4795, -2502, -7503, -5718, -1936, -4874, -2342, -6705, -3951, -2385, -5415, -1580, -5933, -4093, -4805, -4447, -434, -4369, -9380, -3058, -2414, 136, -2390, -3866, -399, -1215, -426, -1308, -730, 367, -624, -2422, -1214, 94, -143, -300, -3342, -1780, -573, -1341, -574, -2416, -2420, -2895, -2159, -2264, -3468, -2696, -6399, -2192, -7865, -3546, -2739, -5516, -1920, -3992, -1381, -3071, -6828, -1953, -1986, -627, -4438, -14195, -2675, -1817, -783, -6759, -5429, -4545, -2529, -1280, -4578, -3751, -9753, -3906, -1992, -3179, -4357, -7842, -6973, -2774, -3563, -9873, -5531, -9936, -3833, -6235, -5801, -5472, -3763, -6988, -9284, -3349, -5654, -1719, -6267, -4157, -3870, -4885, -1131, -3433, -2553, -7299, -3586, -1625, -3430, -1965, -5726, -2724, -2450, -4885, -1753, -3130, -2713, -1726, -3279, -2045, -2039, -3677, -778, -1615, -2952, -1468, -6133, -805, -1362, -4064, -1174, -7408, -1804, -2257, -4640, -1264, -3776, -3375, -4361, -4108, -1838, -1954, -4295, -8549, -3249, -2900, -1471, -3782, -10001, -2904, -4429, -2339, -2827, -6054, -3056, -6183, -5465, -2378, -4583, -3650, -6516, -13738, -2657, -4286, -4733, -5415, -7730, -3047, -5061, -5997, -4215, -7389, -2510, -6914, -6225, -3785, -3804, -1699, -6679, -6278, -4573, -2396, -1465, -4390, -7389, -6590, -2912, -2189, -3232, -9149, -6943, -5554, -4399, -2912, -7426, -3677, -10001, -6666, -3010, -4985, -1450, -8485, -4119, -3344, -3254, -568, -10284, -3244, -3529, -2336, -888, -17034, -3594, -2933, -2283, -2065, -9149, -4478, -2283, -2912, -2756, -7503, -5247, -2583, -3626, -2553, -6565, -5539, -4464, -3866, -2741, -5346, -5273, -6590, -4067, -3624, -4100, -4664, -4616, -4523, -4968, -3509, -3985, -4597, -5266, -6492, -3944, -3124, -5524, -6225, -7583, -5662, -2516, -3460, -7213, -7019, -7865, -2841, -2186, -7371, -6540, -7503, -4896, -2291, -6143, -6153, -7408, -9873, -3326, -5726, -6113, -8393, -5759, -4869, -7819, -7317, -10362, -4311, -6615, -11488, -8865, -8034, -4395, -8034, -6422, -7299, -4203, -4923, -8485, -5509, -5654, -2205, -4985, -8304, -5646, -4847, -1551, -5103, -9064, -5339, -4800, -2020, -6332, -13049, -4226, -5002, -3574, -8192, -12319, -3304, -4858, -6528, -6628, -9284, -3101, -4683, -9193, -6054, -8649, -3589, -4912, -6705, -7299, -9106, -4344, -5561, -6163, -5654, -3549, -3222, -81, -2244, -5694, -3554, -5638, -1350, -2713, -5339, -3027, -5408, -4119, -4455, -6194, -2274, -3850, -28777, -5121, -9812, -2179, -2739, -5367, -3698, -10613, -3042, -1953, -4399, -3656, -5152, -4536, -1574, -7644, -5623, -2448, -4790, -1786, -6492, -6653, -946, -3504, -2783, -2534, -2347, -607, -2427, -4805, -1712, -595, -1822, -1884, -8790, -2567, -433, -7146, -1591, -12776, -4104, -1813, -3913, -1258, -5810, -3748, -4625, -1117, -894, -2475, -3647, -3804, -437, -716, -436, -3507, -2452, -641, -852, 417, -1026, -2107, -1092, -1494, -59, 838, -1694, -742, -3096, -2222, 1690, -683, 137, -4674, -3689, 1758, 488, 596, -3029, -1825, 1156, 1340, 616, -2158, -1854, -73, 1654, 396, -2458, -4157, -2088, 1349, -157, -3281, -8333, -5662, 427, -1249, -3362, -5234, -17034, -968, -2817, -2841, -4482, -7066, -2256, -3999, -2679, -3804, -5247, -3457, -3509, -2519, -3239, -3860, -7097, -3284, -1890, -3830, -2747, -6553, -4869, -1263, -5646, -2155, -2383, -10799, -657, -7371, -1975, -1187, -5415, 69, -6565, -1622, -1250, -3103, 421, -4373, -1006, -1950, -2528, -141, -3349, -964, -2803, -3560, -2305, -3954, -2142, -3493, -7247, -11629, -6870, -4097, -3428, -5360, -3638, -15615, -3401, -2622, -3266, -1790, -7603, -2939, -2188, -3276, -1917, -6399, -4086, -2624, -4790, -3067, -6083, -5539, -4172, -9106, -3989, -6083, -3444, -5509, -8086, -4536, -6388, -1885, -3647, -4112, -6343, -4816, -1435, -2997, -2596, -10362, -2791, -1630, -4869, -2279, -7562, -2232, -2659, -10138, -2918, -6332, -3230, -6016, -2855, -4790, -6376, -3893, -3465, -755, -14195, -6516, -1941, -690, 113, -3804, -5465, -770, -83, 316, -1040, -3686, -543, -1045, -65, -259, -2401, -954, -3692, -983, -763, -2179, -1711, -8649, -1742, -1899, -3078, -1957, -14784, -1571, -2358, -4134, -1236, -6885, -1391, -2152, -3996, -703, -5333, -1912, -1945, -4191, -1024, -5933, -3208, -2184, -5319, -2294, -4601, -4723, -3624, -6310, -4336, -3391, -4115, -8485, -5871, -6093, -4826, -2345, -7796, -5759, -6214, -7623, -1213, -5061, -5292, -6516, -2841, -1245, -5183, -3723, -9812, -1501, -3203, -5979, -2939, -8112, -1826, -12534, -5710, -3144, -4319, -3117, -3329, -5422, -3677, -3105, -3913, -1615, -6083, -3788, -3393, -4130, -1546, -8718, -3612, -5306, -4901, -2473, -9585, -3274, -8683, -4951, -4365, -5599, -2956, -6399, -4184, -7503, -4478, -3347, -5444, -4365, -5662, -4837, -5279, -6123, -6133, -3142, -5743, -12776, -7196, -9753, -2478, -6183, -7299, -7146, -11356, -3168, -6773, -5260, -6267, -28777, -3349, -8276, -4929, -5339, -8192, -2032, -9936, -5599, -4896, -5546, -1317, -10210, -7281, -5260, -4764, -1018, -9531, -9812, -6183, -5221, -639, -8718, -11232, -6602, -6732, -524, -7213, -10138, -6504, -6719, -1026, -6480, -8517, -6856, -5158, -2107, 6798, 7074, 7441, 9543, 2855, 6478, 6828, 7179, 8840, 2171, 5702, 5860, 6589, 6326, 401, 4828, 4017, 6047, -2122, 1098, 3984, 3277, 5626, 3316, 2604, 3289, 3498, 5202, 3879, 2561, 1875, 2019, 4429, 2168, 451, -1842, -115, 2741, 2939, -1832, 3531, 2571, 365, 4447, 2033, 5403, 3833, -34, 4609, 3804, 5307, 4087, -1236, 3605, 4946, 3812, 4262, -3680, 1407, 5968, 1780, 4856, 708, -262, 6632, 1250, 5453, 2222, 1059, 6630, 1805, 5377, 1890, 1673, 5727, 1285, 4189, -82, 1402, 3735, -469, 1713, -524, 663, 1218, 1025, 533, 1409, -74, -756, 1815, 1403, 2102, -127, -2165, 789, 1467, 1872, 660, 1720, 1703, 1005, 1135, 1470, 3094, 4127, 567, 369, 1856, 2864, 5396, 582, 70, 1788, 1698, 5552, 653, 202, 1342, 115, 4523, 342, 326, 482, -8, 1890, -92, 520, -1235, 1628, -3653, 246, 1153, -4935, 2207, -3187, 1469, 1582, -6332, 1355, -3179, 2284, 1064, -6492, -1092, -2778, 2077, -247, -3641, -6045, -616, 583, -208, -1200, -7752, 1076, -2776, 116, -852, -2553, 2368, -5333, -1078, -1647, 123, 3239, -2182, -1962, -1747, 1543, 3547, -1483, -493, -948, 1965, 3185, -2791, -188, -767, 1346, 2088, -8220, -1372, -1261, -671, 383, -5933, -2661, -1453, -5472, -871, -3399, -1666, -1409, -6143, -949, -3535, -1652, -2146, -3889, -1023, -4890, -3830, -3594, -3247, -1568, -2897, -6225, -4365, -2619, -2571, -1023, -5451, -3766, -2181, -3563, -591, -9695, -3543, -2599, -4046, -1336, -6163, -5079, -4078, -3833, -2941, -3535, -13049, -5793, -3144, -4659, -2505, -5494, -7213, -2893, -4826, -1204, -3671, -9639, -3225, -3923, -315, -3814, -8333, -3468, -3264, -473, -3833, -7162, -2914, -2906, -1773, -2008, -5836, -2130, -2827, -3913, -676, -4223, -1717, -3281, -5387, -372, -3316, -1943, -4486, -6553, -1151, -3105, -3126, -7644, -6214, -3471, -3128, -5960, -9936, -3982, -10069, -2975, -4541, -4340, -3294, -6615, -2720, -1559, -2567, -4258, -5871, -2841, -264, -2189, -5743, -8138, -3833, -190, -2597, -4669, -9585, -6516, -1363, -3203, -4123, -8247, -8333, -4075, -3811, -5152, -7213, -4842, -6528, -4901, -7050, -5960, -3583, -5480, -7162, -5630, -4901, -3808, -5451, -10442, -3692, -3507, -5768, -6434, -7484, -2633, -2631, -10138, -7796, -5465, -2197, -2778, -5988, -7503, -4683, -2079, -4142, -4923, -7687, -4688, -1940, -7752, -6225, -8454, -5380, -1899, -10284, -9429, -6565, -7050, -2239, -5458, -7353, -5487, -9936, -2929, -4491, -6457, -5784, -8393, -3230, -4764, -7583, -7179, -6399, -2646, -5037, -9531, -9193, -5615, -2264, -5079, -10069, -9064, -5546, -2677, -5121, -7583, -7687, -5988, -3529, -5158, -5638, -7162, -6653, -3629, -5465, -5793, -6899, -7050, -3609, -6183, -9429, -6577, -6679, -4469, -6590, -6332, -2286, 7785, 7586, 8379, 8107, -3208, 7386, 7148, 7748, 7426, 846, 5927, 5541, 5936, 5140, 2902, 2135, 2276, 5262, -603, 3380, -1943, 3251, 6434, -509, 3575, 2411, 4432, 6523, 1883, 4396, 2794, 3957, 5366, 1586, 5210, 2766, 3328, 3344, -922, 5465, 2846, 3027, 1746, -3360, 4925, 2466, 976, 66, -3331, 3307, 1795, -4311, -3189, -1952, 2354, 1665, 2686, 980, 243, 4576, 2192, 4186, 2379, -316, 5805, 2692, 3983, 1994, -5592, 5902, 2750, 2765, 734, -3968, 5346, 2049, 1378, -448, -2512, 4722, 95, 611, -1438, -5472, 4100, -4644, -379, -2910, -7484, 2689, -3837, -1771, -695, -2590, -2022, -836, 109, 1915, -835, -314, 152, 1830, 2369, 168, 2944, 271, 2218, 117, 767, 3371, 119, 1649, -2699, 925, 2096, 265, 517, 1989, 268, -653, 674, -1380, 3055, -1068, -2062, 842, -8138, 3049, 722, -1236, 346, -2594, 3098, 2574, 36, -1193, -40, 3165, 2749, 1334, -2954, -41, 2734, 1090, 2301, 283, -2465, 1732, -3276, 2716, 2783, -7484, 565, -4816, 2094, 4090, -3689, -180, -5299, -632, 4546, -6093, -1008, -3526, -4985, 4304, -4500, -2683, -1453, 797, 3432, -379, -3060, -976, 2427, 2034, 624, -874, -1425, 2972, 531, 188, 855, -1370, 2824, -466, -794, 1954, -140, 1800, -1478, -1714, 2464, 280, -494, -4207, -3301, 2270, -372, -5026, -11232, -2791, 1055, -1574, -7503, -6492, -1003, -2345, -2666, -5592, -11356, -742, -5879, -2997, -3638, -2393, -1761, -1065, -2847, -2280, -33, -3264, -443, -3130, -2528, 336, -4491, -1681, -3474, -5037, -690, -4679, -4790, -4963, -8754, -2661, -2170, -9873, -7888, -5367, -3058, -441, -11488, -3018, -5710, -2650, 279, -6828, -1573, -7665, -3430, 375, -4831, -2123, -4258, -4373, 148, -4592, -4469, -2175, -3801, -292, -5014, -6973, -1410, -3373, -1063, -4536, -5942, -1623, -2213, -2129, -3554, -6083, -2990, -933, -2785, -2904, -7004, -6457, -852, -3110, -2779, -6615, -12319, -2250, -4031, -3187, -5158, -8138, -5067, -4145, -3971, -3900, -7984, -6973, -3554, -5037, -3232, -4826, -7464, -4164, -6480, -3165, -2950, -7097, -5524, -6666, -3626, -2472, -5531, -6007, -5043, -4654, -2933, -4429, -6899, -4460, -6856, -3754, -3954, -5312, -5145, -28777, -4215, -4082, -3367, -6469, -6299, -4469, -4779, -3087, -6516, -3883, -5607, -5067, -4134, -5158, -3329, -8615, -4611, -5208, -3937, -3893, -9331, -4718, -5465, -3686, -4997, -8192, -5743, -6870, -4527, -6083, -9753, -7196, -8615, -6640, -7542, -17034, -8393, -6692, -9812, -9585, -12123, -8276, -5401, -13365, -9064, -11629, -5951, -5026, -14195, -7842, -14195, -3837, -5951, -8138, -8034, -13049, -3003, -9753, -5970, -9022, -10526, -3754, -11232, -4831, -10442, -9695, -7389, -8649, -4067, -14784, -9639, -9429, -10704, -3600, -11356, 6658, 8051, 3191, 5852, 6426, 5577, 7421, 2768, 5544, 5464, 1428, 5620, 1553, 4373, 1558, 2037, 4506, 1016, 2219, -204, 4467, 5472, 3102, 2415, 3090, 5690, 5947, 4428, 3626, 3214, 6069, 5574, 4416, 4380, 2260, 4960, 4051, 3397, 5238, 1077, 1852, -454, 2164, 5482, 453, 2458, 649, 988, 4630, 834, 3979, 3454, -1805, 2821, 243, 3994, 4088, -2935, 907, -4373, 3141, 4061, 1336, -2793, -2906, 1326, 3585, 2243, -795, -1146, -2617, 2485, 467, 2605, -6007, -622, 865, -5768, 3440, 133, 1673, -1535, 1741, 2965, 3133, 1685, -3512, 3312, 1936, 4194, -718, -1045, 3316, 1025, 4256, -3311, 146, 2550, -603, 3830, 950, 521, 1779, -3362, 3464, 2255, 508, 1732, -360, 3331, 2248, 3, 2168, 1211, 3124, 1261, -1391, 2269, 1214, 2613, -934, -4644, 1496, 18, 1691, -5509, -8683, -625, -1999, 343, -3817, -4108, -6565, -1026, -1347, -2552, -908, -3659, 1291, -3007, -4100, 854, -258, 2611, -597, -2462, 1039, 870, 3040, 1617, -75, 242, 609, 2647, 2241, 480, 571, -1064, 1349, 1493, -95, 1096, -4991, -310, -230, -1198, 551, -7687, 247, -1626, -2499, -439, -1502, 1179, -3249, -4583, -1799, 1162, 1165, -2823, -4923, -4597, 2471, 329, -63, -3814, -2795, 2747, -1219, 1003, -2331, -2619, 2139, -3496, 996, 671, -10526, 918, -4728, 536, 1922, -1693, 58, -2460, 160, 1144, 243, 81, -548, 326, -2391, -519, -113, 261, 1099, -1476, -3321, -964, -23, 1681, -98, -1402, -1852, -1229, 1539, -1240, -712, -1507, -2756, 604, -4442, -2833, -1025, -4327, -877, -8363, -6653, -1325, -5988, -2664, -5451, -3615, -1683, -4017, -4266, -3482, -3792, -1126, -1661, -4743, -3717, -5531, -734, -39, -4153, -7371, -6214, -1065, 761, -3076, -4698, -5942, -1607, 739, -3020, -1880, -6343, -1837, -11, -3961, -1380, -7445, -2548, -1373, -4262, -2569, -4527, -4764, -3577, -3463, -6173, -2239, -8615, -6914, -2425, -11115, -1532, -8649, -5422, -2115, -7371, -2241, -11781, -3468, -3117, -7146, -4929, -10001, -2541, -5164, -6321, -12534, -6666, -2105, -5569, -5662, -6457, -6133, -1836, -5546, -6235, -5115, -7247, -1349, -6814, -7389, -4935, -10138, -908, -7603, -6504, -5615, -7865, -984, -6123, -5026, -7264, -5584, -1760, -4853, -4536, -6103, -5394, -3247, -4344, -5444, -4203, -6692, -4664, -4946, -8220, -4134, -8615, -4049, -6705, -8903, -6814, -8582, -3007, -8827, -7019, -10001, -6540, -2745, -9873, -6516, -4880, -5002, -3444, -9812, -6759, -4108, -4625, -5346, -7050, -8247, -5031, -5273, -5970, -4433, -13365, -6615, -6786, -3769, -2615, -6399, -7865, -9429, -2733, -1760, -4134, -7162, -11945, -2538, -1992, -3729, -4774, -9064, -2952, -3537, -4674, -3621, -7264, -4412, -6163, -6469, -4053, -6786, -8582, -5408, -6343, -5888, -4968, -5422, -3647, -6705, -5592, -4119, -4038, -3119, -7179, -5686, -4246, -3096, -3951, -5353, -4997, -6540, -2613, -5888, -3843, -4089, -10704, -2698, -6732, -3710, -4003, -5759, -3529, -5979, -4831, -4728, -4282, -4940, -6943, -6786, -5546, -3795, -5480, -11629, -7912, -5353, -3792, -4536, -9812, -7247, -4963, -4500, -3518, -7865, -6705, -5195, -6653, -2859, -7912, -6732, -5494, -14195, -2716, -8086, -6615, -5152, -10284, -3339, -7247, -6267, -4616, -8454, -5164, -5494, -7408, -4527, -6480, -8718, -3748, -13738, -5127, -4089, -6899, -2610, -13738, -7213, -2345, -6434, -2613, -7960, -7317, -853, -7353, -4597, -2216, -1503, 455, -2504, -2910, 184, 805, 1343, -59, 191, 874, 1438, 1525, 822, 1243, 203, 718, 790, 591, 720, -1761, -1390, -1001, -513, -1610, -4592, -4980, -3698, -2163, -8009, -6692, -7819, -5710, -3612, -6565, -8942, -6399, -6246, -3999, -6214, -12534, -4863, -7113, -3618, -6973, -13738, -4195, -8165, -3337, -4957, -11232, -4184, -8363, -3566, -3735, -7888, -4597, -10210, -4509, -3543, -5710, -5487, -10799, -6093, -3947, -5037, -6504, -8718, -6504, -4693, -6064, -7583, -8138, -5960, -5897, -10613, -9331, -6842, -6214, -7113, -8549, -9238, -6469, -6759, -7004, -5942, -9022, -9380, -6343, -7130, -5735, -8865, -9380, -5569, -7730, -7353, -7371, -5415, -5037, -7019, -14195, -7464, -4974, -4901, -6194, -6504, -10362, -6480, -5115, -6310, -3580, -11629, -8942, -5465, -6528, -2353, -7335, -8485, -5810, -5776, -2136, -5776, -5997, -5933, -5103, -2770, -5312, -4035, -5726, -5394, -4361, -5646, -3370, -5654, -6943, -7247, -7542, -4038, -6133, -10069, -13049, -10704, -6388, -7542, -8827, -12123, -6492, -9064, -11356, -7426, -10613, -5253, -6943, -10526, -7774, -10704, -5942, -6653, -7936, -8060, -10001, -8393, -8754, -7708, -6870, -9531, -9753, -28777, -8393, -6565, -10899, -7819, -11232, -8718, -7408, -10704, -6732, -9695, -9639, -8790, -7730, -6183, -9149, -14784, -9284, -6288, -6376, -8485, -10899, -9479, -5561, -7066, -7603, -7984, -10526, -5152, -7408, -6856, -7019, -11945, -5158, -8276, -6540, -6759, -11945, -5853, -11115, -6411, -6705, -10001, -7179, -13738, -6376, -6516, -8982, -6577, -9936, -6376, -6173, -9585, -5339, -7542, -6267, -5836, -9695, -5444, -6800, -6422, -5630, -7542, -7113, -7113, -7752, -5844, -5988, -9064, -6973, -11004, -6434, -5061, -7264, -6745, -10442, -7644, -4896, -6163, -7623, -11356, -9812, -5951, -6123, -9873, -13738, -11629, -9873, -6388, -13049, -8649, -11232, -10069, -6628, -13738, -7464, -13049, -6590, -7464, -10442, -7752, -28777, -6035, -9022, -8276, -9284, -9936, -6786, -9585, -7542, -13365, -7960, -8517, -9936, -8423, -13365, -7730, -11115, -12319, -10362, -9585, -9193, -13365, -17034, -8790, -9331, -13049, -12776, -14784, -7708, -11781, -13049, -10526, -13738, -8086, -13738, -12319, -8582, -11115, -8454, -8903, -13049, -7623, -9479, -6759, -15615, -3457, -6278, -8247, -10069, -10613, -3647, -4331, -6679, -8517, -10442, -4348, -4270, -5408, -5539, -14195, -6194, -6480, -4550, -5871, -11356, -11945, -17034, -3843, -8790, -7146, -7299, -8582, -3242, -8790, -5678, -4336, -9639, -3069, -6504, -5401, -2992, -11356, -3498, -5960, -5726, -2420, -6299, -4295, -6103, -6388, -2374, -4923, -5253, -5531, -7503, -2694, -4733, -5951, -4784, -9064, -3299, -4482, -5784, -5085, -9380, -4134, -3840, -6074, -6615, -7842, -4569, -3507, -7097, -9639, -6278, -4211, -3692, -8423, -9238, -5367, -3763, -4315, -11781, -9022, -4469, -3220, -4654, -5061, -9064, -2776, -2306, -3537, -1168, -2399, -686, -940, -1132, 793, 53, 718, 307, 677, 1358, 724, 1026, 774, 1301, 571, -17, 17, 304, 671, -1900, -2108, -2881, -880, -1281, -7888, -4451, -14784, -2030, -4541, -6928, -4010, -6183, -3018, -5776, -6278, -3170, -5360, -4940, -4123, -8009, -2947, -6299, -8393, -2945, -11945, -3225, -7484, -10526, -2359, -9936, -3551, -5844, -28777, -2485, -5862, -3710, -5043, -8718, -3671, -4238, -4295, -6204, -6679, -6773, -3923, -6540, -8754, -7019, -12123, -4357, -11004, -8060, -7912, -5988, -5067, -6246, -8333, -8276, -4469, -6143, -5055, -8754, -9531, -4688, -7562, -5152, -7097, -11629, -6528, -7912, -5844, -7004, -10210, -7752, -8220, -7247, -8304, -8220, -5576, -8942, -8865, -8865, -7247, -4513, -8754, -6354, -8718, -7281, -4191, -8423, -4295, -8138, -7752, -4258, -9193, -3512, -6007, -7523, -4733, -10899, -3726, -4923, -7389, -5793, -11356, -4831, -5115, -8304, -7936, -10526, -6958, -6093, -9695, -13365, -7888, -10704, -6553, -10284, -13049, -6035, -28777, -6123, -11356, -8942, -5615, -13738, -6035, -10899, -6445, -6628, -14195, -6928, -8034, -4980, -8683, -12534, -7888, -6732, -4592, -7842, -9149, -7247, -6103, -5189, -6885, -7034, -6943, -5686, -6640, -7281, -6163, -7503, -5726, -7796, -8903, -6064, -8112, -6745, -7426, -11629, -6083, -7842, -9238, -7583, -28777, -5942, -7353, -14195, -8582, -13738, -6093, -6540, -9380, -8615, -10362, -6988, -5109, -8138, -8942, -9380, -8485, -4378, -8827, -9936, -9695, -9812, -4985, -9873, -6773, -11115, -8683, -7081, -10899, -4759, -9585, -7317, -10362, -8112, -4270, -7146, -7247, -9022, -5353, -4963, -6113, -7819, -6973, -4578, -6719, -6332, -6388, -6083, -5810, -8220, -7708, -4991, -6288, -10613, -6899, -9873, -4640, -7050, -6958, -5888, -10284, -4974, -6692, -5020, -6007, -9873, -5638, -5694, -5221, -6225, -9639, -6800, -5319, -7281, -5422, -9380, -9479, -5694, -13738, -5115, -8982, -28777, -6759, -10799, -5933, -9873, -13738, -8086, -9753, -7179, -15615, -11945, -8865, -11629, -7247, -11629, -10442, -9639, -14195, -6814, -8393, -9238, -12776, -12534, -6705, -7281, -8060, -13738, -9812, -6928, -7213, -6628, -8220, -8485, -7299, -8220, -5670, -6773, -8865, -7912, -11629, -5387, -7464, -10899, -9193, -6246, -7523, -7113, -6602, -4049, -4616, -8363, -5576, -3701, -3626, -3933, -4703, -3866, -2564, -4127, -4416, -4805, -3449, -2429, -5871, -6299, -7299, -4238, -3412, -8754, -10442, -11629, -5915, -6332, -8827, -12123, -13049, -7583, -8485, -5933, -11781, -10613, -8276, -5008, -3714, -13738, -6666, -9149, -3840, -2499, -14784, -4826, -11945, -3580, -2023, -10210, -4223, -14784, -3549, -2270, -7583, -4837, -12534, -3468, -3227, -6602, -7247, -10138, -3319, -4790, -6943, -10899, -7603, -3321, -6445, -8903, -6914, -6016, -3415, -7066, -13738, -5465, -5451, -3112, -6745, -12534, -7819, -6422, -2366, -6602, -7445, -4985, -6759, -1265, -5844, -2259, -255, -2435, 46, -2403, 132, 1713, -43, 902, -53, 802, 2295, 890, 780, 936, -73, 1840, 631, -684, 803, -2672, 524, -828, -4532, -246, -5306, -1502, -3626, -7213, -1797, -5768, -3714, -7464, -3968, -3457, -8790, -4800, -8423, -3339, -5195, -7264, -5415, -8112, -3701, -6640, -6103, -6590, -8865, -4800, -11004, -7426, -7353, -10069, -6204, -7264, -12123, -8138, -10001, -6299, -3710, -13738, -9936, -9695, -4997, -2754, -10704, -11232, -9380, -4486, -3065, -9585, -7960, -8942, -5646, -3222, -9193, -5208, -9812, -9022, -2548, -9873, -3751, -11232, -8165, -2231, -13738, -3266, -7353, -7665, -2639, -11781, -3621, -5008, -8582, -3726, -7796, -4985, -3586, -6376, -5451, -6615, -8009, -2733, -4946, -7888, -6973, -28777, -2571, -4564, -10613, -9429, -11629, -3257, -4644, -6773, -14784, -10001, -4997, -4907, -5037, -7819, -8517, -7464, -5516, -5299, -6035, -7583, -7774, -7264, -8582, -5710, -7984, -7130, -11232, -10613, -6074, -9331, -7426, -6914, -6045, -6399, -8060, -8865, -5085, -5020, -6007, -6719, -12319, -5183, -5360, -5260, -6885, -8942, -6828, -7523, -4769, -8485, -5997, -7603, -8942, -4842, -9531, -5115, -6732, -4536, -5509, -8363, -5710, -7004, -2764, -6786, -8247, -6103, -6958, -2388, -7623, -7912, -5091, -6035, -2941, -6856, -6267, -4759, -6035, -3773, -6457, -5374, -5346, -6958, -3900, -7426, -5554, -6376, -7842, -3580, -9936, -6528, -7445, -8276, -3603, -9812, -7503, -8582, -8276, -4108, -8485, -7644, -9064, -7162, -4790, -9238, -7130, -8942, -6123, -5988, -12123, -6692, -9149, -5670, -8615, -10899, -6653, -8549, -5827, -8485, -9695, -7389, -7389, -5607, -6628, -11945, -9429, -6914, -4250, -6640, -14784, -12534, -7353, -3112, -8086, -10442, -14784, -8333, -2827, -10362, -9936, -13049, -9639, -3422, -10069, -10526, -12534, -11488, -4728, -8192, -10799, -9380, -14195, -6133, -7445, -11115, -6388, -17034, -7196, -7644, -13365, -5103, -28777, -8485, -8034, -28777, -4918, -14195, -9695, -8982, -12776, -5374, -11488, -8363, -11356, -10362, -6183, -11356, -6899, -12534, -9585, -7299, -13049, -6365, -11356, -9380, -9284, -15615, -6800, -8754, -9380, -10210, -28777, -8827, -6773, -9380, -7408, -13365, -17034, -6553, -9936, -6194, -9331, -8903, -8086, 11376, 9600, 11660, 11728, 10794, 10645, 9661, 10965, 11136, 10261, 8080, 9419, 8674, 9319, 8615, -18, 8340, 3679, 6278, 6050, 4297, 6180, -3083, 2848, 4811, 4815, 2931, -853, 375, 4712, 3398, -367, 841, -643, 3351, 2719, -1859, 1574, 86, -243, 545, -2462, 2805, 696, -6745, -297, -1544, 3809, 558, -6745, 5101, 348, 3513, 1460, 543, 6903, 1140, 3359, 3129, 4304, 7444, 2841, 4499, 4339, 6106, 7259, 5262, 5216, 4899, 6658, 6464, 6493, 5168, 4629, 6041, 4908, 6444, 4650, 3293, 3916, 2536, 5282, 3973, 311, -1635, 1323, 3644, 2994, -3650, -1062, 1611, 2734, 1071, 469, 991, 1308, 2214, -3412, 2037, 1585, 1509, 2032, -5458, 2347, 1907, 2238, 2269, -3266, 2357, 791, 2229, 2248, -5422, 2591, -10210, 1589, 1720, -2922, 2683, 1545, 1385, 414, -449, 2201, 4051, 1681, -218, -28, 1164, 4505, 1891, 1978, -683, 1006, 3441, 1794, 3098, -1833, 1661, 361, 980, 2706, -5326, 1731, -9873, -128, 1255, -3420, 1665, -3563, 609, 528, -83, 1988, -6899, 1023, -182, 822, 2326, -4764, -818, -3080, 789, 2510, -1636, -4416, -1648, 747, 2369, -395, 464, -533, 563, 1582, 348, 1789, -2585, -454, 230, 171, 1626, -6163, -2612, -261, -1567, 690, -712, -5623, -11, -9022, -642, 887, -5670, -553, -2770, -2791, 1072, -3910, -1872, 156, -8683, 157, -3659, -2248, 1306, -5487, -1837, -4831, -1674, 1494, -3961, -4831, -6928, -1717, 914, -6365, -5091, -8138, -1934, 148, -8192, -2128, -6602, -1076, 504, -3913, -887, -4703, -1, 1157, -2837, -1026, -4153, 495, 1065, -2509, -2064, -6278, 377, 131, -2153, -2997, -6469, -308, -1456, -1927, -2485, -1819, -1437, -2975, -2003, -1340, -322, -2673, -3010, -1298, -769, -276, -2409, -2447, -143, -840, -1041, -825, -2165, 321, -1030, -2071, 107, -1844, -8, -941, -3194, 137, -1774, -805, -729, -4536, -425, -2424, -1370, -618, -6943, -654, -3714, -1699, -795, -4262, -197, -4821, -3071, -1489, -1746, 121, -4997, -6628, -2735, -1214, -4, -4654, -5014, -3916, -2289, -681, -4723, -3365, -4743, -5539, -2107, -4408, -3354, -5784, -14784, -4003, -2754, -3876, -4991, -8517, -5339, -1248, -3521, -4800, -10442, -5444, -396, -2247, -6615, -6705, -3049, -21, -1444, -5516, -4654, -1859, 102, -1650, -4262, -5326, -2053, 59, -3062, -4669, -5401, -2490, -141, -6354, -4896, -2895, -2370, -507, -4630, -4361, -2871, -2778, -1177, -1438, -4258, -6565, -3380, -2364, 127, -5569, -2495, -2071, -3347, 786, -10001, -135, -656, -2253, 525, -7960, 125, -63, -1122, -1137, -5487, -1067, -40, -1082, -5531, -3773, -3457, -352, -2497, -4319, -3165, -6399, -1491, -6565, -2819, -4226, -12534, -4438, -8942, -3215, -5509, -4698, -3083, -11945, 1793, 7416, 7860, 8286, 5452, 1371, 6707, 7367, 7598, 4865, 859, 4671, 6004, 5249, 3697, 1201, 3925, 4138, -188, 3502, 1367, 4927, 1968, 1484, 3547, 1083, 4869, -311, 2595, 3202, 1199, 3943, -770, 2255, 2986, 2004, 2805, 798, 1919, 2818, 2829, 2493, 2401, 1837, 2409, 3360, 2435, 3461, 1020, 2198, 4199, 2700, 4312, -1683, 3264, 5536, 4216, 5425, 452, 4817, 6465, 5055, 6365, 2468, 5736, 6588, 4760, 6417, 2299, 5879, 5957, 3956, 5170, 312, 5403, 4907, 3864, 1965, -1370, 4463, 4040, 3762, -8718, -732, 3017, 3628, 2079, -3647, 5, 1101, 3116, -4664, -6943, 1374, -280, 2106, -571, -5195, 2164, -1166, 1542, -359, -3782, 2141, -2699, 1374, -2999, -4017, 1695, -4361, -142, -58, -4564, 1226, -3076, -3683, 394, -7299, 659, 12, -2952, -183, -1849, -163, 1972, -465, 1043, -1064, 175, 3156, 1730, 1835, -4821, 1291, 3878, 2879, 1654, -2385, 1302, 4166, 2946, 817, -301, -126, 3942, 2059, -691, -1304, -1654, 3174, 283, -1281, -3726, -618, 1811, -2470, 796, -3954, 438, -478, -6504, 1793, -3386, 1220, -5333, -6123, 1070, -1175, 1843, -2470, -2900, -2622, -39, 1965, 110, -788, -4195, 73, 922, 774, 211, -345, -154, -3286, 238, -9, -127, -353, -1614, -1113, -1513, -1868, -778, 1504, -2358, -1355, -6278, -1746, 2188, -2576, 517, -7162, -2918, 1649, -1753, 1130, -4164, -3612, 174, -191, 631, -2526, -3149, -2462, 1037, -441, -2036, -2006, -5871, 1282, -1180, -2265, -1462, -1961, 118, -1614, -1123, -1900, 403, -3347, -2291, 688, -3014, 1543, -7484, -1928, 1715, -3124, 1816, -7819, -171, 1837, -2129, 1362, -5569, 1082, 1220, -1526, 336, -955, 1433, 536, -1068, -1154, 340, 843, 424, -287, -3515, -196, -471, 35, 240, -10526, -3040, -931, -1404, -147, -4625, -7912, -232, -3683, -1975, -2468, -2130, -132, -4901, -7097, -2363, -719, -894, -3846, -6278, -2897, -536, -2411, -1727, -3049, -3065, -987, -4880, -815, -1836, -1671, -1654, -8549, -1481, -1872, 526, -1587, -5686, -3680, -3629, 1639, -788, -3650, -3189, -8247, 1469, -235, -3208, -1495, -7230, 58, -191, -4408, -921, -10069, -2302, -912, -6692, -979, -7034, -4266, -3189, -2900, -1201, -3804, -4278, -7960, -1328, -752, -3135, -3850, -3504, -1635, -181, -2008, -4495, -1849, -2219, -498, -514, -3284, -1613, -1161, -2030, 177, -1225, -2644, -818, -4250, 22, -892, -6480, -1725, -3067, -911, -2745, -5487, -2646, -1057, -2191, -2666, -2741, -2821, 89, -2427, 166, -2277, -3714, 265, -2612, 874, -2207, -4278, -848, -4532, -226, -1957, -3027, -4500, -12776, -4495, -1318, -1769, -6035, -4940, -4743, -55, -906, -2462, -2648, -1382, 517, -714, -1779, -2086, -870, -413, 3125, 4077, 7513, 329, 5137, 2368, 4078, 7330, 2346, 5914, 4496, 4120, 7077, 4812, 6870, 6162, 4241, 6907, 5747, 7093, 5901, 4017, 6273, 5135, 6445, 3593, 2714, 4624, 2982, 4950, -3704, -676, 1298, -573, 3187, -516, -3903, -6732, -2302, 2372, -807, -1953, -2929, -599, 1732, -3726, -1857, -1777, 933, 969, 2994, -108, 189, 2259, 1100, 5327, 2648, 1713, 2849, 1221, 5969, 4394, 1652, 2570, 933, 5191, 4743, -337, 2764, 2724, 2707, 3459, 601, 3544, 4731, -2994, -82, 2471, 3461, 5554, -6469, 336, 2253, 2219, 5207, -3247, 1469, -86, 388, 3696, -1460, 270, -7426, -368, 1416, -454, -2015, -4795, -135, 303, 1089, -1209, -3034, 67, -227, 2194, -100, -2114, -395, -81, 2402, 201, -1272, -2277, 886, 1891, -98, -612, -6399, 1092, 871, -943, -174, -2201, 1433, -395, -2229, -45, 100, 2453, -821, -3808, -306, 952, 2811, -228, -3597, -1055, 861, 2073, -232, -1474, -2223, -70, 931, -1636, -308, -2646, -1899, 910, -6045, -82, -1747, -4718, 1230, -6553, -297, -722, -5487, 1521, -2622, -855, 190, -3609, 1725, -1241, -2361, 899, -1630, 1705, -921, -5539, 1178, 565, 2127, -1912, -11232, 733, 2054, 2927, -5970, -6204, -594, 2509, 3207, -3566, -2813, -1411, 1982, 2359, -720, -1594, -82, 1084, -559, -83, -1879, 952, 872, -3218, -927, -3314, 1339, 668, 961, -2615, -4420, 1314, -327, 2380, -1076, -2819, 1241, -2238, 2687, 352, -1664, 1511, -5584, 2189, 137, -2259, 1823, -3951, 807, -1777, -5339, 1587, -1368, -1627, -2950, -3455, 416, -294, -2294, -1077, -1773, -2355, 233, -465, -544, -2626, -9753, 520, 412, -1343, -6856, -2722, 345, 363, -2819, -6332, -479, -383, -635, -2681, -3788, 496, -1391, -3036, -1817, -2631, 649, -2460, -6842, -1766, -1320, -39, -3804, -2833, -2022, -242, -1637, -4669, -749, -1838, 117, -2737, -4172, 351, -1682, -605, -1030, -4399, 968, -2404, -2937, 672, -7179, 867, -4352, -8582, 1503, -12123, -470, -2603, -6914, 1408, -7130, -3367, -386, -6885, 355, -8790, -1598, 179, -9022, -1652, -6143, 178, -691, -4295, -3388, -2548, 541, -3463, -2015, -3023, -894, 301, -6692, -1305, -3618, -388, -122, -2510, -1773, -7503, -1050, -809, -1005, -3210, -5394, -3337, -1807, -894, -4831, -3269, -3603, -2675, -1827, -8138, -2294, -1187, -2514, -3089, -6007, -972, -224, -1807, -3597, -1361, -187, -99, -1843, -4086, 148, -406, -730, -3357, -5743, -237, -1953, -2622, -4420, -11945, -3124, -6553, -6376, -1752, -6365, -8247, -6267, -5487, -1097, -3683, -3441, -3615, -4482, -3124, -2567, -2076, -1518, -3329, -7081, -1771, -180, 215, -1460, -2073, -1183, 856, 567, -1010, -923, -1428, 553, -630, -3040, -942, -3635, -4315, -2251, -1484, -4226, -3468, -4688, -2135, -2475, -1104, -3741, -9639, -4207, -7389, -309, -4086, -6666, -5049, -3957, -702, -3632, -3989, -2831, -1501, -596, -3191, -4115, -2514, -586, 129, -3025, -6705, -2534, -976, 439, -2861, -13365, -1102, -3923, 1053, -3177, -6786, 293, -5853, 1860, -3738, -4779, 885, -1515, 1766, -3830, -4795, 757, -824, 165, -5933, -7603, 154, -2038, -4046, -5702, -5195, -627, -5951, -5784, -1778, -2076, -1206, -6074, -3218, -931, -1020, -1165, -3276, -1953, -2197, -1397, -771, -2762, -1080, -7984, -3566, -936, -3147, -509, -2615, -11945, -1678, -2280, 304, 632, -2681, -179, 325, 1363, 2254, -344, 1602, 2122, 2034, 2937, 100, 2137, 2605, 1773, 2796, -949, 1536, 1657, 104, 1900, -3507, -96, -987, -3583, 480, -6354, -3210, -4017, -2514, -1136, -6299, -9106, -4810, -968, -2801, -7371, -2893, -4527, -937, -3773, -9531, -1233, -2573, -1604, -3662, -2502, -1258, -2289, -2458, -3856, -224, -2875, -3447, -2845, -4640, 336, -8060, -5576, -2699, -5678, -279, -8276, -5759, -3054, -6288, -1724, -7562, -4527, -4513, -5970, -3744, -7230, -4412, -6267, -5227, -6628, -2641, -4386, -4880, -4738, -6411, -968, -3119, -3471, -4991, -4348, -782, -2090, -3659, -6143, -3149, -1591, -1651, -6828, -5133, -2176, -2992, -1445, -7842, -2910, -1830, -4433, -1449, -3817, -1525, -2807, -5836, -1595, -3698, -371, -5718, -7984, -1610, -5561, 637, -3701, -13365, -1774, -4974, 1135, -1673, -10362, -2592, -4319, 973, -1406, -9331, -4319, -7774, 277, -2432, -28777, -6814, -5487, -603, -4723, -5353, -6653, -1424, -1394, -7603, -2031, -4718, 68, -2140, -7130, -436, -3635, 450, -2914, -5836, -59, -3301, 278, -4067, -5451, -911, -3271, 2, -7213, -5195, -3112, -3098, -164, -8982, -3271, -6445, -2731, -503, -4348, -2165, -7130, -1869, -1571, -2731, -2497, -4985, -930, -3509, -1847, -3754, -3757, -513, -3344, -1672, -4738, -2248, -679, -2409, -3130, -5333, -476, -1378, -2596, -8485, -6045, 553, -2087, -3850, -3279, -6045, 736, -1773, -9429, -1341, -4527, 148, -930, -4703, -1067, -3603, -1199, -164, -1736, -1507, -3365, -3463, 149, -1435, -2150, -3521, -6225, -406, -3170, -2720, -4769, -4219, -1961, -6516, -2540, -6577, -2608, -4089, -3927, -1720, -5055, -2448, -6214, -2881, -1466, -4495, -3177, -9429, -3814, -2119, -5759, -3814, -12534, -6528, -3036, -9812, -3689, -10526, -6553, -3042, -9873, -3574, -6565, -4625, -3096, -5718, -4258, -5152, -4134, -4078, -4161, -6035, -6267, -5879, -6163, -3441, -8112, -28777, -12534, -7371, -2939, -7687, -5718, -4184, -5502, -2482, -5279, -4031, -2505, -4365, -2140, -3873, -4469, -2521, -4038, -1940, -4416, -4985, -3707, -3850, -1894, -9380, -4234, -6123, -3344, -2119, -5286, -4365, -10210, -3319, -2939, -2799, -6093, -11629, -1542, -2366, -3201, -1569, -4416, -3449, -4104, -8582, -3261, -4230, -2619, -6745, -6103, -6376, -1076, -517, -6343, -3856, -10069, -669, 406, -4238, -4513, -8393, -1117, 415, -2236, -5097, -6565, -1002, -163, -583, -2331, -4003, -1060, -1210, 310, 52, -2735, -2211, -3543, 244, 1264, -3518, -2847, -11945, -851, 1255, -6457, -2040, -2617, -3012, -118, -4021, -2223, -628, -6800, -3540, -2887, -3954, -380, -7708, -12319, -3621, -9695, -1351, -3704, -5306, -4644, -6194, -2843, -1240, -3476, -2776, -2768, -2480, 116, -1819, -907, -1489, -1339, 132, -782, -722, -650, -1144, -1346, -1181, -3271, 1068, -1040, -735, -3378, -1696, 2818, 351, 1279, -1225, 1663, 3821, 1190, 1568, 958, 2741, 4022, 696, -42, 1361, 2391, 3459, -1100, -4774, 352, 804, 2211, -3515, -5247, -1807, -1492, 565, -4606, -4195, -2516, -2778, -787, -3425, -4097, -1961, -2841, -1460, -1834, -3482, -2845, -1598, -2148, -859, -4438, -4997, -460, -4071, -542, -8276, -4112, -56, -11629, -1088, -7730, -2701, -218, -4555, -3319, -5942, -1887, -793, -2879, -7708, -6814, -1078, -1925, -3027, -1839, -8718, -303, -4254, -3383, 105, -4390, 327, -6540, -3496, 557, -1976, 392, -3906, -4262, 150, -1095, -813, -2468, -5879, -665, -1458, -5085, -1777, -7426, -1503, -2954, -4123, -1046, -5429, -2472, -4946, -1647, 120, -3034, -3779, -5367, -1913, 1154, -1711, -2893, -4365, -4352, 1504, -1025, -1050, -4495, -7299, 960, -618, -275, -8582, -4254, -661, -454, -437, -6354, -3367, -3540, -830, -1450, -3110, -4003, -4769, -2076, -3886, -2587, -6194, -4278, -3597, -9064, -3352, -13049, -3964, -2543, -2785, -4863, -9238, -2435, -1218, -270, -6214, -6540, -1810, -726, 1002, -4559, -4795, -2999, -891, 1576, -3117, -3968, -5367, -1825, 1555, -3168, -5031, -3071, -3964, 897, -4464, -6288, -2057, -7819, -626, -4929, -3067, -2863, -9022, -3982, -4134, -1598, -5273, -4703, -6732, -4361, -1378, -7426, -1883, -2803, -5979, -1983, -8615, -586, -1935, -7752, -3830, -6565, -557, -1762, -6814, -10069, -3896, -1704, -771, -6480, -4311, -3276, -2956, 83, -6914, -2112, -4416, -2372, -117, -6388, -2111, -8423, -2065, -1687, -5299, -4238, -8982, -2241, -5319, -4611, -17034, -6321, -1842, -8790, -4021, -4659, -8393, -1534, -7644, -3198, -2781, -8333, -1922, -9193, -2581, -2244, -3954, -2531, -4442, -2851, -2197, -2745, -2833, -1551, -4513, -2659, -2926, -3076, -324, -5906, -4176, -4153, -3098, -378, -4810, -7819, -6565, -2507, -1616, -6422, -6074, -8982, -1713, -4097, -9936, -3455, -8276, -1388, -8827, -3870, -2514, -6914, -2191, -7603, -2986, -2519, -5576, -5326, -3042, -4907, -3140, -5043, -9695, -1066, -11232, -4064, -5502, -5554, -455, -3913, -4738, -6732, -6504, -1077, -2425, -5067, -8060, -8982, -3133, -2677, -5726, -8683, -6278, -3161, -1181, -2789, -5743, -1790, -5607, -4918, -2787, -532, -5055, -4863, -5437, -3438, 1153, -4923, -3968, -2285, -7936, 1457, -939, -1872, -441, -3521, 789, 191, -697, 563, -1176, -606, -186, -867, 711, -702, -1288, -2086, -1765, -68, -1274, -346, -5115, -2460, -1966, -1774, 337, -4664, -3515, -5546, -960, 213, -5793, -6354, -11629, -85, -884, -9873, -9479, -6204, 186, -3551, -5115, -3321, -3644, -237, -8276, -3537, -497, -2560, -1990, -2730, -2142, 1089, -2578, -7752, -346, -1516, 1883, -3474, -1892, 753, -1222, 1911, -5319, -316, 1015, -157, 984, -8865, -1908, 604, -58, -97, -1940, -2442, 101, -2462, 1006, 1032, 1535, 786, -2319, 1736, 2215, 2780, 1759, 652, 996, 2082, 2543, 2055, 1236, -1352, 728, 1643, 1718, 336, -4723, -1878, 1452, 877, -1159, -3218, -5735, 1720, -448, -791, -1093, -4703, 1435, -1644, -20, -108, -2698, 551, -1859, -581, 153, -2569, -187, -2229, -2216, -45, -4238, -26, -2438, -266, -1116, -5888, 353, -1402, 1424, -3571, -3638, 339, -416, 1442, -3114, -2412, -388, 29, 143, -1792, -2065, -2305, 182, -778, -2512, -2000, -5615, 77, -606, -5145, -1980, -4433, -566, -1487, -2422, -2414, -3142, -2107, -2069, -94, -3811, -2821, -5214, -569, 790, -4311, -3101, -15615, 275, 718, -2225, -4644, -5170, 80, -188, -922, -10284, -2774, -1011, -1732, -682, -4545, -1800, -1369, -2178, -1427, -1727, -1899, -487, -1194, -1952, -300, -2926, -540, -804, -103, 464, -2677, -2123, -1423, 1369, 671, -915, -5862, -3334, 1645, 235, -12, -10613, -5853, 708, -1123, -92, -6516, -4258, -1471, -4172, -824, -3896, -3543, -3843, -11115, -1507, -2291, -4420, -4703, -6173, -1923, -1647, -6577, -4532, -5970, -2681, -1674, -8582, -2305, -8333, -3047, -2119, -5615, -1080, -12123, -1630, -2419, -4262, -1087, -5546, -86, -1908, -5408, -1884, -2348, 810, -1678, -9531, -2799, -546, 935, -2883, -3975, -3798, 191, 250, -4024, -1848, -5638, -80, -929, -1782, -1066, -7752, -1378, -1106, -938, -870, -7264, -3433, -510, -1741, -928, -3592, -6540, -792, -4331, -1053, -951, -6928, -2651, -6914, -1189, 250, -3067, -6528, -4254, -1197, 169, -1952, -3933, -3020, -957, -1095, -2309, -1879, -2895, -608, -2228, -3401, -973, -3729, -478, -1579, -4469, -606, -5195, -864, -886, -5247, -554, -5008, -1788, -425, -5584, -799, -2973, -2552, -508, -7146, -1484, -1085, -2841, -1664, -14784, -2701, -54, -4049, -4028, -5970, -4031, -53, -8517, -6194, -4569, -4262, -1013, -6640, -6026, -5109, -3707, -1882, -4089, -3779, -5960, -3417, -1490, -3808, -2288, -5429, -3549, -1206, -4858, -2153, -4810, -3944, -1691, -7113, -3438, -5208, -4191, -3161, -13738, -6411, -7196, -3923, -6828, -7113, -6256, -11781, -3471, -6183, 4555, 15411, 7007, 10967, 10737, 8875, 14992, 7271, 10267, 10109, 10369, 13697, 7163, 7923, 8085, 9998, 11391, 5948, 2320, 4153, 8634, 7948, 3896, -513, 552, 7384, 6331, 2489, 442, 440, 6092, 7580, 1513, 355, -2028, 5616, 7957, -317, 1608, -1364, 6813, 7370, -3060, 1339, 780, 6555, 5815, -2195, 251, 2419, 3138, 3196, 430, 757, 3938, 2245, 1437, 3113, 2371, 5047, 5984, 4148, 4832, 3588, 5594, 6338, 6446, 5374, 4266, 5513, 5190, 7346, 4652, 4298, 4535, 3562, 6799, 2430, 3586, 1997, 2533, 4485, 765, 2135, -1617, 1314, -1242, 1843, 164, 184, -1490, -1172, 1405, -1369, -411, -3232, -1131, -1009, -1508, -4093, -927, -3632, -6332, -879, -4119, -297, -1135, -3237, -139, -2075, -671, 60, -1756, 223, -1356, -2143, -962, -2730, 109, -877, -4718, -7097, -2726, -515, -497, -4759, -2241, 518, -1817, -808, -4890, 893, 1886, -3748, -2483, -9695, 2311, 1818, -3444, -7247, -2799, 3001, 615, -1488, -5037, -1157, 3018, -1370, -308, -2401, -1672, 2199, -2904, -13, -1314, -3766, 387, -2545, -743, -705, -6504, -2024, -1526, -2924, -419, -2208, -3449, -1261, -6943, -254, 319, -6026, -1999, -7865, -143, 1382, -8718, -3133, -8393, -323, 1337, -4769, -3677, -8112, -806, 21, -4592, -3751, -9238, -1176, -3632, -5133, -2502, -7665, -1149, -5827, -5026, -1637, -4664, -1204, -2470, -5615, -2340, -4378, -1817, -2118, -8220, -5686, -7264, -3172, -3140, -8827, -8582, -8718, -4708, -4743, -5710, -4858, -4460, -4912, -4573, -4708, -4764, -3769, -4754, -3563, -5133, -6365, -4748, -5607, -3496, -6469, -7484, -6278, -7819, -3827, -6602, -5623, -5319, -8276, -3227, -5539, -3820, -3603, -6732, -2855, -5306, -2772, -2517, -6411, -3729, -6602, -2637, -1956, -6885, -6973, -8582, -3266, -1771, -7408, -11356, -8827, -3827, -1948, -7583, -5915, -6480, -3744, -2819, -7562, -5247, -4518, -3889, -5292, -7408, -5646, -3441, -4940, -17034, -6434, -5607, -2545, -7687, -5422, -5202, -5189, -2416, -7644, -4067, -4555, -5026, -3543, -5158, -4635, -4703, -4683, -5599, -5026, -6577, -5502, -4583, -6973, -6773, -9873, -6246, -5924, -7730, -6153, -17034, -5960, -8060, -9936, -4800, -7960, -4880, -6628, -14784, -5221, -4759, -4127, -7464, -8138, -7774, -3222, -3846, -6074, -6602, -12776, -2809, -3603, -3208, -6288, -7281, -3203, -3375, -2325, -6615, -5472, -3985, -3417, -2935, -7708, -4880, -4635, -3843, -5189, -9585, -5306, -4821, -5279, -8304, -11356, -6516, -4573, -10704, -5103, -13738, -6016, -3951, -7960, -4046, -14784, -5240, -3594, -5020, -4929, -9429, -5306, -3824, -4250, -7730, -7019, -5879, -4601, -4344, -9479, -5401, -7247, -5853, -5189, -8112, -5312, -9429, -7984, -7050, -6732, -7230, -11629, -15615, -9639, -6267, -6267, -12776, -9106, -8582, -6943, -4573, -8138, -5951, -7264, 8226, 411, 6776, 10899, 8024, 7438, 1696, 6047, 10370, 7498, 4785, 3410, 3550, 8707, 5851, -1383, 4361, 1496, 5573, 3279, -6615, 4550, 3681, 387, 2930, -1050, 4148, 3959, 966, 3766, 2183, 3331, 2484, 2219, 3780, 3329, 2233, -378, 2612, 3424, 3556, 789, -265, 2591, 3346, 2596, 234, -611, 2600, 3792, 1704, 2757, 1456, 3414, 4338, 5176, 4562, 5128, 4379, 4499, 7056, 5170, 6859, 4481, 4032, 7438, 4820, 7148, 3264, 2816, 6602, 3842, 6041, 1187, 666, 4649, 2801, 2942, 2185, -3294, 1847, 2180, -28777, 3045, -6235, -819, 1672, -245, 2564, -3208, -2505, 535, -232, 1386, -2964, -3465, -1451, -786, 438, -2538, -942, -1457, -669, -469, -1540, 1080, -175, -2370, -2226, -1040, 1762, 391, -11488, -4907, -976, 1432, 604, -1869, -5408, -1245, 210, 656, -377, -5487, -1874, -1962, 337, -1040, -7097, -2851, -5836, -747, -4168, -6759, -4504, -9064, -2438, -6163, -4278, -8112, -4473, -1415, -2795, -2837, -5584, -3074, 223, -2270, -2149, -2984, -3286, 756, -3321, -1587, -2331, -5584, 356, -5906, -846, -2378, -12319, -710, -10284, -286, -1996, -5195, -2247, -11629, -341, -776, -3580, -5152, -7644, -1509, 500, -2709, -9284, -4536, -4946, 1008, -1621, -3225, -2841, -2102, 543, -1136, -2386, -2075, 960, -628, -1855, -4500, -2111, 2341, -1690, -4286, -4940, -3112, 2706, -2705, -12776, -2372, -5202, 2177, -4738, -6615, -2807, -4327, 689, -9695, -4295, -5247, -2340, -1011, -6528, -3460, -2610, -1849, -776, -3592, -3482, -1296, -2954, -621, -3225, -4718, -2172, -7335, -1218, -4486, -7644, -6411, -7603, -1245, -5360, -7542, -5576, -4858, -559, -5214, -5630, -3112, -6288, -321, -5202, -4587, -3417, -11945, -932, -4564, -4097, -5286, -6973, -2536, -4307, -4315, -6856, -6692, -5097, -5097, -5240, -5273, -8982, -5353, -7445, -5735, -2914, -10704, -3597, -28777, -4408, -2203, -6885, -2507, -10526, -3301, -3951, -4199, -2107, -9284, -3291, -8034, -2779, -2259, -6928, -4923, -2902, -2630, -2743, -5465, -10899, -2016, -3860, -3331, -5429, -7097, -3391, -6457, -4056, -5346, -5494, -8220, -7842, -4991, -4616, -5422, -6870, -9022, -5253, -5020, -4774, -3920, -17034, -3910, -6602, -3927, -2772, -9022, -2550, -5079, -3441, -2510, -7281, -1973, -3665, -3563, -3140, -6528, -2169, -4028, -3748, -4764, -6553, -2960, -6278, -2954, -6469, -8304, -3717, -7730, -2132, -6103, -14784, -3433, -5678, -2176, -5924, -11004, -2855, -5109, -3339, -6411, -9284, -3042, -5960, -6103, -7019, -9238, -4134, -9106, -14784, -8009, -10362, -5145, -9429, -9873, -10210, -12776, -4853, -5260, -7389, -7842, -9585, -4774, -3644, -6278, -4874, -6870, -5906, -3438, -5576, -3380, -5509, -9238, -4438, -4733, -2918, -5584, -7247, -5979, -3843, -3347, -7464, -4361, -5793, -3266, -4625, -10001, -3638, -5091, 1053, 8110, 8914, 8307, 6042, 624, 7849, 8377, 7697, 6023, 614, 6830, 6761, 5694, 5584, 1187, 4282, 4227, 1468, 3982, 547, -3409, 2171, -3076, 110, -1225, 2598, 2072, -3543, 1042, -665, 4111, 1684, -506, 2658, -964, 3751, -446, 2235, 1984, -7146, 2103, -7936, 2601, -337, 2168, 462, -1580, 2579, 1717, 5343, 1916, 1908, 4177, 4251, 6921, 4386, 3752, 5080, 5244, 7424, 5647, 4202, 4292, 4783, 6883, 5311, 2971, 305, 2614, 5111, 2609, -777, -620, 3635, 1736, -4464, 1146, 2544, 5977, -629, 2458, 2514, 1870, 6709, -634, 3097, 1606, -2359, 6413, -2823, 2131, -1302, -3342, 5643, -7623, 316, -6773, -908, 4793, -5487, -2306, -13049, -1451, 3640, -3151, -4555, -9695, -3574, 1736, -2908, -5234, -6388, -5592, -904, -4759, -9238, -3996, -3723, -2510, -17034, -4274, -2615, -2599, -1828, -5394, -2601, -1887, -1611, -2331, -2945, -3496, -1453, -538, -7752, -2242, -4464, -1450, 44, -1051, -2606, -2166, -1784, 49, 1245, -3773, -1528, -2204, -388, 1328, -4429, -2473, -3158, -1272, -587, -3686, -3594, -5085, -2728, -7081, -2881, -4123, -7408, -5202, -3215, -2132, -5339, -11629, -8982, -1488, -1471, -5031, -4940, -4299, -1189, -1473, -4923, -1805, -1452, -797, -2510, -4010, -677, -91, -222, -4545, -2633, -1019, 204, -349, -6666, -3563, -2386, -385, -1899, -6183, -11356, -1821, -1716, -3036, -4620, -3710, -342, -3817, -531, -4149, -2615, -216, -4386, 781, -4013, -4518, -1874, -2895, 948, -3194, -4010, -6590, -2019, 322, -2008, -1979, -4344, -670, -624, -1414, -2191, -2979, 628, -990, -1710, -4597, -4071, 1114, -976, -3110, -8982, -8754, 807, -1502, -7665, -6914, -7984, -33, -2829, -6045, -7179, -5170, -977, -4620, -2677, -7299, -4336, -1666, -5743, -2254, -6183, -3319, -2350, -5615, -3647, -5853, -2339, -3933, -5539, -7130, -5158, -2069, -8423, -5546, -8903, -4438, -2690, -10069, -4640, -7644, -4403, -4149, -7865, -3586, -7213, -4784, -5494, -12319, -2897, -5686, -4940, -4985, -8485, -2608, -4108, -4847, -4130, -5247, -3027, -3239, -5133, -3940, -4064, -4935, -2950, -6553, -4532, -3683, -10526, -2933, -10613, -5951, -3927, -5735, -3038, -11945, -8333, -5037, -3930, -3433, -7730, -11232, -7146, -3647, -4473, -6016, -13049, -6719, -3629, -6083, -5451, -14195, -4940, -3299, -7960, -6083, -13365, -4331, -3172, -10526, -8304, -17034, -4733, -3843, -15615, -10069, -9695, -6113, -5584, -15615, -9149, -6492, -8220, -7230, -12319, -11004, -5195, -7960, -6123, -6719, -17034, -4759, -6615, -4907, -5043, -9193, -4523, -6376, -3748, -5584, -7644, -4523, -7081, -2651, -7484, -6113, -4698, -8192, -2111, -6640, -4438, -5195, -8363, -2429, -5145, -3795, -6914, -7842, -3843, -4067, -4408, -13049, -7936, -6469, -3840, -5988, -5638, -8718, -8718, -4940, -7708, -3201, -9812, -7936, -7960, -4748, -6653, -4769, -7050, -7603, -6332, -6615, -4513, -7019, -5942, -7299, -6388, -4869, -7774, -4805, -6225, -5879, -5710, -6828, -5429, -5654, -6388, -6590, -4460, -11356, -5879, -8582, -7113, -3680, -5710, -6842, -7960, -7796, -4157, -3375, -7819, -6469, -8333, -5253, -3296, -7445, -6928, -7774, -6528, -4620, -6870, -8247, -6640, -7708, -7445, -6528, -8754, -6153, -8247, -14784, -5844, -9812, -6602, -8009, -11629, -5415, -9753, -8333, -7603, -9193, -5306, -7464, -17034, -7146, -8790, -5554, -5569, -8718, -6786, -7774, -7066, -4482, -5818, -5933, -5569, -8304, -3415, -6064, -4795, -3247, -4890, -1853, -13049, -3291, -1092, -1488, -282, -2670, -1180, 441, 194, 903, 44, 464, 1064, 369, 1400, 853, 1121, 561, -758, 998, 249, 726, -1463, -2859, -374, -1779, -805, -6988, -4679, -2714, -4863, -3757, -5401, -4923, -5784, -5367, -7335, -3383, -5055, -8942, -5374, -6343, -3744, -5951, -12534, -6045, -5638, -5524, -7050, -12534, -6365, -5960, -7730, -6914, -7484, -6516, -7842, -6973, -5879, -5654, -6602, -11488, -6026, -5509, -5085, -6173, -7353, -6602, -5933, -5312, -6045, -6235, -8649, -6422, -6113, -6814, -6928, -11004, -6083, -5888, -8276, -8615, -10284, -5073, -4659, -9380, -8582, -6745, -4238, -4442, -9753, -7865, -4733, -4153, -6083, -9238, -7644, -3954, -4800, -12776, -8582, -6628, -4071, -5686, -9064, -8192, -5079, -4728, -6074, -7464, -8982, -3937, -5189, -5810, -8393, -10613, -3512, -5026, -5509, -11004, -8549, -3954, -5109, -5394, -17034, -7113, -5654, -6434, -5061, -15615, -6666, -9479, -11004, -4438, -11488, -6288, -7353, -9753, -4064, -9695, -6422, -4918, -8485, -4373, -8454, -8060, -4089, -13049, -5408, -8165, -9022, -4226, -6988, -6376, -9331, -6422, -5465, -4482, -6885, -13738, -5623, -8485, -4246, -8276, -10799, -6666, -8718, -5646, -11629, -8423, -10613, -7281, -8363, -13738, -7960, -10899, -9149, -8112, -13365, -8304, -8582, -11945, -6653, -15615, -8138, -9193, -7034, -6235, -11356, -7464, -10069, -5726, -6800, -8615, -7389, -7796, -5743, -8423, -7264, -7774, -6310, -6516, -10442, -7179, -7264, -5776, -7687, -11232, -7819, -6343, -5686, -7445, -9064, -8138, -6123, -5827, -6422, -6870, -7912, -6256, -6278, -6278, -5988, -8165, -6590, -7097, -7004, -6343, -9380, -6745, -8615, -8304, -7562, -11781, -6480, -11115, -10526, -7503, -11356, -6376, -10069, -15615, -7050, -10210, -7353, -7819, -11781, -7960, -9639, -9753, -7162, -10799, -11356, -9380, -10799, -7936, -14784, -15615, -9380, -10284, -10069, -11356, -12776, -8903, -11945, -10210, -8192, -12123, -8903, -13738, -9639, -7130, -8192, -11004, -9380, -11629, -6928, -5853, -11488, -7888, -11356, -7389, -5115, -9193, -8138, -9238, -8790, -5678, -10001, -10362, -9531, -12123, -7230, -11115, -28777, -11356, -28777, -8683, -8903, -10284, -11488, -14784, -8683, -8615, -7960, -10362, -12776, -7984, -10362, -7179, -9380, -11781, -3117, -6870, -7644, -4630, -5247, -3659, -11232, -6016, -7146, -6422, -5561, -12319, -5026, -6457, -8754, -10362, -7130, -4679, -5103, -17034, -5801, -5158, -5346, -5176, -8903, -3801, -4674, -6914, -6842, -6692, -3668, -5195, -7819, -14195, -6719, -4874, -6133, -8112, -8304, -8112, -6288, -6602, -9331, -6054, -8423, -6354, -6093, -8034, -6267, -7774, -6814, -5286, -6899, -7113, -7708, -6842, -4847, -7213, -6045, -7583, -6422, -5103, -6842, -5726, -7066, -7213, -6640, -5437, -7034, -6870, -7708, -13365, -5145, -8790, -6914, -7162, -6928, -5531, -8790, -6153, -6814, -4929, -6054, -6615, -4880, -5055, -5554, -11004, -3296, -2813, -2438, -4230, -4082, -524, -733, -656, -1370, -833, 1182, 493, -67, -185, 223, 1807, 608, -783, -417, -86, 1336, -519, -3058, -2075, -1452, -316, -3094, -6988, -5694, -3417, -3130, -5871, -7603, -7936, -5189, -4963, -6516, -6388, -6885, -6705, -4698, -6299, -4918, -7562, -9812, -4616, -4649, -4348, -8649, -12776, -4518, -4060, -5333, -9695, -10210, -4258, -4344, -9149, -10210, -11945, -4195, -4679, -7796, -9284, -8165, -4912, -4460, -5152, -8009, -5546, -7371, -4035, -4869, -6943, -4532, -12319, -3989, -6074, -6516, -4282, -6343, -4601, -6469, -6786, -4504, -4635, -5759, -4611, -7583, -5133, -4464, -6615, -3751, -8790, -6602, -4790, -6332, -4184, -10899, -10704, -4997, -6365, -6103, -13738, -10799, -6388, -7936, -11488, -12319, -6640, -17034, -13365, -10069, -9812, -5306, -6856, -11004, -7034, -7426, -5008, -4963, -9064, -5646, -5997, -5286, -5465, -6828, -4451, -5710, -6035, -8683, -4754, -3509, -6553, -7389, -11356, -4064, -3194, -8034, -10704, -6842, -4774, -3680, -7162, -13738, -5702, -7213, -5085, -5266, -8034, -5458, -11356, -7371, -4290, -6528, -5444, -11945, -10210, -4258, -6123, -5569, -28777, -9331, -5170, -5836, -6007, -9022, -6958, -6943, -5444, -7097, -6759, -5623, -8903, -5735, -9873, -6480, -5079, -9585, -7644, -10284, -6958, -5103, -9149, -14784, -7019, -6679, -5702, -8034, -9106, -5735, -5554, -6814, -7066, -7353, -5554, -4764, -7708, -6899, -7562, -6332, -4425, -7066, -7353, -8865, -7464, -4455, -6516, -8034, -10613, -6856, -4863, -7004, -8754, -10613, -5836, -5592, -8276, -10069, -8549, -5836, -6153, -9873, -13738, -6732, -6719, -6590, -11356, -12123, -5844, -7603, -7162, -13365, -8165, -5997, -8247, -7752, -10799, -6885, -7389, -9284, -8009, -9106, -7113, -10362, -11488, -8333, -9284, -8718, -14195, -14784, -9380, -10799, -11115, -13365, -11232, -9585, -11781, -10799, -12776, -10284, -8582, -10362, -9331, -13365, -11004, -8333, -9106, -8903, -13365, -10284, -8333, -9193, -9331, -9585, -9380, -8333, -10001, -9936, -7730, -9429, -9238, -8942, -10069, -7523, -8649, -11004, -8247, -9331, -8754, -8454, -12776, -9380, -8220, -11629, -10799, -28777, -14784, -7583, -11356, -14784, -11488, -13049, -8086, -9531, -9022, -9380, -11356, -10899, -9064, -7562, -9873, -7081, -9429, -2805, -8718, -6899, -6800, -10899, -4226, -6653, -7179, -5718, -8827, -8517, -5401, -9193, -5638, -6480, -7034, -4518, -9531, -6133, -4946, -5306, -3804, -6246, -6732, -3830, -5759, -3444, -4527, -5933, -3014, -8192, -3485, -4344, -4138, -2827, -9238, -4056, -5387, -3203, -3523, -5915, -5480, -7162, -3352, -5152, -4282, -6565, -10442, -4649, -6958, -3316, -5437, -11232, -6943, -7665, -2574, -4592, -7081, -7213, -7445, -2163, -4395, -6492, -6376, -7113, -2312, -4460, -8276, -7583, -7146, -3191, -4578, -28777, -8790, -5801, -5183, -4559, -9193, -6885, -5127, -12776, -4545, -6516, -6828, -4769, -5292, -3920, -3900, -3447, -1899, -1621, -1802, -1198, -706, 111, 92, -225, 391, 418, 753, 503, 157, 682, 253, 191, -422, -702, -432, -1141, -1561, -3304, -2975, -3615, -3853, -4532, -7603, -6759, -10284, -7503, -7389, -4901, -7426, -4688, -12123, -7623, -5458, -6928, -3546, -10613, -7299, -9238, -8086, -3482, -7196, -6800, -9106, -11356, -4053, -6469, -6434, -7130, -11356, -5531, -7503, -7353, -7247, -7066, -7752, -11488, -11232, -8903, -5576, -7196, -9380, -11004, -9064, -6153, -6267, -7464, -9380, -5638, -9531, -6225, -8903, -11488, -3592, -10704, -6153, -28777, -9585, -2642, -10069, -5678, -8582, -7179, -2483, -12123, -5516, -8393, -6615, -2912, -6376, -5818, -11945, -7562, -3879, -4323, -6388, -8865, -10704, -4912, -3876, -6553, -7426, -8982, -4774, -4555, -6332, -8034, -6354, -4115, -6399, -6540, -7130, -5592, -4075, -10069, -7774, -5374, -6103, -4640, -10799, -10284, -4985, -7281, -5751, -7888, -12776, -5670, -8138, -7542, -7113, -11488, -5853, -7819, -9531, -7888, -11945, -5008, -7281, -9022, -8615, -28777, -4774, -7371, -7912, -7445, -11115, -5810, -8276, -7213, -6773, -7960, -8615, -10899, -7179, -6565, -6035, -15615, -10442, -8060, -6204, -4759, -15615, -7113, -9873, -6083, -4153, -9429, -6376, -10210, -6422, -4447, -7213, -7960, -10138, -6504, -6074, -6194, -10362, -11232, -5960, -10442, -5234, -6786, -9429, -5630, -12319, -4597, -5768, -7179, -5979, -10799, -4912, -6133, -6026, -7196, -12123, -6376, -6133, -5743, -9380, -8086, -8865, -5415, -6343, -11004, -5793, -9695, -5176, -7583, -10442, -4935, -8423, -5164, -8220, -9531, -5127, -8247, -5164, -7936, -8333, -6310, -9380, -5702, -8333, -6988, -8582, -10704, -6973, -8192, -5897, -12534, -9873, -8485, -7004, -5561, -28777, -8549, -9331, -6800, -6225, -12534, -7888, -10526, -8247, -7281, -11232, -7888, -14195, -11781, -7162, -17034, -8517, -28777, -10704, -6885, -10613, -10001, -17034, -8754, -7196, -8009, -11232, -11004, -8247, -7708, -8247, -8683, -8165, -8790, -7796, -8582, -7162, -7247, -8549, -7687, -6602, -6943, -7796, -7730, -7730, -5784, -7730, -9064, -7936, -8165, -6577, -9429, -8333, -9106, -9936, -9380, -11781, -7066, -10069, -11115, -14195, -11356, -6602, -9429, -7247, -8982, -9429, -6653, -8903, -5735, -7984, 10044, 12648, 12998, 9252, 6231, 9325, 12187, 12390, 8700, 5681, 6793, 10765, 10421, 7132, 3998, -1825, 8281, 6402, 5122, 1148, 3219, 4758, 1900, 3557, -2152, 4456, 1711, 3145, 2012, -3412, 3991, 1942, 1400, 204, -5079, 2605, 2961, -1604, -3856, -5020, 1397, 3208, -3417, -3557, -71, 1218, 2542, -2979, -39, 2241, -2135, 353, -2745, 1046, 3469, -1404, -6856, -1711, 2768, 4068, 1609, 1799, -53, 4306, 4109, 1189, 4070, -76, 4861, 3454, 671, 4427, -2467, 4441, 2259, 1918, 3028, -3788, 3064, 2550, 1989, -1738, -1385, 411, 3822, 681, -1108, -1853, -4693, 4093, -654, 1442, -5979, -2592, 3171, -213, 1945, -4064, -520, 1371, 312, 1726, -2731, 491, -451, 514, 673, -4172, 1095, -4067, 545, -219, -3140, 1267, -3468, 233, 1160, -1015, 1002, -20, -487, 2224, -2, 267, 293, -1090, 2237, 417, -1484, -1315, -949, 1348, 442, -6399, -5152, -560, -150, 79, -6399, -4038, -1063, -1862, -811, -3961, -1042, -3078, -3600, -2512, -4491, 588, -1589, -6153, -4420, -6528, 1425, 177, -5374, -5133, -10284, 1468, -12, -1979, -4847, -6480, 442, -2155, -888, -3274, -3468, -2145, -4403, -1535, -3281, -1610, -2664, -1884, -3529, -7004, -258, -546, -685, -5539, -6235, 641, 7, -525, -6856, -3087, 948, -599, -815, -3659, -3047, 583, -2345, -1077, -2153, -5145, -396, -6235, -1402, -2756, -7162, -1909, -5979, -2105, -3910, -4583, -3996, -3094, -2743, -1780, -4957, -5085, -2401, -2268, -343, -15615, -4616, -2809, -1703, -181, -4509, -5380, -3105, -1949, -1173, -2628, -6235, -2039, -3087, -3465, -2982, -5509, -391, -4491, -8060, -4035, -5827, 967, -4918, -9331, -3944, -7796, 1574, -4774, -3798, -3540, -9429, 1143, -5394, -1564, -3490, -6064, -731, -7752, -671, -3748, -3551, -3738, -5437, -746, -3889, -2417, -1854, -2714, -1722, -3521, -2465, -738, -1511, -3910, -2918, -3286, -1072, -1174, -8060, -2807, -4382, -2477, -1487, -7464, -3817, -6016, -4826, -2521, -5726, -6679, -8034, -7542, -4395, -5539, -10526, -12319, -6828, -5979, -6256, -6480, -6123, -4918, -5584, -5862, -3933, -2470, -4038, -4816, -4071, -2659, -1201, -4303, -4592, -2883, -2589, -1456, -5793, -6035, -2460, -4028, -3042, -7984, -11781, -2988, -7230, -5751, -8138, -4491, -5227, -5043, -7865, -7523, -2336, -6590, -3916, -6553, -7426, -1857, -3170, -5299, -5031, -7230, -2367, -1790, -10362, -4985, -6054, -3674, -1497, -7583, -6204, -4935, -6256, -1909, -7162, -5751, -4733, -6225, -2686, -10001, -4097, -5646, -3695, -2793, -28777, -3757, -8649, -2722, -1804, -11232, -4800, -7984, -2733, -812, -9695, -4464, -4357, -3196, -222, -9936, -3005, -3025, -3399, -19, -6719, -3529, -2975, -3094, -215, -4831, -8060, -3659, -3218, -1018, -4541, -4097, -3975, -3947, -2937, -4491, -1958, -3487, -4134, 7316, 10225, 10623, 7748, -1098, 6444, 9621, 10019, 6996, 330, 3271, 7799, 8140, 4473, -135, 1316, 4928, 4844, -755, -2958, 3602, 1795, 905, -1315, -4578, 3296, -1449, -120, -2182, -543, 2161, -5133, 69, -4108, 879, 2607, -1265, -838, -5164, 1283, 3323, 2438, -72, -4365, 1191, 3383, 3844, 822, -5299, 1048, 2823, 4299, -288, -2566, 1369, 1264, 4253, -757, -248, 1858, -2958, 3479, 1529, -219, 1962, -613, 1344, 2185, -1117, 1743, 2218, -4821, 1460, -1255, 1702, 3058, -2541, 806, -793, 2155, 2695, -548, 1142, 382, 2651, 1144, -873, 1061, 1030, 2641, -1772, -2039, 567, 433, 1850, -1000, -2305, 388, -1616, 94, 759, -1155, 220, -5524, -2779, 1119, -359, -388, -10899, -3128, 900, -437, -1029, -9149, -1604, 812, -1352, -970, -4518, -1346, 688, -3425, -397, -1838, -1963, 276, -4455, 54, -450, -2752, -201, -922, 230, -180, -3003, -514, 990, 258, -1194, -2776, -737, 1673, -29, -3391, -3191, -772, 1287, -1143, -2430, -5487, -663, -184, -3641, -919, -10704, -869, -2573, -9695, -833, -5286, -739, -4790, -5662, -1888, -3846, 539, -5654, -2054, -3289, -4486, 1249, -8009, -517, -4003, -6640, 580, -10442, -43, -6183, -2065, -2142, -4805, 189, -6194, -122, -14195, -3130, 952, -2241, -240, -3769, -2325, 2173, -986, -2333, -2605, -1918, 3172, -964, -2885, -3222, -2003, 3383, -1800, -835, -3850, -2724, 2442, -3811, -587, -2578, -3824, -47, -4564, -2234, -1983, -3083, -1844, -2789, -8276, -2234, -1771, -329, -2622, -4606, -2673, -1662, -251, -4112, -2457, -3860, -3425, -1346, -7371, -2355, -6083, -7196, -2443, -11781, -3168, -4929, -2754, -1961, -9331, -3760, -4238, -1298, -1088, -6083, -3130, -5299, -1543, -916, -4344, -2309, -6457, -2969, -1777, -3951, -2170, -5145, -5394, -3850, -4348, -2918, -3509, -9695, -6016, -4991, -4784, -2406, -9022, -5451, -6602, -8138, -1928, -5480, -5387, -6235, -10362, -1952, -4592, -6278, -2902, -7523, -2291, -5599, -5960, -1404, -4907, -2952, -6480, -5121, -990, -3817, -4327, -4968, -5286, -1119, -4254, -7687, -4957, -6457, -1582, -5055, -12123, -7371, -8086, -2442, -4067, -6973, -15615, -8423, -3707, -3422, -5871, -8304, -7050, -5183, -3773, -5516, -5437, -6267, -7888, -4573, -5451, -3518, -7179, -9585, -4837, -5408, -2683, -9380, -3714, -4545, -5844, -2918, -5599, -1799, -4779, -8649, -3846, -3863, -1524, -6225, -8165, -3985, -3600, -2374, -8718, -4541, -3449, -4021, -3447, -9149, -3344, -3635, -4630, -3937, -9639, -3329, -4564, -5818, -4795, -7162, -4089, -4616, -6469, -5776, -4067, -5221, -3886, -4378, -4028, -2320, -5897, -4134, -3110, -2399, -1634, -5801, -5662, -2855, -1746, -2036, -5458, -9531, -2724, -1821, -3624, -4003, -7113, -1902, -2417, -5615, -2626, -3698, -1022, -3235, 2765, 10743, 11015, 7835, 5167, 2573, 10288, 10453, 7230, 4978, 1899, 8926, 8676, 5477, 4404, 431, 6717, 5342, 2971, 3601, -2510, 4089, 826, -759, 2738, -1116, 2331, 280, -2247, 1585, 1335, 1862, -849, 2278, 958, 2037, 1137, -1499, 3142, 1914, 2121, -359, -1606, 2056, 2766, 2493, -1087, -3067, -531, 3083, 2981, -162, -2845, 1494, 2837, 3208, 1678, 256, 2898, 1355, 2995, 3017, 1510, 2431, -5353, 2078, 3266, 983, 412, 1537, 495, 2329, -2220, -1382, 4611, 45, 753, -3692, -1259, 6111, 41, 850, -150, -1056, 6663, -1833, 1379, 313, -442, 6245, -1875, 1210, -688, -234, 4738, 1059, 939, -2566, -954, 2413, 2204, 1007, -4013, -2999, 1451, 2071, 1366, -3296, -7984, 1487, 869, 1630, -1712, -3840, 921, -915, 1398, -1065, -1305, -226, -2019, 816, -2412, -412, -1913, -2990, 328, -8865, -255, -3626, -5214, -124, -1636, -262, -8009, -10138, -168, 335, -17, -4482, -14784, 497, 609, 795, -1324, -17034, 752, -8, 1509, -1330, -7583, 127, -1352, 1536, -3714, -3417, -922, -4438, 861, -2962, -956, -1306, -9695, -311, -1326, 369, -1134, -4601, -2112, -830, 420, -911, -6376, -5164, -172, -1578, -598, -4880, -1971, 136, -5286, -43, -182, 497, -448, -712, 141, 1578, 1353, -1463, -152, -869, 1793, 1056, -1937, -2879, -3883, 367, -338, -2367, -7353, -7230, -3760, -2299, -3354, -2711, -7644, -1205, -1284, -5008, -3989, -10210, 633, 187, -4754, -7335, -4127, 682, 458, -2353, -3213, -2992, -90, -576, -1166, -1239, -3876, -1210, -2589, -1417, 41, -6577, -3225, -1869, -3316, 408, -13365, -7353, -451, -3827, -439, -9238, -4060, 7, -1758, -2403, -5844, -2334, -20, -1021, -2962, -4555, -2334, -169, -989, -2364, -4046, -3504, -466, -932, -3279, -3856, -5735, -1293, -626, -6565, -4161, -12534, -3003, -228, -8649, -4386, -7066, -3961, 29, -5592, -4071, -4536, -2517, -22, -4327, -4258, -4885, -1637, -541, -3723, -5097, -5494, -1446, -1642, -3689, -5678, -3083, -1635, -3085, -4115, -6064, -1838, -2204, -3523, -4100, -7371, -1822, -2881, -3096, -3833, -11004, -2730, -2391, -2975, -4250, -11115, -4578, -1473, -3105, -5784, -8982, -8060, -1479, -2754, -8138, -9284, -10899, -2883, -2100, -8754, -4425, -7583, -5097, -2042, -6870, -2015, -5121, -3005, -2716, -3999, -1423, -3546, -1384, -3054, -2741, -2403, -3342, -965, -2557, -3194, -4880, -5253, -1343, -2505, -4606, -4733, -11629, -2238, -3184, -4307, -3326, -5139, -3401, -4395, -3393, -2979, -4038, -4601, -6163, -1689, -2849, -4784, -5818, -7335, -26, -2541, -5776, -6577, -5260, 622, -2262, -6278, -6173, -4270, 176, -2344, -8485, -4395, -5164, -1242, -3154, -9064, -2849, -8034, -3225, -4912, -4940, -2698, -8034, -4611, -5646, -3286, -5240, -7665, -2419, -6615, -3482, -1846, -3281, -626, -3304, -2130, -2175, -3569, -105, -1262, -1182, -2008, -3566, -743, -1087, -1198, -1819, -3225, -2300, -2635, -2576, -1603, -3257, -4060, -7146, -3626, -1013, -4438, -5437, -7936, -2214, -312, -9238, -7708, -5997, -2372, -132, -4957, -6666, -6958, -5862, -837, -2285, -3566, -10613, -5049, -2419, -1986, -1772, -13365, -1771, -3680, -3837, -688, -7752, -1085, -3624, -5906, -101, -5844, -1654, -3683, -2975, -80, -5067, -3108, -4336, -2094, -818, -3653, -4071, -4399, -2458, -2770, -2002, -2608, -3158, -3163, -8423, -1108, -1685, -2458, -3751, -6204, -1100, -2282, -2364, -4010, -3210, -1825, -4769, -1646, -3237, -2445, -2762, -5240, -595, -1689, -2711, -3840, -3751, -258, -376, -3744, -6745, -4738, -699, 97, -5367, -9812, -10613, -1406, -557, -6256, -3866, -7796, -1864, -2613, -5008, -1892, -6528, -2502, -5915, -3961, -1087, -9585, -4365, -5387, -3766, -939, -8549, -9753, -3092, -4323, -1217, -6153, -8827, -1828, -5444, -1731, -6246, -7984, -1501, -6745, -2312, -6492, -7230, -1312, -7335, -2475, -4923, -5374, -1098, -7081, -1852, -3586, -4395, -1695, -7842, -1203, -3354, -3992, -3412, -9873, -1341, -4654, -5026, -4382, -8982, -2635, -8649, -8247, -4403, -9022, -4907, -10799, -5801, -6434, -11004, -4858, -9284, -4644, -13049, -8086, -3537, -8060, -5623, -10526, -6469, -3049, -6173, -8683, -28777, -5607, -3119, -4968, -28777, -9753, -5273, -3900, -4161, -13049, -8276, -5437, -6540, -3833, -11232, -5214, -4831, -10526, -3760, -8517, -2564, -4592, -6814, -3386, -5818, -1433, -6528, -7317, -2829, -4082, -1436, -14784, -11945, -2726, -3085, -2257, -8582, -11488, -3365, -2514, -3656, -10799, -11629, -4482, -2470, -4985, -8333, -28777, -4611, -3554, -4597, -5319, -12319, -4361, -7730, -3785, -4858, -13738, -5026, -6773, -4104, -5408, -8942, -5784, -3362, -6615, -5768, -6214, -5451, -2619, -12534, -6026, -5221, -5127, -3054, -5415, -7130, -4951, -5319, -3954, -3927, -8220, -4940, -6590, -3920, -4246, -7936, -5333, -8549, -2853, -6759, -7888, -7213, -6553, -2364, -12319, -5801, -28777, -4863, -3415, -5576, -3668, -6759, -3641, -8517, -3741, -2813, -4764, -2541, -5615, -2982, -3177, -4518, -1999, -2945, -2505, -4918, -4963, -2257, -2580, -2165, -9429, -5158, -3309, -3096, -2128, -11488, -5020, -4929, -3529, -2610, -7960, -5189, -5615, -3927, -3827, -8517, -6204, -4460, -4718, -5678, -13365, -8827, -3455, -5623, -7389, -11945, -13738, -3135, -6388, -9429, -9753, -9479, -3319, -7644, -7503, -10138, -7752, -3583, -10442, -4723, -11945, -7562, -3635, -28777, -3735, -17034, -8517, -3804, -9585, -3906, -12319, -9639, -4282, -7247, -4640, -9531, -9022, -4042, -5942, -5437, -8363, -8582, -3038, -4912, -6492, -7774, -7774, -2550, -4207, -8060, -7335, -7019, -2895, -4024, -10362, -7603, -7936, -4172, -4532, -14195, -9812, -13365, -6786, -6153, -9380, -6365, -2564, -2516, -966, -3968, -5607, -4513, -2347, -2244, -4991, -3339, -8304, -2545, -4968, -7317, -2173, -4764, -3215, -5097, -14784, -2146, -4278, -5037, -4323, -9812, -2937, -6054, -9479, -3662, -8903, -4408, -4728, -9936, -2453, -8827, -7034, -2265, -7426, -2132, -5429, -4929, -1286, -6422, -3182, -3776, -2223, -1296, -5888, -5502, -3196, -1202, -1811, -5793, -6256, -2943, -1328, -2093, -6480, -6133, -2835, -2396, -2184, -7162, -8754, -2781, -4199, -3110, -4028, -12123, -2592, -5638, -5630, -1975, -6759, -2487, -4837, -4847, -1230, -5487, -2758, -3999, -2492, -1394, -4138, -3523, -4718, -1697, -2239, -2191, -4935, -10138, -2014, -3671, -654, -8112, -5951, -3362, -6074, 198, -10284, -3029, -5531, -11629, 268, -4164, -2677, -5743, -12319, -477, -2062, -4038, -4640, -8333, -1868, -1537, -4963, -4060, -6422, -3038, -2447, -3910, -3110, -5240, -2929, -5164, -4550, -2166, -3957, -2080, -7819, -8649, -2393, -3112, -1543, -4907, -7004, -4748, -3357, -1671, -2475, -4649, -12776, -5079, -2528, -1033, -4278, -4123, -8942, -3893, -933, -4640, -2488, -5561, -3583, -2696, -4805, -2419, -3087, -2260, -9639, -4344, -3094, -2082, -1644, -3624, -3923, -3018, -2107, -1825, -1752, -4046, -2219, -3201, -2922, -1724, -4821, -1952, -5584, -5726, -2803, -5871, -2374, -6679, -8138, -4718, -6183, -3114, -5286, -4795, -6773, -5158, -3580, -4759, -3337, -8304, -4242, -3420, -3222, -2967, -9873, -3468, -3083, -1514, -3916, -8942, -2737, -3196, -851, -7213, -7371, -2628, -4290, -1397, -8220, -5031, -3441, -6565, -3518, -8517, -2924, -5306, -7623, -9639, -7936, -2083, -6666, -7730, -7623, -4199, -2509, -3910, -10526, -5871, -3420, -3331, -2225, -5279, -6113, -4307, -3147, -2053, -2893, -7335, -5879, -3314, -3463, -2398, -8393, -6870, -4980, -7542, -3314, -5915, -7484, -8683, -11115, -5979, -4420, -10442, -15615, -7389, -12319, -4319, -9695, -10284, -6973, -5924, -5227, -5862, -5997, -7162, -3720, -6615, -5133, -4323, -6786, -3023, -7230, -5853, -4336, -5623, -3650, -7179, -7730, -5115, -4974, -5862, -7687, -13049, -4153, -5818, -5997, -8247, -10210, -2795, -8754, -3618, -5836, -6928, -2115, -6332, -2590, -3686, -6343, -1878, -4246, -2450, -2675, -7371, -1699, -4067, -2889, -2369, -11004, -1353, -5678, -4017, -2450, -11781, -1020, -12123, -6745, -2751, -8247, -1076, -6615, -8165, -3114, -7426, -1890, -4056, -4616, -3412, -7960, -4046, -3571, -3707, -3883, -8485, -10069, -4754, -4386, -5079, -6786, -5662, -8423, -6732, -7865, -4957, -3373, -7281, -14195, -9753, -3906, -2778, -5152, -8982, -5784, -3501, -3058, -4748, -5853, -3961, -3641, -3707, -4429, -4616, -3227, -4086, -4274, -3487, -4587, -3154, -4559, -4918, -2617, -5735, -3507, -4880, -6074, -2248, -8034, -4307, -5109, -7335, -2512, -9064, -5924, -5292, -8086, -3463, -8276, -8754, -5502, -7299, -5170, -8393, -9639, -6204, -5646, -5638, -4606, -2845, -6278, -11115, -8718, -5008, -3045, -1236, -9106, -4946, -4323, -2920, 372, -6540, -2630, -1996, -2108, 535, -6123, -2531, -1262, -1384, -353, -4842, -3879, -2378, -1149, -2111, -3078, -3910, -5561, -1536, -4319, -2291, -2204, -4134, -2692, -6288, -2541, -1237, -2711, -4199, -8649, -3375, -1152, -2827, -4142, -11004, -3729, -1662, -3744, -3720, -5176, -3523, -2288, -5599, -4286, -2929, -3856, -3194, -7960, -5988, -2138, -5387, -5710, -4963, -10362, -2385, -6492, -28777, -3114, -7299, -3850, -3624, -7146, -2550, -4644, -7583, -1693, -6800, -2875, -4097, -5286, -1039, -9064, -4064, -3615, -2458, -1752, -12319, -6679, -1793, -1298, -4336, -5888, -8165, -202, -1070, -6828, -3449, -5686, 616, -1634, -4664, -3074, -4821, 710, -2984, -5145, -4810, -4425, 164, -4664, -10899, -8192, -5014, -985, -3856, -6870, -4464, -8790, -2733, -2241, -4433, -2904, -8485, -4890, -1319, -4754, -2799, -5561, -6399, -1020, -7264, -3626, -5360, -7730, -1508, -9812, -4946, -6113, -9429, -3215, -8827, -5924, -7984, -5502, -6692, -9284, -6480, -12123, -3989, -5387, -8649, -6786, -8247, -4985, -3609, -6653, -7562, -6267, -9695, -3594, -4460, -9106, -5487, -4013, -5662, -3119, -5726, -5670, -2075, -11781, -2709, -2931, -7004, -1868, -4805, -2964, -1551, -6422, -2709, -2941, -3504, -1157, -4134, -4464, -2254, -4161, -1587, -3487, -7317, -2155, -4810, -2900, -4460, -8754, -2803, -4826, -5751, -6590, -7146, -3889, -4504, -28777, -7213, -5768, -3692, -5085, -5933, -5906, -4532, -3161, -6653, -3729, -3814, -3504, -3971, -7623, -2557, -2758, -2924, -7081, -8112, -1713, -3179, -2924, -6705, -8790, -1219, -4863, -3566, -3968, -9149, -1239, -4611, -5158, -3357, -9380, -1735, -3342, -9106, -4344, -7353, -2398, -3518, -9380, -6943, -5654, -3014, -5561, -6321, -6064, -4365, -3944, -12319, -5710, -4611, -3526, -5710, -8485, -5444, -5312, -3474, -8549, -7004, -4395, -10899, -4382, -14195, -5539, -3729, -6007, -6354, -14784, -3732, -4262, -2947, -6988, -12776, -3108, -6504, -2071, -4940, -7665, -3644, -11629, -2495, -3804, -4541, -4748, -8903, -4082, -3624, -2947, -5152, -7752, -6973, -3900, -2166, -4416, -7146, -10899, -4112, -1940, -3644, -6016, -8138, -4644, -2419, -3853, -5524, -5319, -6492, -3795, -5810, -5997, -4053, -8754, -5933, -13738, -7542, -3896, -6299, -6828, -6093, -10899, -4455, -5353, -5145, -3837, -17034, -5253, -5710, -3860, -3184, -9812, -6399, -6705, -3479, -2956, -7936, -8865, -7146, -3964, -2407, -7371, -14195, -5979, -5208, -2008, -7484, -10899, -5109, -7162, -2302, -7603, -8903, -5214, -10001, -3428, -6480, -8060, -5584, -11781, -5654, -5227, -7335, -5408, -15615, -7865, -4858, -6204, -5176, -8304, -5214, -5751, -5043, -5266, -4963, -3804, -8718, -4153, -5292, -3769, -3951, -8034, -3407, -4951, -3840, -5702, -5091, -2760, -4688, -4616, -10442, -4168, -2538, -5170, 2924, -234, 1360, 6807, -8942, 2066, -2370, 4384, 6357, -5810, -141, -2316, 6118, 5078, -3900, 1102, 864, 6272, 3574, -2939, 2871, 2029, 4982, 2947, -2191, 3429, 2929, 1313, 2390, -2148, 2957, 3148, -353, 643, -5437, 1123, 2033, 3041, -4403, -2204, -4885, -1104, 3754, -2053, 1954, -1183, -6719, 3043, 205, 3676, 1865, -4172, 491, -267, 4413, 2821, -3653, -7752, -1049, 4868, 2344, -1888, -199, 1694, 5207, -359, -9, 972, 3120, 5050, -1632, 595, 83, 3046, 3874, 1955, -1268, -1515, 1653, 578, 2733, -2034, -634, -75, -912, 1786, 2552, 214, 1121, 2255, -864, 3972, 473, 2128, 2530, -2273, 3661, 640, 1934, 1253, -825, 1861, 457, 1079, -446, 292, 123, -219, 514, -4874, 1881, 460, -1259, 630, 63, 3071, 42, -3388, 1278, 3589, 3387, -516, -9639, 1572, 4619, 2800, -265, -1659, 633, 4027, 1366, -817, 320, -2517, 1686, -799, -2762, 270, -7665, -3930, -3968, -4713, -1864, -3692, -3304, -8718, -6299, -8363, -1474, -2526, -3249, -5234, -3128, 612, -2094, -1855, -1449, -2152, 1371, -497, -3147, -19, -3518, 798, 62, -7562, -156, -7317, -391, -900, -2639, -1790, -4858, -388, -3518, -1365, -3726, -2659, -173, -2541, -1549, -2762, -1254, -1080, -837, -1402, -3177, -87, -3883, -672, -1136, -3546, 612, -14195, -1556, -2185, -1011, 683, -5189, -3092, -3299, -127, 255, -4810, -4674, -1074, -408, 469, -5158, -5810, -458, -152, 1380, -2644, -7730, -1654, -81, 1634, -864, -9193, -1208, -2163, 1154, -51, -2672, 674, -4991, 832, 155, -175, 1435, -1433, 1013, -131, 761, 1314, -1182, 998, -1065, 724, 444, -1811, 564, -3135, 65, -1033, -1320, -218, -5221, -1064, -2295, -1850, -1008, -2359, -3001, -2817, -4985, -1698, -306, -5472, -3717, -3147, -3766, 626, -2825, -5915, -875, -8517, 689, -1373, -9695, -643, -1522, 110, -1799, -10284, -1952, 328, -645, -4550, -8393, -5158, 462, -1073, -10704, -4880, -6958, -523, -1486, -3526, -2364, -4800, -1611, -3433, -1904, -806, -4017, -1034, -5607, -2280, -95, -3671, 811, -744, -5607, -347, -3247, 2261, 644, -6480, -1863, -3210, 2734, 110, -1799, -5103, -4810, 2098, -2285, 184, -4659, -28777, 205, -6692, 1041, -2109, -4049, -3264, -9531, 934, -473, -1838, -10704, -5037, -22, 605, -915, -4630, -2875, -1556, 1152, -403, -688, -2859, -2705, 1070, -564, 939, -4733, -2610, 57, -1773, 1155, -6814, -2105, -2377, -3521, 70, -4006, -1277, -6842, -3920, -2624, -2128, -785, -7230, -2054, -4800, -1131, -268, -5480, 427, -2743, -550, 863, -1591, 1982, -1959, -690, 1399, 994, 2627, -2102, -2931, 751, 2205, 2455, -2624, -3235, -981, 2081, 1425, -2661, 732, -2168, 111, -357, -1579, 1804, -2049, 4113, 8691, 7936, 8773, 6012, 3561, 8072, 7149, 8102, 5618, 2114, 6090, 4494, 5874, 4286, 385, 2467, -1467, 1335, 1442, 105, 335, -1512, 891, -3557, 1448, 19, -294, 1187, -653, 1670, 457, 2284, -59, 86, -162, 3511, 3895, 1882, -446, -6310, 5241, 4882, 3950, -804, -1085, 5595, 5534, 4332, 72, 356, 4540, 5713, 2430, 2068, -210, 2264, 5244, -849, 3407, -2129, 3099, 3913, 3563, 3660, -2831, 4469, 1707, 4593, 2972, -179, 4352, 1895, 3800, 1685, 2669, 2937, 3096, 1376, 261, 4384, 420, 2850, -1704, -616, 4854, -2821, 1300, 224, 367, 4011, -3808, -1286, 1808, 2210, 2310, -734, -2758, 2566, 3511, 3004, 259, 414, 3084, 3724, 3945, -255, 2119, 3767, 2385, 3371, -1544, 2519, 4192, -706, 1226, -2429, 2071, 3811, 1582, 282, -1773, 1347, 2525, 3374, 1664, 379, 898, 1309, 3933, 1804, 2168, 288, 1062, 3877, 646, 3217, -1270, 233, 3216, -1975, 3667, -4164, -1948, 1802, -2098, 3631, -8333, -6113, 150, 474, 3106, -8790, -8220, -278, 1453, 1924, -3837, -2977, -114, 1011, 19, -2664, -1399, 94, -1305, -645, -4176, -949, 577, -9064, 109, -5988, -689, 1392, -3321, -468, -1586, -771, 2221, -2843, -2881, 62, -2235, 2652, -4847, -3319, 490, -8304, 2491, -3296, -2752, 628, -4119, 1624, -1343, -3792, 1106, -1913, -182, -769, -3468, 1773, -1367, -3732, -871, -2650, 2176, -909, -5394, -1065, -2475, 2162, -896, -2016, -1130, -4299, 1644, -2359, -556, -1455, -6422, 532, -5037, -201, -2679, -824, 28, -2585, -882, -4451, 369, 777, -1683, -2733, -3365, -473, 747, -3401, -5387, -1928, -1848, -261, -6692, -6365, -1282, -987, -1277, -1773, -4270, -1254, -573, -2485, -30, -2253, -1887, -1288, -5897, 664, -1411, -4299, -3025, -8718, 914, -1321, -6528, -4620, -6973, 688, -1803, -1524, -3971, -5121, -178, -4003, -500, -3689, -2490, -1697, -8112, -1699, -3574, -1091, -3811, -2169, -4250, -3142, -530, -6928, -593, -4357, -3040, -547, -7842, -284, -8138, -3349, -1001, -5195, -504, -3089, -3996, -1679, -4620, -1564, 149, -5561, -2452, -6064, -5333, 1287, -5960, -3624, -12534, -6640, 1418, -2448, -5915, -6133, -2910, 947, -686, -5979, -2606, -2756, -117, -344, -3409, -751, -4266, -2165, -1087, -2391, 30, -7960, -4119, -1837, -1825, -57, -11356, -3225, -1303, -1099, -336, -8549, -3779, -1152, -668, -39, -9022, -8517, -2114, -534, 504, -3420, -7484, -3543, -1040, 1034, -1859, -5415, -3301, -3321, 1024, -2789, -4985, -1226, -3566, -591, -7281, -2912, 223, -1232, -11781, -3479, -1176, 639, -825, -757, -1218, -333, 583, -482, 1616, -476, -729, 900, 508, 2382, -451, -3326, 1327, 1147, 2418, -949, -4473, 1318, 1271, 1921, -2132, 6050, 7975, 8032, 3262, 3201, 5282, 7235, 7407, 4445, 2276, 2882, 4845, 5384, 5737, 1543, -1581, 449, 1204, 6321, 2762, -4365, -1218, -3344, 6202, 1952, 697, 1027, -807, 4913, -3001, 1699, 2207, -634, 394, 156, 1344, 1875, -264, 1794, -994, 1845, 390, 450, 4710, 1510, 2609, -843, -70, 5194, 4848, 2799, 63, -4254, 4680, 5567, 2411, 370, -2308, 3521, 5001, 1114, -894, 1299, 1143, 4606, -326, -3257, 2247, -1267, 4612, 1278, -6666, 1843, 1748, 4153, 2514, -7819, 240, 2820, 3522, 2479, -2283, -3457, 2246, 3871, 1252, 316, -4963, -251, 4898, -861, 2145, -449, -4184, 5257, -1712, 3381, 1314, 194, 4585, -2030, 4337, 2095, 1821, 3929, -4491, 5204, 2646, 2246, 5191, -8220, 5754, 3360, 2008, 6461, -3023, 5697, 3878, 1433, 6915, -40, 4936, 3757, 724, 6530, 1680, 3604, 2780, -300, 5228, 2082, 1923, 676, -2526, 2835, 897, -653, -3668, -5103, -394, -2621, -5853, -5176, -921, -537, -1319, -3142, -1849, 1016, 1414, 647, -2320, -801, 1527, 2562, 925, -3433, -294, 822, 2712, 282, -4842, 242, -1181, 1703, -850, -2309, 769, -1463, -1062, -781, -1052, 1003, 651, -1707, 543, -2061, 541, 1790, 194, 1207, -2345, -1065, 2238, -233, 958, 605, -1566, 2360, -3110, -13, 1942, 931, 2335, -4238, -883, 2114, 2319, 2134, -1013, -851, 1496, 2564, 1534, 32, -915, 278, 1735, 223, -847, -1878, -919, -350, -1991, -4403, -3606, -914, -2020, -3996, -3729, -3729, -993, -544, -4340, -3279, -2585, -2173, -113, -5266, -7774, -2133, -2378, -1091, -6113, -3526, -2512, -1154, -2937, -5458, -1749, -3840, -1378, -2273, -4929, -1987, -5646, -3798, -779, -5286, -2500, -4223, -4698, -480, -5979, -1443, -1889, -2670, -1206, -3674, -34, -395, -3515, -2195, -1741, 739, 45, -10613, -2889, -1006, 747, -929, -6163, -4176, -1250, -63, -3677, -7353, -4800, -1811, -1627, -2330, -4378, -2793, -1310, -2519, -720, -535, -1182, -200, -1823, -1173, 333, -240, 992, -1736, -3930, -823, 254, 1875, -2877, -14195, -4327, 429, 1936, -5827, -6504, -7523, 100, 813, -9531, -2797, -14784, -1054, -2146, -3889, -581, -4420, -3133, -14195, -1062, 378, -1799, -3269, -5465, 192, 678, -927, -1330, -3866, -7, 821, -670, 64, -2156, -1573, 914, -1065, 811, -1184, -1349, 635, -1633, 984, -1702, 282, -463, -217, 855, -4344, 555, -2393, 1105, 618, -4805, -601, -3294, 1347, -242, -3110, -3362, -1070, 658, -2683, -4420, -8615, 1182, -686, -3766, -8086, -7708, 2334, -1922, -1963, -3096, -3438, 2464, -2055, -2703, -1314, -1462, 1785, -1641, -7865, -740, -628, 493, -1010, -5702, -958, -332, -1390, -484, -3337, -2440, -311, -4017, -811, -2766, -4013, -576, -2857, -601, -209, 1245, -2673, 1298, 661, 654, 252, -3543, 2971, 1013, 516, 721, -1936, 3338, 131, -1375, 1236, 68, 3018, -2696, -3785, 1177, 1327, 2426, -9479, 78, 947, 1651, 1838, -2398, 1391, 788, 1071, 1239, -1269, 853, 440, 207, 422, -2348, -1860, -494, -280, -847, -6943, -6679, -1943, -1402, -2452, -3386, -2319, -2529, -4097, -2941, -1127, -1404, -1853, -3172, -1189, -1047, -1489, -1293, -1244, 742, -1659, -1798, -999, -860, 1749, -437, -1694, -812, -1739, 1622, 713, -542, -1050, -4649, 172, 485, 468, -2975, -4469, -2941, -1694, 432, -6943, -1207, -3695, -9064, -1197, -156, -526, -2305, -1646, -6842, 2017, -2334, -1990, 112, -4635, 2738, -3665, -1633, -169, -2789, 2674, 337, -998, -2152, -2605, 2265, 1508, -769, -989, -1740, 1727, 820, -1605, 824, -1331, 879, -2153, -4486, 998, -2066, -701, -5726, -7984, 154, -2473, -3347, -1741, -3680, -452, -1129, -5988, -295, -2648, 89, -513, -7912, 518, -2935, 827, -1335, -6973, 1122, -3586, 1136, -4013, -3137, 1470, -3014, 998, -3760, -1580, 1242, -1921, 720, -1046, -2050, 383, -1482, 581, -225, -6828, -213, -2076, 381, -1055, -3856, -468, -4669, -379, -4119, -941, -1887, -8086, -1652, -10001, -525, -5319, -2455, -1481, -5686, -1408, -8865, -498, -429, -4764, -3586, -6988, 264, -220, -4340, -10899, -2564, -67, -1095, -4790, -4145, -1311, -2416, -2619, -7752, -1577, -1593, -10442, -2425, -6814, -1118, -1611, -2668, -1617, -2906, -1637, -1051, -2626, -1753, -1652, -1893, -945, -4769, -2670, -1755, -2032, -746, -1679, -4130, -2514, -1775, 111, -362, -5871, -2797, -574, 893, -1074, -6800, -2849, -138, 908, -3609, -5531, -4003, -1267, -211, -3094, -3923, -7542, -5208, -2813, -1256, -3373, -15615, -4963, -6692, -761, -4184, -9479, -2522, -8517, -1169, -5979, -6856, -2100, -11232, -2406, -6870, -5458, -1852, -8942, -4112, -5924, -4089, -900, -7146, -3294, -5002, -1823, 169, -4784, -1973, -5638, -466, 480, -2480, -2023, -9753, -169, -562, -1384, -3373, -7819, -484, -3529, -1255, -4242, -5793, -726, -2587, -1207, -3507, -5960, -532, -732, -1140, -3689, -5531, -269, -583, -1970, -4805, -4896, -342, -1430, -4010, -4089, -5630, -886, -2861, -5097, -2887, -7281, -1953, -4728, -4042, -2988, -7936, -3518, -7408, -2683, -4901, -7230, -4425, -10799, -2119, -8582, -4974, -4064, -10799, -3194, -4486, -3365, -3757, -10069, -8220, -2703, -2653, -3603, -9149, -4718, -2659, -2714, -3249, -8086, -1904, -4378, -3665, -2720, -6870, -1067, -10284, -5718, -2090, -5480, -1219, -6480, -8718, -1369, -4104, -2034, -3975, -9331, -729, -3105, -3286, -2929, -7484, -376, -2741, -4723, -2309, -7665, -337, -3261, -6411, -2066, -9812, -478, -5091, -8517, -2555, -5152, -695, -9873, -6679, -709, 749, 1073, 789, -4541, 740, -577, 904, -1058, -8549, 1156, -3551, 870, -2166, -4386, 753, -10001, 436, -1854, -2253, -719, -4433, -1178, -2129, -1395, -3856, -3428, -5888, -2566, -1168, -8363, -2084, -7562, -2633, -1356, -4616, -531, -5942, -3401, -2072, -258, 85, -6183, -5810, -3054, 1888, -54, -3161, -11781, -3119, 2511, -246, -2468, -7644, -2450, 1853, -121, -3147, -6278, -2181, -247, 11, -3612, -7066, -2650, -5299, -127, -3151, -10284, -4038, -6445, -541, -1998, -6173, -4527, -3045, -1063, -1405, -3321, -2004, -2385, -1916, -2125, -2698, -337, -3695, -3870, -4395, -3023, 292, -6045, -4863, -5502, -1621, 209, -1432, -3023, -4172, -233, -193, 118, -2617, -4299, 0, -488, -440, -2986, -5768, -739, -495, -3142, -2155, -5333, -2004, -517, -1988, -821, -2964, -2662, -907, -31, 89, -1550, -1799, -1979, 87, 592, -1302, -483, -3498, -1293, 585, -2385, 208, -2361, -4738, -436, -5170, -160, -283, -7097, -4053, -8220, -2018, 734, -3827, -4635, -7730, -3386, 706, -3060, -911, -8060, -798, -471, -4067, -11, -7912, 597, -3827, -9531, 182, -6480, 923, -4578, -5437, 365, -5429, 456, -925, -1790, 118, -5394, -811, 63, -111, -1167, -6064, -3532, -400, 533, -3989, -7213, -10526, -2068, 359, -6422, -10138, -2003, -4071, -239, -3110, -10069, 33, -3732, -1289, -949, -4361, 77, -3266, -4464, -87, -2066, -2130, -4056, -7019, -314, -1101, -13365, -6628, -2339, -1238, -1084, -3460, -15615, -1271, -2168, -1814, -3509, -10001, -1096, -3409, -2799, -8683, -8247, -1614, -4874, -3360, -6885, -6653, -2813, -1683, -3244, -5127, -4592, -2119, 410, -2815, -5607, -2984, -1017, 1034, -2849, -4718, -2339, -1382, 479, -3621, -2865, -2699, -3227, -1015, -4659, -1931, -4149, -5623, -2973, -5037, -2545, -7389, -5353, -5997, -5189, -6256, -6074, -3352, -5306, -6457, -7317, -2653, -2153, -1521, -8304, -3496, -1321, -1957, -14, -6899, -2977, -1733, -2514, 171, -5933, -3723, -4425, -3744, -520, -5008, -4946, -2383, -5299, -1011, -3349, -5472, 306, -3824, -392, -1729, -4344, 1274, -1784, 296, -718, -2797, 1281, -1105, 520, -301, -2020, 748, -1867, 155, -361, -2268, -138, -4649, -1076, -1074, -3468, -1559, -11115, -3370, -2871, -5312, -4112, -4620, -3449, -6256, -7665, -8982, -2952, -1940, -11488, -9753, -5960, -2522, -1542, -15615, -8192, -4390, -2945, -1807, -14195, -4412, -4115, -4620, -2347, -10210, -1902, -4075, -7888, -2982, -5509, -675, -3999, -5240, -3449, -3098, -513, -3982, -3792, -3249, -1768, -1423, -4031, -3923, -2986, -1088, -3837, -3493, -2879, -3624, -915, -10704, -2670, -1344, -5810, -1065, -8247, -2505, -1144, -9022, -1416, -7389, -3147, -2672, -7912, -2207, -9284, -3971, -7562, -8112, -3779, -7179, -4153, -7264, -10001, -5844, -5319, -3853, -6204, -2741, -1903, -147, -1215, -9380, -3463, -862, 2102, -2152, -7247, -632, -530, 3003, -3222, -3889, 647, -1274, 2930, -3201, -3563, 860, -3294, 2001, -1062, -5997, 307, -6035, 89, 314, -7426, -960, -5480, -2146, 416, -3436, -3007, -4295, -1282, -359, -2462, -4108, -4172, -637, -1090, -2999, -2728, -4853, -1076, -1717, -3485, -1733, -3686, -1728, -2482, -2156, -1543, -1748, -1637, -2655, -1439, -1873, -858, -793, -2897, -2606, -1940, -1012, -339, -3375, -7004, -1064, -1882, -1002, -4718, -2574, -63, -2596, -3474, -5465, -942, 266, -3837, -6434, -2720, -1802, -687, -9106, -1718, -2477, -5915, -5026, -1501, 50, -5247, -3540, -3177, 1141, 87, -3487, -1670, 33, 2131, -1875, -1046, -1908, 910, 2149, -3886, -485, -2378, 1063, 1523, -375, -819, -1366, 804, 560, 919, -1498, -714, 76, -571, 758, -2396, -1143, -510, -2152, -573, -3776, -2192, -1300, -4564, -2908, -6016, -2500, -4373, -6194, -4951, -9936, -2613, -8549, -7004, -4728, -10899, -3792, -3515, -7912, -2312, -6590, -6388, -2443, -5979, -383, -3996, -6679, -2241, -5422, 538, -2018, -4698, -3393, -6332, 634, -883, -4149, -8423, -7445, -6, -973, -2641, -6773, -9479, -1308, -2745, -347, -4053, -14195, -3140, -7113, 920, -3114, -7503, -4654, -6914, 1292, -2040, -6204, -1914, -7299, 1184, -1188, -5615, 295, -8718, 830, -897, -4295, 986, -5458, -97, -1002, -3512, 450, -3354, -2265, -1050, -3529, -858, -2170, -5751, -827, -3760, -2152, -1726, -3038, -749, -3804, -3773, -1651, -663, -1448, -3906, -5888, -1802, 726, -3982, -4060, -4108, -2247, 1211, -7353, -3526, -2184, -2785, 685, -2774, -2952, -1182, -3014, -1072, -2000, -3860, -1123, -3142, -4266, -4056, -10138, -1974, -4038, -4395, -7912, -4238, -2404, -7130, -3103, -2256, -1768, -1397, -10284, -3603, -916, -1850, -798, -6565, -6310, -1300, -4536, -1077, -5509, -5437, -3175, -5960, -1790, -3274, -2552, -7034, -2596, -1533, -1529, -1532, -13738, -1816, -679, -836, -1527, -8942, -2083, -526, -1005, -2541, -6786, -2910, -1432, -1894, -6899, -8333, -5020, -3597, -3455, -4831, -5607, -11945, -7130, -5623, -1396, -2879, -6422, -6225, -6299, -824, -2887, -5152, -3893, -4764, -1813, -4630, -4784, -2783, -3754, -3951, -2653, -3551, -2612, -3087, -5176, -1005, -2781, -3347, -2534, -3244, -877, -2825, -4929, -2350, -1650, -1693, -3433, -4779, -2696, -1063, -2150, -4769, -3076, -3452, -1459, -1511, -7445, -2646, -4403, -2964, -1259, -9193, -3714, -5097, -6332, -2214, -8615, -6399, -4940, -13365, -5091, -10001, -7960, -4918, -7335, -11356, -13049, -6235, -5429, -8060, -5367, -9753, -4523, -3903, -8138, -3621, -6914, -2847, -2291, -3521, -3144, -6163, -1782, -2057, -1672, -3535, -7004, -1395, -3130, -1264, -4482, -7842, -1332, -5002, -1865, -5465, -7984, -1394, -5776, 9769, 6855, 9619, 7873, -3078, 9177, 6752, 9152, 7200, -1055, 7333, 6116, 7837, 4981, 348, 4069, 4419, 6083, 1119, 1049, 119, 1465, 4351, 1858, 1673, -395, 163, 2094, 2644, 1980, 500, 1204, -1384, 2232, 1923, -56, 1983, -1361, 1315, 1625, 5, 2429, -92, 134, 947, 2500, 2451, -816, -968, 213, 4231, 2225, -1921, -654, 1059, 5210, 2732, 574, 95, 2593, 5428, 3905, 1860, 549, 3684, 4655, 4581, 1394, 1347, 4413, 2737, 4293, -2031, 1791, 5014, 1532, 2643, -494, 881, 5499, 2091, -1937, 2910, -2235, 5614, 1513, -798, 3929, -1957, 5017, 1211, 1418, 3626, 37, 3356, 2627, 1121, 2149, 162, 263, 3491, -1133, -964, -645, -2483, 3994, -6299, -5951, -1007, 677, 4492, -6745, -2576, -229, 3384, 4505, -3089, -2109, 219, 4694, 3663, -587, -3254, -430, 4865, 2234, 59, -4447, -1858, 4118, 1442, -1265, -3632, -1008, 2796, 1035, -4451, -2447, 231, 1771, 52, -1766, -3049, 359, 1503, -253, -28, -6492, -305, 1201, 696, 906, -1032, -1226, 422, 1320, 1853, 1128, -576, -569, 1342, 2422, 1451, 1376, -663, 898, 2146, 613, 2591, -229, 323, 491, -535, 2781, -729, 332, -5139, -770, 1932, -3034, 880, -1125, -904, -161, -7113, 1135, 1081, -2159, -4097, -4513, 594, 806, -5662, -7371, -3449, -813, -1595, -10899, -7066, -3012, -2521, -2262, -4683, -4597, -2924, -3058, -570, -2429, -2622, -3135, -2624, -941, -1569, -2289, -2967, -2924, -2677, -2184, -2869, -2228, -5726, -2550, -4863, -3085, -1432, -8086, -1446, -8333, -3189, -1390, -2975, -1159, -4145, -4748, -2608, -1704, -1385, -2234, -8649, -5026, -1918, -1864, -1439, -6365, -5014, -2857, -2550, -1763, -5942, -4569, -3294, -3296, -2954, -8009, -6516, -3683, -3726, -3254, -7623, -5326, -5152, -4262, -2592, -5784, -2538, -6640, -6007, -2288, -5260, -2069, -7019, -8165, -2334, -6246, -3744, -13049, -6666, -2601, -5979, -8754, -5997, -6565, -2720, -3487, -8034, -3163, -6814, -2534, -2499, -7665, -2601, -4254, -2698, -2969, -5784, -3449, -2380, -3665, -4997, -5247, -5429, -1660, -5415, -9531, -6899, -8165, -1889, -6773, -8220, -5509, -8982, -3121, -5509, -5561, -4078, -6504, -5569, -3474, -4412, -4399, -4246, -9812, -2548, -4119, -6445, -3020, -14784, -2606, -4082, -5133, -2853, -9479, -2988, -3978, -2267, -3388, -6773, -3291, -4504, -1141, -3154, -4831, -3632, -6666, -1165, -2105, -3554, -4089, -8393, -1857, -1498, -3124, -4795, -5638, -2644, -1553, -3873, -5906, -4311, -3276, -2347, -6434, -7389, -2920, -3846, -4299, -7213, -7752, -1706, -3476, -9284, -3194, -5008, -933, -2935, -9284, -941, -2543, -461, -3339, -5827, 185, -1084, -645, -4373, -4880, 258, -545, -1922, -4184, -5623, -864, -852, -4545, -2571, -10704, -3014, -1778, -8363, -777, 3635, 4384, 1687, -227, 2784, 3471, 4154, 4135, -37, 2584, 2680, 3439, 5566, 480, 2660, 359, 2276, 5339, 1050, 3081, -3546, 859, 3326, 1143, 3028, 373, -932, -2956, 435, 2454, 1205, -2433, 1387, 454, 1202, 35, -1587, 3163, 1920, -1775, -2811, 337, 3076, 2428, -7752, -6246, 2418, 1908, 1587, -5576, -198, 4141, -330, -500, -1397, 2932, 5306, -2173, -3518, 1349, 4328, 5803, -968, -4486, 2056, 4561, 5567, -2273, -1465, 946, 3988, 4576, -1794, 1865, -2495, 3117, 2839, 2138, 4000, -1786, 2268, 392, 3583, 4893, -155, 1083, -3105, 3671, 4613, -186, -471, -7247, 2895, 2933, 226, -2122, -812, 1924, -1329, 1588, -6786, 1411, 1640, -888, 2786, -3391, 1831, 1708, 652, 3294, -1073, 817, 1269, -1542, 2676, -1802, 1615, -347, -745, 171, -5079, 3858, -4738, 2705, -10138, -2724, 4731, -5195, 3710, -1281, -1320, 4285, -3326, 3817, 496, -1303, 2613, -4683, 4140, 1152, -981, 266, -5266, 4415, 1026, -591, 143, -4545, 3915, 175, -1142, 1680, -5020, 2466, -375, -2482, 2820, -4523, 624, 506, -2887, 3223, -4523, -28, 1665, -1000, 2880, -4234, -139, 2264, 731, 1805, -1455, -680, 2045, 1351, 251, 232, -1189, 946, 817, -297, 610, -1208, -155, -841, 144, -186, -1581, -113, -3496, 22, -2140, -3326, -461, -5183, -444, -5176, -3457, -1548, -4912, -760, -7264, -489, -2770, -4779, -1446, -5743, 929, -4738, -3870, -2353, -4738, 1264, -4842, -3449, -2497, -4669, 861, -3893, -4784, -1963, -5638, -160, -5145, -6914, -1119, -9064, -1499, -4683, -5031, -849, -9064, -1748, -2772, -4006, -1664, -5014, -1656, -2716, -3717, -1998, -3615, -2504, -4748, -3208, -611, -3316, -2483, -6516, -2253, -227, -3927, -1044, -4583, -1548, -1515, -5988, -241, -5569, -1716, -4219, -6786, -118, -10210, -2982, -3695, -4620, -555, -4703, -3471, -3677, -4821, -1762, -3460, -2817, -6492, -8903, -4219, -4067, -3837, -8086, -6870, -4821, -5234, -7213, -5008, -3754, -2370, -3830, -4743, -3474, -2236, -1043, -1611, -3773, -2659, -1469, -546, -485, -5183, -3020, -1864, -786, -695, -8942, -5061, -3785, -1819, -2730, -5422, -5415, -4863, -3309, -8549, -2685, -2799, -3294, -3334, -4049, -1298, -1514, -2941, -1864, -2835, -819, -1047, -3975, -666, -3074, -938, -987, -6745, -243, -2578, -1491, -806, -6602, -575, -1707, -2417, -263, -5333, -1176, -1434, -3668, 77, -8903, -1542, -1819, -5615, -327, -5451, -1773, -2916, -8615, -1697, -1753, -1809, -4348, -9022, -4207, -614, -1748, -4331, -5960, -8754, -801, -2046, -3804, -4006, -12534, -1666, -2893, -3944, -3468, -9531, -2319, -4086, -4703, -4021, -11356, -3038, -4031, -5152, -5487, -8112, -4784, -2420, -4234, -9873, -4491, -2608, -1307, -4067, -8982, -2578, -325, -1029, -5561, 2080, 5215, 106, 2922, 2841, 3014, 5221, 172, 2269, 4181, 4165, 5141, 2035, 2117, 5452, 4538, 4770, 3580, 3754, 5490, 4196, 3956, 3785, 4526, 3901, 3537, 2557, 2738, 4043, -932, 2591, 269, 703, 2291, 1136, 458, -2306, -1136, -365, 2445, -4555, 45, -577, 826, 1757, -4031, 1951, 1058, 3043, 3471, -2994, 2842, 1736, 4276, 5582, -12, 3222, 1102, 4634, 6587, 1515, 3365, -537, 4061, 6540, 1412, 3187, -369, 2224, 5179, 512, 2445, 532, -1320, 1188, 389, 926, 4, -310, -1679, 422, -1736, -2046, 1038, 2003, -644, -3957, -3179, 699, 2666, -3080, -385, -2058, -1343, 3228, -5394, 1313, -1268, -15615, 3414, -8615, 1454, -339, -1452, 2847, -1385, 980, 822, 629, 1934, 1523, 1624, 1683, 733, 1499, 2381, 2301, 1903, -531, 1708, 1669, 2042, 1588, -2626, 1667, -601, 1059, 1265, -2390, 326, -2688, -727, 972, -1036, -5638, -1495, -4199, 37, -371, -735, -1308, -2012, -371, -271, 1794, -3417, -1298, 900, -525, 1968, -4035, -4046, 1326, -799, 465, -1141, -2648, 552, -834, -1868, -967, 96, -976, -816, -1463, -3040, 1115, -2933, -1254, -476, -2918, 1369, -6278, -2399, 238, -440, 928, -5906, -1975, 454, 118, 163, -3007, -295, -71, -1624, -79, -549, 188, -1409, -9106, -364, 849, -588, -2843, -907, -671, 917, -2383, -2450, 312, 221, 113, -3261, -1683, -1227, 1036, -36, -1566, -969, -10613, 1015, 105, -454, -418, -1932, 620, -840, -350, -629, -864, 409, -3156, -802, -2172, -2226, -97, -5735, -1373, -5422, -5801, -1458, -5374, -2366, -5686, -7603, -3621, -4980, -4500, -5615, -4282, -5451, -5509, -4578, -6035, -2720, -5091, -5933, -2382, -6256, -2559, -4679, -6007, -1722, -12319, -3438, -4420, -4625, -2339, -5531, -4327, -5253, -2594, -3436, -3321, -5387, -28777, -1814, -2631, -3339, -8138, -3324, -2372, -1339, -4378, -7562, -854, -3415, -992, -4885, -8683, -247, -2984, -1777, -5387, -10069, -818, -2282, -3804, -9149, -4743, -2475, -1983, -7562, -6692, -3710, -5189, -1753, -28777, -3463, -4625, -6007, -1887, -7335, -2960, -7888, -4784, -2910, -3662, -3954, -8393, -3811, -5121, -1665, -5319, -5037, -3124, -7583, -941, -4764, -3551, -3441, -8754, -1377, -3311, -2442, -5678, -28777, -2803, -3274, -1479, -10362, -6553, -4659, -5346, -1108, -7796, -3422, -5844, -4738, -1702, -4100, -2047, -5240, -2448, -3170, -890, -1210, -3600, -1640, -3665, 753, -627, -2344, -1449, -2829, 1092, -773, -2008, -1364, -2458, 217, -1782, -2875, -1402, -2453, -1925, -2336, -5234, -1950, -2683, -4625, -2229, -8754, -3213, -3886, -6163, -3509, -7523, -4460, -7196, -12123, -4644, -5836, -4134, -4042, -5897, -2203, -4957, -3603, -1553, -3175, -1107, -4733, -3910, -755, -2407, -1088, -5326, -5202, -6577, -2509, -2453, -7034, 339, -3108, -1198, -1880, -4611, 522, -1729, -1155, -1035, -4093, -162, -1394, -2205, -734, -4997, -1186, -1895, -4601, -1124, -6615, -1296, -3428, -7936, -1670, -8060, -843, -7179, -5509, -1585, -8423, -717, -8942, -4028, -1123, -5115, -886, -5387, -2975, -822, -2891, -1418, -4469, -1714, -1076, -1874, -3045, -3441, -1076, -2173, -1815, -6388, -2205, -1487, -3940, -2799, -3103, -1495, -2825, -4816, -4880, -1481, -1315, -2566, -4611, -3650, -1877, -1534, -854, -4659, -1245, -4438, -1843, 29, -5152, -156, -9238, -2306, -47, -6225, -106, -5208, -3509, -1227, -8827, -1007, -4006, -5043, -4425, -10899, -3062, -4119, -4901, -6973, -6035, -6553, -5133, -5584, -3707, -4145, -5670, -4858, -10210, -3237, -3769, -4270, -2587, -9193, -3149, -4464, -4438, -1303, -6183, -2316, -4929, -5623, -1301, -4759, -1826, -3417, -5367, -2683, -3016, -2108, -2034, -3535, -5793, -1842, -3069, -1681, -2369, -6445, -1514, -4331, -2621, -1698, -4918, -1800, -5195, -5422, -1742, -4420, -2125, -5115, -10526, -3284, -3978, -2004, -4486, -6786, -8942, -3930, -2014, -3846, -5751, -8333, -5189, -2939, -3337, -6074, -8865, -10799, -5776, -2990, -6553, -8086, -6321, -12776, -3042, -4826, -3738, -3606, -5266, -3352, -3119, -2979, -3569, -3689, -3947, -2644, -4172, -6163, -3430, -5554, -3227, -7687, -9479, -3103, -5387, -4378, -9331, -6163, -1904, -3347, -4997, -4968, -5897, -969, -2984, -4331, -2747, -6278, -912, -4278, -3563, -1466, -6332, -1704, -7796, -3220, -1170, -6745, -2935, -12123, -3112, -2130, -8276, -3896, -7264, -3903, -5079, -9284, -4597, -7050, -7583, -7562, -7299, -5429, -10899, -5810, -3603, -4382, -7066, -6800, -2811, -2087, -2317, -8192, -4242, -2045, -1884, -1615, -5444, -3689, -2297, -3012, -2181, -4195, -3971, -2937, -6288, -3876, -4286, -4295, -3798, -9753, -7523, -5227, -4907, -5115, -5127, -8423, -6928, -5844, -5115, -3049, -3449, -8112, -5085, -4089, -1868, -1882, -6814, -4403, -4056, -1379, -1733, -6354, -5561, -4869, -1489, -2331, -7583, -9585, -5988, -2086, -2914, -10526, -7247, -7623, -3083, -2637, -11004, -6083, -9193, -4473, -1753, -8138, -7503, -9064, -6026, -1228, -6267, -6759, -8942, -4837, -1526, -5879, -4578, -8393, -3393, -2933, -6113, -3913, -8138, -3422, -6103, -4869, -4242, -9331, -5037, -17034, -3788, -5097, -11781, -6133, -6653, -4028, -5888, -11115, -4597, -4138, -5997, -6016, -7603, -4112, -2997, -13365, -5576, -4853, -4759, -2861, -9380, -5152, -3455, -5480, -3436, -7408, -5227, -3163, -5253, -4315, -7665, -6173, -3798, -5429, -5726, -8649, -8827, -4826, -7542, -7113, -8138, -7542, -4991, -28777, -5049, -6899, -4769, -4800, -7936, -3916, -6719, -3944, -5960, -7213, -4187, -8165, -4611, -11945, -9106, -5422, -10899, -6928, -7264, -12534, -6786, -8009, -10799, -4266, -11488, -7317, -6445, -8790, -3370, -8582, -7865, -5326, -1923, 445, -1426, -4795, -4847, -2690, 167, -2256, -2211, -6480, -5630, -872, -3276, -1275, -8423, -5279, -2445, -4130, -1697, -5494, -2369, -4429, -4464, -2703, -4683, -1072, -7503, -4086, -2482, -6064, -546, -9429, -3133, -2452, -5367, -837, -6183, -2417, -4587, -2292, -2488, -4929, -2435, -11488, -959, -6399, -4056, -3399, -3683, -1087, -5735, -3532, -5061, -2276, -3054, -4795, -3833, -4683, -2465, -12776, -6411, -4307, -3189, -3689, -4089, -8903, -3306, -2969, -5718, -2326, -8865, -1875, -4486, -5970, -2785, -10138, -1058, -5678, -4112, -5394, -10704, -986, -3468, -3449, -9479, -9149, -1589, -3142, -4491, -6457, -7050, -2855, -5183, -7984, -5942, -6035, -5055, -6214, -7503, -6759, -5139, -6786, -2931, -7665, -6123, -3968, -4149, -1355, -8485, -3996, -3824, -2482, -812, -3856, -2655, -5002, -2176, -1260, -1868, -2128, -4693, -3274, -3227, -845, -2239, -2988, -6267, -10284, -485, -2859, -2531, -8485, -5654, -959, -3710, -3051, -6267, -4826, -2011, -4420, -3975, -6653, -5312, -2865, -4708, -4683, -9022, -2411, -4373, -4698, -4901, -8549, -892, -6422, -4523, -3975, -10069, -684, -2960, -4108, -2791, -9064, -1157, -1516, -3856, -2325, -3947, -1793, -1693, -4369, -2791, -2102, -2478, -3137, -4395, -4282, -1538, -3194, -5234, -3239, -6267, -1655, -3792, -5326, -2733, -5718, -2198, -4733, -4460, -2994, -4042, -3624, -7050, -4523, -3600, -3133, -8333, -8086, -5818, -4134, -3286, -6814, -4373, -7730, -3910, -4997, -3788, -2737, -6786, -3569, -9022, -3526, -2536, -6615, -3954, -6183, -4698, -3748, -7912, -4805, -4262, -5014, -6885, -4630, -5718, -3365, -3597, -7097, -2336, -7819, -2472, -2997, -4790, -1603, -13049, -1875, -3485, -3978, -2115, -9284, -2236, -4810, -3893, -3964, -9022, -3535, -6732, -4469, -8276, -12123, -3425, -10362, -6759, -8304, -9380, -2873, -14784, -12319, -5437, -6388, -4307, -10442, -5879, -4805, -4968, -9193, -6376, -5073, -4486, -4390, -4199, -4282, -5942, -3034, -4138, -2601, -4086, -4951, -1771, -4104, -2847, -5472, -4290, -1703, -4382, -4659, -7842, -4541, -3388, -4403, -8549, -8649, -3632, -6235, -3329, -5367, -7484, -3244, -3177, -2453, -3089, -7445, -4464, -1921, -2560, -2260, -9479, -5465, -1873, -3814, -2337, -8827, -4478, -2213, -6103, -3264, -8754, -4408, -3007, -6842, -4592, -13738, -5584, -4748, -6007, -3856, -6528, -7542, -4869, -6123, -2351, -4541, -6692, -3409, -7230, -1662, -4473, -4569, -3135, -9429, -1779, -5615, -3067, -3856, -11356, -2540, -7687, -2231, -4991, -10001, -3680, -11115, -2276, -5630, -8549, -4790, -12534, -3386, -5768, -7665, -5599, -6679, -5871, -6225, -7389, -6332, -4451, -12319, -6679, -6064, -7004, -4067, -10138, -5253, -4266, -6602, -5862, -7665, -3944, -3501, -5888, -17034, -7752, -3833, -3496, -5942, -5960, -8865, -5049, -3425, -6666, -4412, -8903, -7819, -3239, -7408, -5037, -7687, -13365, -1137, -2559, -1426, -6299, -6773, -2512, -3158, -1682, -5109, -7730, -3886, -3940, -2182, -4250, -10069, -3964, -4513, -3198, -5810, -9149, -4134, -4980, -3474, -11115, -6565, -4250, -7146, -2964, -3732, -6123, -3999, -8276, -3007, -1831, -6615, -3788, -4578, -2322, -1531, -7097, -3726, -3103, -1208, -2194, -7523, -3853, -2533, -1122, -3773, -8192, -2969, -2809, -2204, -7960, -9479, -1736, -4035, -3707, -6828, -12534, -1417, -5801, -3940, -2853, -10899, -2083, -6411, -3269, -1472, -9585, -3624, -3707, -3067, -1500, -10442, -6074, -1999, -4559, -3010, -6045, -9429, -1872, -8649, -5346, -3710, -11356, -3259, -4482, -3281, -2531, -9022, -5145, -3347, -2011, -1359, -6640, -3025, -5014, -2111, -419, -5623, -885, -9695, -3080, -238, -5670, 387, -3463, -4416, -812, -5951, 943, -1497, -5702, -1848, -7066, 897, -952, -7247, -2997, -12123, 607, -1319, -12534, -4238, -9479, 547, -2557, -7230, -5888, -6842, 461, -4403, -4509, -8790, -6113, -341, -4258, -4491, -28777, -5020, -2248, -3092, -7562, -10613, -3804, -4021, -2849, -5273, -9695, -3903, -2533, -3444, -2191, -8454, -6246, -1432, -3923, -1086, -4578, -7371, -1526, -3415, -994, -2309, -5367, -2815, -3182, -1505, -1452, -5784, -3944, -3933, -2242, -1813, -6842, -3449, -5694, -2891, -3074, -5776, -3674, -7796, -3407, -4082, -4361, -5253, -6732, -3975, -4654, -3108, -8086, -4195, -4769, -6343, -2264, -10284, -2543, -5853, -8086, -1987, -8060, -1844, -7066, -6133, -2216, -6399, -1868, -8517, -5584, -2578, -6016, -1864, -10362, -7066, -2487, -7317, -1236, -10210, -12123, -1979, -11945, -479, -6759, -7230, -1711, -7230, -266, -4180, -4935, -2328, -4644, -981, -2559, -4234, -4718, -3342, -2958, -1860, -4541, -11781, -2242, -6457, -2057, -5836, -5176, -1033, -6828, -3130, -7503, -3957, -168, -4963, -4532, -8034, -4693, -21, -4238, -4874, -6469, -6814, -643, -4816, -4963, -4592, -8165, -1863, -6480, -4991, -4352, -7213, -2982, -7819, -3535, -6153, -5906, -3269, -7464, -2111, -5020, -4408, -3425, -4640, -1471, -2707, -3916, -3668, -3010, -1532, -2277, -5234, -3386, -3027, -2238, -3452, -9585, -3279, -4513, -3430, -6343, -6411, -4659, -7097, -4307, -9380, -5286, -7888, -8649, -3592, -8485, -7130, -5678, -6988, -2737, -9284, -11488, -5202, -5026, -2416, -14195, -5997, -6745, -3795, -2051, -8718, -4733, -5312, -3331, -1759, -6299, -4698, -3487, -3788, -2305, -5623, -4089, -2847, -5367, -4274, -5339, -3163, -3117, -7426, -7353, -4907, -3056, -3957, -7730, -7034, -4336, -4130, -5312, -8615, -7097, -3879, -6870, -8549, -9149, -7623, -3444, -15615, -12123, -7408, -7299, -2933, -11356, -7335, -7687, -7213, -2813, -10704, -6856, -12319, -7687, -3296, -9238, -5942, -9106, -8754, -3856, -7130, -4425, -6310, -8754, -3856, -6332, -3723, -5751, -8112, -3933, -6321, -3668, -5951, -8615, -4597, -5836, -3766, -5827, -8942, -5776, -4082, 15079, 1996, 10173, 9749, 8284, 14678, 5449, 9501, 9080, 10074, 13441, 6789, 7260, 6834, 10033, 11279, 6239, 2289, 1501, 9131, 8396, 4271, 379, 853, 8032, 7499, 1618, 725, 1957, 6314, 8352, 35, -328, -609, 3415, 8633, -837, 177, -7019, 5102, 8143, -501, -542, -380, 5954, 6802, 1346, 1343, 1246, 4327, 4699, 3374, 3619, 2342, -3430, 3032, 4847, 4777, 2973, 1407, 3215, 5570, 5121, 3062, 1920, 4733, 5418, 4779, 2581, -1020, 5585, 4180, 3864, 1055, -6773, 4934, 1705, 2704, -2482, -3741, 2161, 513, 1702, -3133, -2997, -1296, 1091, 825, -1759, -4896, 1491, 453, 65, -1928, -2165, 1940, -1082, -638, -2567, -645, 977, -2097, -1932, -6173, -178, -1760, -1270, -4157, -3879, 1276, -5827, -543, -4104, -904, 2354, -3018, -950, -3820, -853, 2725, -2578, -2445, -6565, -1860, 2679, -3512, -2155, -6988, -956, 2077, -6577, -713, -4550, -176, 74, -6928, -394, -5158, -589, -9064, -1549, -1189, -5339, -1860, -1729, 496, -3284, -4046, -2935, -333, 1063, -7774, -3754, -2238, -1078, 587, -28777, -3401, -946, -1641, -483, -9812, -3161, -315, -1799, -1278, -5214, -3999, -675, -3441, -1319, -3465, -5189, -2244, -5472, -1206, -3326, -6365, -3863, -4382, -1671, -4373, -10799, -2475, -5615, -3269, -6007, -9429, -1656, -8754, -4620, -6628, -8683, -2049, -3674, -3286, -5979, -12534, -3177, -2743, -2646, -5333, -8086, -4238, -3600, -2829, -5554, -5266, -6256, -5139, -3321, -6943, -3635, -10001, -6074, -3738, -8034, -3087, -4951, -4323, -4123, -6786, -3840, -3526, -2317, -4635, -6719, -5055, -3860, -1154, -4929, -9429, -3347, -5380, -554, -4630, -11629, -2049, -7299, -448, -4161, -6899, -2022, -7371, -976, -3996, -5451, -2807, -6615, -2339, -4541, -4664, -3476, -6973, -5061, -6035, -4403, -3647, -8615, -9531, -7644, -4896, -4089, -8333, -7865, -6973, -6074, -5494, -6246, -7542, -6411, -7230, -9380, -4373, -7034, -7445, -7317, -9106, -3005, -6083, -11629, -6225, -5569, -2430, -4974, -9936, -5055, -4733, -2701, -4130, -6376, -4307, -5429, -3741, -4340, -4323, -4078, -7281, -5247, -5743, -3130, -4274, -10284, -6267, -7644, -2817, -4625, -14195, -5793, -7687, -3309, -4649, -9531, -5465, -6800, -4395, -4649, -9064, -6565, -8649, -5480, -5509, -12319, -9193, -8903, -5818, -8333, -11115, -8009, -3612, -5970, -13365, -8454, -6540, -1952, -6299, -8754, -8165, -6577, -1671, -6343, -7523, -9331, -7842, -2169, -5801, -7687, -9479, -9639, -3396, -5061, -7281, -8485, -9380, -5827, -4880, -5710, -8718, -9639, -11629, -5853, -4980, -10362, -13365, -9873, -7708, -5158, -11004, -13738, -7004, -6422, -5879, -9753, -9106, -5906, -4573, -6943, -9429, -7752, -5067, -4336, -8276, -9331, -7774, -3683, -6445, -10210, -8582, -8423, -2869, -12776, -9380, -7264, -8138, -3291, -6800, -7445, -6332, -7299, 8604, 3945, 6864, 8571, 7383, 7855, 3964, 6139, 8137, 7006, 5364, 3619, 3539, 6914, 5897, -274, 2199, -7523, 5283, 4622, -5240, -1046, 484, 3958, 4359, -3119, -1418, 512, 3032, 4121, -662, 1403, -3342, 1925, 3168, -599, 3199, -151, 3, 2474, -3054, 4122, 1936, -3827, 3063, -7081, 4206, 3093, -8683, 3985, 714, 4162, 4738, -2758, 4335, 3758, 4887, 6199, 115, 3745, 5275, 5632, 6833, 1408, 2127, 5620, 5737, 6451, 1162, -254, 4831, 5174, 4797, 469, -1992, 2837, 4148, 1409, 2100, -1279, 135, 2813, 989, 3339, -287, -241, 872, 2252, 3304, -571, 65, -1625, 1699, 2089, -2726, -411, -245, -88, -215, -6745, -1345, 1370, -2047, -2749, -3498, -2432, 1928, -3498, -4486, -2320, -2672, 1882, -5743, -3824, -2580, -1515, 1601, -6640, -2564, -3609, -797, 1335, -5933, -3824, -4669, -1195, 1133, -7353, -5702, -4460, -3244, 810, -14784, -1836, -3078, -10069, 47, -6943, -506, -2064, -6173, -1304, -4946, -315, -1832, -3735, -2182, -4486, -667, -2311, -2621, -1766, -4299, -2057, -3177, -2264, -1648, -3551, -7281, -3738, -2849, -1826, -3597, -4664, -3886, -4395, -1638, -6143, -1424, -3824, -6577, -1468, -5862, -165, -3698, -7865, -1752, -3187, 485, -3720, -5906, -2541, -3430, 761, -4130, -3529, -3817, -6246, 486, -5694, -2200, -5615, -6133, -790, -11356, -1873, -7644, -4630, -4486, -8790, -2473, -7162, -5133, -6814, -6577, -4078, -5360, -5008, -2217, -6411, -7247, -4606, -3309, -1123, -5133, -11115, -4784, -2452, -1197, -3937, -6640, -5319, -2845, -2043, -4266, -4816, -6299, -4997, -3362, -7230, -4929, -11232, -9695, -4112, -11004, -7842, -7146, -6016, -3092, -5546, -11004, -3837, -5133, -2020, -4327, -6288, -3187, -5951, -1836, -4331, -5970, -4123, -6163, -2664, -5121, -7774, -4842, -5718, -4523, -5988, -10899, -3824, -7097, -7752, -6457, -8112, -3662, -28777, -13365, -7019, -6745, -5103, -7603, -9429, -7371, -7050, -8942, -5853, -8549, -6914, -8790, -9149, -6278, -11488, -6457, -8192, -7146, -7408, -10704, -6958, -6016, -6615, -6814, -6235, -9429, -4532, -6719, -6173, -4693, -9639, -3674, -7865, -6870, -4331, -6745, -3714, -11945, -9106, -4597, -6256, -4816, -10899, -11781, -5170, -7730, -6885, -7464, -11629, -5853, -13049, -8454, -6577, -10362, -6143, -8582, -7687, -7213, -8615, -5735, -5592, -6540, -10001, -7644, -4974, -4573, -6628, -28777, -7281, -4564, -4795, -7842, -10069, -7179, -4728, -6434, -9149, -8942, -7299, -5158, -11629, -13365, -10069, -7542, -5480, -8582, -9531, -11781, -7162, -5607, -5049, -6615, -8517, -6615, -5067, -3729, -6214, -6958, -6235, -4348, -3729, -6553, -7097, -5933, -4226, -5240, -6299, -8517, -6133, -4708, -9284, -5979, -10362, -7317, -5686, -8982, -5924, -11115, -8112, -7066, -7583, -5960, -10526, -7842, -7774, -9531, -6163, -10069, -9429, -7213, -12776, 4310, 2708, 6990, 7471, -15615, 3226, 1575, 6534, 7170, -5319, -565, -1330, 5369, 6403, -1790, -1323, 1284, 4390, 5600, 1713, -1967, 2902, 4127, 4938, 4045, -6163, 3210, 3792, 3977, 5217, -1403, 2642, 2997, 2856, 5416, -3629, 1050, 1590, 2355, 4620, -1743, -1913, -605, 1507, 2126, 2935, -3040, -3168, -1542, -3626, 4946, 1173, -948, -2146, 2887, 5787, 4314, 1140, 1218, 4354, 5668, 5813, 1252, 2007, 3854, 4538, 5779, -493, 2074, 2001, 2451, 3882, 611, 2980, 2509, 942, -3210, 2276, 3721, 4021, 702, 231, 1892, 3317, 4409, -103, 1213, -609, 1603, 4021, -608, -1343, -4495, -1340, 3247, -650, -9429, -6540, -6540, 2242, -958, -2698, -6093, -5871, 719, -927, -2102, -2073, -2619, -1591, -356, -1857, -1686, -2222, -1594, 196, -1391, -3626, -2175, -136, 147, -1688, -11356, -1900, 259, -920, -2887, -6246, -2314, -224, -3656, -4234, -3863, -3866, -1571, -10001, -4176, -3259, -5516, -3729, -4527, -3187, -3635, -4021, -4299, -3996, -2847, -5008, -3314, -2316, -7708, -4093, -7912, -5121, -761, -4759, -6299, -13738, -6870, -336, -1613, -2912, -12776, -2495, -1371, -860, -1158, -7562, -1300, -4199, -1588, -863, -5176, -1625, -4532, -3463, -1439, -4784, -2737, -3071, -4053, -2289, -5509, -4010, -2447, -3242, -3225, -5524, -5509, -1953, -3671, -4974, -6093, -7603, -2178, -5286, -7445, -9429, -9022, -3444, -6246, -6885, -7335, -9695, -4532, -6399, -6928, -6026, -12123, -3971, -7623, -9639, -8247, -6590, -4219, -9331, -12319, -9753, -3422, -6988, -9429, -8454, -4469, -2002, -9753, -8615, -5853, -3005, -1741, -5646, -7299, -4142, -3119, -2416, -6310, -5979, -3814, -4138, -3618, -11232, -4946, -4885, -4688, -3571, -5008, -4226, -5554, -4442, -2670, -3707, -3840, -4176, -5067, -2688, -4918, -3680, -3644, -8865, -3886, -11356, -3580, -4307, -6354, -5646, -7603, -3683, -5784, -2825, -6602, -5584, -4473, -7503, -1782, -7146, -6235, -6653, -8982, -2195, -7426, -9753, -11629, -7708, -3913, -6679, -11781, -9873, -6411, -7353, -5091, -7603, -9106, -6214, -8220, -3846, -6553, -8363, -7281, -5871, -3436, -6719, -6973, -10613, -5751, -3798, -8060, -6759, -7644, -7371, -4821, -10210, -7888, -5299, -9873, -6214, -9064, -9873, -4831, -9753, -7353, -7113, -11629, -5584, -9479, -8790, -5793, -11781, -7081, -9812, -11232, -5374, -10442, -8649, -9753, -7484, -6457, -8903, -9238, -10069, -5183, -11945, -8247, -8454, -10442, -4464, -7708, -8423, -7113, -8517, -4679, -4513, -9149, -6411, -6870, -4997, -3621, -9380, -6235, -6376, -4951, -4086, -9284, -5735, -6528, -5415, -5524, -9695, -4759, -7066, -6914, -7353, -10613, -4168, -8649, -7335, -8333, -10899, -4013, -11629, -6354, -7687, -9284, -4010, -8827, -6732, -8192, -8192, -3947, -6565, -9331, -13049, -8333, -3773, -5818, -9149, -9331, -9531, -3785, -6321, -6773, -7623, -5139, -5897, -6973, -6074, -7230, -7281, -6365, -7912, -6256, -7842, -4587, -6288, -10799, -6628, -8454, -2613, -5768, -10526, -6504, -8754, -2219, -5970, -9149, -5561, -7445, -3540, -6528, -9873, -4946, -5879, -6914, -6288, -8517, -5266, -5133, -5576, -5183, -8138, -6628, -5214, -3916, -4060, -11945, -8790, -6343, -3549, -3386, -11004, -10899, -9639, -3801, -3409, -7865, -10799, -14195, -4215, -4157, -6973, -8903, -8827, -4078, -5539, -6914, -7752, -8942, -3551, -7730, -9022, -7912, -12319, -3751, -7865, -12123, -8517, -14195, -4654, -6204, -7445, -7912, -10362, -4957, -4478, -5202, -9639, -7774, -4093, -2210, -3027, -6814, -3580, -2316, -69, -818, -1828, -467, -735, 1194, 803, 382, 1201, 75, 1347, 1438, 1068, 1630, -57, 377, 925, 464, 862, -1274, -1599, -921, -1469, -1321, -3863, -4031, -4774, -5121, -5686, -8615, -5997, -8827, -12319, -8942, -15615, -6602, -6492, -10001, -7603, -12319, -6204, -6434, -7179, -6899, -11115, -5844, -7888, -6163, -6194, -10613, -6183, -11629, -5888, -5970, -9284, -7464, -11781, -5997, -5897, -8423, -8790, -8393, -6577, -6035, -7484, -8423, -7146, -7960, -6719, -6007, -7912, -7464, -10284, -7960, -5422, -6773, -9936, -11781, -8982, -6469, -5139, -10362, -11232, -9639, -11629, -4211, -7888, -11488, -11356, -8009, -4097, -7623, -13365, -15615, -5055, -4369, -8942, -14784, -14195, -4286, -4616, -11629, -11356, -10799, -4853, -5152, -11945, -9064, -8865, -6628, -6083, -9284, -8304, -9022, -7774, -7019, -7912, -8903, -12319, -6745, -8790, -7708, -10442, -13365, -6256, -17034, -8683, -9106, -9149, -6885, -9753, -10799, -6899, -8165, -8247, -7752, -13738, -5942, -8060, -7213, -8582, -17034, -6246, -8615, -5853, -13365, -28777, -8454, -9936, -6204, -14195, -17034, -13365, -12534, -8982, -11356, -13738, -8683, -10613, -11945, -9064, -12534, -8247, -8865, -9193, -7484, -12776, -10613, -9531, -9936, -7247, -17034, -14195, -11004, -14195, -8060, -13365, -11232, -8423, -9695, -9149, -10210, -11488, -7353, -7644, -9238, -9064, -13049, -7583, -7484, -8220, -9106, -11945, -8304, -7408, -6988, -9695, -10284, -8754, -6113, -6615, -9639, -9238, -8865, -4929, -7408, -9639, -8363, -8903, -4307, -9284, -9639, -8276, -8754, -4495, -10362, -8827, -9064, -8615, -5888, -9022, -8393, -10362, -9064, -8754, -7665, -8582, -11781, -9936, -8582, -6828, -8903, -14195, -10442, -6528, -6615, -9193, -12123, -10210, -5888, -6973, -9429, -8982, -10001, -6540, -7562, -9753, -7888, -10001, -9022, -7730, -10613, -8220, -10362, -17034, -7730, -12319, -10362, -11488, -15615, -8582, -12534, -28777, -13049, -15615, -11004, -9429, -14195, -12776, -9380, -13365, -7865, -12776, -11945, -7146, -10799, -8009, -14784, -11945, -6411, -8754, -10001, -12534, -12534, -6828, -8423, -12534, -10899, -11945, -8192, -9812, -10899, -10138, -10526, -9585, -12776, -10799, -10362, -9585, -9695, -13365, -12776, -11356, -9936, -9429, -10442, -13049, -10799, -11945, -6602, -9331, -17034, -6692, -7960, -7113, -8754, -11781, -6745, -6504, -8165, -9331, -13365, -7196, -5988, -11115, -10899, -14195, -7066, -5444, -9585, -9585, -10001, -6343, -4743, -6958, -7603, -9873, -6235, -4168, -6376, -6666, -12123, -7281, -4006, -7230, -6553, -13738, -10526, -4361, -9380, -7230, -11488, -15615, -5306, -12534, -8754, -8615, -9531, -6480, -9585, -8903, -6842, -7752, -6958, -6745, -7196, -6590, -7408, -6759, -6064, -6434, -8086, -8393, -6577, -7353, -6602, -13365, -10210, -6504, -10526, -6376, -12123, -11945, -6732, -12534, -5387, -8790, -15615, -6565, -9106, -5942, -9479, -7687, -5576, -4923, -10362, -7752, -3535, -3840, -1920, -2664, -2432, -788, -1616, -269, 35, -115, 743, 13, 29, 912, 614, 1152, 624, -1164, 438, 96, 421, 120, -4541, -1426, -1563, -1617, -1613, -12123, -5279, -4215, -5183, -4644, -8649, -28777, -7179, -6800, -7842, -8649, -11629, -9106, -6719, -7730, -6856, -11115, -9238, -7842, -6540, -5121, -9639, -7353, -9064, -6615, -4303, -8718, -6083, -9585, -7264, -4713, -8718, -6343, -9238, -7019, -6376, -9873, -8393, -9149, -6943, -7426, -13049, -10210, -10210, -8060, -7213, -28777, -7426, -14784, -11356, -8718, -14195, -6153, -11488, -14195, -12534, -15615, -6143, -8112, -11004, -7389, -17034, -6988, -7050, -10613, -5380, -10001, -8549, -7335, -12123, -5097, -7936, -11004, -8582, -12319, -6615, -7130, -15615, -9429, -9064, -14195, -7281, -15615, -8009, -8276, -8485, -8517, -11115, -6064, -9429, -6422, -11945, -9585, -5422, -11488, -6628, -15615, -8982, -6469, -12123, -7623, -10613, -8982, -11004, -11629, -7960, -9585, -9022, -9106, -9331, -7819, -9429, -8549, -6516, -8165, -8138, -9022, -7281, -6163, -8903, -9479, -8138, -6411, -6899, -11781, -10799, -7484, -6310, -8333, -10362, -10362, -7523, -6856, -9639, -7644, -10442, -8423, -7299, -9022, -6343, -12123, -10210, -7019, -8517, -5924, -14784, -12123, -6914, -9873, -6434, -28777, -13365, -7644, -15615, -8009, -13365, -12534, -9380, -14784, -10001, -9531, -10899, -11781, -12534, -10526, -8112, -10799, -13049, -10001, -10613, -7842, -13049, -11945, -8865, -9022, -7936, -28777, -11356, -10138, -7888, -8165, -10442, -12319, -14784, -7687, -8903, -8865, -17034, -12776, -8034, -11232, -8009, -12123, -17034, -7796, -15615, -6973, -9429, -11629, -7196, -9753, -6745, -8485, -8517, -7281, -8485, -7730, -8549, -8393, -8060, -8865, -9380, -9331, -9812, -9331, -10001, -9639, -10799, -10613, -10138, -12319, -10210, -13365, -10138, -10613, -15615, -11629, -17034, -10210, -11488, -11781, -10704, -15615, -10613, -12776, -10526, -10526, -11356, -11356, -28777, -11488, -12123, -9639, -11781, -12319, -28777, -14195, -9064, -11115, -9873, -10069, -15615, -9531, -11004, -10138, -7687, -15615, -10899, -12776, -11945, -7317, -11232, -13049, -28777, -12776, -8363, -9429, -12123, -11945, -12534, -11232, -8865, -10526, -9812, -11945, -14195, -9022, -9429, -9695, -11004, -14784, -10442, -9238, -11004, -11629, -10069, -4104, -8333, -5801, -9149, -9429, -4447, -14784, -5554, -9106, -8060, -4654, -13365, -5871, -6399, -6299, -4985, -10613, -6745, -5472, -5253, -5326, -10069, -8086, -5678, -5026, -5234, -10526, -10613, -6434, -5422, -4625, -9531, -13365, -7408, -6143, -3937, -6628, -8982, -8423, -7019, -3507, -5312, -7019, -9284, -8247, -3546, -5073, -5951, -9936, -10526, -4127, -5353, -5584, -11488, -14784, -4728, -5743, -6026, -11781, -15615, -4447, -6565, -7146, -9936, -10613, -4180, -8754, -8009, -9284, -8790, -5234, -12123, -8009, -9639, -8827, -8517, -8865, -8220, -11488, -8549, -9812, -6093, -6679, -11629, -5061, -5670, -3237, -3656, -4826, -2012, -1978, -693, -1030, -1746, -188, -34, 920, 530, -283, 484, 425, 1414, 892, -63, 72, -546, 703, -42, -1096, -1479, -3375, -1434, -2578, -3738, -4234, -11781, -4774, -8060, -10069, -7179, -8333, -5279, -15615, -8060, -7665, -8009, -6183, -17034, -6365, -7665, -9753, -9873, -11004, -5906, -8165, -8549, -8247, -8942, -5339, -10138, -5988, -7213, -8192, -4800, -13738, -5014, -8942, -7353, -4863, -9193, -5360, -14195, -6773, -5524, -8454, -6640, -7960, -6943, -6267, -10613, -8276, -6143, -7708, -6457, -12776, -8942, -5915, -8304, -6732, -7774, -8615, -6745, -9106, -7644, -6007, -8549, -8247, -10899, -8903, -6016, -9695, -9022, -13049, -9873, -7865, -12319, -8903, -12123, -12776, -11629, -10069, -9064, -9331, -12123, -9695, -7912, -8942, -7050, -8754, -9022, -7196, -7960, -5801, -8220, -9479, -7912, -7281, -5554, -10001, -9106, -10704, -7389, -6288, -17034, -8333, -28777, -8649, -7819, -10526, -7936, -28777, -12319, -8982, -8454, -7408, -13049, -15615, -9193, -8165, -6422, -8423, -10899, -10704, -8982, -5623, -7196, -10799, -14784, -10442, -5286, -8138, -14784, -9331, -12123, -5266, -10799, -15615, -7583, -12319, -5516, -7603, -10362, -7464, -10613, -6445, -5247, -9639, -7687, -9695, -8615, -4336, -10613, -7687, -10526, -12776, -4295, -13365, -8034, -17034, -28777, -4733, -12123, -9022, -10362, -15615, -5286, -9812, -10799, -7842, -11488, -5768, -8683, -14784, -7353, -9873, -6045, -8333, -14195, -8582, -8683, -6332, -8615, -9479, -13049, -7774, -7230, -9639, -7752, -17034, -7247, -8683, -12534, -7299, -12776, -7445, -8009, -17034, -7503, -11356, -8393, -6814, -11004, -8060, -9695, -10284, -6590, -9812, -9380, -8754, -13365, -7179, -10210, -11945, -8165, -14784, -8582, -11232, -13738, -8363, -12776, -11232, -10613, -15615, -9753, -10704, -28777, -10442, -15615, -11781, -9531, -11781, -10704, -11115, -10210, -8615, -9429, -9064, -9284, -8903, -7912, -9193, -7503, -8683, -8582, -7819, -9753, -6504, -9193, -8942, -8582, -9873, -6064, -10704, -9873, -10284, -9873, -6235, -13049, -11781, -14784, -11232, -7097, -13049, -14195, -14784, -13365, -8982, -11781, -17034, -10362, -11356, -13738, -11945, -10899, -8827, -9380, -15615, -13049, -8827, -8333, -8393, -12319, -13365, -8549, -8363, -8304, -14784, -13738, -9585, 8691, 10305, 10541, 8363, 6601, 7910, 9849, 9903, 7804, 6059, 5271, 8450, 7889, 6106, 4381, 2415, 6066, 4679, 3269, 1449, 3746, 3056, 3635, -135, -1732, 2977, 1488, 2915, -2326, -3242, 1084, 2377, 314, -3227, -10362, 1812, 3353, -1552, -1758, -9, 2880, 3452, -1317, 255, 2692, 2860, 2480, -2229, 1058, 3712, 1121, -330, -3824, 1567, 3828, -1906, -2217, -5784, 3306, 3465, -906, 2508, -5367, 4815, 2717, -2032, 4277, -3779, 5221, 1198, -297, 4506, -3801, 4428, -1244, 1773, 3323, -4874, 2258, 699, 1762, 222, -3574, -1859, 2634, -210, -3474, -1026, -4230, 2955, -6786, -395, 729, -3103, 1975, -3235, 766, 1489, -3182, 25, -913, 1107, 1108, -3036, -3247, -458, 987, -859, -2470, -3695, -1216, 718, -5214, -1939, 724, -3490, 430, -3417, -674, 1651, -3034, -301, -1909, 543, 121, -1499, -2123, -570, 478, -8220, -2148, -6422, 845, -1650, -2236, -1663, -7665, 1426, -28777, -1095, -287, -3016, 1119, -2076, -1716, -1664, -1746, 342, -150, -677, -8517, -2730, -131, 258, 982, -354, -7408, -391, -114, 1613, 886, -5109, -628, -244, 676, 383, -4412, -501, 496, -4067, -910, -6565, -777, 1177, -1882, -2829, -4412, -2807, 1366, 1056, -7960, -3401, -15615, 993, 1442, -4541, -2871, -2735, 13, 377, -1948, -930, -955, -888, -2300, -1862, -33, -836, -284, -10069, -3493, -756, -1612, 337, -5853, -4831, -1978, -2877, 10, -4500, -3692, -220, -4089, -1151, -4089, -2716, 1032, -5346, -2460, -2605, -2490, 888, -5646, -3606, -1341, -3621, -652, -3147, -5879, -839, -8112, -3903, -1432, -14195, -1252, -7445, -8165, -824, -8865, -2881, -4112, -13365, -1057, -7484, -5670, -3704, -5055, -1760, -6321, -6773, -4728, -2445, -2448, -4021, -9695, -5576, -1677, -2988, -2416, -8790, -4100, -1923, -3375, -1634, -4597, -3187, -2762, -2935, -1601, -3062, -3674, -4010, -2057, -2430, -2516, -5240, -5333, -1733, -4290, -2943, -6899, -5164, -2188, -6376, -4420, -13365, -4274, -3094, -5735, -6422, -6278, -4176, -3808, -4901, -8485, -3586, -5079, -4262, -4640, -11945, -3557, -6856, -4635, -4357, -7464, -6173, -8454, -4800, -3951, -5546, -13049, -7865, -4968, -3686, -5253, -6183, -6214, -5214, -3683, -5793, -5759, -5458, -5049, -3978, -6692, -8683, -6103, -4336, -4482, -7623, -10210, -8304, -3840, -4997, -8086, -5569, -11356, -4250, -5888, -7371, -4378, -9695, -5487, -7484, -6332, -4442, -7081, -6516, -9022, -6113, -5367, -6480, -6388, -9753, -6885, -7034, -7230, -6173, -9531, -9284, -9429, -7912, -6899, -8718, -14195, -28777, -8138, -10442, -8649, -10362, -7936, -8683, -11781, -11781, -10613, -5401, -8615, -8683, -8247, -9873, -4708, -7213, -8615, -5170, -7936, -5164, -6143, -9106, -4382, -6988, -6445, -5906, -9022, -4940, -5465, -8363, -6365, -8649, -6540, -4089, -5646, 5776, 7356, 3662, -4733, -891, 4819, 6828, 3205, -2859, 332, 1246, 5321, 1950, -203, -938, 82, 3287, -24, 509, -5103, 1880, 1533, -2011, -545, -3311, 673, -508, -1247, -2386, -1726, 81, -8517, -1443, -5299, -1130, 1969, 499, -263, -3964, -234, 2762, 3183, 1844, -1575, 614, 2807, 4262, 2043, -974, 942, 2151, 4793, -92, 1499, 666, 24, 4919, 621, 3218, 66, -5031, 4265, 3095, 3609, -451, 562, 2416, 3298, 3098, -804, 2856, -732, 1155, 2234, -976, 3584, -1030, -11945, 1723, -486, 3028, 96, 444, 1906, 586, 914, 578, 1841, 1995, 1404, -2605, 808, 1760, 1269, 1355, -1232, 521, 1411, -642, -42, -377, -578, 1605, -4723, -3383, -871, -1250, 2108, -9531, -3824, -2795, -475, 2321, -4559, -3168, -3526, -563, 1969, -3714, -4250, -1292, -2276, 950, -3316, -5380, -1071, -5266, -620, -2173, -6343, -3067, -3698, -2121, -1644, -5615, -7708, -1516, -2692, -2690, -6719, -3741, -222, -2179, -5960, -8982, -1137, 155, -1559, -5097, -3615, 536, -715, -1587, -3769, -1940, 1480, -4086, -1873, -4478, -1514, 1701, -7066, -1580, -7004, -1689, 1130, -2935, -1197, -12534, -2581, -372, -3468, -1499, -10526, -5319, -3175, -6256, -2664, -4550, -3748, -11004, -2422, -4049, -1393, -977, -6074, -513, -4215, -142, -642, -3843, -126, -2155, -431, -2592, -4149, -813, 157, -2058, -7179, -8247, -2589, 1296, -3417, -4123, -5145, -6183, 1086, -3378, -3968, -1775, -7371, -866, -4258, -3215, -509, -3985, -7984, -6388, -1246, -78, -2958, -3523, -9193, -662, -246, -3490, -1799, -11004, -1445, -1325, -5353, -2192, -11629, -3367, -3906, -4486, -3496, -12534, -5844, -6026, -2701, -4831, -12776, -7796, -4693, -2236, -5662, -10613, -6553, -5183, -2350, -6225, -9106, -5853, -6388, -2388, -6899, -9284, -7213, -6235, -2458, -8363, -8454, -9429, -5759, -2839, -11004, -6773, -9193, -4569, -3689, -7146, -6365, -11629, -3529, -4826, -5494, -7179, -12534, -3365, -5516, -6445, -8718, -7984, -3876, -4649, -11781, -9380, -5584, -4654, -3117, -7730, -11356, -4097, -5286, -2355, -5888, -15615, -3521, -5897, -2443, -5710, -8423, -3860, -7317, -2999, -5853, -6899, -5292, -9753, -3383, -5768, -7113, -8393, -11232, -2979, -5437, -8517, -11488, -14784, -2084, -4957, -10799, -7819, -9812, -1522, -4559, -11781, -6480, -7081, -1630, -4478, -8517, -6399, -6540, -2505, -4795, -6516, -7130, -7389, -4230, -5306, -5897, -7644, -9238, -6143, -5827, -6388, -7146, -10899, -5380, -6870, -7603, -6666, -9936, -4219, -9479, -8086, -6759, -8009, -3785, -12123, -7583, -7464, -6457, -3710, -8304, -7542, -8790, -5630, -3701, -7936, -8649, -8903, -5360, -3910, -10899, -13049, -6214, -5494, -4679, -11004, -11232, -4795, -5862, -6321, -7562, -7484, -4478, -6288, -9331, -7130, -6492, -4901, -6113, -12776, -8549, -6457, -2505, -4842, 2010, 3905, 962, 931, -1150, 2331, 2455, 4825, 2939, 1276, 2948, -12123, 6643, 3103, 2313, 3325, 1971, 6810, 1326, 2360, 3195, 3111, 5724, -1206, 1605, 2525, 1581, 3512, 149, 81, 1509, 532, 1417, -60, -2447, 528, 2746, 835, 1160, -4805, -479, 2964, 1023, 3140, -3042, -3788, 1231, 2606, 3882, 269, -2610, 1012, 3180, 3560, 2815, 1979, 2340, 1817, 2254, 3991, 3427, 1267, 245, -174, 3757, 3255, -3526, 2637, -1163, 1815, 1866, 974, 3641, 347, -1141, 667, 2125, 4254, 427, 760, 598, 835, 5135, -1214, 1375, -187, -3487, 5450, -4168, 602, -1979, -7687, 4788, -1616, -490, -3554, -4153, 3180, 491, -645, -4274, -3927, 1757, 1151, -23, -3232, -5933, 2244, 860, 300, -1203, -9429, 2633, 495, -227, 95, -3069, 1981, 450, -1686, 478, -1450, -36, -83, -3830, -208, -1324, -4644, -1547, -6045, -2422, -1701, -6310, -3964, -8485, -6590, -855, -2226, -7019, -6628, -3571, 705, -1452, -7542, -4184, -1956, 1596, -3042, -5915, -3420, -1749, 1607, -5576, -4592, -3827, -2578, 742, -2460, -3203, -4611, -4810, -1168, -1341, -1930, -4361, -12123, -6214, -2116, -1302, -3853, -5768, -4307, -7130, -1501, -4191, -2182, -743, -4416, -1949, -4455, 17, 415, -2943, -2045, -3103, 1169, 582, -6267, -2578, -2211, 1153, 183, -2608, -3025, -2472, -375, -695, -344, -2277, -4089, -3014, -1815, -394, -2603, -10899, -1472, -1127, -2189, -5253, -4425, -875, 327, -5145, -15615, -1682, -2442, 743, -4708, -11629, -1515, -5615, 166, -3540, -11115, -3971, -4340, -688, -2787, -9639, -10799, -4184, -1343, -2785, -13365, -3744, -7389, -2690, -4093, -6246, -2950, -7523, -5509, -7066, -4303, -3600, -3161, -7562, -6814, -4348, -4451, -1787, -8060, -5827, -5776, -4601, -1865, -7623, -5897, -7464, -4495, -3365, -4907, -5339, -6928, -4946, -7583, -3817, -3808, -5844, -5793, -9585, -3692, -2564, -5380, -5273, -6516, -3425, -2257, -5524, -4104, -7730, -3001, -2971, -6194, -3457, -10613, -3433, -4161, -6928, -3342, -6773, -5718, -4373, -7113, -3763, -5970, -8363, -3889, -6786, -5152, -6988, -4635, -3830, -6590, -8865, -8982, -3482, -4683, -7004, -12534, -10210, -3656, -6376, -8718, -8165, -10284, -4399, -6354, -11488, -7230, -8112, -5085, -5189, -7562, -7247, -6083, -5836, -5133, -5415, -8034, -5494, -6615, -6173, -4842, -9936, -6343, -6745, -7819, -5472, -12123, -7281, -6074, -8827, -6943, -11945, -5751, -5472, -8363, -8247, -10284, -4564, -5710, -7281, -8034, -8865, -4207, -7130, -6343, -7247, -8112, -4348, -8942, -5844, -7081, -7665, -4382, -8517, -5599, -7708, -7130, -3873, -8220, -5451, -9380, -6692, -3071, -8982, -6204, -14784, -6759, -2517, -9429, -9429, -11945, -7113, -2597, -7842, -14195, -8517, -7603, -3624, -7034, -10799, -7936, -8220, -6054, -7644, -13365, -10284, -7196, -9106, -9193, -3674, -8086, -7445, -9812, -10799, -4541, -5997, -6153, -8086, -7426, -7623, -5020, -4504, -6814, -5451, -7299, -4573, -3501, -6759, -4779, -4473, -4266, -3306, -7542, -5306, -3920, -4046, -3766, -8454, -7097, -4940, -4142, -4635, -8683, -10138, -7687, -4907, -5451, -8549, -10210, -10526, -6540, -6434, -7984, -8192, -7936, -6640, -8549, -7213, -7230, -7281, -4929, -11004, -7066, -7623, -8718, -4323, -7888, -8615, -9812, -9331, -5073, -5970, -11945, -15615, -6577, -7796, -5037, -8615, -13738, -5437, -28777, -4611, -7230, -12776, -5623, -8192, -4513, -6745, -12534, -6973, -6492, -5273, -6173, -11232, -10284, -6235, -7484, -4963, -9695, -12123, -7179, -8790, -3853, -9193, -7097, -11115, -7984, -3701, -9873, -5319, -11004, -10001, -4805, -12319, -5115, -8112, -15615, -7230, -12319, -6267, -8009, -8683, -9531, -10526, -9022, -8485, -7213, -9812, -8827, -14784, -9380, -7130, -10899, -7426, -28777, -14784, -7888, -11781, -6759, -12534, -9479, -9238, -12123, -6692, -10138, -6267, -11356, -10526, -7146, -8517, -5061, -13365, -8903, -8549, -7583, -4853, -12319, -9331, -12123, -7389, -5444, -9936, -10899, -12776, -8060, -7004, -8754, -9064, -9193, -9639, -7562, -9695, -7842, -8393, -11232, -6064, -13049, -7819, -8423, -11356, -5615, -9331, -8247, -8615, -10613, -6469, -6719, -9193, -10069, -9331, -7353, -5208, -10442, -10362, -8304, -6602, -4620, -9812, -8393, -7819, -5879, -4985, -7708, -8304, -8034, -5686, -6256, -6267, -9695, -9022, -5638, -8485, -5960, -10613, -11781, -5654, -10613, -6773, -9531, -17034, -5743, -8549, -8683, -8454, -11004, -5592, -6615, -10526, -9106, -10138, -4874, -5924, -8942, -13365, -10799, -4112, -6246, -7730, -10704, -10899, -3893, -7426, -7623, -8423, -9695, -4433, -8192, -8454, -8086, -9193, -5862, -7774, -10704, -8138, -9639, -7708, -8086, -13049, -8060, -10613, -7730, -10704, -10001, -8220, -10613, -7162, -13365, -8683, -8942, -9479, -7484, -9429, -9193, -10138, -8718, -8247, -8582, -11488, -11004, -8718, -8649, -8827, -11945, -10704, -8615, -8549, -9193, -11115, -10069, -8754, -8220, -10284, -11629, -9479, -10210, -7426, -14784, -12319, -8942, -11945, -6628, -11629, -12776, -8615, -10442, -6434, -7708, -17034, -8517, -10442, -7213, -6480, -17034, -8393, -14195, -9695, -6504, -12534, -8192, -14195, -13365, -7281, -13738, -7687, -10069, -9639, -8333, -28777, -7230, -9380, -8517, -9479, -10210, -7113, -9695, -9064, -11232, -8192, -7299, -10526, -9284, -12319, -7960, -7426, -12534, -7984, -11004, -9193, -7819, -28777, -7730, -9695, -11488, -8903, -14195, -8718, -9585, -14784, -11356, -14784, -10138, -10704, -13365, -15615, -12319, -12534, -13049, -10362, -28777, -9936, -28777, -12534, -9238, -28777, -9479, -10799, -11004, -9238, -17034, -10001, -9585, -11004, -9812, -14195, -10704, -10799, -11945, -11629, -12776, -11781, -28777, -10799, -14784, -12534, -13738, -17034, -8982, -14195, -14784, -15615, -11629, -8192, -13049, -17034, -17034, -5554, -5502, -11115, -10284, -6759, -6153, -5472, -9531, -8790, -7371, -6973, -6492, -8220, -8138, -7562, -8112, -8718, -7562, -7936, -7050, -9022, -9873, -7819, -8086, -7542, -9284, -8423, -8683, -8790, -9022, -9064, -6958, -9479, -9753, -9380, -8942, -6074, -10138, -10001, -8790, -8220, -5997, -11629, -9479, -8485, -7353, -6540, -9429, -9106, -8517, -7752, -7371, -6786, -7912, -9585, -10704, -8582, -5862, -6577, -11232, -15615, -12123, -6492, -6163, -12534, -10704, -12319, -9380, -6615, -12776, -10704, -8942, -28777, -7371, -12776, -11232, -8086, -9812, -7687, -11945, -10526, -6914, -7888, -8138, -10799, -10442, -5879, -6928, -9639, -11781, -8827, -5853, -6332, -10362, -13365, -6870, -6602, -5970, -8333, -8790, -5988, -7984, -5818, -7583, -7523, -6016, -11115, -5942, -8718, -7865, -6653, -9380, -6692, -12534, -8363, -7426, -7445, -9429, -13049, -7523, -7665, -8034, -12776, -13049, -6469, -7665, -9585, -7865, -17034, -5979, -8192, -8060, -7335, -14784, -6434, -9479, -7665, -9149, -11629, -7408, -10613, -9193, -15615, -10069, -7081, -10210, -12776, -15615, -8942, -6653, -9531, -14195, -11356, -8276, -7281, -9064, -17034, -8423, -7730, -8165, -8683, -12776, -6928, -6943, -7888, -8138, -9380, -6973, -6422, -7562, -7542, -8615, -9064, -6516, -8220, -7484, -10001, -13049, -7146, -9936, -8165, -13738, -10526, -8086, -9695, -9149, -11945, -11115, -8790, -7865, -9479, -9531, -12776, -8903, -7130, -8485, -7503, -9753, -8517, -7774, -7644, -6376, -7865, -7888, -10069, -7888, -6204, -6719, -7371, -28777, -9936, -6958, -6615, -7583, -10069, -11488, -8582, -7912, -8827, -8034, -8086, -11232, -10284, -11629, -7912, -6842, -28777, -10284, -28777, -9531, -6914, -10704, -9936, -17034, -9585, -8112, -7960, -10362, -14195, -7912, -10799, -7819, -10442, -12776, -7888, -13738, -10210, -9149, -12776, -9873, -9106, -15615, -8363, -12776, -12776, -7353, -11232, -9284, -12123, -10899, -7389, -10526, -14784, -10799, -9149, -8485, -10799, -12319, -9639, -8192, -7464, -13365, -9238, -9531, -7774, -6422, -12776, -8615, -11004, -7960, -6828, -9585, -8615, -14784, -8865, -8517, -9585, -8827, -17034, -10526, -10362, -12123, -9639, -12123, -9873, -10138, -17034, -11629, -9331, -7796, -9149, -12776, -13365, -8086, -6705, -9429, -11488, -11629, -8060, -6705, -11232, -11115, -11004, -9022, -8165, -15615, -11232, -11115, -10526, -13049, -28777, -13738, -11781, -12534, -11488, -28777, -28777, -11629, -28777, -9531, -13738, -11115, -10799, -12319, -9873, -12123, -9639, -9639, -9531, -10210, -11945, -10001, -9064, -8982, -9531, -11232, -11115, -9106, -10069, -8363, -8982, -9812, -9331, -12776, -7865, -7503, -7984, -9238, -17034, -8485, -6899, -7113, -9695, -14195, -10362, -7081, -7019, -11488, -11115, -11232, -7819, -7542, -15615, -9936, -10210, -8982, -8683, -17034, -9753, -9585, -10799, -10704, -17034, -10210, -9106, -15615, -13365, -17034, -10899, -8790, -12776, -13365, -14784, -11356, -9022, -9429, -13365, -13049, -12534, -9531, -9331, -9695, -11629, -10362, -11945, -10001, -13738, -14195, -12776, -11004, -7034, -14784, -14195, -9106, -12776, -5960, -10069, -9873, -7353, -28777, -6035, -8649, -6828, -6332, -9753, -5970, -9238, -5531, -5759, -7426, -5726, -14784, -5109, -5897, -6745, -6492, -9531, -5299, -6745, -7081, -8982, -6553, -5702, -7623, -8649, -11945, -5654, -6113, -7503, -9753, -11945, -5888, -7034, -6045, -7687, -11115, -7317, -9284, -4901, -6457, -8276, -11356, -11488, -4759, -6026, -7019, -12123, -9531, -5630, -6045, -7004, -8009, -8827, -7464, -6365, -7644, -6842, -9106, -10210, -6492, -8582, -7213, -9695, -15615, -5988, -9812, -7708, -9639, -13365, -5480, -9695, -6256, -7730, -8582, -5085, -7623, -5472, -6225, -6640, -4693, -6958, -6354, -6113, -6204, -4464, -8304, -8454, -7960, -6828, -4460, -14195, -8333, -10899, -8086, -4759, -11781, -8393, -8718, -9284, -5569, -9064, -8903, -9479, -9639, -7019, -7796, -7066, -15615, -8754, -8942, -6653, -5933, -10799, -8034, -11356, -5879, -6026, -8649, -7353, -28777, -6064, -6786, -7353, -7034, -9585, -7583, -7247, -6759, -7912, -6528, -9639, -6800, -7130, -11356, -5516, -9429, -6225, -8165, -12534, -5853, -10069, -6204, -8827, -10613, -6842, -11781, -6870, -8649, -14784, -7665, -13365, -7960, -8393, -10613, -9149, -14784, -8220, -8683, -6914, -10069, -11781, -8009, -9479, -5678, -8060, -10138, -9193, -8549, -5726, -7752, -10613, -11356, -6828, -6870, -9639, -13365, -9753, -6007, -8615, -9873, -28777, -9238, -6299, -8649, -8393, -12319, -8485, -7730, -8423, -9429, -9284, -6745, -9873, -9429, -13049, -7445, -5718, -11488, -11115, -11232, -6388, -5561, -12776, -13738, -10138, -6083, -6026, -12319, -12319, -10442, -6267, -6692, -10799, -9429, -8903, -6565, -6732, -10284, -9149, -7264, -6928, -5951, -10284, -11004, -6615, -7936, -4885, -10069, -15615, -6745, -9936, -4180, -10899, -11004, -7247, -12776, -4250, -17034, -9531, -7644, -15615, -5286, -11232, -9812, -7984, -11781, -7213, -8683, -11781, -8790, -9695, -8112, -8754, -17034, -9106, -8982, -7912, -11629, -12534, -8754, -8485, -8683, -14195, -10799, -9238, -7984, -10704, -11629, -9873, -9531, -7936, -12319, -12776, -9106, -9479, -7912, -12534, -14784, -9022, -11945, -7984, -14784, -12534, -9639, -15615, -8363, -28777, -10138, -9639, -9936, -9064, -12776, -8304, -9479, -8549, -8517, -11356, -7299, -10210, -8034, -7623, -11004, -7179, -11115, -7523, -7842, -10001, -7796, -10613, -7408, -9695, -9380, -9531, -10526, -7912, -14195, -9812, -13738, -11356, -10001, -28777, -11781, -17034, -13738, -28777, -28777, -14195, -11945, -28777, -9429, -13365, -12123, -10138, -14784, -7708, -12534, -10001, -9106, -12776, -7936, -17034, -9022, -8790, -11356, -9479, -14195, -9022, -9380, -10704, -11629, -10613, -10001, -10613, -10526, -11115, -10362, -12123, -10799, -10284, -9531, -11629, -13738, -10138, -10284, -8827, -15615, -11629, -10704, -10704, -9284, -17034, -11004, -12319, -11629, -10613, -12123, -12534, -12319, -11488, -12534, -7912, 8129, 8421, 4616, -91, -5208, 7667, 8075, 5018, 389, -3412, 6217, 7030, 5460, 639, -1710, 3433, 5274, 5332, 427, 1114, -2217, 2927, 4709, 850, 3155, -662, 578, 3903, 1078, 3852, 970, -1786, 2948, -412, 2963, 594, -8393, 1261, -3701, -587, -1247, -2245, -2217, 919, -951, -2749, 439, -2153, 2934, 1518, -1398, 1739, -17, 3694, 1447, 72, 2577, 49, 3955, 134, 1663, 2943, -1025, 3872, -1774, 2634, 2519, -565, 3053, -2194, 2594, 766, 973, 632, -985, 1323, -4518, 1671, -1203, -1142, -2094, -979, 1525, 2144, -2555, -5183, 1761, 946, 3236, -3748, -1343, 2641, 1113, 2723, -8549, -981, 2386, 2234, 930, -3067, -1508, 953, 3135, -57, 413, -727, -2273, 3407, -346, 1639, -181, -8192, 3019, -5061, 1671, -1185, -7113, 1992, -1153, 673, -3436, -10799, 44, 2113, -1646, -1458, -4278, -4527, 3050, -5444, 107, -2885, -2182, 2826, -4064, 295, -3540, 293, 1696, -1480, -95, -2478, 637, -295, -243, -21, -812, 326, -1317, -374, 306, -1037, 1164, 100, -1299, 74, -4901, 2180, 1009, -1759, -752, -3763, 2296, 1240, -832, -1872, -349, 1388, 1079, 676, -3339, 2, -304, 441, 1219, -6064, -1645, -1207, -1156, 393, -7230, -5531, -861, -4640, -1244, -2071, -3543, -1275, -7603, -1078, 108, -2222, -3080, -4097, -773, 777, -2339, -5979, -2231, -2156, 148, -2924, -7004, -1341, -6958, -2383, -3947, -5458, -1268, -7583, -11232, -4195, -3471, -1645, -5026, -3344, -2294, -2049, -2220, -4123, -2877, -1233, -1253, -2783, -2232, -5472, -1025, -1301, -2756, -872, -10284, -589, -2064, -2294, -487, -8247, 466, -3187, -1788, -1037, -6958, 1229, -5480, -1302, -2305, -3225, 1182, -5139, -1156, -3566, -1562, 155, -1846, -1830, -5008, -1327, -2032, -539, -3886, -6679, -2234, -5487, -243, -6235, -4784, -4157, -5176, -421, -4669, -3641, -6528, -3220, -884, -4442, -3751, -8112, -2661, -1820, -5592, -5014, -8718, -3404, -3316, -6800, -7936, -8754, -5214, -3518, -7865, -7984, -10210, -6054, -2198, -10899, -8086, -14195, -5554, -1443, -11004, -14195, -9936, -4455, -1409, -6553, -6705, -8982, -2877, -1998, -3798, -5247, -10001, -1698, -3056, -1842, -6103, -11232, -1157, -3830, -744, -9429, -13738, -1310, -3612, -526, -13365, -9873, -2330, -3121, -1324, -7426, -5654, -4307, -2992, -3422, -4821, -3701, -4790, -3306, -6267, -3704, -2889, -3360, -3883, -5879, -3971, -3089, -2819, -4323, -6113, -5451, -4532, -3201, -4373, -7583, -6422, -7984, -4278, -4331, -7687, -6054, -13049, -5844, -4664, -6885, -5299, -13738, -6074, -6045, -5768, -4315, -8865, -4649, -10210, -4764, -3937, -6640, -4089, -11232, -4869, -4303, -6256, -4286, -7445, -6800, -5247, -6759, -4327, -6256, -15615, -6679, -8276, -4145, -5055, -7081, -8276, -12319, -4509, -4286, -5031, 5810, 2751, -3003, 7114, -1794, 5418, 2238, 3725, 6585, 1614, 4093, 685, 5400, 4857, 2891, 1271, 812, 4932, 2564, 1994, -6143, 2495, 2201, 3529, -1765, -4078, 2793, 446, 4063, -5646, -2043, 1563, 3779, 2944, -1987, -73, -741, 4886, 951, -3641, 1109, 535, 4795, 682, -9380, 1309, 2366, 3656, -273, -2364, 977, 3028, 1304, -5924, -327, 785, 2696, 784, -983, 822, 1122, 2017, 3220, 1278, 1077, 1885, 2691, 4575, 1727, 180, 2938, 3463, 4949, 1296, -1754, 3983, 2996, 4442, 255, -2783, 4638, 729, 2959, -985, -1745, 4593, -3589, 119, -174, -1396, 3498, -1326, -3201, 2031, -2305, 626, -854, -706, 3390, -4017, -1043, -2162, 473, 3675, -6786, 1434, -4863, -47, 3198, -6914, 1734, -11488, -1307, 2907, -2245, 728, -2637, 106, 2779, -1092, -103, -201, 1108, 1615, -884, 94, 218, 542, -373, 777, 109, -1231, -1205, 134, 1873, 98, -2015, -1610, 41, 1161, 808, 797, -1238, -2432, -2831, 1786, 2177, -2685, -10526, -3615, 2351, 2540, -3112, -6504, -1518, 2203, 2385, -201, -5480, -4352, 1230, 1832, 710, -5776, -4679, -322, 609, -284, -9238, -2265, -1097, -1628, -4564, -10442, -2677, -516, -4230, -4460, -6814, -1613, 538, -4810, -1797, -7503, -42, 1397, -6064, -2071, -10001, 538, 1530, -11356, -3814, -2455, 176, 566, -5465, -5109, 413, -1173, -2320, -3175, -3957, 1652, -3060, -13738, -3301, -2560, 1715, -3896, -3933, -4759, -1663, 636, -4262, -3641, -3449, -1377, -1990, -4336, -5121, -2095, -1987, -7299, -4064, -6225, -2019, -3763, -4795, -3479, -5437, -3154, -4115, -3618, -2863, -4123, -6016, -2204, -3776, -3058, -3656, -8615, -1599, -4089, -3873, -4307, -7019, -2412, -4195, -3529, -6565, -7687, -5014, -4713, -2694, -12123, -8903, -9936, -6653, -2657, -4795, -8754, -5444, -11629, -3347, -2709, -9531, -3751, -8304, -4478, -2605, -9812, -3237, -7004, -5494, -4078, -5458, -3286, -7019, -5702, -4688, -3609, -4161, -7019, -5401, -3010, -3449, -6958, -6628, -5516, -1701, -4473, -8982, -5970, -6399, -549, -6299, -8393, -5509, -7623, 134, -8086, -8363, -5662, -7523, 20, -8549, -3560, -6064, -6310, -985, -7708, -2178, -5853, -5638, -2893, -5451, -3085, -6411, -5743, -5615, -4527, -5472, -9936, -6133, -9106, -5827, -2956, -11945, -5970, -13365, -12319, -1656, -6885, -5273, -13738, -9585, -1994, -4319, -4951, -10442, -7730, -3644, -2833, -5710, -7247, -6299, -6842, -2720, -6565, -5380, -5306, -28777, -4315, -5546, -4644, -5702, -8423, -9149, -5279, -4659, -7796, -6133, -6842, -6885, -4698, -7842, -5662, -5444, -11781, -4161, -5654, -6602, -6988, -9531, -3465, -5164, -6705, -10210, -7623, -3324, -6016, -4810, -6615, -7034, -4180, -7752, -4060, -5408, -6885, -6183, -8754, -4683, -5576, -7066, -8982, -7730, -6540, -6577, -7426, 7775, 3486, -3409, 6394, 8147, 7302, 2951, -449, 6089, 7915, 5722, 1586, 1184, 5311, 7244, 2010, 796, 1186, 4451, 6152, -1259, 1258, -143, 3733, 4391, 3176, 1783, -1680, 2617, 2593, 4027, 2024, -818, 940, 4178, 3651, 1508, 642, 1854, 4899, 3008, -50, 1485, 2837, 3291, 2594, -1202, 1176, 2496, -949, 1762, -714, -1098, 1766, 3303, -217, -906, -9193, 1214, 4537, -4536, -1948, -20, 431, 4869, -3051, -3428, 2048, 862, 5421, 9, -5654, 2373, 1696, 5574, 1413, -4912, 1299, 1275, 5145, 1772, -1607, -880, -945, 4881, 977, 366, -679, -4644, 4832, -1743, 1576, 555, -2873, 4192, -3360, 2583, 878, -1392, 2959, 293, 3527, 613, -306, 2757, 1714, 4104, 309, -101, 3943, 2141, 4010, 797, -980, 4874, 1935, 3045, 1596, -2488, 4965, 1063, 1165, 1614, -3301, 3808, -674, -618, 227, -2893, 170, -3163, -1216, -4382, -2688, -1249, -2943, -2112, -4060, -3407, 1858, -1005, -1935, -613, -2294, 1852, 326, -1055, 170, 94, 143, 1129, -904, -427, 1297, -2583, 1531, -1292, -2635, 1298, -3665, 1668, -2020, -7730, -15, -2960, 1607, -2366, -12123, -3208, -2994, 1257, -2372, -7196, -4491, -4108, 349, -1875, -2801, -2228, -5312, -1377, -277, -804, -1556, -4754, -2490, 165, 258, -1644, -2973, -1534, -1685, 980, -2268, -1210, -632, -6666, 1193, -3923, -272, -311, -1448, 502, -7960, -698, -1348, -619, -1335, -4357, -3680, -5836, -1920, -3479, -2168, -7230, -5801, -3846, -3417, -2079, -2309, -3396, -3523, -3808, -3776, -2241, -4226, -3738, -4601, -7335, -4912, -6235, -3606, -4254, -8363, -3158, -6278, -2698, -4723, -6278, -739, -4569, -3433, -7230, -3644, -133, -3792, -7503, -9936, -2613, -839, -4555, -5988, -9106, -3357, -2545, -6504, -4654, -7984, -6103, -3208, -4764, -6225, -6365, -5401, -2424, -2701, -6899, -6800, -3316, -2280, -2060, -6628, -13365, -2724, -2745, -2776, -6745, -7583, -2871, -3360, -5444, -3735, -4985, -3254, -4211, -14784, -2288, -4219, -3078, -6214, -6310, -2404, -4010, -2121, -10362, -5049, -3913, -3957, -1096, -9193, -5273, -7097, -3840, -438, -9936, -6399, -12319, -3326, -169, -11232, -8615, -11945, -2688, -95, -10001, -10210, -11488, -2409, -150, -14195, -8138, -11115, -2670, -566, -5924, -7523, -10613, -3354, -1602, -3430, -7774, -10001, -3940, -3354, -2922, -7408, -10284, -3947, -5662, -3589, -6113, -9429, -4112, -8517, -4064, -5109, -6988, -5067, -13738, -4089, -4907, -5879, -6628, -12319, -5394, -5718, -6540, -7408, -10799, -8138, -8009, -9429, -7317, -10284, -5546, -14784, -7179, -8304, -7888, -4064, -8754, -4606, -10210, -6885, -4100, -6163, -3665, -7146, -7687, -5319, -5292, -3837, -5444, -11781, -8454, -5444, -4997, -5444, -10284, -13365, -6528, -6411, -6679, -6928, -8423, -8865, -7113, -7960, -5827, -8034, -8393, -8903, -5516, -4659, -4713, -8982, -7464, -6492, -6480, -5422, -11232, -8363, -6856, -7426, -6842, -6666, -11488, -6745, -5494, -8485, -4438, -28777, -7196, -4718, -8827, -3766, -12123, -8827, -5170, -7888, -3856, -8615, -10613, -6814, -7034, -4024, -6457, -10284, -10138, -7004, -4145, -5127, -8754, -13365, -7484, -4901, -4826, -7426, -11488, -6958, -7066, -6035, -7335, -10704, -5694, -12776, -10442, -7445, -9695, -5091, -13365, -9479, -6640, -8517, -5158, -9695, -6457, -6035, -7542, -5844, -7335, -5592, -6225, -6958, -7408, -6173, -5678, -7796, -6602, -9193, -6745, -6411, -11781, -6786, -11629, -10362, -6666, -6163, -7960, -8790, -4869, -4536, -2833, -6422, -3989, -2273, -2716, -1138, -3641, -1965, -1694, -2068, -603, -2534, -1450, -2610, -2617, -1166, -2945, -2211, -4416, -4311, -2994, -4963, -4455, -5133, -5818, -6692, -9238, -8582, -5592, -5339, -10362, -13049, -10704, -7335, -5465, -8718, -11781, -11115, -9585, -6928, -9380, -10284, -14195, -9064, -8165, -11115, -10442, -17034, -8423, -6640, -10799, -13365, -13738, -8827, -5401, -9331, -11781, -13365, -8754, -5353, -8220, -9193, -15615, -8034, -6800, -7984, -8138, -13049, -8276, -9331, -8363, -7960, -12534, -9873, -9753, -7066, -8192, -14195, -12319, -10138, -5888, -8009, -14784, -12776, -10362, -6074, -8615, -13049, -9479, -7819, -7665, -12319, -15615, -7162, -6759, -10526, -11004, -17034, -6194, -7464, -12776, -8903, -14784, -6183, -9331, -10210, -10442, -28777, -6288, -9479, -8454, -15615, -10001, -6143, -8393, -8582, -14784, -7665, -6083, -7523, -10526, -17034, -7752, -6653, -6615, -17034, -10526, -10799, -8790, -5960, -12123, -9149, -11232, -12534, -6183, -8333, -9479, -7503, -8034, -7774, -6516, -9873, -6343, -6719, -11781, -5554, -10799, -6045, -6828, -8517, -5121, -14784, -6204, -7796, -6411, -5103, -14195, -6388, -9695, -6246, -5662, -11945, -6422, -10284, -7603, -7034, -11945, -6828, -8086, -10613, -9022, -11115, -8485, -6973, -13738, -10284, -9873, -14195, -7034, -28777, -11356, -9238, -11488, -7687, -12319, -13049, -8942, -8423, -8138, -9479, -11781, -8982, -7842, -8333, -9193, -9193, -9531, -8423, -9022, -10613, -8192, -10526, -9695, -9812, -11945, -8304, -11356, -8982, -9695, -10362, -8982, -10613, -7888, -9238, -9380, -8942, -9193, -8276, -9193, -8827, -8363, -8086, -11356, -10138, -8247, -7865, -8009, -17034, -12776, -8060, -7912, -9380, -11945, -14195, -9022, -8827, -13365, -13738, -12319, -11945, -10069, -15615, -17034, -12319, -28777, -9695, -13738, -10899, -11629, -15615, -8982, -15615, -10284, -9812, -15615, -9479, -17034, -12123, -8615, -12776, -10526, -14195, -17034, -8304, -11356, -11115, -10799, -28777, -9149, -11356, -12319, -8982, -15615, -11232, -11356, -15615, -8276, -12534, -13049, -11115, -17034, -8903, -12123, -14784, -11356, -13365, -11356, -13738, -15615, -13738, -10284, -28777, -28777, -14195, -17034, -8683, -12534, -17034, -11488, -12776, -8485, -11004, -13365, -10899, -11004, -9429, -10613, -11781, -10069, -6553, -8903, -8865, -7353, -9284, -6332, -9812, -14784, -7281, -7708, -7842, -8942, -8982, -9064, -6343, -11115, -8517, -7281, -8393, -5933, -7819, -8903, -7644, -4901, -6786, -6615, -8942, -10210, -3833, -9022, -7353, -8485, -13365, -4469, -11488, -9531, -8649, -9429, -6856, -9479, -12123, -9695, -8582, -8423, -6628, -10284, -9936, -9531, -6365, -4985, -8009, -9238, -12319, -5810, -4319, -6973, -9193, -17034, -6457, -4238, -7196, -9531, -15615, -8192, -4327, -8790, -8276, -10442, -14195, -4327, -12123, -7004, -7464, -9695, -4395, -14784, -6411, -6354, -6434, -5133, -10799, -5437, -6321, -5607, -8220, -5888, -3589, -5888, -6828, -8649, -2902, -1778, -3641, -8276, -3989, -1348, -695, -2039, -4082, -2509, -972, -555, -1717, -2545, -2517, -1735, -1415, -2737, -2841, -3707, -3804, -3373, -4555, -4826, -5888, -7644, -6469, -4527, -8517, -8138, -17034, -10442, -4203, -13365, -10442, -12534, -12319, -5085, -9531, -11781, -8865, -11781, -7162, -7426, -9022, -7130, -10362, -10799, -7542, -7196, -6246, -8827, -28777, -9531, -6504, -6457, -8247, -28777, -14784, -6842, -8276, -9380, -11004, -14784, -7912, -13049, -17034, -7230, -11115, -8865, -11356, -10001, -5630, -10001, -9479, -9695, -7665, -5584, -9936, -9022, -9639, -7583, -6914, -10069, -7335, -9429, -9022, -8942, -7819, -6153, -8865, -9936, -9639, -6035, -6143, -8942, -9022, -9753, -5502, -7774, -9429, -8649, -8060, -5997, -12776, -10069, -8333, -6973, -7264, -11488, -10613, -7562, -7162, -8718, -9812, -10001, -6988, -8454, -10069, -10362, -9380, -7034, -10613, -11945, -11232, -8304, -7888, -14195, -10899, -11488, -6856, -9753, -14784, -9380, -11629, -6235, -11356, -11004, -9639, -12319, -6814, -9284, -9284, -10704, -14784, -9331, -7230, -8718, -10442, -28777, -15615, -6103, -8423, -11356, -12776, -8903, -5970, -8165, -17034, -12534, -7389, -7019, -8304, -13738, -14784, -7752, -9531, -8790, -11115, -12123, -8790, -9585, -8865, -10442, -10138, -8517, -8086, -8549, -9936, -9149, -8220, -7888, -8363, -8865, -7960, -8423, -8247, -8827, -7796, -7179, -8060, -8615, -10526, -7503, -6800, -7264, -9106, -14784, -8517, -6679, -7162, -9873, -13738, -12123, -6719, -8009, -10138, -11488, -14195, -6958, -9753, -9531, -11004, -9429, -7583, -11004, -8982, -11232, -8754, -9193, -10210, -8393, -11945, -9639, -13365, -10362, -7819, -12319, -10442, -13049, -12319, -8112, -13738, -10704, -9936, -28777, -9753, -14784, -12123, -9479, -17034, -14784, -12776, -13738, -10069, -14784, -14195, -11356, -11781, -11488, -14195, -12123, -10210, -9022, -14195, -11356, -12534, -9193, -7445, -11232, -8982, -13365, -8718, -7130, -8393, -7842, -11945, -9022, -8060, -7644, -7936, -10704, -9873, -9812, -8454, -9585, -9531, -9238, -11232, -10899, -13738, -8942, -8165, -12534, -14195, -28777, -9064, -7865, -13738, -11488, -15615, -9585, -8363, -15615, -9479, -15615, -9753, -9753, -15615, -8982, -17034, -10613, -11781, -13049, -10001, -15615, -12534, -12776, -12776, -13049, -8138, -7865, -5554, -10001, -8649, -9193, -7842, -5818, -9429, -6653, -9936, -7888, -6679, -7426, -6628, -10526, -7162, -8517, -6640, -7523, -8060, -5615, -11629, -6299, -7335, -7912, -4336, -12776, -5615, -8276, -10442, -3923, -11232, -4274, -28777, -8220, -4611, -9284, -3137, -7464, -6235, -6870, -8165, -2801, -5539, -5751, -11232, -7842, -3311, -5592, -5933, -11781, -7097, -4532, -7034, -6235, -10069, -6540, -6163, -9936, -6194, -7066, -7445, -7865, -13365, -5862, -5387, -10526, -8649, -13049, -5678, -5055, -11232, -8454, -11945, -5818, -5897, -8517, -8615, -10526, -6773, -7317, -6411, -8220, -7335, -7796, -6007, -4149, -5584, -3982, -4616, -3930, -2168, -3281, -2036, -2698, -2823, -1128, -1967, -1420, -2253, -2741, -1185, -1613, -2040, -2889, -3920, -2462, -2334, -3971, -4336, -6365, -5234, -4386, -7562, -6267, -6278, -10138, -7623, -14784, -7503, -5599, -9479, -6773, -13738, -6074, -6856, -7281, -5924, -11004, -4880, -10362, -5451, -6565, -9531, -4664, -28777, -4299, -8423, -8790, -5380, -17034, -4075, -9873, -8549, -7066, -28777, -4946, -9936, -8304, -9531, -28777, -7196, -10442, -8363, -8903, -15615, -11945, -8363, -8903, -6973, -14195, -14195, -6365, -10210, -6143, -14195, -9193, -5576, -10526, -6083, -12776, -7130, -5662, -9531, -6365, -9695, -6310, -6577, -9284, -6628, -7730, -6504, -7708, -9331, -7019, -6856, -7562, -7445, -8683, -8060, -6800, -8790, -7389, -8112, -10138, -7066, -8138, -8086, -8112, -12123, -7179, -7066, -8086, -8220, -11115, -7426, -6492, -8865, -7936, -9380, -7888, -6310, -14784, -7081, -8423, -8582, -6653, -10442, -6422, -8138, -9873, -7562, -8009, -6434, -8276, -8790, -8517, -7687, -7213, -8086, -6899, -9479, -8138, -8247, -7371, -6469, -11488, -8393, -8683, -6343, -7687, -28777, -7984, -9022, -5429, -11488, -13365, -7730, -9531, -4957, -11004, -10799, -7865, -9639, -5061, -9238, -9531, -8220, -9873, -5853, -9531, -8754, -8582, -11945, -7603, -10799, -9193, -9284, -14195, -10284, -9695, -11356, -10799, -10362, -11115, -8454, -12319, -12319, -9064, -9238, -8582, -11004, -11781, -8649, -8034, -10442, -12319, -10613, -8517, -7464, -13049, -14784, -9639, -8363, -7665, -11629, -11629, -9149, -8454, -9331, -10442, -10001, -9149, -8754, -28777, -9106, -9531, -9531, -8718, -9238, -8423, -10526, -11232, -8247, -7247, -8517, -14195, -15615, -8192, -7774, -9106, -10704, -11945, -8865, -11232, -10442, -8363, -10442, -10704, -11945, -14195, -7960, -11115, -13049, -10138, -28777, -8649, -13049, -12123, -11781, -14784, -10442, -17034, -12776, -14195, -15615, -12534, -28777, -28777, -12123, -15615, -11232, -15615, -12319, -12319, -13365, -10210, -13738, -9936, -13365, -10899, -10362, -11488, -9479, -13365, -9380, -11629, -10526, -10210, -12776, -8982, -13365, -11356, -11488, -11781, -9753, -15615, -12123, -13365, -11232, -12319, -28777, -11781, -17034, -11945, -17034, -17034, -10799, -28777, -14195, -12123, -12123, -9639, -28777, -28777, -10526, -10001, -10284, 4117, -1741, 9439, 9312, 2929, 4284, 3780, 9089, 8741, 3537, 3546, 5573, 8139, 6969, 2777, 77, 5538, 6789, 3793, -832, 507, 4484, 5032, -1375, 2805, 1841, 4026, 2905, -4071, 3685, -490, 4578, 1425, -2758, 2398, 458, 4783, 2331, -3201, 1941, 2624, 4456, 3865, -749, 2661, 2622, 3622, 4037, 2250, 1839, 2018, 2369, 2478, 3507, 644, 2440, 1644, -681, 3310, 3949, 3087, 2569, -214, 2662, 6229, 3034, 3999, 1167, 3524, 7221, 2032, 4742, 2237, 4177, 7205, 1220, 4302, 3191, 3378, 6255, 1632, 2944, 3826, 324, 4266, 755, 3572, 3941, -5662, 652, -3412, 4796, 3351, -770, -8165, -3357, 4906, 1831, 557, -985, 358, 4203, -1154, 1485, 947, 3721, 3249, -5266, 2252, 1828, 5710, 2217, -2133, 3012, 2522, 6438, 254, -589, 3494, 3352, 6161, -3589, -192, 3259, 3915, 5106, 963, -496, 2047, 3842, 3530, 3031, -504, -223, 2924, 1435, 3332, -164, -1337, 954, -1360, 2077, -599, -29, -2297, -866, -1878, -2659, 1208, -4373, -668, -883, -9531, 2301, -707, -6504, 1977, -3968, 3284, 981, -403, 2637, -1710, 3956, 1025, 2695, 1865, -885, 4103, 302, 3660, -1123, -897, 3684, 222, 3544, -3586, -1897, 2782, 35, 2671, 818, -4331, 1276, -1210, 1024, 1553, -6773, -1669, -2617, -1780, 71, -4527, -4478, -2152, -2730, -5670, -3860, -1207, -1155, -566, -2241, -4123, -442, -263, 373, -511, -3007, -1201, 340, 491, -918, -1462, -3367, 250, 208, -2363, -759, -6759, -1057, -143, -3065, -858, -4795, -4550, -870, -2470, -1504, -2823, -9873, -2795, -2651, -2312, -1758, -7936, -5374, -4215, -3254, -1158, -6299, -2873, -5085, -4923, -1030, -3927, -1384, -3594, -8304, -1410, -3342, -940, -2659, -8827, -1766, -3583, -1076, -1906, -6705, -1193, -4049, -1614, -1075, -5726, -683, -5221, -2495, -660, -4795, -1190, -6553, -3583, -1224, -4262, -3252, -6163, -4679, -3641, -4429, -10001, -5960, -5306, -9193, -4564, -4134, -5836, -4295, -5085, -4270, -1272, -5234, -3135, -5458, -4386, -361, -4718, -2859, -9812, -4630, -674, -4664, -3744, -6745, -2861, -1711, -5472, -5312, -5109, -1241, -2348, -8304, -4991, -4425, -891, -1728, -5818, -4738, -4278, -1773, -806, -3342, -5221, -6214, -3968, -556, -2918, -3989, -10138, -7542, -1268, -3856, -2881, -4826, -11232, -3067, -4974, -3175, -3760, -8865, -6153, -4713, -5465, -4473, -5531, -8942, -3720, -12776, -6388, -3662, -7464, -3069, -5726, -8517, -2941, -5014, -3378, -3650, -8827, -3294, -3076, -5061, -3274, -8192, -4123, -1979, -8086, -4683, -8086, -3937, -1515, -8683, -9936, -9064, -3546, -1564, -5818, -4616, -8982, -3523, -1957, -3741, -1935, -7484, -3319, -2576, -2992, -1060, -6814, -3227, -3629, -3638, -1564, -6365, -3404, -3479, -6615, -3879, -6235, -3566, -2186, -9531, 6803, 9364, -4743, 4275, 9806, 6092, 8981, -377, 4063, 9215, 3944, 7910, 1949, 3178, 7333, 886, 6396, 2910, 2059, 3891, 539, 4752, 3404, 2191, 1230, 2443, 3137, 3821, 2050, 2253, 2887, 2212, 3979, 886, 2908, 935, 2848, 3917, -157, 2637, -1532, 3687, 3734, -219, 1128, 1752, 3753, 3302, -985, -1205, 2359, 2832, 2821, -2288, -2016, 1916, 716, 2936, 264, -266, 2262, -3396, 3667, 1652, 1017, 2916, -293, 4315, 1773, 1691, 3217, 2884, 4483, 1961, 2831, 3601, 4208, 4235, 2651, 3658, 4113, 4035, 3815, 3109, 3289, 4379, 1922, 3346, 2946, 1350, 4232, -4258, 2606, 1940, -2472, 3801, 545, 1129, 540, -4968, 3411, 1727, -1748, 1032, -6235, 2953, 1598, -4698, 1944, -4693, 2074, 634, -4513, 1989, -2300, 757, -121, -4486, 2266, 700, -1212, 2880, -918, 3610, 2747, -1140, 4536, 460, 4539, 3819, 1327, 4779, 542, 4573, 4236, 2028, 4032, 1154, 4013, 4197, 881, 2632, 1796, 3564, 3842, -3010, 736, 1195, 3340, 3341, -3692, -1967, -945, 2819, 2825, -1001, -7335, -3729, 2154, 2324, -172, -9585, -3404, 2086, 1895, 379, -9753, -2977, 2253, 1590, 868, -7464, -4184, 1805, 1304, 925, -4382, -4230, 159, 876, 240, -5067, -2104, -4336, 667, -1389, -4810, -1882, -2749, 1094, -3201, -1576, -3606, -125, 1286, -2071, -437, -4654, 30, 482, -1386, -1085, -2873, -1636, -1678, -2569, -4455, -2055, -2859, -5014, -7050, -6914, -1747, -1120, -6016, -5630, -2958, -1727, -1106, -7299, -2686, -3668, -2101, -3342, -9284, -1620, -8192, -2082, -5494, -7066, -1754, -1736, -1399, -3515, -6870, -3149, 466, -749, -3449, -5751, -6800, 1016, -236, -4826, -3662, -8276, 385, -15, -5374, -2675, -3147, -1336, -179, -3339, -2437, -1522, -3808, -489, -2068, -2378, -1380, -5326, -975, -2128, -2409, -2273, -4991, -2112, -3903, -2815, -3785, -4184, -4625, -8220, -3748, -5115, -4142, -11004, -7097, -3893, -5176, -6143, -4764, -6653, -2510, -4403, -9479, -2203, -7730, -1546, -3833, -4708, -1125, -5429, -1141, -4049, -3766, -1216, -2813, -684, -4703, -4733, -2958, -1710, -160, -4299, -5020, -9106, -2054, -124, -3512, -3401, -6113, -3741, -712, -3560, -2661, -5367, -6083, -1682, -4433, -2673, -9284, -7464, -2952, -5202, -3040, -9873, -7603, -5253, -5139, -3779, -6943, -5960, -7484, -4764, -5115, -6628, -3606, -5451, -3951, -8165, -5253, -1947, -4847, -3412, -7603, -3154, -1143, -5502, -3744, -4089, -1949, -1174, -7264, -5049, -2926, -1984, -2088, -7583, -6973, -2964, -2871, -3101, -5260, -7317, -3529, -3383, -2129, -4504, -6814, -3937, -4153, -1065, -5451, -7665, -4086, -6828, -1231, -7912, -8393, -4946, -5208, -2937, -12776, -6988, -6973, -3714, -4191, -7146, -6434, -5422, -5097, -2644, -4238, -7464, -3490, -13738, -2661, -4157, 5486, 3550, 4844, 8175, 8460, 5170, 3253, 3870, 7568, 8093, 4392, 2279, 1352, 5729, 7079, 3654, 309, 2109, 3368, 5881, 3139, -3668, 2386, 2603, 5308, 2364, -8718, 25, 1314, 5027, 954, -4592, -1019, -1668, 4008, -1091, -5694, -124, -885, 1579, -2493, -5401, -2617, 1393, 2270, -812, -468, -3650, 2522, 4231, 1549, 1044, -4078, 2252, 4803, 3187, 1508, -2751, -310, 5157, 3896, 2408, 242, -2160, 5623, 3491, 2656, -224, 2457, 5488, 1534, 1314, -926, 3846, 4459, -2553, 733, 1956, 3667, 2790, -1379, 1855, 2803, 2220, 1933, -639, 1429, 1960, 41, 2406, -1353, 895, 35, -1813, 2323, -2060, 2131, -1625, -13049, 1137, -1410, 2833, -2186, -281, -752, 498, 2583, -1550, 2102, -2289, 2368, 1526, -1194, 2105, -1291, 3310, -269, -1906, -200, 423, 2948, -2686, -3580, -5988, 1673, 944, -6035, -5227, 44, 2718, -748, -8549, -4336, 1949, 3219, 624, -3420, -2696, 2753, 3215, 240, -1534, -1060, 2976, 3404, -2350, -1011, 456, 2636, 3995, -3354, -1177, 1455, 1662, 4339, -1947, -1081, 1825, 307, 4072, -2610, -688, 1728, -275, 3103, -5097, -1049, 1468, -274, 1509, -4145, -2833, 1249, -1048, -3, -1979, -5694, 910, -2216, -152, -1130, -4127, 189, -751, -208, -1515, -2531, -918, 877, -835, -4262, -2002, -1690, 1630, -395, -4395, -1661, -840, 1837, 461, -897, -621, 139, 1759, 545, -180, 34, 72, 1428, 226, -1002, -608, -1502, 841, 222, -1966, -2914, -4847, 164, 579, -1713, -4451, -3612, -274, 639, -1577, -4319, -2460, -340, -86, -1999, -7865, -3054, -164, -1470, -2859, -8009, -4127, 94, -2163, -4433, -4303, -2969, 286, -2071, -7097, -2997, -1438, 197, -2385, -8086, -2427, -750, -224, -3085, -6411, -2945, -831, -647, -3757, -5615, -5630, -1552, -668, -4290, -5897, -6628, -3189, -624, -4963, -7984, -2752, -7034, -1196, -5531, -7162, -2084, -11488, -2897, -3860, -3399, -3433, -7687, -5429, -1557, -1965, -3365, -4795, -4644, -287, -2211, -1878, -2088, -3354, 54, -4664, -2297, -765, -3352, -291, -11488, -4963, -507, -5768, -1282, -3707, -4399, -1078, -6577, -3203, -2057, -1956, -2407, -2091, -3992, -1900, -1040, -4769, -717, -1906, -2507, -1232, -8790, -824, -740, -2735, -2528, -6163, -2170, -543, -2407, -4234, -5546, -5638, -1051, -2666, -4108, -8790, -7426, -2071, -3853, -4153, -5502, -2971, -2943, -5576, -5576, -2823, -1522, -2783, -6653, -5888, -2222, -1382, -2201, -6332, -4447, -2897, -2361, -1945, -5615, -4172, -4142, -4901, -2239, -5743, -4635, -4262, -8790, -3237, -7603, -4348, -3978, -5554, -4997, -8754, -3632, -3261, -4130, -6666, -4447, -2597, -1600, -3535, -6288, -2571, -1420, -776, -3560, -4869, -2213, -1073, -1289, -5326, -2952, -3149, -2082, -3218, -8247, -1549, -6719, -5997, -3763, -2377, -3992, -3662, -4254, -4985, -5202, -2762, -2493, -2635, -11356, -6113, -3760, -2419, -1961, -4907, -3076, -4659, -2787, -2257, -2323, -2555, -1855, -2967, -3487, -2100, -3266, -850, -2670, -5897, -3856, -5061, -1705, -2414, -9585, -5408, -10138, -4842, -2644, -7865, -2825, -6133, -9639, -3757, -6457, -1792, -3449, -10362, -6321, -6814, -1902, -2835, -7752, -8112, -10362, -2628, -3436, -3653, -4491, -8165, -3930, -5061, -2342, -2330, -4238, -6411, -7146, -2232, -1533, -2910, -5623, -7247, -2560, -2306, -3184, -3027, -6828, -2813, -6278, -5319, -2311, -6469, -2641, -4743, -7503, -3465, -4469, -1841, -1353, -3704, -4968, -1794, -867, -386, -1854, -2222, 59, -291, -631, -1258, -1011, 840, -452, -1650, -1797, -1335, 566, -1607, -3069, -3883, -2512, -619, -4211, -4764, -9380, -3641, -2355, -7774, -6376, -9695, -5818, -4282, -5718, -6225, -8827, -11629, -4968, -4816, -5429, -10362, -4064, -3165, -5853, -4559, -6354, -2305, -1973, -10362, -3665, -3916, -2135, -1928, -6705, -3289, -3261, -2754, -3036, -3388, -4042, -3903, -3566, -4104, -2140, -7113, -4559, -4270, -3621, -2326, -10704, -4460, -4352, -3893, -3886, -5408, -5678, -3714, -5569, -7066, -4003, -11945, -3683, -4863, -11356, -3723, -8363, -5043, -3441, -7730, -4130, -6388, -8549, -3626, -7335, -5374, -5686, -6504, -5247, -8060, -8220, -4460, -4112, -7583, -4311, -17034, -3650, -3194, -8192, -2510, -6786, -3543, -3007, -7371, -2286, -3975, -3766, -3276, -7960, -3087, -2610, -3947, -3824, -8192, -3999, -2271, -4408, -4500, -4769, -5127, -2739, -5472, -5152, -3126, -9238, -3779, -6692, -5367, -2837, -8423, -4748, -6528, -4764, -3476, -5394, -4795, -6246, -4357, -4769, -5784, -4733, -6914, -4974, -6204, -8865, -5630, -7708, -6653, -6310, -11115, -8086, -7213, -7523, -5592, -9695, -11232, -5836, -6267, -5592, -9022, -8649, -4703, -4336, -6814, -6445, -6885, -4238, -3144, -6943, -3886, -6256, -4112, -3362, -4348, -2540, -6870, -4112, -5451, -2793, -2488, -7317, -4918, -5408, -2306, -3732, -5176, -7503, -3056, -2690, -6278, -3638, -9380, -2420, -4049, -10138, -2859, -7004, -2865, -6026, -8517, -2594, -7335, -3741, -5827, -5638, -2885, -12776, -4282, -5326, -5152, -3923, -8034, -4195, -5988, -6504, -5879, -5710, -4164, -6732, -7299, -9479, -6103, -4997, -7213, -6143, -12123, -8138, -7130, -8333, -6026, -9585, -9064, -8903, -9479, -6719, -10362, -11115, -10210, -8363, -7066, -17034, -12534, -12534, -6504, -6214, -11232, -8754, -7371, -5292, -4896, -7936, -8086, -5988, -5020, -4108, -5906, -7644, -6007, -5759, -4207, -4869, -6759, -6204, -7796, -5260, -4923, -6016, -5654, -9022, -7230, -6434, -5183, -4759, -7464, -8034, -10704, -4460, -4270, -7264, -6705, -6590, -4352, -4625, -8192, -6310, -3913, -4863, -5933, -8827, -7445, -2891, -5915, -7912, -8304, -12319, -2992, -7484, -7960, -7213, -10138, -9380, -3198, -4853, -4295, -8247, -5208, -4573, -3269, -5286, -4901, -2557, -9106, -3225, -4863, -2065, -1252, -7542, -3662, -5561, -1290, -945, -4390, -4583, -6928, -994, -1398, -3222, -6928, -6800, -747, -2217, -2823, -28777, -4683, -983, -3344, -2512, -6540, -3242, -1728, -6354, -2286, -4420, -3471, -2276, -8827, -2631, -4104, -6016, -2254, -3543, -3827, -4416, -8615, -2257, -1908, -5702, -4145, -6842, -2597, -1442, -7426, -3846, -8827, -3412, -1750, -6163, -4089, -28777, -5227, -2910, -4433, -4412, -9331, -9873, -4880, -3913, -4583, -5401, -5654, -6445, -5127, -5234, -3870, -2733, -8942, -7644, -7097, -4357, -1243, -7960, -2900, -4940, -3049, -371, -2897, -697, -2018, -369, 88, -1191, -128, -795, 869, 184, -1080, -729, -956, 933, -136, -2139, -2060, -2672, 54, -1031, -3735, -3042, -7774, -1542, -2696, -4482, -3367, -7264, -3399, -5374, -4478, -3820, -4935, -5360, -9380, -4369, -4504, -5888, -8060, -14784, -4142, -5429, -8393, -9639, -15615, -3324, -5638, -5202, -10284, -28777, -2351, -4003, -3266, -8363, -12123, -2019, -2683, -2657, -6153, -8827, -2455, -2333, -3352, -5862, -8247, -2631, -2492, -6278, -5871, -5801, -1885, -2223, -8683, -4115, -3683, -1462, -1820, -4935, -2724, -3309, -1690, -2053, -4024, -2566, -4513, -2232, -3080, -4064, -4024, -5253, -2517, -4451, -4286, -8086, -3714, -2739, -4784, -4728, -4625, -2716, -4060, -3951, -6267, -2622, -2462, -8485, -3254, -13365, -2336, -2751, -8165, -3003, -5465, -2941, -3521, -6732, -2766, -2605, -3754, -4743, -8942, -2455, -1535, -4157, -6528, -17034, -2562, -1482, -4336, -7503, -11232, -3239, -2075, -4620, -5726, -7583, -3754, -3128, -4541, -4089, -4460, -3940, -4429, -4616, -3271, -2875, -4759, -5346, -6256, -3352, -2730, -6814, -5109, -8903, -4460, -3782, -10138, -4606, -5801, -7146, -4597, -13738, -4997, -4759, -17034, -4145, -12319, -5043, -5061, -8754, -4164, -10362, -3515, -5988, -7034, -4810, -11004, -2789, -7687, -7034, -4985, -12534, -3391, -8423, -6246, -4649, -12534, -5584, -7562, -4464, -4478, -9936, -11945, -7484, -3653, -3732, -6615, -8112, -6988, -3896, -2578, -5374, -5374, -6719, -4708, -2130, -5853, -4683, -7888, -5546, -2867, -8333, -5801, -10284, -6958, -5408, -15615, -11232, -8827, -8683, -10442, -12123, -7687, -7912, -6399, -7603, -9479, -5801, -8790, -4907, -7562, -6885, -6773, -8827, -4901, -9479, -5437, -10442, -6310, -6299, -11004, -5401, -8615, -5061, -9284, -9531, -7066, -7464, -5127, -13049, -7936, -12319, -6943, -6615, -13049, -7796, -11115, -5234, -10138, -11488, -9106, -7230, -3992, -8865, -11356, -11356, -5031, -3686, -7097, -11781, -11356, -3804, -4093, -7130, -11232, -8304, -3741, -4713, -8582, -9193, -6123, -5195, -4754, -12534, -7960, -4842, -9479, -4006, -13049, -8304, -4311, -8903, -3191, -9873, -11356, -4504, -7213, -3025, -8982, -10069, -5862, -8333, -3863, -8718, -6870, -5247, -4654, -6411, -3069, -1035, -7730, -4555, -7819, -1087, -1342, -5793, -2967, -4473, -272, -2170, -2918, -2353, -2538, 8, -3001, -1487, -1935, -1790, -342, -3540, -1089, -1391, -1646, -1800, -4266, -1343, -995, -1936, -3040, -5735, -1846, -942, -2416, -1246, -7445, -2502, -1150, -2128, -392, -7081, -4060, -1581, -1503, -831, -7317, -6445, -2747, -1493, -2198, -8304, -4067, -5879, -2066, -3692, -7213, -2385, -13738, -2741, -4382, -5451, -1823, -8454, -3304, -4693, -4078, -1647, -7842, -3961, -5026, -3906, -1611, -7503, -4184, -5494, -4469, -2280, -8865, -3814, -5253, -3334, -5014, -10526, -5686, -4821, -2962, -4963, -4779, -5793, -6143, -5509, -1939, -1962, -893, -5339, -5801, -1399, -953, 636, -2308, -2420, -2447, -1412, 543, -889, -1892, -3827, -3210, -730, -471, -3133, -3080, -5793, -2355, -653, -6577, -2703, -7562, -2999, -1036, -7644, -4017, -8865, -3334, -1310, -4923, -6399, -10210, -3788, -1838, -4703, -4748, -9812, -3717, -3144, -6988, -3916, -9936, -3266, -4583, -8393, -3689, -8247, -3201, -3957, -5793, -3252, -6504, -3441, -3128, -7389, -3158, -5768, -3457, -3119, -6914, -3281, -5759, -2950, -4093, -3047, -3242, -6590, -2303, -6692, -2143, -2924, -9284, -2162, -11356, -3069, -1932, -12534, -2743, -6093, -5735, -1068, -6759, -3751, -4234, -8192, -985, -4597, -4664, -3444, -6457, -1686, -3314, -5227, -2646, -5299, -2897, -2437, -5253, -2032, -4718, -4559, -1932, -4559, -2176, -4142, -7445, -1959, -3367, -3051, -3378, -28777, -2960, -2257, -3840, -2677, -6988, -5888, -1494, -3889, -2366, -4262, -7371, -1097, -3279, -2641, -2988, -4968, -1021, -2743, -3249, -2762, -5326, -1308, -3184, -3428, -3409, -7034, -2049, -5437, -3087, -3850, -7264, -3208, -15615, -2939, -3321, -8034, -4207, -6745, -3698, -3244, -11004, -4157, -4597, -6083, -4203, -12776, -4119, -3529, -9238, -5844, -11945, -5292, -2458, -11232, -6692, -6988, -9812, -1581, -11115, -5615, -4679, -8363, -1255, -6856, -4013, -4203, -4985, -1556, -7752, -3065, -5524, -4219, -2495, -11356, -2926, -9695, -4923, -3961, -5127, -3347, -12534, -7299, -5221, -3580, -3779, -13738, -11115, -5394, -3704, -3735, -8790, -6457, -5487, -5346, -3485, -5879, -3493, -5751, -11004, -3311, -4800, -2051, -5401, -7523, -3276, -4097, -1771, -4399, -5008, -3493, -3249, -2398, -3569, -4569, -4164, -2488, -3490, -3474, -4654, -5176, -2023, -4336, -4482, -4357, -5951, -2102, -4784, -7389, -4049, -5979, -2962, -5401, -9238, -4115, -5776, -4382, -7213, -6354, -4064, -6267, -5759, -12319, -5897, -3798, -7936, -8485, -12534, -6943, -3933, -9639, -11945, -8982, -8582, -4478, -10284, -6828, -6870, -8363, -4754, -11629, -6074, -6183, -7503, -4863, -10442, -6914, -7019, -7146, -5516, -7730, -8333, -8276, -7004, -5818, -6278, -8790, -7130, -6204, -5109, -6214, -7960, -6445, -5067, -5214, -7213, -7050, -7113, -4564, -6653, 8198, 5825, 565, 6157, -726, 8211, 6039, 937, 5454, -1500, 7961, 5718, 1930, 2821, -1419, 6996, 3610, 3491, -2125, 778, 5105, -701, 4384, 2225, 1888, 2860, 2874, 3799, 2570, 1659, 1944, 3990, 757, 6, 290, 2955, 3960, -313, -4550, 736, 4407, 3787, 2482, -13, 2463, 4907, 3661, 2428, 1038, 3412, 4593, 3283, 160, 2893, 3943, 4378, 2556, -6653, 4867, 4183, 4084, 3063, -2468, 5775, 4065, 2255, 4607, -936, 5456, 3534, -2251, 5324, -1104, 3646, 2312, 637, 5050, -2286, 152, -54, 1147, 4049, -2288, 1191, -2440, -34, 2488, -1036, 2116, -2567, -18, -227, -804, 1244, -4290, 1057, -7113, -1859, -1124, -6516, 1512, -4416, -3569, -5055, -2477, 1477, -1324, -3920, -6054, -589, 1325, 33, -2380, -4064, -160, 762, -497, 55, -1526, -1123, -42, -3455, 1225, 705, -3501, 694, -2492, 1104, 1705, -2016, 1467, -1420, 769, 1596, 43, 1437, -4223, 1187, 339, 402, 1444, -1094, 918, -3930, -1041, 1311, 1932, -814, -2984, -3964, -87, 2749, -571, 483, -760, -4067, 1963, 1360, 691, 598, -11781, -884, 1887, -1220, -117, -9193, -5292, 1071, -1963, -2268, -7081, -2286, -1614, -180, -1212, -3618, -2590, -10210, 186, -399, -1580, -3367, -1739, -271, -1497, 119, -1307, -209, -666, -2229, 1094, 208, -312, -470, -27, 1304, 583, -1302, -130, 1320, 1171, -440, -1944, -270, 1714, 1237, -3624, -1451, -1228, 1456, 1535, -2159, -400, -2783, 980, 1626, -77, 549, -3580, 757, 1075, 81, 654, -3140, 555, -480, -854, -543, -2197, -50, -3856, -1857, -3220, -1787, -894, -11115, -1628, -2835, -2587, -1603, -4311, -553, -1333, -3695, -2292, -3056, 260, -1349, -2020, -2916, -2982, 472, -2470, -460, -3080, -3140, 130, -3557, 129, -3126, -2797, -666, -2879, -131, -4100, -2022, -2007, -1925, -1522, -7984, -1648, -4473, -1732, -5862, -9022, -1961, -9331, -2541, -5516, -6163, -2875, -7004, -4693, -1872, -7034, -4203, -5888, -9873, -937, -7484, -6354, -6577, -6628, -914, -6422, -8192, -6256, -3523, -1178, -6399, -4853, -4587, -2443, -1405, -6885, -3543, -3603, -2986, -1479, -7888, -3985, -3574, -6035, -1498, -7912, -6054, -4254, -8138, -1556, -5686, -7984, -5189, -5043, -1677, -4254, -5630, -6321, -5810, -2093, -3827, -3701, -7562, -11115, -3005, -4464, -2432, -7389, -8060, -4625, -6153, -1654, -6828, -7019, -7819, -6679, -1536, -8247, -8393, -17034, -5360, -2342, -9695, -7389, -7984, -5103, -4203, -5638, -6194, -7353, -6679, -5279, -4918, -7299, -8718, -14784, -5164, -6732, -11781, -8718, -8034, -6388, -12776, -7389, -9106, -6528, -8827, -13365, -5686, -17034, -7865, -14784, -13365, -5793, -9873, -17034, -8865, -9531, -6828, -8549, -8454, -5942, -8333, -7796, -9331, -5183, -5387, -8903, -7503, -9380, -3754, 1488, 4732, 5435, 3299, 860, 2075, 3934, 4830, 2558, 1286, 2330, 1112, 2417, 1071, 1434, 1165, -8363, -3886, 2056, 1478, -1660, -4616, 2254, 3008, 2384, -1958, -10362, 2932, 2279, 2697, -718, -3479, 629, -65, 1658, -270, -1728, 11, 1675, 800, 77, -2100, 3171, 3169, 2379, -347, -1384, 4349, 2465, 3936, -3521, 511, 5009, 619, 5251, -852, 2031, 5436, 3324, 6009, 2604, 3193, 5140, 4662, 5949, 3812, 3872, 3587, 3984, 5094, 3644, 3951, -497, 399, 3731, 2084, 3418, -3961, 651, 2635, -1610, 2150, -303, 3766, 2558, -978, -292, -478, 4689, 2681, 720, -2050, 274, 4780, 1965, 118, -1257, 2008, 4519, -164, -2843, -2743, 2550, 4088, -4184, -7004, -3179, 1817, 3563, -3798, -3860, -1303, 299, 3029, -3076, -3940, -2207, 505, 2487, -4115, -6469, -6235, 1721, 1771, -5214, -7213, -5394, 1936, 830, -4606, -2642, -6800, 615, -7, -4042, -706, -3289, -4299, -335, -1880, 224, -629, -1722, -274, 326, 795, 420, 779, -327, 1319, 1012, 995, 639, -702, 1040, 654, 1419, -1532, -1244, -445, -207, 1283, -1665, -1869, -2528, -804, -170, -231, -2112, -2962, -937, -5401, -1052, -2047, -1992, -1880, -2900, -3944, -2583, -605, -2653, -581, -2295, -3704, 611, -1237, -618, -710, -4451, 1218, -912, -1821, -88, -3085, 1122, -2241, -2902, 337, -823, 645, -5091, -1728, 559, 342, 452, -7081, -194, 312, 296, 440, -3393, 847, -706, -910, -13, -696, 1511, -3036, -3067, -868, 661, 1809, -6565, -4089, -1280, 971, 1570, -4532, -3222, -1412, 392, 500, -3698, -2879, -2223, -1051, -1976, -3689, -3707, -3554, -3563, -8220, -2958, -5662, -4545, -7708, -6153, -2225, -5686, -5055, -8165, -5031, -2030, -4863, -4816, -8582, -6870, -2188, -5480, -4764, -17034, -15615, -2677, -7034, -5387, -7299, -10526, -3618, -8683, -6225, -6653, -13365, -4784, -7960, -7464, -9238, -8549, -5735, -6828, -8718, -6299, -4693, -6083, -7081, -6745, -3569, -3329, -5997, -6628, -5554, -2073, -3242, -6343, -5726, -6692, -1243, -4089, -8138, -5260, -9936, -1058, -5686, -11629, -4064, -5630, -1614, -6988, -9639, -2895, -3863, -3023, -7097, -10899, -2377, -3425, -5827, -7264, -6914, -2443, -3754, -9695, -7665, -3184, -2885, -4532, -5326, -7281, -1505, -3407, -5240, -3668, -6288, -1109, -3896, -5810, -3779, -5531, -1808, -4569, -5801, -5836, -5319, -3409, -5164, -5170, -8363, -5879, -4564, -5380, -4923, -4968, -7264, -4195, -5810, -4991, -3940, -8423, -4108, -6492, -5020, -4649, -7562, -4779, -6705, -5189, -7066, -5933, -5561, -6083, -5853, -10799, -5214, -5472, -5531, -7019, -8333, -5569, -5176, -5623, -8454, -6225, -6705, -5646, -6504, -9429, -5292, -8333, -7019, -8192, -10001, -5326, -12123, -8790, -10526, -9479, -5997, -12534, -9479, -11115, -7299, 6416, 2356, 4664, 4031, -5299, 5458, 1289, 4241, 3522, 3198, 1889, 1076, 3307, 2987, 5682, -4035, 3271, 3179, 3621, 6467, 59, 4035, 3779, 3662, 5954, 1569, 3567, 3884, 2134, 4082, 2618, 1938, 3351, 1349, 1174, 1829, -1816, 2461, 3482, -75, 696, -2000, 1162, 3919, 2162, 3512, 195, -3866, 2144, 3865, 5329, -174, 928, 1771, 3107, 5968, 2492, 4503, 4015, -511, 5618, 4771, 5457, 3596, 3888, 4171, 5142, 4513, -1174, 5022, 1539, 3408, 845, 2442, 3508, 593, -4985, 461, 4277, 1141, 911, 1157, 2545, 3506, 3875, -508, 2441, 2172, 332, 4892, -2675, 1350, 582, -8615, 4703, -1820, -1203, -755, -6321, 3747, -788, -3971, -398, -7464, 2446, -422, -4918, 387, -3692, 1952, -274, -5394, 804, -1739, 1899, 15, -7984, 865, -494, 1162, -218, -28777, 590, -50, -82, -1703, -8827, -114, -985, -533, -4795, -6163, -1497, -4119, -419, -5710, -4226, -4134, -1442, -325, -5319, -3792, -13049, 877, -304, -5444, -4688, -5360, 1446, -1034, -1832, -3843, -2853, 881, -1636, 495, -1986, -2173, -539, -513, 1571, -1239, -2722, -2480, -15, 1774, -952, -3996, -5026, -761, 1241, -701, -5346, -8060, -1784, -104, -1099, -7179, -4266, -891, -2424, -2472, -4176, -2655, -268, -4307, -3557, -1370, -2465, -664, -2546, -2875, -335, -2845, -877, -605, -1921, -770, -3067, -707, 113, -1986, -2306, -2276, -1312, -1001, -2125, -2260, -961, -2552, -6800, 205, -1553, -26, -3680, -3230, 1694, -2138, 262, -6411, -1366, 1734, -2295, 14, -6759, -2095, 468, -1256, -340, -2545, -4219, -1418, -1221, -522, -1363, -7050, -2198, -2366, -1086, -1909, -10362, -3119, -3306, -2743, -4258, -6856, -5451, -2386, -6214, -8276, -6692, -7299, -1541, -8942, -7936, -12534, -6321, -1470, -6163, -8517, -7019, -4968, -2194, -4172, -11232, -4134, -4386, -3769, -3465, -11781, -3409, -5437, -6602, -3923, -6194, -3735, -7097, -11488, -4307, -4403, -4447, -3782, -12534, -3487, -4295, -5091, -1998, -10899, -3058, -5121, -5924, -1595, -6422, -4053, -5951, -7888, -2160, -4968, -8247, -6235, -12123, -3532, -5458, -6692, -6679, -8517, -5458, -7984, -3465, -8454, -6590, -7665, -13365, -2592, -9106, -6064, -10001, -15615, -2795, -7019, -6814, -6035, -12776, -3577, -6225, -9873, -3856, -8454, -4555, -5202, -8754, -3294, -7687, -5415, -3827, -6194, -3951, -8754, -5888, -3140, -5836, -5531, -8276, -5516, -3276, -6628, -6194, -7708, -4774, -3910, -7623, -5195, -10442, -4683, -4698, -7752, -4482, -10210, -5759, -5906, -7888, -4219, -6590, -8393, -8165, -9936, -4319, -5988, -9585, -15615, -28777, -4929, -6759, -6973, -9149, -9585, -6553, -7034, -5924, -6828, -7888, -11004, -5793, -6759, -6083, -6007, -9106, -4790, -11945, -5615, -4527, -6434, -4620, -8034, -5480, -4238, -6214, -5273, -5480, -6343, -6343, -9238, -6773, -8009, -3386, -8683, -7960, -7113, -7213, -3776, -8009, -7162, -10362, -7708, -4536, -5339, -7665, -11356, -10069, -5031, -4195, -9873, -7819, -11629, -4997, -4199, -12319, -8034, -9936, -5208, -4382, -10526, -10284, -9106, -6123, -4035, -8982, -12776, -9479, -7665, -4180, -7960, -14195, -13049, -7796, -5546, -7865, -10613, -10069, -6388, -8304, -8754, -7464, -6565, -5465, -11781, -9429, -5879, -5546, -4896, -13049, -10069, -5970, -6214, -5014, -8549, -7687, -7097, -8649, -5924, -9936, -6288, -7281, -13738, -6480, -8790, -5031, -6988, -8220, -5458, -10284, -6492, -9284, -12776, -9936, -304, -622, 154, -394, 27, 3828, 3713, 4003, 3698, 4086, 5846, 5794, 5951, 5755, 6050, 6437, 6405, 6546, 6426, 6623, 5763, 5698, 5893, 5839, 5941, 3711, 3461, 3829, 3848, 3851, -232, -1519, -371, -255, -389, -8865, -5630, -10362, -11115, -14784, -11232, -3671, -7113, -7426, -6973, -15615, -5458, -12123, -10284, -11488, -11781, -7484, -10442, -7774, -12123, -8034, -7708, -7081, -8086, -10284, -7408, -8009, -5312, -9639, -8790, -8718, -10442, -5115, -14784, -8649, -9479, -13738, -6133, -11004, -9064, -7408, -11781, -8393, -8247, -9585, -6310, -12776, -10704, -7542, -9639, -6958, -8683, -10210, -7888, -9479, -9639, -6256, -11356, -8790, -10210, -17034, -5202, -17034, -8683, -13365, -14784, -5031, -15615, -7842, -28777, -13049, -5360, -10613, -7708, -17034, -12123, -6183, -8247, -8790, -14784, -12319, -7583, -8304, -11488, -10799, -14784, -9380, -11629, -11781, -8165, -15615, -10899, -14195, -10704, -7264, -11232, -11004, -10001, -11945, -7687, -8649, -9479, -9429, -13365, -9284, -7113, -8423, -9812, -9149, -10899, -6445, -8423, -10704, -7408, -10362, -6786, -9284, -11356, -6899, -9331, -8423, -9149, -9531, -7247, -8718, -11945, -8423, -7665, -8683, -8363, -11356, -8165, -6679, -11232, -8247, -9064, -7984, -6814, -10704, -8304, -8454, -8086, -8454, -10069, -8827, -9331, -8582, -10362, -9873, -9193, -11629, -9284, -8754, -9479, -8517, -11629, -9936, -8517, -9531, -8138, -10284, -11232, -10069, -10704, -8790, -10138, -15615, -13738, -13049, -10138, -9531, -13049, -15615, -14784, -10362, -8112, -10799, -15615, -12776, -9639, -7281, -10362, -15615, -11232, -9753, -7542, -8903, -13365, -10138, -11488, -8454, -7984, -12534, -9812, -28777, -8790, -8485, -14784, -10069, -14195, -9531, -10210, -28777, -10001, -11115, -12319, -11356, -12776, -9479, -9936, -17034, -11356, -11232, -8942, -9873, -14784, -11488, -11004, -8754, -11004, -14784, -11945, -11488, -9238, -15615, -11781, -11781, -11781, -11356, -13365, -10613, -12319, -12776, -28777, -10799, -10899, -13365, -13049, -13049, -11356, -11629, -13738, -11356, -11781, -15615, -10704, -14195, -10704, -13049, -28777, -9873, -13365, -10899, -14784, -28777, -10210, -11004, -12123, -14195, -14784, -11781, -10613, -15615, -13365, -14195, -14195, -11115, -14784, -13049, -17034, -13049, -11945, -12123, -11356, -28777, -12319, -11781, -11004, -9753, -14195, -6365, -9753, -9238, -7113, -5810, -6492, -8903, -8615, -5115, -5751, -6745, -8276, -8009, -4541, -7842, -6153, -7623, -8363, -4858, -12319, -5599, -6332, -10613, -5836, -7196, -6321, -5079, -12776, -7708, -5702, -8718, -4569, -10442, -10704, -5422, -10069, -4831, -8790, -11945, -5531, -11356, -5630, -8138, -13365, -5818, -12123, -6480, -7936, -7796, -6640, -10284, -7019, -7687, -5079, -8247, -11356, -7247, -7445, -4021, -8903, -12319, -8942, -8615, -4157, -6943, -9695, -12776, -10613, -5055, -5776, -11356, -10001, -8112, -6973, -7665, -8393, -7066, -5599, -7644, -8304, -17034, -7842, -10362, -10704, -10899, -463, -258, -579, -346, -735, 3740, 3829, 3777, 3803, 3715, 5796, 5856, 5835, 5855, 5858, 6417, 6453, 6427, 6491, 6529, 5751, 5747, 5709, 5866, 5905, 3657, 3566, 3521, 3875, 3843, -577, -903, -882, 30, -296, -28777, -15615, -8982, -7130, -7081, -7004, -6943, -8615, -10284, -7623, -9479, -5662, -11488, -11004, -7230, -11945, -5266, -9429, -10799, -6343, -10799, -6332, -9238, -15615, -8718, -10210, -8112, -8582, -10138, -11356, -11232, -11945, -8423, -9753, -11488, -12123, -17034, -7335, -11232, -11945, -12776, -10899, -6615, -17034, -13365, -17034, -8718, -6928, -28777, -12123, -13738, -8009, -8009, -28777, -7503, -9149, -8454, -8009, -13738, -5487, -7842, -9695, -6786, -10899, -4784, -8165, -10613, -6553, -10613, -5158, -10001, -10210, -7730, -11232, -6590, -10704, -9639, -9585, -10526, -9193, -9331, -8615, -9812, -9585, -12319, -8982, -8220, -9429, -9936, -14195, -8865, -9531, -9429, -12534, -17034, -8086, -13049, -10799, -28777, -13738, -8086, -10284, -13049, -14784, -10613, -8790, -9753, -10362, -17034, -7984, -7888, -12534, -8790, -13049, -6745, -7113, -14784, -7796, -11629, -6828, -7523, -12123, -7019, -11356, -8192, -8827, -11115, -6759, -11115, -10526, -10899, -10138, -7264, -10138, -11356, -11232, -9639, -8649, -9284, -9936, -11004, -10704, -10799, -9695, -9106, -11945, -12776, -13365, -11945, -9149, -10704, -11945, -17034, -28777, -9873, -8683, -10069, -17034, -13738, -10899, -8485, -9331, -12776, -12776, -11629, -9695, -9936, -11004, -14195, -11945, -11781, -12534, -10442, -28777, -12534, -13738, -14195, -10613, -17034, -12319, -14784, -10799, -11781, -12534, -10526, -14784, -8982, -14784, -11004, -9064, -13738, -8086, -12319, -10442, -8903, -13365, -8333, -10442, -10362, -10069, -13365, -10001, -10704, -10613, -13049, -14784, -14784, -12319, -11629, -28777, -17034, -13365, -12123, -14195, -14784, -17034, -11232, -11004, -28777, -13049, -13738, -11488, -11356, -17034, -11781, -12776, -13738, -13049, -17034, -11629, -11488, -17034, -12776, -17034, -12534, -10284, -15615, -11945, -17034, -14195, -9639, -15615, -12319, -28777, -14195, -9873, -28777, -13365, -15615, -12534, -11115, -28777, -14195, -12319, -12534, -13365, -14195, -14195, -11488, -13365, -15615, -13365, -14195, -12123, -14784, -15615, -15615, -13365, -14784, -15615, -14784, -17034, -11629, -28777, -17034, -13365, -28777, -10799, -17034, -15615, -5253, -8454, -6615, -5133, -8982, -7865, -28777, -7865, -6054, -28777, -9639, -10442, -8333, -8138, -10001, -8865, -13738, -8615, -9812, -7912, -9380, -10210, -8718, -9284, -7445, -8485, -7752, -8165, -9531, -8865, -8060, -8363, -6732, -12534, -12534, -9380, -9812, -5726, -13365, -8247, -8649, -9429, -5694, -9331, -6885, -7247, -8827, -6103, -7665, -6943, -7796, -8827, -6973, -6914, -7426, -9873, -9479, -8754, -7730, -8517, -10704, -8718, -9238, -14195, -10442, -9753, -6332, -7230, -10284, -8865, -11488, -6288, -6679, -10613, -10613, -8485, -6914, -6899, -7019, -7484, -9531, -6870, -6773, -6204, -8517, -466, -145, -95, -355, -422, 3651, 3885, 3750, 3753, 3830, 5698, 5914, 5730, 5808, 5899, 6308, 6529, 6341, 6438, 6532, 5592, 5882, 5697, 5793, 5904, 3327, 3857, 3651, 3756, 3930, -1577, -60, -461, -267, 173, -7796, -8649, -11629, -10001, -5951, -6899, -9695, -8060, -11232, -6870, -13049, -11488, -10001, -9193, -6786, -9284, -9238, -8393, -7213, -6745, -9531, -8333, -8942, -8615, -6602, -8086, -7665, -10799, -11781, -6103, -7097, -7113, -12534, -9380, -6278, -6615, -7066, -13049, -7936, -6814, -6705, -8276, -11945, -8718, -7353, -7264, -9812, -12534, -13049, -7865, -9331, -9284, -28777, -11945, -8754, -28777, -8790, -11004, -8827, -11781, -11004, -8982, -9106, -7912, -15615, -9284, -9753, -8683, -7888, -9585, -9106, -10526, -8454, -8982, -8333, -9585, -10210, -8247, -12319, -8903, -11488, -8718, -8517, -14784, -10362, -10799, -7665, -9695, -10210, -9106, -7960, -7730, -10069, -8423, -7819, -6732, -8790, -8754, -7687, -8009, -6745, -10001, -7842, -7984, -9873, -7819, -9639, -7503, -9585, -13365, -10362, -8454, -7603, -13365, -13049, -17034, -7542, -8060, -13738, -12776, -17034, -7050, -8865, -11945, -17034, -12776, -6732, -9812, -11781, -15615, -9639, -6540, -10526, -12319, -11356, -8754, -6773, -10442, -12776, -10210, -10362, -7408, -9639, -13049, -10210, -10799, -8247, -9284, -13738, -10526, -8333, -8903, -9695, -13049, -11629, -7426, -9106, -10899, -11781, -15615, -7523, -8982, -11781, -10526, -28777, -8333, -9064, -11115, -10284, -17034, -9639, -9753, -11004, -11004, -28777, -11004, -11356, -12319, -10704, -17034, -11115, -11945, -17034, -9695, -12123, -10613, -10704, -17034, -9753, -11356, -11004, -10001, -13738, -11004, -13049, -11629, -9639, -12319, -14784, -14784, -10799, -9812, -12319, -28777, -13738, -10069, -9812, -14195, -11945, -12319, -11004, -9106, -17034, -9812, -11781, -14195, -8790, -14195, -9106, -12534, -12776, -9695, -14784, -9753, -13365, -12534, -12123, -17034, -12319, -12319, -13738, -28777, -11945, -28777, -11356, -12123, -28777, -10613, -28777, -12319, -11488, -28777, -11115, -14784, -12123, -13049, -15615, -12776, -11115, -9639, -28777, -17034, -14195, -10613, -8582, -28777, -28777, -13049, -11629, -8247, -28777, -14195, -11004, -12319, -7912, -28777, -10899, -10799, -11781, -8009, -17034, -9936, -11781, -12123, -8649, -13738, -10284, -12534, -13365, -9585, 13663, 14366, 4813, 9113, 11708, 13034, 13853, 4611, 8494, 11025, 10985, 12278, 4030, 6553, 8801, 6567, 9566, 4556, 3159, 4258, 23, 5985, 5758, 1153, -1510, 4596, 3621, 5802, 1683, -3940, 4343, 4039, 4320, 489, -3597, 2011, 4334, 2002, -489, -2114, 583, 3693, 2781, 2757, 2647, 3150, 2999, 3816, 4459, 4923, 3320, 3110, 4217, 5034, 5775, 1425, 3950, 4379, 4757, 6105, -2950, 4772, 4336, 3451, 6336, -4779, 5028, 3919, 436, 6201, -1146, 4583, 3020, 206, 5210, 888, 3344, 2187, 2548, 2965, 1294, 1055, 2540, 2995, 508, 1023, -2831, 3195, 2080, 1107, 250, -3920, 3249, 899, 1211, -3422, -2881, 2700, 2154, 958, 1131, -3707, 1843, 3627, 1307, 4062, -4060, 550, 4293, 1474, 4927, -2178, -2010, 4267, 970, 4235, -928, -2791, 3646, 26, 1260, -346, -392, 2637, -1267, -3707, -201, 601, 1883, -1302, 1531, -1050, 632, 1692, 3, 1726, -1791, -271, 1323, -476, -535, 412, -2737, 283, -2330, -4810, 1448, -5227, -1626, 131, -5718, 1085, -2871, -4307, 1252, -4536, 95, -3425, -8454, 590, -364, -333, -2939, -7960, -143, 2446, -253, 306, -3792, 1164, 3844, -286, 1537, -2555, 1973, 3894, -777, 1300, -1574, 1533, 2500, -2628, -71, -1296, -489, -1166, -3121, -2726, -3433, -5670, -3792, -128, -8582, -8485, -6235, -58, 854, -7687, -2871, -6143, 1347, 377, -7730, -2181, -5759, 1924, -1303, -6183, -2034, -3184, 1734, -4352, -4901, -1175, -1961, 690, -6123, -6163, -380, -1114, -1276, -4134, -6434, -104, -255, -4373, -3757, -3147, -476, 242, -4180, -3269, -1111, -1338, 104, -2061, -2219, 166, -2512, -538, -1373, -1912, 685, -4003, -1385, -1579, -1990, 342, -4191, -2155, -2162, -1939, -832, -3269, -3213, -2741, -2222, -2703, -2967, -5960, -2692, -3177, -4837, -3360, -10138, -2100, -4946, -7464, -4119, -7264, -1641, -7960, -17034, -5208, -7912, -1717, -6457, -6163, -7603, -10526, -3117, -3422, -4688, -10362, -11629, -9873, -2331, -5694, -4713, -12123, -4805, -3354, -8220, -2881, -14195, -2801, -9380, -10442, -2935, -28777, -3447, -5569, -8423, -4078, -9149, -6445, -4630, -5853, -5031, -3927, -10362, -5208, -4369, -5818, -1274, -6123, -4115, -2705, -9238, -275, -4299, -4246, -1044, -6786, -542, -2567, -5085, -193, -2811, -1527, -2231, -4769, -594, -1943, -2416, -3638, -4795, -2257, -2841, -3760, -5607, -6354, -3386, -5115, -7445, -4826, -12123, -2664, -8982, -11945, -3455, -8485, -2128, -9873, -8304, -2768, -6814, -2460, -6786, -9531, -2829, -8790, -4532, -7034, -10210, -3428, -9873, -9639, -10613, -6480, -4238, -8112, -11232, -11115, -5623, -4386, -10799, -7408, -12123, -5319, -3916, -9106, -2730, -8034, -5103, -4319, -8393, -1135, -5539, -6332, -6093, -9936, -994, -4447, -7019, -10362, -8393, -1819, -4451, -8220, 8822, 6405, 7399, 8736, 8940, 8108, 6463, 6945, 8230, 8444, 6300, 5574, 5860, 6894, 6892, 4971, 1103, 5156, 5220, 4105, 3752, 1794, 5631, 3523, 308, 941, 4355, 6534, 2315, -1042, -1475, 3609, 7092, 1064, -262, 2831, 2053, 7104, -2149, 141, 5010, 3075, 6424, -2136, 967, 5572, 3899, 4428, -3080, 2160, 5193, 4063, -1720, -3971, 2729, 4869, 3813, 3597, 729, 2838, 5201, 3285, 5870, 2287, 2616, 5477, 3139, 6462, 2691, 1934, 5416, 3392, 6174, 2617, 1037, 5274, 2939, 5375, 2343, 409, 5104, 835, 4338, 1477, 20, 4546, -6434, 3082, -1333, -794, 3018, -3301, 1368, -551, -3161, -1070, -3110, 82, 2614, -7752, -1746, -8485, 427, 3135, -2280, 2055, -6928, 76, 1302, -39, 2952, -4674, -1500, -1419, 786, 2431, -367, -2659, 1626, 321, 516, 1682, -2716, 2762, -2399, -3096, 2207, -1478, 3437, -4842, -5170, 1807, 292, 3899, -40, -6480, 826, 1054, 3570, 669, -6422, -1270, 853, 2182, -1006, -2841, -10001, -349, -527, -1803, -1647, -1090, -4195, -5524, -187, -1622, 1487, -3321, -7752, -444, -1934, 2397, 37, -5576, -772, -613, 2402, 782, -4991, -122, 1514, 1893, 341, -4315, -382, 2946, 1275, -874, -2813, -1966, 3649, 905, -2939, -385, -2994, 3805, 447, -6705, 1507, -1546, 3452, -891, -8086, 2821, -1213, 2358, -2705, -4234, 3670, -2559, -119, -2245, -2073, 3915, -4115, -7179, -2847, -282, 3381, -3521, -2299, -6732, 646, 1818, -2195, -74, -2236, 308, -1558, -804, 581, -606, -1475, -5584, -561, 125, -1294, -3961, -1442, -2034, -1497, -2772, -3249, -499, -8138, -2528, -1841, -2152, -958, -3546, -1837, -1595, -2038, -2450, -634, -2030, -2883, -2504, -4258, 264, -2891, -5208, -2893, -4266, 104, -3498, -6786, -3304, -3571, -714, -4049, -6299, -5195, -3726, -1544, -3975, -5020, -8683, -3971, -2061, -3776, -3471, -3027, -2982, -3042, -4810, -2534, -1400, -2198, -5152, -5524, -3170, -1548, -2393, -8683, -4234, -6870, -3309, -3577, -7623, -2933, -6343, -6093, -5079, -5115, -1865, -4447, -4500, -5260, -4442, -1204, -4518, -4625, -3944, -4769, -918, -4215, -8649, -3393, -5333, -1063, -4234, -5020, -4038, -5759, -2000, -5871, -4500, -4659, -6267, -4108, -7865, -6173, -4491, -6814, -6870, -6204, -2407, -4386, -6679, -9429, -6256, -920, -5037, -6133, -7562, -5408, -1164, -3735, -5387, -4805, -4369, -2677, -2198, -5646, -4299, -4089, -5085, -2396, -6434, -5097, -3843, -6026, -4592, -5502, -6504, -4464, -5221, -6194, -5067, -6899, -7050, -5906, -3182, -5951, -5879, -14195, -10069, -2356, -7130, -5509, -5339, -7796, -3476, -8423, -5333, -2999, -3944, -5494, -15615, -5710, -2583, -1894, -5465, -9331, -8165, -3291, -989, -7665, -9149, -6540, -3370, -1182, -7730, -10526, -7353, -3507, -2797, -5933, -9238, 7163, 3687, 5260, 8213, 6927, 7099, 2930, 4980, 7774, 6104, 6680, 494, 4202, 6396, 3805, 5330, -2238, 3077, 4062, 3177, 2075, -2030, 1648, 2540, 3088, 1958, 913, -385, 3181, 857, 3995, 2958, -693, 3621, 2641, 4066, 3034, 1153, 3868, 3757, 3306, 881, 1696, 3399, 2009, 2354, -2000, 1067, 1075, -7335, 972, 1108, -542, -2813, 1110, -754, 2354, -2477, -681, 1451, -1726, 2622, 1049, -1597, 1460, -3038, 2053, 3143, 894, 2779, -4559, 424, 3398, 2886, 2453, 1076, -2425, 1810, 3045, 1969, 3164, -1512, -599, 1551, 4105, 3482, 703, 1603, -2733, 5065, 2147, 1542, 2633, -4086, 4530, -3331, 2566, 2539, -2406, 2913, 76, 3736, 2075, -5286, 2058, 3235, 4006, 1889, -3621, 2842, 4099, 3106, 2235, -1203, 3599, 3643, 834, 2223, -1038, 3658, 1940, -3701, 1122, -2016, 2423, -1124, -4357, -1084, -3574, 113, -4071, -4378, -1717, -5031, 1767, -2879, -5158, -511, -2135, 3054, -760, -1125, 505, 548, 3064, 974, -66, 1112, 2247, 2563, 2056, -524, 927, 3215, 1915, 2428, -1174, -555, 3404, 1122, 2253, -1849, -4064, 2614, 788, 1757, -2546, -4997, 329, 1078, 931, -3546, -2900, -5401, 1319, -44, -6422, -567, -2659, 1296, -811, -2208, 732, -833, 861, -1465, -1203, 497, -430, -227, -904, -3296, -324, -495, -1476, 583, -10899, 290, -957, -1272, 1293, -2485, 515, -2176, -1158, 596, -350, -718, -4438, -2345, -1813, 460, -2560, -5408, -2924, -2211, 262, -3230, -5487, -956, -522, -364, -4053, -4805, 120, -213, -522, -2793, -2733, -241, -1401, -573, -1804, -2594, -2897, -5387, -1062, -2271, -5020, -4640, -6856, -2235, -3257, -12319, -1258, -4460, -4509, -3215, -9479, -1044, -5214, -7247, -2801, -3944, -2756, -4038, -11629, -2226, -1211, -4754, -1913, -7583, -1734, -355, -4923, -1044, -4352, -2238, -647, -4640, -1345, -4640, -4728, -1616, -3396, -2811, -9380, -8304, -2655, -3490, -5516, -5638, -5862, -2514, -7146, -9106, -3215, -7230, -1398, -6163, -12534, -2817, -7281, -679, -3126, -9238, -3399, -4795, -641, -3618, -7034, -4010, -3577, -981, -8192, -6885, -4935, -2589, -1117, -7523, -9585, -7865, -2090, -989, -5818, -10613, -6577, -2225, -910, -7842, -7665, -5127, -2641, -1227, -10284, -7179, -5702, -2793, -2450, -7445, -7179, -6469, -3020, -5718, -5871, -6103, -6516, -3729, -10069, -4664, -5599, -6204, -4693, -6083, -3964, -6332, -5710, -5615, -6016, -3906, -7213, -5933, -6354, -6899, -4601, -6457, -6434, -7066, -7503, -6958, -5183, -6653, -8363, -10613, -11629, -4821, -7213, -8517, -7912, -5827, -5127, -9331, -7888, -5333, -5008, -3782, -10001, -6133, -5516, -5871, -3242, -8485, -4664, -7912, -6692, -5353, -11115, -4464, -9873, -7317, -28777, -8517, -4246, -5997, -9639, -9284, -7130, -3971, -4805, -11629, -9106, -5623, -3029, -4323, -5451, -6204, -4112, -4089, -4035, -3659, -5299, -4191, -5743, -5346, -4130, -4447, -7603, -7523, -8138, -5801, -3479, -8683, -7066, -8454, -7317, -3252, -6343, -5247, -6093, -13049, -4307, -8220, -3760, -5319, -7247, -6133, -8363, -3580, -5121, -4980, -6590, -10526, -5480, -4266, -5630, -6422, -11629, -8582, -5189, -6183, -8903, -6173, -4274, -10442, -5576, -5458, -3391, -2406, -4491, -5346, -6083, -9238, -5906, -4536, -6615, -3594, -4527, -5844, -2210, -2393, -5073, -4974, -5444, -4425, -7708, 1869, 1882, 1049, 1145, 1714, -6035, -8192, -4104, -7984, -7066, 8644, 8718, 8778, 8646, 8552, 12957, 12975, 12939, 12875, 12866, 15047, 15028, 14991, 14946, 14945, 15688, 15638, 15619, 15581, 15573, 15034, 14952, 14964, 14925, 14906, 12932, 12802, 12877, 12820, 12782, 8632, 8327, 8645, 8488, 8397, -6528, -2889, -3769, -8903, -5915, 1222, 2427, 1013, 1494, 1667, -7408, -2831, -4042, -6828, -5509, -3170, -7426, -2312, -3641, -2776, -10899, -6388, -4901, -11488, -7603, -7426, -2621, -4278, -6204, -4858, -10138, -3518, -6103, -10704, -6679, -5394, -5073, -7865, -8718, -13049, -8363, -4369, -7623, -5326, -12534, -7034, -3306, -4896, -3689, -10799, -7912, -4187, -6016, -4373, -9753, -14195, -6480, -8754, -4743, -4874, -10001, -8718, -9695, -5266, -4748, -9429, -9022, -11232, -6666, -8582, -10069, -8086, -12123, -7583, -9936, -11488, -9531, -10799, -10442, -6278, -9380, -10799, -8683, -9873, -5247, -7484, -8549, -9585, -10704, -5374, -6163, -6973, -8138, -13365, -7066, -5933, -6045, -6354, -12776, -9531, -6759, -5768, -6153, -11945, -10799, -10001, -5662, -7752, -11781, -6235, -9873, -4997, -8582, -9531, -4157, -7888, -5539, -8485, -7130, -4559, -9531, -8454, -9380, -5458, -6719, -11629, -10899, -6590, -4795, -7004, -7066, -8582, -4821, -5026, -6602, -5933, -8112, -4587, -6026, -7730, -6914, -8060, -5924, -8165, -9753, -8034, -8165, -9238, -11488, -10362, -6988, -8582, -11945, -9479, -10799, -8034, -8517, -10526, -9812, -12776, -15615, -9238, -9064, -17034, -13738, -10526, -10001, -9873, -11781, -9022, -9284, -9284, -13738, -10704, -7162, -8942, -10799, -17034, -11488, -6480, -6914, -28777, -12776, -10362, -6856, -6504, -10284, -11232, -9585, -9429, -8304, -7842, -28777, -9585, -14784, -9812, -6786, -10442, -10799, -8333, -12319, -6786, -9695, -11945, -8192, -14784, -7623, -8060, -8485, -10442, -11004, -9639, -6590, -7842, -11115, -11629, -13365, -6973, -9331, -10362, -13738, -12319, -8423, -11115, -8790, -10613, -12534, -10138, -8942, -6628, -7464, -10799, -10799, -7687, -5546, -8247, -7484, -11945, -9064, -6173, -17034, -5195, -28777, -13738, -9149, -11115, -4486, -17034, -10284, -17034, -11781, -5055, -11781, -8138, -15615, -14784, -5933, -10284, -7819, -11232, -10899, -6354, -11781, -9284, -8827, -8790, -6773, -15615, -12776, -8009, -7665, -7623, -14195, -28777, -8903, -7730, -9331, -12123, -28777, -10210, -11004, -4307, -6577, -6590, -7389, -5776, -4923, -13365, -6256, -8582, -6885, -6445, -11488, -6321, -11488, -11781, -7730, -9380, -7644, -6235, -6870, -6640, -11781, -6653, -5702, -4858, -8423, -6516, -6842, -6153, -3349, -8086, -4713, -15615, -5997, -2956, -5960, -4282, -10138, -5346, -3586, -6516, -4774, -8582, -3975, -3493, -5942, -5195, -5176, -4142, -2552, -9695, -2924, -3354, -8649, -2383, -11781, -1787, -2612, -5979, -8060, -4683, -5195, -4583, -9331, -4504, -1870, -3425, -3391, -3012, -7408, -8903, -9639, -4847, -7371, 1023, 1298, 733, 1225, 1518, -6235, -6732, -4935, -3870, -8649, 8697, 8728, 8774, 8757, 8620, 12889, 12938, 12926, 12920, 12889, 14951, 14991, 14962, 14962, 14956, 15584, 15612, 15572, 15578, 15579, 14929, 14946, 14892, 14903, 14907, 12833, 12834, 12757, 12777, 12785, 8538, 8507, 8347, 8410, 8461, -6553, -9585, -5158, -7752, -12534, 1497, 1372, 1741, 1370, 603, -4625, -8790, -6422, -5970, -8423, -7484, -2807, -3339, -2589, -2065, -5539, -7484, -9064, -6064, -3811, -3071, -8718, -5480, -7335, -2463, -5678, -8276, -7665, -10001, -4130, -6692, -4299, -11629, -7408, -6093, -6007, -5273, -13738, -9639, -7912, -3529, -7264, -13738, -5273, -9022, -3474, -6914, -6958, -5897, -8060, -4357, -5319, -4748, -7299, -7752, -4805, -5546, -5726, -6732, -11232, -4518, -7888, -9812, -7687, -9812, -4698, -10210, -10069, -9331, -7247, -6093, -9639, -9695, -6679, -7408, -7464, -11115, -9639, -6310, -7623, -8549, -12319, -7708, -8827, -7464, -8718, -8304, -7034, -14784, -8718, -8942, -7623, -8333, -12319, -10899, -8304, -6732, -10138, -8363, -9380, -8393, -5678, -10001, -8333, -10613, -8683, -5592, -7445, -10001, -15615, -8615, -7247, -7050, -10613, -11629, -9022, -13049, -8138, -8982, -7426, -8393, -12319, -8649, -6914, -6054, -7562, -8827, -8192, -5554, -5678, -7842, -7113, -8615, -5158, -6445, -10069, -6565, -8865, -5458, -8754, -14195, -7389, -7819, -5623, -8304, -14784, -8982, -7960, -5158, -7865, -14195, -9284, -9022, -4620, -8060, -13738, -10001, -9284, -4674, -7623, -11629, -9531, -8942, -5516, -7389, -10001, -8865, -8485, -6899, -8827, -11629, -9380, -8485, -7162, -10704, -8582, -7796, -7842, -6267, -8754, -6828, -6856, -7752, -6225, -9022, -7708, -7445, -9284, -7281, -9812, -10526, -7523, -10362, -7503, -9022, -11629, -7019, -10899, -6399, -10138, -10210, -7247, -14784, -6093, -28777, -10138, -8034, -10799, -7299, -9585, -11488, -10210, -9639, -10799, -7583, -10284, -13738, -9531, -14195, -7130, -7687, -9936, -9936, -9531, -6422, -5871, -10069, -10284, -7583, -6123, -5942, -28777, -10613, -8220, -7408, -7819, -10210, -11004, -12534, -8454, -8718, -8649, -10899, -12534, -7912, -7865, -9193, -10069, -11232, -8683, -8009, -11629, -9149, -11629, -10069, -9193, -17034, -9380, -11781, -10899, -11781, -9753, -9873, -11115, -10799, -14195, -8615, -10138, -9331, -9936, -14195, -8582, -9064, -8903, -9284, -11004, -6615, -4323, -5546, -7464, -7984, -6074, -4408, -7146, -8304, -6870, -6553, -3798, -6528, -7484, -7842, -8865, -3689, -7796, -5286, -10210, -6870, -4134, -8034, -4578, -10138, -6343, -4031, -4831, -2960, -7730, -9639, -2918, -3964, -1644, -6064, -6705, -2709, -4523, -2032, -6235, -4805, -3641, -5531, -3804, -7066, -4006, -3498, -5915, -3133, -8363, -3563, -3031, -13049, -2590, -4573, -3496, -2594, -6553, -2954, -6246, -14195, -4545, -6469, -8903, -3121, -3375, -4616, -2267, -3985, -4708, -3900, -3314, -5546, -5055, 1399, 1967, 2093, 896, 1351, -7623, -6928, -8549, -3824, -5743, 8664, 8640, 8637, 8910, 8824, 12887, 12912, 12897, 12993, 12948, 14942, 14968, 14952, 14998, 14964, 15560, 15579, 15567, 15588, 15559, 14886, 14896, 14890, 14893, 14870, 12760, 12763, 12765, 12748, 12730, 8405, 8412, 8417, 8354, 8329, -5924, -13365, -9022, -7562, -6103, 1189, 779, 1209, 1178, 1529, -7113, -4442, -7542, -12319, -7162, -2817, -1299, -3996, -2751, -3422, -7819, -5569, -12123, -9429, -9380, -5743, -7542, -4748, -6504, -5836, -14195, -6064, -10899, -14784, -9193, -6640, -5266, -6354, -6480, -6504, -7960, -5933, -9022, -7819, -8790, -7912, -5546, -10138, -13738, -10799, -7888, -7097, -8485, -9753, -12776, -10442, -13738, -6842, -6653, -9429, -9812, -12534, -6093, -7984, -9193, -6988, -8363, -7281, -10362, -9149, -6540, -7523, -8276, -7353, -7865, -7445, -7162, -7335, -6321, -6343, -7819, -8549, -8034, -6310, -5654, -6786, -17034, -8247, -7299, -5710, -7130, -10442, -6988, -8112, -5784, -10210, -10799, -7464, -7230, -5924, -13738, -10210, -7912, -7389, -6163, -8165, -7583, -8903, -11488, -5933, -5380, -5592, -10799, -10362, -5576, -4769, -5494, -8549, -9193, -7335, -5312, -6445, -5933, -8517, -8220, -5599, -6679, -4997, -8333, -6540, -5380, -5862, -4901, -9429, -7081, -5960, -5853, -5437, -10362, -8582, -7819, -7464, -7004, -9873, -9873, -9380, -9531, -8649, -11356, -9479, -7984, -8304, -8086, -13738, -7583, -6469, -7066, -8034, -8827, -8009, -6457, -7281, -10001, -9193, -14195, -7774, -7752, -10704, -9531, -7050, -8549, -6153, -10899, -8649, -6399, -9238, -4940, -8982, -9695, -9284, -11781, -5247, -6615, -7984, -17034, -9479, -7130, -6365, -5569, -10069, -8517, -9193, -8086, -5014, -9284, -8982, -8790, -10526, -6310, -10362, -8790, -7644, -10704, -10526, -11781, -7603, -7066, -14195, -10442, -9639, -6958, -7317, -17034, -8393, -7426, -7179, -8454, -14784, -8485, -6800, -7464, -10001, -13049, -8454, -7353, -7179, -10138, -12776, -8485, -8276, -6973, -9149, -12123, -9812, -9479, -7752, -9695, -9106, -12319, -14195, -10138, -10799, -7281, -12123, -10613, -13738, -7842, -6800, -11945, -8304, -14195, -6321, -7960, -14784, -9639, -13365, -6288, -10799, -14784, -15615, -13738, -7623, -13738, -13049, -28777, -14195, -10526, -15615, -12776, -17034, -14784, -12776, -14784, -17034, -15615, -13738, -11232, -11356, -14195, -28777, 12983, 8466, 12344, 11392, 6461, 12380, 8703, 11634, 10869, 5922, 10364, 8737, 9285, 9233, 4385, 5508, 8522, 4691, 6360, 3469, 3990, 8762, 3806, 2616, 4362, 6738, 8873, 3098, 927, 4760, 6552, 8370, 1133, 3740, 4637, 4825, 7566, 1153, 4516, 4528, 505, 6857, 585, 2372, 4276, 326, 6123, 1571, -416, 3811, 3583, 5147, 2412, 4610, 3586, 4122, 3992, 2286, 5935, 3851, 2898, 3285, 1987, 5780, 4498, -1384, 3170, 2228, 4459, 5196, -2026, 2326, 2240, 2699, 5702, 1171, 506, 1386, 3207, 5755, 1764, 2206, 904, 3826, 4887, 2222, 3757, 1995, 3129, 2468, 3180, 3870, 2658, 942, 52, 3634, 2839, 2456, 320, 976, 3623, 1191, 1604, 2480, -885, 4603, 1822, -525, 3460, -782, 5581, 2952, -7583, 3661, 1818, 5375, 2516, 1379, 3371, 1904, 3979, 1095, 3413, 2724, 295, 2803, 2173, 3843, 2163, -2385, 2485, 2834, 3487, 1736, -2409, 713, 1200, 2875, 930, -201, -2075, -2698, 2360, -206, 1030, -335, 1973, 2030, -1165, 1748, -562, 3507, 1755, -2140, 2111, -2956, 3447, 1208, -3479, 1329, -7774, 2264, -274, -2064, -2785, -4100, 446, -5810, -735, -425, 42, -35, -2204, -666, 2481, 1366, 911, 852, -333, 2815, 934, 1890, 1563, 554, 1385, -1336, 2567, 1102, 550, -1894, -6376, 2435, -70, -911, -2829, -2457, 958, -1321, -3425, -1625, 208, -495, -1875, -1609, -1192, 1831, 1443, -1879, 491, -833, 2715, 2199, -1954, 1279, -1153, 2768, 1427, -1787, 1024, -2191, 1800, -707, -1361, 429, -1825, -546, -3438, -1469, 132, -506, -3306, -3067, -2342, -434, 361, -1826, -2148, -2438, -1419, 693, -1060, -2789, -1291, -2326, 540, -1398, -5646, -281, -3230, 120, -2630, -11488, 255, -4086, -627, -5260, -6332, 89, -3741, -1594, -15615, -3076, -947, -2797, -1242, -8009, -1610, -2895, -2657, -440, -8192, -1745, -5759, -3449, -303, -10613, -3589, -10442, -3436, -614, -3603, -5997, -10613, -2567, -1078, -1281, -4863, -10138, -2612, -1569, -520, -4495, -7408, -3833, -1657, -926, -3920, -4923, -6388, -1532, -2597, -2969, -3811, -7523, -2140, -5735, -2642, -2462, -5569, -3792, -8903, -2857, -1095, -3814, -4282, -7081, -3203, -232, -2463, -3808, -4550, -3029, 77, -2125, -5353, -3463, -2450, -288, -2714, -5827, -3230, -2220, -1383, -3518, -3274, -3360, -2747, -3014, -3735, -2954, -3860, -4664, -4266, -3515, -4620, -5145, -10138, -4303, -3276, -8549, -7408, -11232, -4743, -3592, -13049, -7523, -7371, -5367, -4664, -12534, -4142, -4679, -4075, -4683, -7819, -1976, -3738, -2964, -3396, -6064, -914, -4863, -3261, -3286, -4100, -790, -9873, -5026, -4779, -2705, -1613, -4451, -5115, -7912, -2533, -3729, -2303, -3540, -8982, -3714, -8485, -2100, -3257, -5897, -6267, -6828, -3168, -4416, -3299, -5208, 6641, -9022, 10014, 6932, -1285, 6421, -1480, 9436, 7458, 1188, 5645, 2610, 7535, 8047, 2195, 4735, 4517, 3383, 7927, 1683, 5629, 4916, 677, 7040, 793, 6675, 4017, 3672, 5761, 24, 6487, 2575, 4180, 5137, 538, 5092, 2426, 3491, 5309, 924, 3984, 2299, 1425, 5228, -717, 3747, 2723, -1441, 4428, 616, 1867, 4179, 1667, 2892, 3293, 1701, 4930, 3607, 1086, 4534, 4106, 4823, 3888, 466, 5018, 4366, 4170, 2549, 1764, 4844, 2309, 3279, 1656, 3391, 3867, -3065, 2441, 3906, 4277, 2018, 2846, 1991, 5039, 4113, -508, 4320, 1427, 4954, 2669, -2954, 4298, -544, 3932, -1070, -4532, 3797, -1827, 2483, -3689, -4800, 3753, 796, 1513, 252, -2135, 4138, 1456, 1353, 1074, -456, 4171, 898, 1583, 871, -337, 3238, 175, 1024, 1179, -1526, 566, 287, -1177, 2338, -1895, -3903, 874, -4447, 3044, -501, -182, 686, -5702, 3154, 282, 680, -897, -3301, 3143, 548, 350, -3985, -1326, 3063, 734, 651, -5208, -1914, 2360, 1041, 1284, -2238, -6615, 387, 1321, 1603, -596, -3417, -4340, 1313, 2419, -419, -267, -6343, 929, 3345, -1096, 1233, -4509, 503, 3560, -2006, 1986, -4578, 421, 2957, -3375, 2159, -3137, 481, 1964, -2125, 1832, -2116, 563, 1390, 388, 1080, -2204, 597, 1090, 1687, -76, -3194, 23, 254, 1963, -1079, -834, -1623, -2399, 1268, -702, 1592, -3647, -6113, -443, 252, 2691, -4482, -453, -2270, 784, 2846, -3208, 1029, -1537, 470, 2426, -989, 1175, -343, -1194, 1835, -405, 404, 38, -5933, 1317, -1371, -1761, -562, -5784, 731, -2118, -4500, -1603, -3154, -261, -1164, -1740, -1446, -2731, -1899, -1024, -816, -1005, -2999, -3609, -1717, -1398, -1076, -3817, -3087, -2260, -3447, -1105, -5458, -1917, -2435, -7050, -742, -9429, -1559, -2653, -2837, -443, -5487, -2207, -2908, -1002, -616, -2232, -4184, -3210, -769, -1488, -1135, -9380, -3577, -1431, -3196, -1630, -5793, -4157, -2182, -4172, -4311, -2885, -4743, -2132, -2201, -11629, -1680, -4784, -1212, -723, -4270, -814, -4708, -487, -185, -3133, 428, -5784, -565, -483, -3220, 1544, -14784, -1568, -1605, -3515, 1989, -5524, -3415, -3294, -3600, 1609, -3452, -5997, -4774, -2975, 283, -4138, -9106, -4412, -1765, -2497, -3996, -12123, -1937, -904, -10799, -1660, -12776, -887, -837, -5429, -947, -9022, -1666, -1611, -4250, -1784, -8086, -3455, -3007, -5897, -3900, -6299, -2897, -3947, -17034, -6590, -4089, -2849, -3896, -5091, -9022, -3326, -4532, -4754, -3110, -5524, -3833, -6842, -11629, -3213, -3038, -3996, -8393, -4017, -5152, -1874, -2465, -9753, -476, -8138, -1381, -1210, -7523, 1019, -7389, -1357, -724, -4049, 1292, -5152, -1799, -1083, -1897, 459, -2644, -2716, -2390, -1028, -1522, -1132, -3989, 8639, 8433, -1228, 8965, 4876, 8228, 7718, 4726, 8594, 5063, 7076, 5210, 6354, 7458, 4833, 5526, -2424, 5894, 5453, 3010, 4164, 1836, 3901, 2248, -1123, 3075, 2791, 3507, -4997, 3103, 1547, 1485, 4525, -1727, 4722, -669, -1895, 4015, 660, 4281, -1112, -9812, 1797, 682, 357, 551, -7081, 203, -1030, 1809, 2363, -4805, 1729, -2295, 5573, 3098, 957, 1841, -1607, 6763, 2731, 3022, 246, -4138, 7010, 2067, 3062, -430, -1722, 6901, 1854, 751, 1400, 1568, 6515, 1354, -1704, 1351, 2000, 5632, 229, 1042, -1413, -132, 4024, -1084, 157, -2303, -5333, 1880, -3399, -11115, 231, -2480, 2450, -6615, 1257, 103, -8112, 4125, -1409, 3194, -1411, 408, 4623, 513, 3307, -3373, 2865, 3766, 1561, 2018, -3659, 3266, 886, 2293, -1206, -615, 2429, -1319, 2346, -2475, 1007, 750, 1659, 1237, -173, 1398, -1381, 1832, -1701, -92, 1144, -2637, -613, -9873, -1564, 975, -3933, -1284, -11356, -4097, 1184, -2793, 2481, -5079, -4620, 1234, 1121, 3869, -593, -2943, 907, 2930, 4064, 1427, -2205, 494, 3505, 3465, 2313, -2933, 318, 3319, 2384, 2448, -4587, 446, 2791, 1361, 1854, -2659, 610, 2286, 1592, 246, -1155, 575, 1779, 3000, -2831, -1207, 415, 890, 4033, -2644, -2430, 240, 52, 4175, -656, -4991, 246, 1121, 3334, 146, -8903, 865, 2385, 1424, 232, -1411, 1617, 2712, -1662, -424, 975, 1771, 2113, -4935, -1887, 1733, 1068, 756, -4042, -3817, 1432, -459, -953, -1926, -4336, 443, -1721, -2394, -605, -3133, -275, -1533, -3187, -620, -2311, -118, -1638, -3644, -2713, -2172, -356, -2204, -5109, -4733, -2364, -2047, -1807, -6553, -1473, -2793, -4447, -1011, -3526, -836, -3814, -2730, -825, -1912, -1361, -4713, -2764, -1393, -1556, -1480, -4195, -6719, -2564, -2201, -1628, -3999, -5686, -3843, -3430, -2891, -3732, -3144, -4946, -3047, -6321, -3289, -4071, -5079, -1706, -7004, -3824, -11004, -3433, -897, -2590, -3853, -6093, -2707, -684, -628, -2450, -4021, -3788, -1165, 208, -2008, -3951, -7819, -2500, 203, -2997, -4278, -6480, -4340, -338, -5020, -3850, -3388, -5776, -845, -4230, -2887, -1583, -8754, -1543, -2960, -2257, -490, -8942, -3168, -2522, -2334, -160, -4664, -3656, -1959, -3130, -648, -2910, -2090, -1419, -4211, -2229, -2087, -1033, -1469, -4664, -5906, -2068, -348, -2148, -4654, -7752, -3187, -275, -3163, -5662, -6103, -6332, -1275, -4010, -8363, -9753, -7523, -4038, -3732, -4738, -7796, -5539, -7960, -2495, -2902, -4361, -5793, -4640, -1578, -2839, -3396, -6856, -2698, -1377, -3396, -3108, -9193, -1689, -1841, -3557, -3357, -8247, -1904, -2670, -4491, -4130, -2811, -3618, -3729, -9284, -4108, -436, -3801, -5286, -6914, -3671, 602, -1820, -6457, -3964, -4149, 782, -1314, -4429, -4278, -7583, -1988, -2573, -3798, -3401, -6153, -1867, -1335, -4478, -2322, -4093, -2514, -1215, -7081, -1609, -4550, -2581, -2153, -6143, -1119, -10362, -2172, -4089, -3417, -1093, -5127, -2505, -5158, -2906, -1857, -2259, -3479, -3964, -4416, -3257, -1897, -4089, -2550, -8276, -3396, -3482, -3662, -1197, -6093, -2956, -5561, -3005, -405, -5516, -3860, -2622, -3133, -451, -5776, -8086, -1141, -4541, -1394, -3543, -6958, -915, -7936, -2776, -2172, -3319, -1323, -10799, -2906, -1923, -2242, -1740, -6235, -2445, -2545, -2337, -2102, -4226, -2470, -4149, -3449, -3112, -3321, -2437, -7484, -5662, -5592, -3479, -2050, -4509, -5176, -4929, -4679, -1811, -1759, -3147, -2711, -4853, -2040, -792, -2628, -2217, -4046, -3154, -1075, -3624, -2964, -4518, -5862, -1859, -6411, -4743, -4620, -6705, -1925, -9753, -6899, -3031, -4573, -1916, -7984, -7179, -2091, -4262, -2578, -6958, -7542, -2058, -5109, -3923, -6653, -8276, -2975, -5592, -5353, -6365, -6899, -5008, -4478, -5844, -5718, -6399, -5367, -3396, -5988, -5702, -5776, -3695, -2863, -6007, -5942, -4262, -3360, -2791, -6411, -5133, -3843, -3930, -3191, -7603, -3916, -5444, -4451, -4199, -7445, -3154, -9695, -5240, -6640, -7865, -3415, -5942, -7299, -14195, -15615, -4896, -5227, -6786, -4635, -6653, -6123, -6225, -4759, -2279, -3999, -5836, -5554, -4319, -1663, -3329, -7371, -4874, -4935, -2594, -4010, -8517, -5670, -5951, -6083, -5801, -3951, -7130, -6399, -7179, -5871, -2030, -6958, -5097, -3883, -4307, -1505, -5853, -3540, -3460, -3886, -2225, -4438, -2613, -4869, -4784, -4611, -3316, -1983, -8718, -7335, -12319, -3144, -1329, -6800, -14784, -8112, -4172, -971, -4532, -9149, -6492, -6469, -1242, -3954, -7842, -5569, -5897, -2128, -4469, -8276, -4669, -4473, -3286, -5592, -8582, -4674, -4282, -4500, -6246, -7888, -5480, -4460, -6278, -6113, -6870, -6143, -4382, -9331, -5374, -5970, -5429, -4365, -10526, -4759, -5793, -3773, -4518, -6705, -4486, -6692, -2902, -4215, -4569, -4021, -7819, -3098, -3537, -3760, -3609, -6899, -3717, -3225, -3930, -3754, -6745, -4149, -3748, -4451, -4282, -8247, -4386, -5759, -4573, -4800, -7960, -4495, -10210, -4420, -5458, -7230, -4901, -8454, -4482, -6943, -8718, -6214, -9479, -5516, -10899, -10899, -8304, -11781, -9064, -11004, -11356, -6914, -8034, -8790, -6759, -11781, -6074, -8112, -5793, -5339, -5997, -7523, -10704, -4896, -4991, -3452, -10284, -13738, -4644, -5353, -2605, -8790, -12319, -4664, -6183, -3156, -7503, -11232, -5073, -7623, -5394, -6354, -11232, -6246, -9873, -11232, -5346, -12776, -6692, -11356, -10442, -5079, -10613, -4951, -8549, -8718, -6026, -8393, -3886, -6445, -8485, -7389, -7389, -3985, -5394, -8304, -6516, -6842, -5227, -5253, -8363, -6123, -5960, -7752, -6434, -8192, -7371, -4769, -9695, -10613, -7299, -11232, -4234, -7865, -8304, -7213, -12534, -4940, -6719, -5607, -4097, -1277, -4093, -629, -5152, -4299, -2417, -3748, -1023, -6214, -3029, -3933, -2964, -2319, -8790, -1610, -4625, -3218, -4769, -6163, -842, -4211, -3641, -7162, -2624, -879, -4157, -3047, -5055, -1195, -1696, -5061, -2690, -3820, -1165, -3476, -5784, -3326, -3686, -2430, -7230, -4698, -3989, -4086, -5133, -7230, -3367, -3259, -4420, -7796, -4545, -2624, -2795, -4555, -7774, -3674, -2399, -3130, -5202, -6679, -3373, -2347, -4024, -6958, -4086, -3360, -2149, -5266, -7484, -2455, -3788, -1884, -7050, -4968, -1965, -4340, -1810, -11781, -3393, -2325, -4688, -2060, -9873, -2950, -3067, -5599, -2166, -6914, -4203, -4438, -9380, -1485, -6064, -8649, -8903, -8718, -856, -5133, -3589, -5623, -5127, -1114, -4282, -1720, -3334, -3430, -2282, -3889, -1959, -3244, -1872, -2597, -3540, -4395, -3609, -1138, -1833, -2787, -15615, -3391, -1660, -1713, -1877, -4708, -2941, -4013, -1927, -1303, -3518, -2364, -28777, -1980, -1443, -4504, -2414, -4625, -2305, -2499, -7687, -3689, -2969, -2867, -3586, -6321, -6194, -3415, -3187, -2863, -4134, -8982, -6064, -3201, -2422, -4180, -12776, -8683, -2528, -3274, -7603, -13049, -4532, -1939, -4779, -7708, -10362, -3103, -2490, -3571, -3927, -8942, -3031, -4858, -1898, -3621, -8060, -4286, -10799, -1147, -5630, -6480, -9331, -28777, -1127, -11004, -4779, -6528, -8393, -1725, -5103, -4134, -3005, -4352, -3071, -2831, -4821, -1917, -2809, -5970, -1917, -7484, -2166, -2728, -12123, -1922, -7426, -3656, -3866, -8060, -2875, -4038, -6153, -6173, -7644, -4527, -2514, -7583, -8827, -6007, -5380, -2143, -7484, -10069, -4006, -5623, -2831, -5638, -9149, -3117, -6899, -4482, -4319, -7389, -3045, -8304, -6445, -4161, -7196, -3741, -7542, -9873, -3916, -8485, -5827, -6445, -5915, -2758, -10526, -14195, -5516, -2969, -1825, -8220, -7113, -5158, -2289, -1682, -4974, -5133, -5374, -3386, -2433, -3357, -4784, -6035, -6214, -4230, -2986, -4748, -5247, -6343, -6814, -3656, -4587, -3036, -5422, -7130, -5127, -4606, -1727, -6113, -6054, -6434, -5380, -1586, -7665, -5387, -5524, -7213, -2316, -8304, -4974, -4282, -8086, -2943, -7081, -4874, -3903, -7335, -2924, -5915, -5480, -4644, -7445, -3566, -5127, -6565, -6988, -7004, -5759, -4500, -6705, -9585, -5615, -7299, -4075, -5970, -6679, -4378, -6411, -4299, -5002, -4869, -3804, -7936, -5933, -4669, -3870, -4412, -10138, -11781, -5879, -3612, -7484, -6113, -8683, -11232, -4191, -10613, -4795, -6828, -6640, -5253, -5844, -5109, -7888, -4153, -6411, -5472, -6973, -11232, -3594, -7665, -6445, -11356, -7583, -4108, -9193, -6814, -13049, -4545, -5176, -13738, -7317, -7445, -2939, -6332, -13365, -9022, -5646, -2470, -8138, -10442, -9106, -5654, -3089, -13738, -11232, -7066, -6943, -4805, -8615, -11488, -5844, -7842, -7583, -6411, -8333, -5623, -7179, -7984, -6692, -6745, -6173, -6628, -6343, -7888, -6376, -6800, -6973, -6194, -5630, -3504, -5152, 304, -2356, -5279, -3930, -4513, -717, -5924, -6469, -4290, -3215, -2268, -7562, -9873, -4769, -2571, -3833, -3468, -7066, -6267, -2463, -3785, -2490, -4738, -10442, -2478, -3476, -2926, -3785, -11356, -2457, -4357, -4550, -3247, -8615, -2642, -5546, -5444, -2900, -8790, -3309, -3996, -2730, -2979, -7936, -4573, -2752, -1042, -4138, -5576, -6492, -2429, -863, -8718, -4038, -8754, -2630, -2257, -5055, -3108, -5888, -3218, -5353, -2028, -2580, -2947, -4315, -5008, -1020, -2605, -1484, -5353, -3776, -923, -3729, -1239, -4693, -3609, -1018, -7484, -2447, -3463, -3259, -800, -8942, -6928, -2709, -2299, -601, -4611, -6045, -2361, -1372, -976, -3546, -3096, -2396, -920, -1943, -3896, -3189, -3007, -1016, -2869, -5718, -5306, -4790, -1264, -3337, -11781, -5630, -9812, -1020, -3889, -7247, -3873, -7130, -521, -4408, -4500, -3751, -4513, -359, -4319, -3632, -4985, -3668, -828, -3896, -3501, -6958, -3677, -2409, -3968, -3444, -8790, -4469, -7842, -5539, -3501, -7623, -5630, -4869, -13738, -3409, -6045, -6074, -1869, -5784, -2553, -4890, -5103, -1226, -3563, -1982, -3463, -3498, -1678, -3349, -2756, -2799, -2789, -2799, -4071, -6666, -3571, -3168, -4303, -4246, -5979, -6973, -3853, -5988, -3732, -2285, -9585, -4500, -7408, -3896, -1483, -4997, -6653, -6828, -4946, -2378, -3606, -11356, -4723, -6054, -5776, -2871, -6093, -3701, -5862, -9639, -2545, -3999, -4056, -4968, -4774, -2677, -2916, -5189, -4390, -4130, -3078, -2567, -5569, -4357, -4674, -3085, -2967, -6899, -4703, -5408, -3117, -4527, -9238, -4688, -6246, -4149, -11488, -4064, -4842, -7730, -5380, -5049, -1793, -6278, -9695, -3441, -2143, -734, -4654, -10613, -1937, -1323, -417, -1908, -6299, -1546, -1647, -674, -812, -4127, -2146, -2541, -1348, -1010, -3763, -3951, -3149, -2207, -2024, -5139, -4654, -3404, -2999, -2639, -9284, -2200, -3563, -3515, -2386, -14195, -1123, -3378, -3615, -2391, -11629, -1485, -2977, -3254, -3027, -11488, -3365, -2929, -2933, -4723, -8754, -7213, -3886, -2855, -9753, -7081, -8718, -6692, -2745, -7774, -5915, -7960, -6590, -2543, -4509, -4698, -8790, -4230, -2776, -3795, -3650, -9812, -3589, -4230, -4630, -2952, -9064, -3968, -7542, -5997, -2698, -7281, -4946, -5670, -5202, -2922, -5836, -6064, -4010, -4842, -3665, -5367, -7542, -3866, -5152, -4738, -6153, -10613, -4569, -4006, -5924, -7752, -9149, -6093, -2958, -6988, -6856, -6828, -8363, -3124, -7623, -5615, -6153, -6653, -4625, -8304, -5509, -6540, -4527, -6899, -7445, -6376, -8276, -3735, -7562, -5145, -8220, -13738, -3776, -8649, -3937, -8982, -11488, -4246, -12534, -3975, -7865, -8220, -5360, -12534, -5073, -7019, -6814, -7583, -11115, -7034, -6590, -6278, -6399, -11356, -9479, -6540, -6504, -4266, -28777, -14784, -7081, -7353, -3386, -11945, -10138, -7665, -7004, -3512, -9873, -6480, -8165, -5429, -4578, 6593, 3030, 1538, 6735, -3388, 6250, 2597, 1701, 6297, -1212, 5305, 1149, 1623, 5029, 852, 4075, -2288, 823, 3180, 2145, 3078, -7796, 216, 1115, 2889, 2249, -2043, 993, -2197, 2992, 943, -1459, 1852, -5133, 2263, 410, -1761, 2430, -72, 800, 819, -179, 2860, 1829, 553, -1209, 1652, 2740, 2877, 2116, 1362, 3020, 1299, 3377, 3701, 4582, 4225, -37, 3143, 5044, 5643, 5346, 2696, 1786, 5895, 5377, 6168, 3704, -242, 6002, 4448, 6394, 2690, 929, 5225, 3888, 5742, -526, 1833, 3773, 3467, 3792, 1936, 1358, 2873, 2329, -393, 3745, 94, 2228, 1512, 75, 3814, -1690, -93, 2392, 1020, 2661, -3612, -1816, 2772, -695, 969, -287, -583, 1903, -561, 232, 1779, -974, -475, 969, -1284, 2667, 1299, -5494, -222, -8393, 2952, 2553, -6988, -11115, 945, 2854, 1571, -5109, 688, 3075, 2353, -2945, -3071, 2798, 3446, 1365, 1195, -7, 3496, 2658, -465, 3161, 1703, 3593, 1298, -4625, 3128, 2164, 3229, 325, -1254, 1624, 1362, 2432, -48, 1774, -1066, -1865, 1408, 750, 3080, -3012, -3893, 411, 1726, 3408, -5312, 961, -517, 1730, 3047, -6332, 2111, -1748, 678, 2222, -3487, 1821, -2429, -403, 1194, -3814, 564, -382, -424, 331, -4842, -989, 817, -1142, -140, -2101, -939, 432, -2326, -365, -87, 378, -1663, -1107, -599, 1056, 1447, -3629, -744, -1047, 1613, 1991, -3142, -2698, -1760, 1621, 2080, -5380, -2630, -2714, 1089, 1814, -7162, -266, -3795, 104, 1204, -3391, -181, -3860, -1191, 177, -3213, -2232, -2369, -2751, -1324, -3893, -6590, -1126, -4578, -3365, -2383, -6640, -771, -4821, -5793, -834, -10362, -1288, -4021, -4378, 73, -7644, -2118, -4211, -2409, 533, -4386, -2004, -5615, -1627, 432, -3156, -1762, -6565, -1683, -450, -2336, -2546, -5531, -2115, -2312, -1854, -4180, -5079, -2083, -3860, -2130, -3751, -5145, -1793, -2752, -3883, -2356, -4748, -2251, -1627, -9193, -1781, -4053, -4464, -1368, -7665, -1781, -3798, -5360, -2297, -9106, -1923, -4728, -1756, -5031, -7264, -1875, -8165, -585, -11115, -3117, -1738, -8086, -1181, -7264, -2344, -1690, -5487, -3840, -5879, -3910, -1807, -4659, -17034, -5380, -8549, -2040, -4258, -6705, -5139, -3933, -2396, -4790, -5678, -5333, -2265, -3034, -7213, -5853, -5906, -2168, -4327, -7912, -5451, -6411, -3010, -6615, -5494, -4145, -6759, -4352, -7623, -5451, -2871, -8086, -4912, -6705, -8060, -2115, -17034, -4495, -7317, -11781, -2000, -8517, -4754, -10138, -7752, -2409, -6113, -5970, -12534, -9022, -3239, -6093, -7299, -8982, -7984, -4738, -7603, -7097, -6074, -4482, -8112, -9531, -5793, -4348, -3401, -8865, -9585, -4991, -3744, -3757, -5458, -7865, -5353, -4311, -4968, -4923, -5970, -7317, -6343, -6153, -6856, -4597, -9873, -10899, -6204, 1100, 6058, 1262, 2909, -8304, 2480, 5532, 2293, 2255, 1405, 3401, 3810, 3401, -217, 3985, 2749, 476, 3689, -7819, 4990, 398, -847, 3265, -284, 5012, 553, 668, 2244, 1759, 4306, 3124, 1150, 286, 2546, 2994, 4618, 1022, -4974, 2675, 810, 5369, 61, -3067, 2254, -2435, 5451, 1225, -1758, 1528, -3618, 5105, 4067, -62, 1110, -161, 5514, 5608, 3900, 1295, 2631, 6450, 5978, 5828, 1423, 3820, 6658, 5414, 6206, 1258, 3695, 5953, 4252, 5103, 2447, 2361, 4714, 2964, 1905, 4220, -153, 3574, 1759, -1407, 5231, -3373, 2705, -175, 986, 5531, -4713, 1455, -6083, 310, 5342, -4071, -1755, -483, -3218, 4798, -4821, -7842, 874, -10442, 3995, -4874, -3170, -946, -8649, 3129, -3744, -2666, -1948, -4769, 2334, -4713, -280, 1915, -440, 1301, -3311, 1086, 3469, 1578, -460, -1780, 1468, 3979, 2469, -1979, -2764, 1497, 3816, 2633, 65, -4086, 1528, 3136, 2198, 1650, -1067, 1651, 2419, 1097, 1922, -8, 1788, 2395, -647, 826, -665, 1778, 2654, -1939, -2472, -3354, 1547, 2531, -1566, -7603, -4442, 1264, 1722, -675, -1455, -575, 1309, -370, -272, -99, 1310, 1612, -1725, -852, -430, 2251, 1652, 1252, -2540, -1670, 2593, 1005, 2489, -4620, 217, 2450, -641, 2245, -4536, 2304, 1829, -3729, 548, -2219, 3283, 760, -5546, -3334, -639, 3546, -400, -2587, -14784, -60, 3408, -842, -471, -4991, -119, 3013, -117, 982, -638, -645, 2390, 931, 1808, 1517, -1510, 1431, 1485, 1993, 2218, -2069, -135, 1363, 1547, 1881, -2363, -1277, 650, 499, 1021, -3237, -583, -364, -1250, 259, -4795, -439, -978, -4145, -734, -6054, -1390, -930, -4270, -2990, -5888, -3014, -990, -2590, -7936, -5073, -4664, -1563, -3137, -10210, -4555, -5061, -2414, -7445, -6035, -4985, -4357, -3042, -7247, -2813, -6256, -3309, -3225, -4601, -1790, -5286, -2068, -3580, -5678, -2762, -3563, -1158, -5061, -6914, -7484, -3078, -849, -8454, -3704, -6928, -3913, -1121, -7317, -2083, -4319, -6246, -1507, -6504, -1624, -5073, -8903, -1521, -6666, -2095, -8942, -6988, -1499, -4963, -3490, -8903, -5121, -1668, -3441, -5810, -5437, -4311, -1918, -2900, -6773, -3971, -4640, -2062, -3650, -4826, -3476, -5584, -1869, -6321, -3237, -3893, -5630, -1827, -10138, -2213, -5109, -5273, -2617, -10704, -1868, -6492, -5569, -4630, -11232, -2455, -6565, -6183, -6943, -5221, -4447, -6123, -7230, -5415, -3386, -8790, -5836, -9873, -4089, -3184, -8615, -5539, -9753, -3840, -4369, -6705, -5380, -8517, -4935, -6528, -5524, -5408, -9873, -9479, -6133, -4951, -5751, -11232, -6267, -5979, -5266, -6628, -10799, -3321, -8393, -6246, -7888, -12319, -2666, -7819, -6973, -8363, -11232, -3422, -5933, -7050, -6204, -9936, -5509, -6565, -6679, -4447, -9639, -9064, -8454, -7865, 6384, 8433, 6336, -1661, 2254, 6190, 7798, 6460, 4567, 4610, 5623, 6069, 6709, 6674, 5012, 4822, 4554, 6703, 6995, 3751, 3834, 3798, 5914, 5827, 458, 2226, 1892, 3772, 2775, -1699, 919, -2082, 1070, 361, -1205, 1609, -7162, 1990, 1068, -4578, 1643, -3184, 1957, 2505, -3412, 715, -877, 2185, 5062, 1287, 500, -36, 3480, 6450, 3364, 1762, 233, 3873, 6837, 4204, 2522, 91, 2879, 6135, 3929, 2207, -1136, -383, 3287, 2281, 788, -5319, -6602, 1016, -1621, -2222, -1546, -911, 5163, -1417, -6399, 602, -1000, 6003, 314, -1749, 715, -2538, 5599, -180, -1145, -336, -3284, 5076, -2475, -3656, -1872, -3535, 4641, -7230, -3957, -3306, -1466, 3675, -14195, -678, -3571, -320, 2228, -8009, -95, -3269, -952, 907, -4451, -1287, -3529, -3311, 22, -3375, -4880, -2945, -5751, -427, -4100, -8276, -1433, -5458, -1026, -8009, -7034, -302, -5008, -1895, -6225, -5646, 172, -4403, -1174, -2648, -2351, 92, -4035, -23, -1707, -1615, -535, -3751, 230, -2340, -2964, -1887, -3140, -276, -3632, -5710, -3680, -2605, -1382, -2845, -4416, -4071, -3436, -4184, -1916, -2918, -2391, -6411, -5306, -1193, -2234, -422, -1541, -1468, 25, -2686, 676, 819, -617, 708, -4583, 616, 1322, -1187, 154, -4693, -595, 305, -2733, -2350, -2639, -810, -2528, -5346, -5109, -1642, 636, -12534, -2644, -2534, -1726, 1346, -3811, -352, -3600, -1944, 1705, -1487, 634, -2813, -585, 1998, -1370, 995, 746, 581, 1725, -3485, 1000, 1936, 794, 496, -12534, 578, 1525, 184, -1491, -6553, -574, -590, -981, -1893, -5387, -2650, -6434, -2317, -783, -4718, -5049, -5374, -3316, -217, -4361, -7708, -3763, -3677, -430, -4708, -14195, -5227, -3618, -1553, -4896, -7644, -8649, -3482, -3992, -4779, -6376, -5247, -3632, -7113, -4912, -6565, -3886, -4473, -5516, -5085, -5942, -4211, -6492, -4929, -5422, -4759, -5776, -9812, -5615, -6705, -4234, -7687, -8165, -6480, -8982, -4013, -7888, -5776, -7196, -7912, -3412, -7665, -4420, -9753, -6434, -2589, -7665, -3766, -15615, -5494, -2086, -6786, -3589, -8485, -4270, -2326, -5970, -3930, -7408, -3189, -3763, -6045, -5279, -8247, -2781, -7936, -6214, -9936, -9479, -3244, -8549, -6153, -7865, -9753, -4587, -4278, -6679, -4282, -9331, -6640, -2747, -7888, -3347, -8942, -7960, -2222, -8754, -4031, -8363, -8165, -2447, -7912, -6214, -5360, -8615, -3269, -6376, -6943, -4082, -8718, -4180, -5260, -5576, -4597, -8138, -4234, -4880, -4640, -6093, -8086, -3460, -5576, -4127, -6679, -9022, -2662, -7542, -4311, -7960, -11781, -2289, -7353, -5458, -9639, -13738, -2447, -7408, -7936, -7730, -8790, -3232, -11356, -10899, -7162, -7623, -4863, -5346, -8192, -8423, -8454, -7004, -3388, -6653, -14784, -10704, -7230, -3404, -6332, -11115, -10442, -7281, -8009, -3903, -7687, -12776, -5387, -5189, -3686, -6422, -9429, -4991, -4555, -3686, -6183, -7623, -5915, -4935, -3710, -6256, -6469, -8549, -5694, -3808, -5862, -6457, -7389, -7426, -4611, -5380, -7464, -6123, -8276, -6759, -5702, -6504, -6786, -5759, -11488, -7066, -4957, -7623, -4282, -13738, -9429, -4541, -7389, -3571, -10284, -11781, -5133, -7162, -3269, -8790, -11004, -6054, -6133, -3242, -8549, -8423, -6288, -5152, -3546, -8549, -7281, -6492, -4929, -4344, -7687, -6828, -7603, -5260, -6016, -7730, -6516, -8942, -5623, -10210, -8903, -6786, -8423, -5630, -11232, -8454, -7774, -8363, -5524, -7583, -7730, -9064, -9284, -5801, -7179, -6504, -9149, -11945, -6899, -8649, -5109, -6899, -10362, -8827, -11629, -4640, -5353, -6759, -8649, -11629, -5279, -5055, -5247, -7464, -9331, -7004, -5630, -4810, -7603, -6899, -8112, -5942, -5133, -9284, -5539, -6653, -5592, -6026, -12534, -5429, -5801, -6016, -6914, -11356, -6590, -5623, -8454, -7004, -9695, -8683, -5561, -11115, -6943, -8304, -10362, -5312, -7888, -7865, -6885, -9331, -5020, -7264, -10001, -5630, -7281, -4935, -8138, -9695, -4968, -6343, -5415, -10799, -7097, -5292, -6565, -6705, -28777, -5662, -6814, -7353, -7484, -9429, -5401, -8517, -7912, -6540, -7503, -6045, -7644, -8333, -6214, -7445, -7130, -7113, -8138, -6899, -8454, -7752, -7796, -7623, -8192, -9873, -7335, -8649, -7230, -9585, -10613, -6732, -7774, -7299, -10704, -9873, -6692, -5988, -8165, -10899, -8060, -7113, -4805, -9284, -10210, -7371, -7445, -4644, -8865, -9284, -8220, -7426, -5836, -8718, -7819, -11781, -6602, -9149, -8333, -6958, -14195, -5670, -9479, -7542, -7299, -10362, -5599, -7196, -7796, -8982, -8982, -6422, -6705, -10210, -9753, -7665, -8112, -6640, -17034, -8827, -6422, -10704, -6376, -9531, -9193, -5836, -10442, -6399, -8485, -11629, -6007, -8549, -7081, -9531, -13049, -6856, -8060, -8517, -13049, -11232, -7819, -9149, -10362, -28777, -10284, -8060, -13738, -10613, -14195, -8683, -8333, -11232, -9429, -11356, -7912, -9585, -8086, -8086, -8942, -8615, -13738, -7066, -7774, -7484, -12319, -28777, -7247, -8903, -7408, -14195, -12123, -8363, -13365, -9380, -9753, -12776, -10526, -12776, -13738, -8982, -12319, -12776, -11004, -7936, -9284, -8393, -13738, -13049, -6288, -9238, -6434, -13365, -10069, -6445, -8485, -5718, -11945, -7523, -8333, -8112, -5951, -10613, -6504, -12123, -8423, -7213, -10526, -6321, -9022, -9238, -9639, -10284, -7081, -7644, -9873, -12319, -9238, -9193, -8423, -10138, -12123, -9149, -12123, -11004, -10284, -14195, -10442, -12534, -10069, -10210, -28777, -12123, -10210, -9284, -10069, -12123, -12319, -8304, -11356, -11356, -10442, -10138, -7687, -14784, -28777, -9873, -8827, -7936, -10613, -13365, -9531, -8790, -8865, -9106, -11004, -8790, -10284, -10526, -9193, -10526, -8112, -13738, -14195, -10138, -10899, -7730, -28777, -28777, -10138, -11945, -7865, -17034, -13365, -10210, -10138, -8485, -15615, -12123, -6246, -4003, -9331, -11945, -9284, -5569, -5002, -9531, -9284, -13049, -4728, -7426, -10526, -7081, -9873, -4238, -8393, -11945, -5793, -7464, -4504, -7426, -11488, -5401, -6602, -5759, -6422, -9479, -5801, -5121, -7960, -5561, -8333, -6692, -4031, -10284, -5599, -7960, -7562, -4064, -12776, -6800, -8060, -8582, -5451, -11232, -8165, -8485, -8790, -9064, -8615, -8276, -8485, -6870, -11945, -7503, -7819, -6814, -6026, -8649, -7213, -7335, -5360, -6928, -8034, -7113, -7464, -5139, -10704, -8903, -6666, -8683, -5988, -11356, -12123, -5951, -11232, -5960, -7687, -12776, -5458, -13365, -5189, -6422, -9331, -5360, -10526, -5710, -6204, -8423, -5546, -9331, -7819, -6786, -8942, -5710, -8718, -8112, -8393, -9753, -5638, -6590, -7583, -10799, -8454, -5607, -4713, -10001, -9585, -7299, -5678, -4097, -11356, -8138, -6914, -5638, -4779, -5979, -7842, -7408, -5853, -6842, -4491, -7865, -8903, -6885, -10613, -4759, -7130, -10001, -7542, -28777, -6516, -6143, -9238, -5906, -12319, -8454, -5607, -7912, -4764, -9695, -8086, -5615, -6388, -4874, -9238, -8582, -5888, -5472, -6299, -9936, -9936, -6267, -5465, -10362, -11488, -8942, -6666, -6679, -12534, -14784, -8009, -7335, -10210, -8549, -11629, -8112, -9064, -11781, -8086, -9331, -8138, -11945, -7819, -8333, -9284, -7644, -12534, -6899, -8517, -10284, -6842, -28777, -7264, -9936, -9936, -6133, -9149, -8276, -10526, -9585, -6553, -6469, -9238, -7912, -8982, -9695, -5408, -10069, -6411, -7146, -11629, -5202, -11356, -5960, -6204, -7936, -5988, -13365, -6321, -6246, -7774, -7888, -11945, -7708, -6732, -8086, -7960, -10138, -9753, -7050, -7371, -6828, -9429, -9479, -6870, -6602, -6469, -9284, -8247, -6553, -6194, -6732, -9149, -8220, -6577, -6267, -7644, -9331, -8903, -7299, -7213, -9106, -10138, -9812, -8582, -9585, -10526, -13738, -10526, -8754, -13049, -12534, -14195, -11115, -8304, -10899, -28777, -9284, -11781, -8718, -9429, -11629, -7936, -12123, -10284, -8982, -10069, -8165, -12776, -13049, -9193, -11356, -9753, -14195, -28777, -10899, -17034, -10613, -13365, -13049, -12123, -17034, -8615, -9429, -11232, -8754, -13738, -7179, -7796, -11781, -7213, -9331, -6719, -7752, -14195, -7050, -7196, -7081, -8827, -11488, -7774, -6842, -8333, -10069, -9106, -8485, -8165, -10799, -10362, -9064, -8034, -12319, -28777, -10613, -11781, -7113, -28777, -12534, -12123, -11629, -6943, -13049, -10001, -14195, -8903, -8363, -11115, -9331, -12534, -8615, -12319, -10138, -9380, -10210, -9695, -13049, -10899, -9238, -8790, -10704, -12319, -11781, -9585, -7912, -9873, -11945, -10899, -10704, -7353, -8827, -9639, -10526, -9479, -7426, -7888, -8942, -11004, -7960, -8517, -7299, -10138, -12123, -7542, -10526, -7562, -14195, -12319, -8060, -10069, -9064, -12776, -11115, -9331, -9193, -12534, -10210, -11356, -10799, -10138, -17034, -9873, -12534, -11629, -14784, -15615, -10704, -11115, -12123, -13738, -14784, -11004, -9812, -11629, -10442, -12123, -10362, -10138, -10362, -4863, -7264, -8363, -10001, -8582, -7353, -10138, -7842, -11004, -7146, -7335, -12776, -8615, -12534, -5702, -5915, -10613, -10284, -28777, -6299, -5997, -11232, -12534, -11629, -9531, -8393, -13738, -12319, -10138, -8615, -10799, -9812, -11004, -13365, -6615, -6732, -7281, -11945, -13738, -6885, -5346, -5759, -28777, -9429, -9284, -5429, -4968, -15615, -8138, -13365, -7299, -4923, -12319, -7213, -8982, -11945, -5286, -10613, -7034, -7774, -8754, -5524, -9429, -8276, -7960, -7503, -5472, -9531, -12319, -8718, -7097, -5768, -13049, -10284, -9695, -6615, -7408, -10526, -7484, -10799, -6814, -11945, -7317, -6434, -9064, -8754, -17034, -6214, -6267, -7230, -10284, -12534, -5195, -6786, -6516, -7542, -7842, -3989, -8192, -6719, -7113, -6399, -3422, -11115, -7819, -8454, -6914, -3930, -11004, -8549, -9193, -8220, -5380, -8485, -7371, -8304, -8423, -6457, -7281, -6288, -8615, -8582, -6745, -6492, -5915, -9429, -9812, -7464, -5906, -6214, -8827, -11488, -9753, -5630, -6828, -7583, -10899, -14784, -5784, -6988, -6123, -11004, -7842, -6143, -6256, -4847, -9479, -6225, -6288, -5374, -4161, -7162, -6093, -6480, -4974, -4075, -6074, -6504, -6773, -5158, -4523, -5879, -6870, -7179, -5853, -5561, -6163, -7004, -8549, -7213, -7583, -6705, -7247, -12319, -9238, -9695, -6973, -8363, -11232, -9936, -8517, -6885, -11781, -8485, -8649, -8582, -7752, -13738, -7730, -7426, -11004, -11232, -10138, -7819, -7034, -13738, -14195, -10138, -7960, -7389, -13049, -10613, -12319, -7960, -7819, -13738, -9022, -12319, -8333, -8423, -13365, -7264, -11781, -9639, -9812, -17034, -6745, -14195, -11945, -10799, -12319, -7264, -14784, -12123, -12123, -8112, -8086, -9531, -10704, -11629, -6628, -8423, -6914, -10899, -8649, -6332, -8615, -5592, -11781, -7426, -6666, -9064, -5360, -13738, -6899, -7317, -9753, -6214, -17034, -6928, -8549, -10210, -8942, -10799, -7730, -10526, -10899, -28777, -8165, -9531, -10899, -12776, -9695, -7097, -12319, -10799, -11781, -8754, -7050, -28777, -13738, -9238, -10442, -7484, -12123, -14195, -8903, -13738, -7796, -8683, -11629, -11356, -10362, -7842, -7034, -12123, -15615, -9380, -8034, -6246, -11945, -9380, -10442, -8517, -6628, -10210, -8582, -13365, -9149, -8790, -9812, -9695, -13365, -9380, -13738, -10001, -11004, -11629, -9479, -13365, -9238, -10799, -10442, -10526, -10526, -8060, -11232, -10799, -13049, -7960, -7247, -12319, -12319, -14195, -6653, -6928, -12319, -15615, -13365, -6299, -7113, -12123, -28777, -12776, -6666, -7842, -11629, -28777, -10284, -7865, -9479, -12319, -28777, -8827, -10613, -13049, -14784, -28777, -8903, -17034, -28777, -17034, -14784, -10284, -13365, -13365, -12123, -11629, -12319, -14195, -12123, -11356, -9936, -13365, -28777, -11629, -11945, -9695, -11629, -14195, -11488, -12319, -10799, -10138, -13365, -11781, -10799, -13365, -9873, -14195, -11945, -10284, -12534, -11781, -14784, -12319, -11356, -11232, -28777, -13365, -11488, -17034, -11629, -11115, -10138, -9812, -13738, -13049, -9585, -8790, }; \ No newline at end of file diff --git a/sw/applications/trans_versasense/tokenPosEmbeddingC.c b/sw/applications/trans_versasense/tokenPosEmbeddingC.c new file mode 100644 index 00000000..39a63e40 --- /dev/null +++ b/sw/applications/trans_versasense/tokenPosEmbeddingC.c @@ -0,0 +1,33 @@ +// +// Created by alireza on 10/6/23. +// + +#include "tokenPosEmbeddingC.h" + + +void createTokenPosEmbedding(TokenPosEmbedding* tokenPosEmbedding, quant_bit_width* pos_matrix, quant_bit_width* cls_token_vector, size_t seq_len, size_t input_dim, size_t pos_matrix_dim) { + tokenPosEmbedding->cls_token_vector_ = cls_token_vector; + tokenPosEmbedding->pos_matrix_ = pos_matrix; + tokenPosEmbedding->seq_len_ = seq_len; + tokenPosEmbedding->input_dim_ = input_dim; +} + +void clsConcatenate(TokenPosEmbedding* tpe, quant_bit_width* input, quant_bit_width* concatenated_input) { + // Copy cls_token_ into the concatenated array column-wise at the beginning + for (size_t i = 0; i < tpe->input_dim_; ++i) { + concatenated_input[i] = tpe->cls_token_vector_[i]; + } + // Copy the input array into the concatenated array + for (size_t i = 0; i < tpe->seq_len_ * tpe->input_dim_; ++i) { + concatenated_input[i + tpe->input_dim_] = input[i]; + } +} + +void posEmbedding(TokenPosEmbedding* tpe, quant_bit_width* input) { + for (size_t i = 0; i < (tpe->seq_len_ + 1); ++i) { + for (size_t j = 0; j < tpe->input_dim_; ++j) { + input[i * tpe->input_dim_+ j] += tpe->pos_matrix_[i * tpe->input_dim_ + j]; + } + } +} + diff --git a/sw/applications/trans_versasense/tokenPosEmbeddingC.h b/sw/applications/trans_versasense/tokenPosEmbeddingC.h new file mode 100644 index 00000000..9357a153 --- /dev/null +++ b/sw/applications/trans_versasense/tokenPosEmbeddingC.h @@ -0,0 +1,24 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H +#define FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H + +#include "param.h" +#include "stdlib.h" + +typedef struct{ + quant_bit_width* cls_token_vector_; + quant_bit_width* pos_matrix_; + size_t seq_len_; + size_t input_dim_; +} TokenPosEmbedding; + + +void createTokenPosEmbedding(TokenPosEmbedding*, quant_bit_width* pos_matrix, quant_bit_width* cls_token_vector, size_t seq_len, size_t input_dim, size_t pos_matrix_dim); +void clsConcatenate(TokenPosEmbedding* tpe, quant_bit_width* input, quant_bit_width* concatenated_input); +void posEmbedding(TokenPosEmbedding* tpe, quant_bit_width* input); + + +#endif //FVLLMONTITRANSFORMER_TOKENPOSEMBEDDINGC_H diff --git a/sw/applications/trans_versasense/transformerBlockC.c b/sw/applications/trans_versasense/transformerBlockC.c new file mode 100644 index 00000000..111a36af --- /dev/null +++ b/sw/applications/trans_versasense/transformerBlockC.c @@ -0,0 +1,116 @@ +// +// Created by alireza on 10/6/23. +// + +#include +#include "transformerBlockC.h" +#include "multiply_cgra.h" + +SingleHeadSelfAttn global_selfatten [NUM_LAYERS * NUM_HEAD]; +Dense global_query_layer[NUM_LAYERS * NUM_HEAD]; +Dense global_key_layer[NUM_LAYERS * NUM_HEAD]; +Dense global_value_layer[NUM_LAYERS * NUM_HEAD]; + +Dense global_condense[NUM_LAYERS]; +Dense global_patch; +Dense global_FF[NUM_LAYERS * 2]; +Dense global_mlp; + +TransformerBlock global_transformer_block; +TokenPosEmbedding global_token_embedding; + +TransformerBlock* createTransformerBlock(size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, size_t num_heads, size_t ff_size, int32_t** weightVector, int32_t** biasVector, int32_t* clsTokenVector, int32_t* posMatrix) { + TransformerBlock* transformerBlock = &global_transformer_block; + transformerBlock->num_heads_ = num_heads; + transformerBlock->head_hidden_size_ = head_hidden_size; + transformerBlock->input_dim_ = input_dim; + transformerBlock->ff_size_ = ff_size; + + transformerBlock->addNorm = createAddNormalize(pre_seq_len, D_EMBEDDING, weightVector[0], biasVector[0]); + transformerBlock->patchEmbedding = &global_patch; + createDense(transformerBlock->patchEmbedding, D_EMBEDDING, D_MODEL, weightVector[1], biasVector[1]); + transformerBlock->addNorm2 = createAddNormalize(pre_seq_len, D_MODEL, weightVector[2], biasVector[2]); + transformerBlock->token = &global_token_embedding; + createTokenPosEmbedding(transformerBlock->token, posMatrix, clsTokenVector, pre_seq_len, input_dim, D_SEQ + 1); + + for (int l = 0; l < 4; l++) { + transformerBlock->transformer_layer_0_addNorm[l] = createAddNormalize((pre_seq_len + 1), D_MODEL, weightVector[l * 17 + 3], biasVector[l * 17 + 3]); + + for (int n = 0; n < num_heads; n++) { + transformerBlock->selfatten[l * num_heads + n] = &global_selfatten[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->query_layer = &global_query_layer[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->key_layer = &global_key_layer[l * num_heads + n]; + transformerBlock->selfatten[l * num_heads + n]->value_layer = &global_value_layer[l * num_heads + n]; + + create_SingleHeadSelfAttn(transformerBlock->selfatten[l * num_heads + n], (pre_seq_len + 1), input_dim, head_hidden_size, weightVector + l * 17 + 4 + n * 3); + } + + transformerBlock->condense[l] = &global_condense[l]; + createDense(transformerBlock->condense[l], num_heads * head_hidden_size, input_dim, weightVector[l * 17 + num_heads * 3 + 4], biasVector[l * 17 + num_heads * 3 + 4]); + + transformerBlock->transformer_layer_1_addNorm[l] = createAddNormalize((pre_seq_len + 1), input_dim, weightVector[l * 17 + num_heads * 3 + 5], biasVector[l * 17 + num_heads * 3 + 5]); + + transformerBlock->feedForward0[l] = &global_FF[2*l]; + createDense(transformerBlock->feedForward0[l], input_dim, ff_size, weightVector[l * 17 + num_heads * 3 + 6], biasVector[l * 17 + num_heads * 3 + 6]); + + transformerBlock->feedForward1[l] = &global_FF[2*l + 1]; + createDense(transformerBlock->feedForward1[l], ff_size, input_dim, weightVector[l * 17 + num_heads * 3 + 7], biasVector[l * 17 + num_heads * 3 + 7]); + } + + transformerBlock->mlp_head_norm = createAddNormalize(1, D_MODEL, weightVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 8], biasVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 8]); + + transformerBlock->mlp_head_linear = &global_mlp; + createDense(transformerBlock->mlp_head_linear, D_MODEL, D_MODEL, weightVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 9], biasVector[(NUM_LAYERS - 1) * 17 + NUM_HEAD * 3 + 9]); + + return transformerBlock; +} + + +void destroyTransformerBlock(TransformerBlock* transformerBlock) { + // Free dynamically allocated memory + + free(transformerBlock); +} + +void computeFixedPoint(TransformerBlock* transformerBlock, size_t seq_len, quant_bit_width * input, + quant_bit_width * input_normalized, quant_bit_width * output, + quant_bit_width* intermediate, quant_bit_width* qkv, quant_bit_width * aux_padding, void * kperf) { + + //printf("\rStep 1\n"); + normalize(&transformerBlock->addNorm, input, input); // 12x400 + computeDense(transformerBlock->patchEmbedding, seq_len, input, output); // 12x400x16 -> OK + normalize(&transformerBlock->addNorm2, output, output); // 12x16 + + clsConcatenate(transformerBlock->token, output, input); // 13x16 + seq_len++; + posEmbedding(transformerBlock->token, input); // 13x16 + + //printf("\rStep 2\n"); + for (int l = 0; l < 4; l++) { + normalize(&transformerBlock->transformer_layer_0_addNorm[l], input, input_normalized); // 13x16 + for (int n = 0; n < NUM_HEAD; n++) { + // printf("\rl%d: Step 3\n", l); + compute_SingleHeadSelfAttn(transformerBlock->selfatten[l * NUM_HEAD + n], input_normalized, + output + n * (seq_len * transformerBlock->head_hidden_size_), qkv, intermediate, aux_padding); +// destroy_SingleHeadSelfAttn(transformerBlock->selfatten[l * NUM_HEAD + n]); + } + //printf("\rl%d: Step 4\n", l); + multihead_transpose(output, intermediate, seq_len, transformerBlock->head_hidden_size_, transformerBlock->num_heads_); + + int padding = 3; + computeDense(transformerBlock->condense[l], seq_len + padding, intermediate, output); // 13x16x16 + + add(input, output, seq_len, transformerBlock->input_dim_ ); // 13x16 + + normalize(&transformerBlock->transformer_layer_1_addNorm[l], input, input_normalized); // 13x16 + computeDense(transformerBlock->feedForward0[l], seq_len + padding, input_normalized, intermediate); // 13x16x4 + activation(transformerBlock->feedForward0[l], seq_len * transformerBlock->ff_size_, intermediate, intermediate); // 13x4 + + computeDense(transformerBlock->feedForward1[l], seq_len + padding, intermediate, output); // 13x4x16 + add(input, output, seq_len, transformerBlock->input_dim_ ); // 13x16 + } + //printf("\rStep 5\n"); + normalize(&transformerBlock->mlp_head_norm, input, input_normalized); // 13x16 + computeDenseOneRow(transformerBlock->mlp_head_linear, 1, input_normalized, output); // 1x16x16 +} + diff --git a/sw/applications/trans_versasense/transformerBlockC.h b/sw/applications/trans_versasense/transformerBlockC.h new file mode 100644 index 00000000..f783d2a7 --- /dev/null +++ b/sw/applications/trans_versasense/transformerBlockC.h @@ -0,0 +1,48 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H +#define FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H + +#include +#include +#include "selfattentionC.h" +#include "addNormC.h" +#include "dense_layerC.h" +#include "tokenPosEmbeddingC.h" +#include "param.h" +#include "transposeC.h" +#include "cgra.h" + +typedef struct { + size_t num_heads_; + size_t head_hidden_size_; + size_t input_dim_; + size_t ff_size_; + SingleHeadSelfAttn* selfatten[NUM_LAYERS*NUM_HEAD]; + int32_t* multihead_out; + int32_t* condense_out; + int32_t* intermediateFF; + int32_t* intermediateFFBlockWise; + AddNormalize addNorm; + AddNormalize addNorm2; + AddNormalize transformer_layer_0_addNorm[NUM_LAYERS]; + AddNormalize transformer_layer_1_addNorm[NUM_LAYERS]; + AddNormalize mlp_head_norm; + TokenPosEmbedding* token; + Dense* condense[NUM_LAYERS]; + Dense* feedForward0[NUM_LAYERS]; + Dense* feedForward1[NUM_LAYERS]; + Dense* patchEmbedding; + Dense* mlp_head_linear; + #ifndef REARRANGE + int32_t* multihead_out_reshape; + #endif +} TransformerBlock; + +TransformerBlock* createTransformerBlock(size_t pre_seq_len, size_t input_dim, size_t head_hidden_size, size_t num_heads, size_t ff_size, int32_t** weightVector, int32_t** biasVector, int32_t* clsTokenVector, int32_t* posMatrix); +void destroyTransformerBlock(TransformerBlock* transformerBlock); +void computeFixedPoint(TransformerBlock* transformerBlock, size_t seq_len, int32_t* input, int32_t* input_normalized, int32_t* output, int32_t* intermediate, int32_t* aux_padding, int32_t* qkv, void * kperf); + +#endif //FVLLMONTITRANSFORMER_TRANSFORMERBLOCK_H diff --git a/sw/applications/trans_versasense/transposeC.c b/sw/applications/trans_versasense/transposeC.c new file mode 100644 index 00000000..2c27aa52 --- /dev/null +++ b/sw/applications/trans_versasense/transposeC.c @@ -0,0 +1,31 @@ +// +// Created by alireza on 10/6/23. +// + +#include "softmaxC.h" + + +void multihead_transpose(const quant_bit_width * input, quant_bit_width* output, size_t seq_len, + size_t head_hidden_size, size_t num_head) { + const quant_bit_width * initial_input = input; + for (int i=0; i < seq_len; i++){ + for (int n=0; n< num_head; n++){ + input = initial_input + i*head_hidden_size + n*seq_len*head_hidden_size; + for (int j=0; j < head_hidden_size; j++){ + *output++ = *input++; + } + } + } +} + + +void transpose_quant(const quant_bit_width * input, quant_bit_width* output, + size_t width, size_t height) { + for (size_t i = 0; i < height; i++) { + for (size_t j = 0; j < width; j++) { + output[i * width + j] = input[j * height + i]; + } + } +} + + diff --git a/sw/applications/trans_versasense/transposeC.h b/sw/applications/trans_versasense/transposeC.h new file mode 100644 index 00000000..500c100e --- /dev/null +++ b/sw/applications/trans_versasense/transposeC.h @@ -0,0 +1,22 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_TRANSPOSEC_H +#define FVLLMONTITRANSFORMER_TRANSPOSEC_H + + + +#include +#include "param.h" + +// Replace class with struct +typedef struct { + // struct members +} Transpose; + +// Function prototypes +void transpose_quant(const quant_bit_width* input, quant_bit_width* output, size_t width, size_t height); +void multihead_transpose(const quant_bit_width * input, quant_bit_width* output, size_t seq_len, size_t head_hidden_size, size_t num_head); + +#endif //FVLLMONTITRANSFORMER_TRANSPOSEC_H diff --git a/sw/applications/trans_versasense/weightsAndBiasesC.c b/sw/applications/trans_versasense/weightsAndBiasesC.c new file mode 100644 index 00000000..2fd600f0 --- /dev/null +++ b/sw/applications/trans_versasense/weightsAndBiasesC.c @@ -0,0 +1,181 @@ +// +// Created by alireza on 10/6/23. +// +#include "weightsAndBiasesC.h" +#include +#include +#include "data_cpp/data.cpp" + +void getWeights(quant_bit_width * weightVec[]){ + + int weightVectorIndex = 0; + weightVec[weightVectorIndex++] = to_patch_embedding_layer_norm1_weight; + weightVec[weightVectorIndex++] = to_patch_embedding_linear_weight; + weightVec[weightVectorIndex++] = to_patch_embedding_layer_norm2_weight; + + + /* *************************** Layer 1 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_0_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_0_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_0_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_0_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_0_1_fn_ff2_weight; + + /* *************************** Layer 2 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_1_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_1_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_1_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_1_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_1_1_fn_ff2_weight; + + /* *************************** Layer 3 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_2_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_2_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_2_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_2_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_2_1_fn_ff2_weight; + + /* *************************** Layer 4 ***************************** */ + weightVec[weightVectorIndex++] = transformer_layers_3_0_norm_weight; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H0; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H1; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H2; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_Q_H3; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_K_H3; + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_to_qkv_weight_V_H3; + + weightVec[weightVectorIndex++] = transformer_layers_3_0_fn_projection_weight; + + weightVec[weightVectorIndex++] = transformer_layers_3_1_norm_weight; + + weightVec[weightVectorIndex++] = transformer_layers_3_1_fn_ff1_weight; + weightVec[weightVectorIndex++] = transformer_layers_3_1_fn_ff2_weight; + + /* *************************** MLP HEAD ***************************** */ + weightVec[weightVectorIndex++] = mlp_head_layer_norm_weight; + weightVec[weightVectorIndex++] = mlp_head_linear_weight; + +} + +void getBiases(quant_bit_width * biasVec[]){ + int biasVectorIndex = 0; + biasVec[biasVectorIndex++] = to_patch_embedding_layer_norm1_bias; + biasVec[biasVectorIndex++] = to_patch_embedding_linear_bias; + biasVec[biasVectorIndex++] = to_patch_embedding_layer_norm2_bias; + + /* *************************** Layer 1 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_0_0_norm_bias; + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_0_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_0_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_0_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_0_1_fn_ff2_bias; + + /* *************************** Layer 2 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_1_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_1_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_1_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_1_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_1_1_fn_ff2_bias; + + /* *************************** Layer 3 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_2_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_2_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_2_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_2_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_2_1_fn_ff2_bias; + + /* *************************** Layer 4 ***************************** */ + biasVec[biasVectorIndex++] = transformer_layers_3_0_norm_bias; + + for (int i=0; i<3*4; i++) + biasVec[biasVectorIndex++] = (quant_bit_width *) NULL; + + biasVec[biasVectorIndex++] = transformer_layers_3_0_fn_projection_bias; + biasVec[biasVectorIndex++] = transformer_layers_3_1_norm_bias; + + biasVec[biasVectorIndex++] = transformer_layers_3_1_fn_ff1_bias; + biasVec[biasVectorIndex++] = transformer_layers_3_1_fn_ff2_bias; + + /* *************************** MLP HEAD ***************************** */ + biasVec[biasVectorIndex++] = mlp_head_layer_norm_bias; + biasVec[biasVectorIndex++] = mlp_head_linear_bias; +} + +quant_bit_width * getPosEmbedding(){ + quant_bit_width * posMatrix; + posMatrix = pos_embedding; + return posMatrix; +} + +quant_bit_width * getClassToken(){ + quant_bit_width * clsTokenVector; + clsTokenVector = cls_token; + return clsTokenVector; +} + + diff --git a/sw/applications/trans_versasense/weightsAndBiasesC.h b/sw/applications/trans_versasense/weightsAndBiasesC.h new file mode 100644 index 00000000..b16d6468 --- /dev/null +++ b/sw/applications/trans_versasense/weightsAndBiasesC.h @@ -0,0 +1,15 @@ +// +// Created by alireza on 10/6/23. +// + +#ifndef FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H +#define FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H + +#include "param.h" + +void getWeights(quant_bit_width * weightVec[]); +void getBiases(quant_bit_width * biasVec[]); +quant_bit_width * getPosEmbedding(); +quant_bit_width * getClassToken(); + +#endif //FVLLMONTITRANSFORMER_WEIGHTSANDBIASESC_H From f5434756ccdda49c5932094185159162a03dc267 Mon Sep 17 00:00:00 2001 From: mbelda <11842513+mbelda@users.noreply.github.com> Date: Tue, 9 Jul 2024 12:25:46 +0200 Subject: [PATCH 14/27] adapt minimal cfg for the cgra --- .../core-v-mini-mcu/peripheral_subsystem.sv | 135 ++++++------------ .../esl_epfl_x_heep/mcu_cfg_minimal.hjson | 4 +- sw/applications/trans_versasense/SYLT-FFT | 1 + .../transformer_without_cgra/SYLT-FFT | 1 + 4 files changed, 49 insertions(+), 92 deletions(-) create mode 160000 sw/applications/trans_versasense/SYLT-FFT create mode 160000 sw/applications/transformer_without_cgra/SYLT-FFT diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv index 5c28e195..bb1c1d19 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv @@ -292,21 +292,10 @@ module peripheral_subsystem ); - gpio #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) gpio_i ( - .clk_i(clk_cg), - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::GPIO_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_IDX]), - .gpio_in({cio_gpio_i, 8'b0}), - .gpio_out({cio_gpio_o, cio_gpio_unused}), - .gpio_tx_en_o({cio_gpio_en_o, cio_gpio_en_unused}), - .gpio_in_sync_o(), - .pin_level_interrupts_o({gpio_intr, gpio_int_unused}), - .global_interrupt_o() - ); + assign cio_gpio_o = '0; + assign cio_gpio_en_o = '0; + assign gpio_intr = '0; + assign peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_IDX] = '0; reg_to_tlul #( .req_t(reg_pkg::reg_req_t), @@ -325,34 +314,27 @@ module peripheral_subsystem .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2C_IDX]) ); - i2c i2c_i ( - .clk_i(clk_cg), - .rst_ni, - .tl_i(i2c_tl_h2d), - .tl_o(i2c_tl_d2h), - .cio_scl_i, - .cio_scl_o, - .cio_scl_en_o, - .cio_sda_i, - .cio_sda_o, - .cio_sda_en_o, - .intr_fmt_watermark_o(i2c_intr_fmt_watermark), - .intr_rx_watermark_o(i2c_intr_rx_watermark), - .intr_fmt_overflow_o(i2c_intr_fmt_overflow), - .intr_rx_overflow_o(i2c_intr_rx_overflow), - .intr_nak_o(i2c_intr_nak), - .intr_scl_interference_o(i2c_intr_scl_interference), - .intr_sda_interference_o(i2c_intr_sda_interference), - .intr_stretch_timeout_o(i2c_intr_stretch_timeout), - .intr_sda_unstable_o(i2c_intr_sda_unstable), - .intr_trans_complete_o(i2c_intr_trans_complete), - .intr_tx_empty_o(i2c_intr_tx_empty), - .intr_tx_nonempty_o(i2c_intr_tx_nonempty), - .intr_tx_overflow_o(i2c_intr_tx_overflow), - .intr_acq_overflow_o(i2c_intr_acq_overflow), - .intr_ack_stop_o(i2c_intr_ack_stop), - .intr_host_timeout_o(i2c_intr_host_timeout) - ); + assign i2c_tl_d2h = '0; + assign cio_scl_o = '0; + assign cio_scl_en_o = '0; + assign cio_sda_o = '0; + assign cio_sda_en_o = '0; + assign i2c_intr_fmt_watermark = '0; + assign i2c_intr_rx_watermark = '0; + assign i2c_intr_fmt_overflow = '0; + assign i2c_intr_rx_overflow = '0; + assign i2c_intr_nak = '0; + assign i2c_intr_scl_interference = '0; + assign i2c_intr_sda_interference = '0; + assign i2c_intr_stretch_timeout = '0; + assign i2c_intr_sda_unstable = '0; + assign i2c_intr_trans_complete = '0; + assign i2c_intr_tx_empty = '0; + assign i2c_intr_tx_nonempty = '0; + assign i2c_intr_tx_overflow = '0; + assign i2c_intr_acq_overflow = '0; + assign i2c_intr_ack_stop = '0; + assign i2c_intr_host_timeout = '0; reg_to_tlul #( .req_t(reg_pkg::reg_req_t), @@ -380,56 +362,29 @@ module peripheral_subsystem .intr_timer_expired_1_0_o(rv_timer_3_intr_o) ); - spi_host #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) spi2_host ( - .clk_i(clk_cg), - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI2_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI2_IDX]), - .alert_rx_i(), - .alert_tx_o(), - .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), - .passthrough_o(), - .cio_sck_o(spi2_sck_o), - .cio_sck_en_o(spi2_sck_en_o), - .cio_csb_o(spi2_csb_o), - .cio_csb_en_o(spi2_csb_en_o), - .cio_sd_o(spi2_sd_o), - .cio_sd_en_o(spi2_sd_en_o), - .cio_sd_i(spi2_sd_i), - .rx_valid_o(), - .tx_ready_o(), - .intr_error_o(), - .intr_spi_event_o(spi2_intr_event) - ); + assign peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI2_IDX] = '0; + assign spi2_sck_o = '0; + assign spi2_sck_en_o = '0; + assign spi2_csb_o = '0; + assign spi2_csb_en_o = '0; + assign spi2_sd_o = '0; + assign spi2_sd_en_o = '0; + assign spi2_intr_event = '0; assign peripheral_slv_rsp[core_v_mini_mcu_pkg::PDM2PCM_IDX] = '0; - assign pdm2pcm_clk_o = '0; + assign pdm2pcm_clk_o = '0; - assign pdm2pcm_clk_en_o = 1; + assign pdm2pcm_clk_en_o = 1; - i2s #( - .reg_req_t(reg_pkg::reg_req_t), - .reg_rsp_t(reg_pkg::reg_rsp_t) - ) i2s_i ( - .clk_i, - .rst_ni, - .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::I2S_IDX]), - .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX]), - - .i2s_sck_o(i2s_sck_o), - .i2s_sck_oe_o(i2s_sck_oe_o), - .i2s_sck_i(i2s_sck_i), - .i2s_ws_o(i2s_ws_o), - .i2s_ws_oe_o(i2s_ws_oe_o), - .i2s_ws_i(i2s_ws_i), - .i2s_sd_o(i2s_sd_o), - .i2s_sd_oe_o(i2s_sd_oe_o), - .i2s_sd_i(i2s_sd_i), - .intr_i2s_event_o(i2s_intr_event), - .i2s_rx_valid_o(i2s_rx_valid_o) - ); + assign peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX] = '0; + + assign i2s_sck_oe_o = 1'b0; + assign i2s_sck_o = 1'b0; + assign i2s_ws_oe_o = 1'b0; + assign i2s_ws_o = 1'b0; + assign i2s_sd_oe_o = 1'b0; + assign i2s_sd_o = 1'b0; + assign i2s_intr_event = 1'b0; + assign i2s_rx_valid_o = 1'b0; endmodule : peripheral_subsystem diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson index 98440522..df3b6ad1 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson @@ -103,7 +103,7 @@ rv_plic: { offset: 0x00000000, length: 0x00010000, - is_included: "no", + is_included: "yes", path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson" }, gpio: { @@ -121,7 +121,7 @@ rv_timer: { offset: 0x00040000, length: 0x00010000, - is_included: "no", + is_included: "yes", path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_timer/data/rv_timer.hjson" }, spi2: { diff --git a/sw/applications/trans_versasense/SYLT-FFT b/sw/applications/trans_versasense/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/trans_versasense/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b diff --git a/sw/applications/transformer_without_cgra/SYLT-FFT b/sw/applications/transformer_without_cgra/SYLT-FFT new file mode 160000 index 00000000..c6f58caa --- /dev/null +++ b/sw/applications/transformer_without_cgra/SYLT-FFT @@ -0,0 +1 @@ +Subproject commit c6f58caa8d3d01c622768b5c66a0be1d7953235b From af41634c9940945d7e0b00ed0f495bda48cd1d7e Mon Sep 17 00:00:00 2001 From: jmiranda Date: Wed, 25 Sep 2024 20:36:34 +0200 Subject: [PATCH 15/27] revendorizing oe-cgra --- hw/vendor/esl_epfl_cgra/.gitignore | 12 + hw/vendor/esl_epfl_cgra/OpenEdgeCGRA.core | 54 + hw/vendor/esl_epfl_cgra/data/cgra_reg_gen.sh | 9 +- hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson | 271 ---- .../esl_epfl_cgra/data/cgra_regs.hjson.tpl | 93 ++ hw/vendor/esl_epfl_cgra/{ => hw}/rtl/alu.sv | 0 .../{ => hw}/rtl/cgra_controller.sv | 0 .../cgra_pkg.sv => hw/rtl/cgra_pkg.sv.tpl} | 51 +- .../esl_epfl_cgra/{ => hw}/rtl/cgra_rcs.sv | 24 +- .../esl_epfl_cgra/{ => hw}/rtl/cgra_top.sv | 38 +- .../{ => hw}/rtl/conf_reg_file.sv | 16 +- .../{ => hw}/rtl/context_memory.sv | 4 +- .../{ => hw}/rtl/context_memory_decoder.sv | 0 .../{ => hw}/rtl/data_bus_handler.sv | 14 +- .../esl_epfl_cgra/{ => hw}/rtl/datapath.sv | 10 +- hw/vendor/esl_epfl_cgra/{ => hw}/rtl/mux.sv | 0 .../hw/rtl/peripheral_regs.sv.tpl | 88 ++ .../{ => hw}/rtl/program_counter.sv | 0 .../{ => hw}/rtl/reconfigurable_cell.sv | 60 +- .../esl_epfl_cgra/{ => hw}/rtl/reg_file.sv | 16 +- .../{ => hw}/rtl/synchronizer.sv | 130 +- .../{ => hw}/wrapper/cgra_top_wrapper.sv | 106 +- hw/vendor/esl_epfl_cgra/lint/cgra.vlt | 48 +- hw/vendor/esl_epfl_cgra/rtl/cgra_reg_pkg.sv | 369 ----- hw/vendor/esl_epfl_cgra/rtl/cgra_reg_top.sv | 1339 ----------------- .../esl_epfl_cgra/rtl/peripheral_regs.sv | 117 -- .../esl_epfl_cgra/sim/cgra_sram_wrapper.sv | 2 +- hw/vendor/esl_epfl_cgra/sw/cgra_regs.h | 125 -- .../util/INSTRUCTIONS_FFT_SPLITOPS.py | 186 +++ .../cgra_bitstream_gen.py.tpl} | 62 +- .../util/instructions_check_size.py | 33 + .../instructions_dbl_max.py | 10 +- .../instructions_dbl_min.py | 10 +- .../util/instructions_fft_bitrev.py | 103 ++ .../instructions_fft_cplx.py | 12 +- .../instructions_fft_cplx_forever.py | 12 +- .../instructions_func_test.py | 64 +- .../util/instructions_max_peak.py | 87 ++ .../util/instructions_min_max_circular.py | 83 + .../instructions_while_loop_100percent.py | 32 +- .../instructions_while_loop_50percent.py | 16 +- .../instructions_while_loop_75percent.py | 24 +- .../{utilities => util}/log2file.py | 0 .../util/lowrisc_opentitan/reggen/README.md | 113 ++ .../util/lowrisc_opentitan/reggen/__init__.py | 0 .../util/lowrisc_opentitan/reggen/access.py | 121 ++ .../util/lowrisc_opentitan/reggen/alert.py | 54 + .../util/lowrisc_opentitan/reggen/bits.py | 87 ++ .../reggen/bus_interfaces.py | 187 +++ .../lowrisc_opentitan/reggen/enum_entry.py | 35 + .../util/lowrisc_opentitan/reggen/field.py | 291 ++++ .../lowrisc_opentitan/reggen/fpv_csr.sv.tpl | 177 +++ .../lowrisc_opentitan/reggen/gen_cfg_html.py | 113 ++ .../lowrisc_opentitan/reggen/gen_cheader.py | 439 ++++++ .../util/lowrisc_opentitan/reggen/gen_dv.py | 108 ++ .../util/lowrisc_opentitan/reggen/gen_fpv.py | 81 + .../util/lowrisc_opentitan/reggen/gen_html.py | 325 ++++ .../util/lowrisc_opentitan/reggen/gen_json.py | 34 + .../util/lowrisc_opentitan/reggen/gen_rtl.py | 136 ++ .../lowrisc_opentitan/reggen/gen_selfdoc.py | 306 ++++ .../lowrisc_opentitan/reggen/html_helpers.py | 83 + .../lowrisc_opentitan/reggen/inter_signal.py | 81 + .../util/lowrisc_opentitan/reggen/ip_block.py | 365 +++++ .../util/lowrisc_opentitan/reggen/lib.py | 262 ++++ .../reggen/multi_register.py | 142 ++ .../util/lowrisc_opentitan/reggen/params.py | 341 +++++ .../util/lowrisc_opentitan/reggen/reg_base.py | 45 + .../lowrisc_opentitan/reggen/reg_block.py | 431 ++++++ .../lowrisc_opentitan/reggen/reg_html.css | 74 + .../lowrisc_opentitan/reggen/reg_pkg.sv.tpl | 347 +++++ .../lowrisc_opentitan/reggen/reg_top.sv.tpl | 712 +++++++++ .../util/lowrisc_opentitan/reggen/register.py | 375 +++++ .../util/lowrisc_opentitan/reggen/signal.py | 63 + .../lowrisc_opentitan/reggen/uvm_reg.sv.tpl | 14 + .../reggen/uvm_reg_base.sv.tpl | 431 ++++++ .../util/lowrisc_opentitan/reggen/validate.py | 155 ++ .../util/lowrisc_opentitan/reggen/version.py | 24 + .../util/lowrisc_opentitan/reggen/window.py | 169 +++ .../util/lowrisc_opentitan/regtool.py | 235 +++ .../util/lowrisc_opentitan/topgen/__init__.py | 8 + .../util/lowrisc_opentitan/topgen/c.py | 444 ++++++ .../util/lowrisc_opentitan/topgen/gen_dv.py | 46 + .../lowrisc_opentitan/topgen/intermodule.py | 1005 +++++++++++++ .../util/lowrisc_opentitan/topgen/lib.py | 497 ++++++ .../util/lowrisc_opentitan/topgen/merge.py | 1081 +++++++++++++ .../topgen/templates/README.md | 4 + .../templates/chip_env_pkg__params.sv.tpl | 17 + .../topgen/templates/chiplevel.sv.tpl | 1218 +++++++++++++++ .../topgen/templates/clang-format | 4 + .../tb__alert_handler_connect.sv.tpl | 21 + .../topgen/templates/tb__xbar_connect.sv.tpl | 124 ++ .../topgen/templates/toplevel.c.tpl | 21 + .../topgen/templates/toplevel.h.tpl | 201 +++ .../topgen/templates/toplevel.sv.tpl | 832 ++++++++++ .../topgen/templates/toplevel_memory.h.tpl | 62 + .../topgen/templates/toplevel_memory.ld.tpl | 30 + .../topgen/templates/toplevel_pkg.sv.tpl | 112 ++ .../templates/toplevel_rnd_cnst_pkg.sv.tpl | 44 + .../templates/xbar_env_pkg__params.sv.tpl | 88 ++ .../util/lowrisc_opentitan/topgen/top.py | 122 ++ .../topgen/top_uvm_reg.sv.tpl | 151 ++ .../util/lowrisc_opentitan/topgen/validate.py | 878 +++++++++++ .../utilities/instructions_fft_bitrev.py | 209 --- hw/vendor/eslepfl_cgra.lock.hjson | 2 +- hw/vendor/eslepfl_cgra.vendor.hjson | 2 +- 105 files changed, 15068 insertions(+), 2841 deletions(-) create mode 100644 hw/vendor/esl_epfl_cgra/OpenEdgeCGRA.core delete mode 100644 hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson create mode 100644 hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson.tpl rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/alu.sv (100%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/cgra_controller.sv (100%) rename hw/vendor/esl_epfl_cgra/{rtl/cgra_pkg.sv => hw/rtl/cgra_pkg.sv.tpl} (81%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/cgra_rcs.sv (94%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/cgra_top.sv (90%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/conf_reg_file.sv (77%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/context_memory.sv (91%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/context_memory_decoder.sv (100%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/data_bus_handler.sv (92%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/datapath.sv (96%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/mux.sv (100%) create mode 100644 hw/vendor/esl_epfl_cgra/hw/rtl/peripheral_regs.sv.tpl rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/program_counter.sv (100%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/reconfigurable_cell.sv (66%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/reg_file.sv (73%) rename hw/vendor/esl_epfl_cgra/{ => hw}/rtl/synchronizer.sv (57%) rename hw/vendor/esl_epfl_cgra/{ => hw}/wrapper/cgra_top_wrapper.sv (57%) delete mode 100644 hw/vendor/esl_epfl_cgra/rtl/cgra_reg_pkg.sv delete mode 100644 hw/vendor/esl_epfl_cgra/rtl/cgra_reg_top.sv delete mode 100644 hw/vendor/esl_epfl_cgra/rtl/peripheral_regs.sv delete mode 100644 hw/vendor/esl_epfl_cgra/sw/cgra_regs.h create mode 100644 hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py rename hw/vendor/esl_epfl_cgra/{utilities/cgra_bitsream_gen.py => util/cgra_bitstream_gen.py.tpl} (84%) create mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_check_size.py rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_dbl_max.py (98%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_dbl_min.py (98%) create mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_fft_bitrev.py rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_fft_cplx.py (98%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_fft_cplx_forever.py (98%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_func_test.py (98%) create mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py create mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_while_loop_100percent.py (97%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_while_loop_50percent.py (98%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/instructions_while_loop_75percent.py (97%) rename hw/vendor/esl_epfl_cgra/{utilities => util}/log2file.py (100%) create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/README.md create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/__init__.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/access.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/alert.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bits.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bus_interfaces.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/enum_entry.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/field.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/fpv_csr.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cfg_html.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cheader.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_dv.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_fpv.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_html.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_json.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_rtl.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_selfdoc.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/html_helpers.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/inter_signal.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/ip_block.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/lib.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/multi_register.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/params.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_base.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_block.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_html.css create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_pkg.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_top.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/register.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/signal.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg_base.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/validate.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/version.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/window.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/regtool.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/__init__.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/c.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/gen_dv.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/intermodule.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/lib.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/merge.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/README.md create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chip_env_pkg__params.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chiplevel.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/clang-format create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__alert_handler_connect.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__xbar_connect.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.c.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.h.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.h.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.ld.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_pkg.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_rnd_cnst_pkg.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/xbar_env_pkg__params.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top.py create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top_uvm_reg.sv.tpl create mode 100644 hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/validate.py delete mode 100644 hw/vendor/esl_epfl_cgra/utilities/instructions_fft_bitrev.py diff --git a/hw/vendor/esl_epfl_cgra/.gitignore b/hw/vendor/esl_epfl_cgra/.gitignore index 9550a8bc..cbfbb313 100644 --- a/hw/vendor/esl_epfl_cgra/.gitignore +++ b/hw/vendor/esl_epfl_cgra/.gitignore @@ -2,3 +2,15 @@ build *_app bitstream +*__pycache__* + +# Generated hardware files +hw/rtl/cgra_pkg.sv +hw/rtl/cgra_reg_pkg.sv +hw/rtl/cgra_reg_top.sv +hw/rtl/peripheral_regs.sv +data/cgra_regs.hjson + +# Generated software files +sw/cgra_regs.h +util/cgra_bitstream_gen.py diff --git a/hw/vendor/esl_epfl_cgra/OpenEdgeCGRA.core b/hw/vendor/esl_epfl_cgra/OpenEdgeCGRA.core new file mode 100644 index 00000000..21fa115d --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/OpenEdgeCGRA.core @@ -0,0 +1,54 @@ +CAPI=2: + +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +name: "eslepfl::cgra" +description: "CGRA HDL" + +filesets: + files_rtl: + depend: + - x-heep::packages + - pulp-platform.org::common_cells + files: + - hw/rtl/cgra_pkg.sv + - hw/rtl/cgra_reg_pkg.sv + - hw/rtl/cgra_reg_top.sv + - hw/rtl/peripheral_regs.sv + - hw/rtl/program_counter.sv + - hw/rtl/alu.sv + - hw/rtl/reg_file.sv + - hw/rtl/mux.sv + - hw/rtl/datapath.sv + - hw/rtl/conf_reg_file.sv + - hw/rtl/reconfigurable_cell.sv + - hw/rtl/data_bus_handler.sv + - hw/rtl/synchronizer.sv + - hw/rtl/cgra_controller.sv + - hw/rtl/cgra_rcs.sv + - hw/rtl/context_memory_decoder.sv + - hw/rtl/cgra_top.sv + - hw/rtl/context_memory.sv + - hw/wrapper/cgra_top_wrapper.sv + file_type: systemVerilogSource + + + files_behav_rtl: + files: + - sim/cgra_clock_gate.sv + - sim/cgra_sram_wrapper.sv + file_type: systemVerilogSource + + files_verilator_waiver: + files: + - lint/cgra.vlt + file_type: vlt + +targets: + default: + filesets: + - files_rtl + - tool_verilator? (files_verilator_waiver) + - target_sim? (files_behav_rtl) diff --git a/hw/vendor/esl_epfl_cgra/data/cgra_reg_gen.sh b/hw/vendor/esl_epfl_cgra/data/cgra_reg_gen.sh index 8829ffb8..5e44b337 100755 --- a/hw/vendor/esl_epfl_cgra/data/cgra_reg_gen.sh +++ b/hw/vendor/esl_epfl_cgra/data/cgra_reg_gen.sh @@ -2,7 +2,8 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -echo "Generating CGRA Register RTL" -python3 ../utilities/lowrisc_opentitan/regtool.py -r -t ../rtl cgra_regs.hjson -echo "Generating CGRA Register SW" -python3 ../utilities/lowrisc_opentitan/regtool.py --cdefines -o ../sw/cgra_regs.h cgra_regs.hjson +echo "Generating RTL" +${PYTHON} ../util/lowrisc_opentitan/regtool.py -r -t ../hw/rtl ./cgra_regs.hjson +echo "Generating SW" +mkdir -p ../sw +${PYTHON} ../util/lowrisc_opentitan/regtool.py --cdefines -o ../sw/cgra_regs.h ./cgra_regs.hjson diff --git a/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson b/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson deleted file mode 100644 index 6d8b01d3..00000000 --- a/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -{ name: "cgra", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - regwidth: "32", - registers: [ - { name: "COL_STATUS", - desc: "CGRA columns status (0:free, 1:used)", - swaccess: "ro", - hwaccess: "hrw", - resval: 0, // all column free - fields: [ - { bits: "3:0", name: "COL_STATUS", desc: "CGRA columns status (0:free, 1:used)" } - ] - }, - { name: "SLOT0_KER_ID", - desc: "Slot 0 kernel ID", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "SLOT0_KER_ID", desc: "Slot 0 kernel ID" } - ] - }, - { name: "SLOT1_KER_ID", - desc: "Slot 1 kernel ID", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "SLOT1_KER_ID", desc: "Slot 1 kernel ID" } - ] - }, - { name: "SLOT0_PTR_IN_C0", - desc: "Slot 0 input data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_IN_C0", desc: "Slot 0 input data pointer for first column used" } - ] - }, - { name: "SLOT0_PTR_OUT_C0", - desc: "Slot 0 output data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_OUT_C0", desc: "Slot 0 output data pointer for first column used" } - ] - }, - { name: "SLOT0_PTR_IN_C1", - desc: "Slot 0 input data pointer for second column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_IN_C1", desc: "Slot 0 input data pointer for second column used" } - ] - }, - { name: "SLOT0_PTR_OUT_C1", - desc: "Slot 0 Output data pointer for second column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_OUT_C1", desc: "Slot 0 Output data pointer for second column used" } - ] - }, - { name: "SLOT0_PTR_IN_C2", - desc: "Slot 0 input data pointer for third column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_IN_C2", desc: "Slot 0 input data pointer for third column used" } - ] - }, - { name: "SLOT0_PTR_OUT_C2", - desc: "Slot 0 output data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_OUT_C2", desc: "Slot 0 output data pointer for first column used" } - ] - }, - { name: "SLOT0_PTR_IN_C3", - desc: "Slot 0 input data pointer for fourth column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_IN_C3", desc: "Slot 0 input data pointer for fourth column used" } - ] - }, - { name: "SLOT0_PTR_OUT_C3", - desc: "Slot 1 output data pointer for fourth column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT0_PTR_OUT_C3", desc: "Slot 0 output data pointer for fourth column used" } - ] - }, - - { name: "SLOT1_PTR_IN_C0", - desc: "Slot 1 input data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_IN_C0", desc: "Slot 1 input data pointer for first column used" } - ] - }, - { name: "SLOT1_PTR_OUT_C0", - desc: "Slot 1 output data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_OUT_C0", desc: "Slot 1 output data pointer for first column used" } - ] - }, - { name: "SLOT1_PTR_IN_C1", - desc: "Slot 1 input data pointer for second column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_IN_C1", desc: "Slot 1 input data pointer for second column used" } - ] - }, - { name: "SLOT1_PTR_OUT_C1", - desc: "Slot 1 Output data pointer for second column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_OUT_C1", desc: "Slot 1 Output data pointer for second column used" } - ] - }, - { name: "SLOT1_PTR_IN_C2", - desc: "Slot 1 input data pointer for third column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_IN_C2", desc: "Slot 1 input data pointer for third column used" } - ] - }, - { name: "SLOT1_PTR_OUT_C2", - desc: "Slot 1 output data pointer for first column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_OUT_C2", desc: "Slot 1 output data pointer for first column used" } - ] - }, - { name: "SLOT1_PTR_IN_C3", - desc: "Slot 1 input data pointer for fourth column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_IN_C3", desc: "Slot 1 input data pointer for fourth column used" } - ] - }, - { name: "SLOT1_PTR_OUT_C3", - desc: "Slot 1 output data pointer for fourth column used", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "SLOT1_PTR_OUT_C3", desc: "Slot 1 output data pointer for fourth column used" } - ] - }, - { name: "PERF_CNT_ENABLE", - desc: "Enable performance counters", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "0", name: "PERF_CNT_ENABLE", desc: "Enable performance counters" } - ] - }, - { name: "PERF_CNT_RESET", - desc: "Reset performance counters", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "0", name: "PERF_CNT_RESET", desc: "Reset performance counters" } - ] - }, - { name: "PERF_CNT_TOTAL_KERNELS", - desc: "Total number of kernels executed (all columns)", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_TOTAL_KERNELS", desc: "Total number of kernels executed" } - ] - }, - { name: "PERF_CNT_C0_ACTIVE_CYCLES", - desc: "Number of active cycles (configuration+execution)) of column 0", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C0_ACTIVE_CYCLES", desc: "Number of active cycles (configuration+execution)) of column 0" } - ] - }, - { name: "PERF_CNT_C0_STALL_CYCLES", - desc: "Number of stall cycles during execution of column 0", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C0_STALL_CYCLES", desc: "Number of stall cycles during execution of column 0" } - ] - }, - { name: "PERF_CNT_C1_ACTIVE_CYCLES", - desc: "Number of active cycles (configuration+execution)) of column 1", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C1_ACTIVE_CYCLES", desc: "Number of active cycles (configuration+execution)) of column 1" } - ] - }, - { name: "PERF_CNT_C1_STALL_CYCLES", - desc: "Number of stall cycles during execution of column 1", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C1_STALL_CYCLES", desc: "Number of stall cycles during execution of column 1" } - ] - }, - { name: "PERF_CNT_C2_ACTIVE_CYCLES", - desc: "Number of active cycles (configuration+execution) )of column 2", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C2_ACTIVE_CYCLES", desc: "Number of active cycles (configuration+execution) )of column 2" } - ] - }, - { name: "PERF_CNT_C2_STALL_CYCLES", - desc: "Number of stall cycles during execution of column 2", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C2_STALL_CYCLES", desc: "Number of stall cycles during execution of column 2" } - ] - }, - { name: "PERF_CNT_C3_ACTIVE_CYCLES", - desc: "Number of active cycles (configuration+execution) of column 3", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C3_ACTIVE_CYCLES", desc: "Number of active cycles (configuration+execution) of column 3" } - ] - }, - { name: "PERF_CNT_C3_STALL_CYCLES", - desc: "Number of stall cycles during execution of column 3", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "31:0", name: "PERF_CNT_C3_STALL_CYCLES", desc: "Number of stall cycles during execution of column 3" } - ] - }, - { name: "RESERVED30", - desc: "Reserved", - swaccess: "ro", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "RESERVED30", desc: "Reserved" } - ] - }, - { name: "RESERVED31", - desc: "Reserved", - swaccess: "ro", - hwaccess: "hro", - fields: [ - { bits: "31:0", name: "RESERVED31", desc: "Reserved" } - ] - }, - ] -} diff --git a/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson.tpl b/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson.tpl new file mode 100644 index 00000000..bfba1e54 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/data/cgra_regs.hjson.tpl @@ -0,0 +1,93 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +{ name: "cgra", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + regwidth: "32", + registers: [ + { name: "COL_STATUS", + desc: "CGRA columns status (0:free, 1:used)", + swaccess: "ro", + hwaccess: "hrw", + resval: 0, // all column free + fields: [ + { bits: "${cgra_num_columns-1}:0", name: "COL_STATUS", desc: "CGRA columns status (0:free, 1:used)" } + ] + }, + { name: "KERNEL_ID", + desc: "Kernel ID acceleration request", + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "31:0", name: "KERNEL_ID", desc: "Kernel ID acceleration request" } + ] + }, + + % for col in range(cgra_max_columns): + { name: "PTR_IN_COL_${col}", + desc: "Input data pointer for column ${col} used", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", name: "PTR_IN_C${col}", desc: "Input data pointer for column ${col} used" } + ] + }, + { name: "PTR_OUT_COL_${col}", + desc: "Output data pointer for column ${col} used", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", name: "PTR_OUT_COL_${col}", desc: "Output data pointer for column ${col} used" } + ] + }, + % endfor + + { name: "PERF_CNT_ENABLE", + desc: "Enable performance counters", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", name: "PERF_CNT_ENABLE", desc: "Enable performance counters" } + ] + }, + { name: "PERF_CNT_RESET", + desc: "Reset performance counters", + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "0", name: "PERF_CNT_RESET", desc: "Reset performance counters" } + ] + }, + { name: "PERF_CNT_TOTAL_KERNELS", + desc: "Total number of kernels executed (all columns)", + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "31:0", name: "PERF_CNT_TOTAL_KERNELS", desc: "Total number of kernels executed" } + ] + }, + + % for col in range(cgra_num_columns): + { name: "PERF_CNT_COL_${col}_ACTIVE_CYCLES", + desc: "Number of active cycles (configuration+execution)) of column ${col}", + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "31:0", name: "PERF_CNT_COL_${col}_ACTIVE_CYCLES", desc: "Number of active cycles (configuration+execution)) of column ${col}" } + ] + }, + { name: "PERF_CNT_COL_${col}_STALL_CYCLES", + desc: "Number of stall cycles during execution of column ${col}", + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "31:0", name: "PERF_CNT_COL_${col}_STALL_CYCLES", desc: "Number of stall cycles during execution of column ${col}" } + ] + }, + % endfor + ] +} diff --git a/hw/vendor/esl_epfl_cgra/rtl/alu.sv b/hw/vendor/esl_epfl_cgra/hw/rtl/alu.sv similarity index 100% rename from hw/vendor/esl_epfl_cgra/rtl/alu.sv rename to hw/vendor/esl_epfl_cgra/hw/rtl/alu.sv diff --git a/hw/vendor/esl_epfl_cgra/rtl/cgra_controller.sv b/hw/vendor/esl_epfl_cgra/hw/rtl/cgra_controller.sv similarity index 100% rename from hw/vendor/esl_epfl_cgra/rtl/cgra_controller.sv rename to hw/vendor/esl_epfl_cgra/hw/rtl/cgra_controller.sv diff --git a/hw/vendor/esl_epfl_cgra/rtl/cgra_pkg.sv b/hw/vendor/esl_epfl_cgra/hw/rtl/cgra_pkg.sv.tpl similarity index 81% rename from hw/vendor/esl_epfl_cgra/rtl/cgra_pkg.sv rename to hw/vendor/esl_epfl_cgra/hw/rtl/cgra_pkg.sv.tpl index 143dea5d..9e9c615d 100644 --- a/hw/vendor/esl_epfl_cgra/rtl/cgra_pkg.sv +++ b/hw/vendor/esl_epfl_cgra/hw/rtl/cgra_pkg.sv.tpl @@ -4,32 +4,33 @@ package cgra_pkg; - // This configures the number of peripheral registers - // in order to have independent set of registers for each slot - localparam N_SLOTS = 2; - localparam N_SLOTS_LOG2 = $clog2(N_SLOTS); - // CGRA GRID CONFIGURATION - localparam N_ROW = 4; - localparam N_ROW_LOG2 = $clog2(N_ROW); - localparam N_COL = 4; - localparam N_COL_LOG2 = $clog2(N_COL); - - // Data bus master ports - localparam MP = N_COL; - localparam ID = 9; - - // CGRA APB REGISTERS - localparam N_PERIPH_REGS = 32; - localparam N_PERIPH_REGS_LOG2 = $clog2(N_PERIPH_REGS); + localparam N_ROW = ${cgra_num_rows}; + localparam N_ROW_LOG2 = N_ROW == 1 ? 1 : $clog2(N_ROW); + localparam N_COL = ${cgra_num_columns}; + localparam N_COL_LOG2 = N_COL == 1 ? 1 : $clog2(N_COL); + + // Maximum number of columns a kernel can use + localparam MAX_COL_REQ = ${cgra_max_columns}; + localparam MAX_COL_REQ_LOG2 = $clog2(MAX_COL_REQ); - localparam CGRA_APB_REG_STATE = 0; + // Registers: + // 0: Status + // 1: Kernel ID + // 2-...: 2*MAX_COL_REQ (2 pointers per columns) + // ...: Performance counters enable + // ...: Performance counters reset + // ...: Performance counter number of executed kernels + // ...: Performance counter 2*N_COL (active and stall cycles) + localparam CGRA_PERIPH_STATUS_REG_OFFSET = 0; + localparam CGRA_NUM_PERIPH_REG = ${5+2*cgra_max_columns+2*cgra_num_columns}; + localparam CGRA_NUM_PERIPH_REG_LOG2 = $clog2(CGRA_NUM_PERIPH_REG); // RCs CONFIGURATION localparam RC_NUM_REG = 4; localparam RC_NUM_REG_LOG = $clog2(RC_NUM_REG); - localparam RCS_NUM_CREG = 32; + localparam RCS_NUM_CREG = ${cgra_rcs_num_instr}; localparam RCS_NUM_CREG_LOG2 = $clog2(RCS_NUM_CREG); localparam DP_WIDTH = 32; @@ -41,23 +42,19 @@ package cgra_pkg; localparam N_MEM_BANKS = N_ROW+1; localparam N_MEM_BANKS_LOG2 = $clog2(N_MEM_BANKS); - localparam IMEM_N_LINES = 128; // per RC + localparam IMEM_N_LINES = ${cgra_cmem_bk_depth}; // per RC localparam IMEM_N_LINES_LOG2 = $clog2(IMEM_N_LINES); // for compatibilty reason localparam RC_INSTR_N_REG = IMEM_N_LINES; localparam RC_INSTR_N_REG_LOG2 = IMEM_N_LINES_LOG2; - localparam KER_CONF_N_REG = 16; + localparam KER_CONF_N_REG = ${cgra_kmem_depth}; localparam KER_CONF_N_REG_LOG2 = $clog2(KER_CONF_N_REG); // Number of bits needed to write to the multi-banks instruction memory localparam WR_INSTR_ADD_LEN = N_MEM_BANKS_LOG2+RC_INSTR_N_REG_LOG2; - // PLATFORM SPECIFIC CONFIGURATION - localparam CGRA_BITSTREAM_FILENAME = "$IPS_ROOT/cgra/mem/cgra_imem.bit"; - localparam CGRA_KER_MEM_FILENAME = "$IPS_ROOT/cgra/mem/cgra_kmem.bit"; - // AHB MEMORY INTERFACE localparam DATA_BUS_DATA_WIDTH = 32; localparam DATA_BUS_ADD_WIDTH = 32; @@ -135,8 +132,4 @@ package cgra_pkg; localparam KER_N_COL_LB = RCS_IMEM_ADD_HB+1; localparam KER_N_COL_HB = KER_N_COL_LB+N_COL-1; - // Maximum number of columns a kernel can use - localparam MAX_COL_REQ = N_COL; - localparam MAX_COL_REQ_LOG2 = $clog2(MAX_COL_REQ); - endpackage diff --git a/hw/vendor/esl_epfl_cgra/rtl/cgra_rcs.sv b/hw/vendor/esl_epfl_cgra/hw/rtl/cgra_rcs.sv similarity index 94% rename from hw/vendor/esl_epfl_cgra/rtl/cgra_rcs.sv rename to hw/vendor/esl_epfl_cgra/hw/rtl/cgra_rcs.sv index 28ca4a75..ef06ede5 100644 --- a/hw/vendor/esl_epfl_cgra/rtl/cgra_rcs.sv +++ b/hw/vendor/esl_epfl_cgra/hw/rtl/cgra_rcs.sv @@ -21,6 +21,7 @@ module cgra_rcs output logic [ N_COL-1:0] data_ind_o, output logic [ DP_WIDTH-1:0] data_add_o [0:N_COL-1], output logic [ DP_WIDTH-1:0] data_wdata_o [0:N_COL-1], + output logic [ RC_CONST_WIDTH-1:0] add_inc_o [0:N_COL-1], output logic [ N_COL-1:0] rcs_br_req_o, output logic [RCS_NUM_CREG_LOG2-1:0] rcs_br_add_o [0:N_COL-1], output logic [ N_COL-1:0] rcs_stall_o, @@ -43,6 +44,7 @@ module cgra_rcs logic [ N_COL-1:0] data_ind_s [0:N_ROW-1]; logic [DP_WIDTH-1:0] data_add_s [0:N_ROW-1][0:N_COL-1]; logic [DP_WIDTH-1:0] data_wdata_s [0:N_ROW-1][0:N_COL-1]; + logic [RC_CONST_WIDTH-1:0] add_inc_s [0:N_ROW-1][0:N_COL-1]; logic [DP_WIDTH-1:0] rcs_wdata_s [0:N_COL-1]; logic [ DP_WIDTH-1:0] rcs_res [0:N_ROW-1][0:N_COL-1]; @@ -144,7 +146,6 @@ module cgra_rcs begin rvalid_demux[j] = '0; // for each row - for (int k=0; k HW type - typedef struct packed { - cgra_reg2hw_col_status_reg_t col_status; // [933:930] - cgra_reg2hw_slot0_ker_id_reg_t slot0_ker_id; // [929:898] - cgra_reg2hw_slot1_ker_id_reg_t slot1_ker_id; // [897:866] - cgra_reg2hw_slot0_ptr_in_c0_reg_t slot0_ptr_in_c0; // [865:834] - cgra_reg2hw_slot0_ptr_out_c0_reg_t slot0_ptr_out_c0; // [833:802] - cgra_reg2hw_slot0_ptr_in_c1_reg_t slot0_ptr_in_c1; // [801:770] - cgra_reg2hw_slot0_ptr_out_c1_reg_t slot0_ptr_out_c1; // [769:738] - cgra_reg2hw_slot0_ptr_in_c2_reg_t slot0_ptr_in_c2; // [737:706] - cgra_reg2hw_slot0_ptr_out_c2_reg_t slot0_ptr_out_c2; // [705:674] - cgra_reg2hw_slot0_ptr_in_c3_reg_t slot0_ptr_in_c3; // [673:642] - cgra_reg2hw_slot0_ptr_out_c3_reg_t slot0_ptr_out_c3; // [641:610] - cgra_reg2hw_slot1_ptr_in_c0_reg_t slot1_ptr_in_c0; // [609:578] - cgra_reg2hw_slot1_ptr_out_c0_reg_t slot1_ptr_out_c0; // [577:546] - cgra_reg2hw_slot1_ptr_in_c1_reg_t slot1_ptr_in_c1; // [545:514] - cgra_reg2hw_slot1_ptr_out_c1_reg_t slot1_ptr_out_c1; // [513:482] - cgra_reg2hw_slot1_ptr_in_c2_reg_t slot1_ptr_in_c2; // [481:450] - cgra_reg2hw_slot1_ptr_out_c2_reg_t slot1_ptr_out_c2; // [449:418] - cgra_reg2hw_slot1_ptr_in_c3_reg_t slot1_ptr_in_c3; // [417:386] - cgra_reg2hw_slot1_ptr_out_c3_reg_t slot1_ptr_out_c3; // [385:354] - cgra_reg2hw_perf_cnt_enable_reg_t perf_cnt_enable; // [353:353] - cgra_reg2hw_perf_cnt_reset_reg_t perf_cnt_reset; // [352:352] - cgra_reg2hw_perf_cnt_total_kernels_reg_t perf_cnt_total_kernels; // [351:320] - cgra_reg2hw_perf_cnt_c0_active_cycles_reg_t perf_cnt_c0_active_cycles; // [319:288] - cgra_reg2hw_perf_cnt_c0_stall_cycles_reg_t perf_cnt_c0_stall_cycles; // [287:256] - cgra_reg2hw_perf_cnt_c1_active_cycles_reg_t perf_cnt_c1_active_cycles; // [255:224] - cgra_reg2hw_perf_cnt_c1_stall_cycles_reg_t perf_cnt_c1_stall_cycles; // [223:192] - cgra_reg2hw_perf_cnt_c2_active_cycles_reg_t perf_cnt_c2_active_cycles; // [191:160] - cgra_reg2hw_perf_cnt_c2_stall_cycles_reg_t perf_cnt_c2_stall_cycles; // [159:128] - cgra_reg2hw_perf_cnt_c3_active_cycles_reg_t perf_cnt_c3_active_cycles; // [127:96] - cgra_reg2hw_perf_cnt_c3_stall_cycles_reg_t perf_cnt_c3_stall_cycles; // [95:64] - cgra_reg2hw_reserved30_reg_t reserved30; // [63:32] - cgra_reg2hw_reserved31_reg_t reserved31; // [31:0] - } cgra_reg2hw_t; - - // HW -> register type - typedef struct packed { - cgra_hw2reg_col_status_reg_t col_status; // [369:365] - cgra_hw2reg_slot0_ker_id_reg_t slot0_ker_id; // [364:332] - cgra_hw2reg_slot1_ker_id_reg_t slot1_ker_id; // [331:299] - cgra_hw2reg_perf_cnt_reset_reg_t perf_cnt_reset; // [298:297] - cgra_hw2reg_perf_cnt_total_kernels_reg_t perf_cnt_total_kernels; // [296:264] - cgra_hw2reg_perf_cnt_c0_active_cycles_reg_t perf_cnt_c0_active_cycles; // [263:231] - cgra_hw2reg_perf_cnt_c0_stall_cycles_reg_t perf_cnt_c0_stall_cycles; // [230:198] - cgra_hw2reg_perf_cnt_c1_active_cycles_reg_t perf_cnt_c1_active_cycles; // [197:165] - cgra_hw2reg_perf_cnt_c1_stall_cycles_reg_t perf_cnt_c1_stall_cycles; // [164:132] - cgra_hw2reg_perf_cnt_c2_active_cycles_reg_t perf_cnt_c2_active_cycles; // [131:99] - cgra_hw2reg_perf_cnt_c2_stall_cycles_reg_t perf_cnt_c2_stall_cycles; // [98:66] - cgra_hw2reg_perf_cnt_c3_active_cycles_reg_t perf_cnt_c3_active_cycles; // [65:33] - cgra_hw2reg_perf_cnt_c3_stall_cycles_reg_t perf_cnt_c3_stall_cycles; // [32:0] - } cgra_hw2reg_t; - - // Register offsets - parameter logic [BlockAw-1:0] CGRA_COL_STATUS_OFFSET = 7'h 0; - parameter logic [BlockAw-1:0] CGRA_SLOT0_KER_ID_OFFSET = 7'h 4; - parameter logic [BlockAw-1:0] CGRA_SLOT1_KER_ID_OFFSET = 7'h 8; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_IN_C0_OFFSET = 7'h c; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_OUT_C0_OFFSET = 7'h 10; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_IN_C1_OFFSET = 7'h 14; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_OUT_C1_OFFSET = 7'h 18; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_IN_C2_OFFSET = 7'h 1c; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_OUT_C2_OFFSET = 7'h 20; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_IN_C3_OFFSET = 7'h 24; - parameter logic [BlockAw-1:0] CGRA_SLOT0_PTR_OUT_C3_OFFSET = 7'h 28; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_IN_C0_OFFSET = 7'h 2c; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_OUT_C0_OFFSET = 7'h 30; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_IN_C1_OFFSET = 7'h 34; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_OUT_C1_OFFSET = 7'h 38; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_IN_C2_OFFSET = 7'h 3c; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_OUT_C2_OFFSET = 7'h 40; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_IN_C3_OFFSET = 7'h 44; - parameter logic [BlockAw-1:0] CGRA_SLOT1_PTR_OUT_C3_OFFSET = 7'h 48; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_ENABLE_OFFSET = 7'h 4c; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_RESET_OFFSET = 7'h 50; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_TOTAL_KERNELS_OFFSET = 7'h 54; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C0_ACTIVE_CYCLES_OFFSET = 7'h 58; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C0_STALL_CYCLES_OFFSET = 7'h 5c; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C1_ACTIVE_CYCLES_OFFSET = 7'h 60; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C1_STALL_CYCLES_OFFSET = 7'h 64; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C2_ACTIVE_CYCLES_OFFSET = 7'h 68; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C2_STALL_CYCLES_OFFSET = 7'h 6c; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C3_ACTIVE_CYCLES_OFFSET = 7'h 70; - parameter logic [BlockAw-1:0] CGRA_PERF_CNT_C3_STALL_CYCLES_OFFSET = 7'h 74; - parameter logic [BlockAw-1:0] CGRA_RESERVED30_OFFSET = 7'h 78; - parameter logic [BlockAw-1:0] CGRA_RESERVED31_OFFSET = 7'h 7c; - - // Register index - typedef enum int { - CGRA_COL_STATUS, - CGRA_SLOT0_KER_ID, - CGRA_SLOT1_KER_ID, - CGRA_SLOT0_PTR_IN_C0, - CGRA_SLOT0_PTR_OUT_C0, - CGRA_SLOT0_PTR_IN_C1, - CGRA_SLOT0_PTR_OUT_C1, - CGRA_SLOT0_PTR_IN_C2, - CGRA_SLOT0_PTR_OUT_C2, - CGRA_SLOT0_PTR_IN_C3, - CGRA_SLOT0_PTR_OUT_C3, - CGRA_SLOT1_PTR_IN_C0, - CGRA_SLOT1_PTR_OUT_C0, - CGRA_SLOT1_PTR_IN_C1, - CGRA_SLOT1_PTR_OUT_C1, - CGRA_SLOT1_PTR_IN_C2, - CGRA_SLOT1_PTR_OUT_C2, - CGRA_SLOT1_PTR_IN_C3, - CGRA_SLOT1_PTR_OUT_C3, - CGRA_PERF_CNT_ENABLE, - CGRA_PERF_CNT_RESET, - CGRA_PERF_CNT_TOTAL_KERNELS, - CGRA_PERF_CNT_C0_ACTIVE_CYCLES, - CGRA_PERF_CNT_C0_STALL_CYCLES, - CGRA_PERF_CNT_C1_ACTIVE_CYCLES, - CGRA_PERF_CNT_C1_STALL_CYCLES, - CGRA_PERF_CNT_C2_ACTIVE_CYCLES, - CGRA_PERF_CNT_C2_STALL_CYCLES, - CGRA_PERF_CNT_C3_ACTIVE_CYCLES, - CGRA_PERF_CNT_C3_STALL_CYCLES, - CGRA_RESERVED30, - CGRA_RESERVED31 - } cgra_id_e; - - // Register width information to check illegal writes - parameter logic [3:0] CGRA_PERMIT [32] = '{ - 4'b 0001, // index[ 0] CGRA_COL_STATUS - 4'b 1111, // index[ 1] CGRA_SLOT0_KER_ID - 4'b 1111, // index[ 2] CGRA_SLOT1_KER_ID - 4'b 1111, // index[ 3] CGRA_SLOT0_PTR_IN_C0 - 4'b 1111, // index[ 4] CGRA_SLOT0_PTR_OUT_C0 - 4'b 1111, // index[ 5] CGRA_SLOT0_PTR_IN_C1 - 4'b 1111, // index[ 6] CGRA_SLOT0_PTR_OUT_C1 - 4'b 1111, // index[ 7] CGRA_SLOT0_PTR_IN_C2 - 4'b 1111, // index[ 8] CGRA_SLOT0_PTR_OUT_C2 - 4'b 1111, // index[ 9] CGRA_SLOT0_PTR_IN_C3 - 4'b 1111, // index[10] CGRA_SLOT0_PTR_OUT_C3 - 4'b 1111, // index[11] CGRA_SLOT1_PTR_IN_C0 - 4'b 1111, // index[12] CGRA_SLOT1_PTR_OUT_C0 - 4'b 1111, // index[13] CGRA_SLOT1_PTR_IN_C1 - 4'b 1111, // index[14] CGRA_SLOT1_PTR_OUT_C1 - 4'b 1111, // index[15] CGRA_SLOT1_PTR_IN_C2 - 4'b 1111, // index[16] CGRA_SLOT1_PTR_OUT_C2 - 4'b 1111, // index[17] CGRA_SLOT1_PTR_IN_C3 - 4'b 1111, // index[18] CGRA_SLOT1_PTR_OUT_C3 - 4'b 0001, // index[19] CGRA_PERF_CNT_ENABLE - 4'b 0001, // index[20] CGRA_PERF_CNT_RESET - 4'b 1111, // index[21] CGRA_PERF_CNT_TOTAL_KERNELS - 4'b 1111, // index[22] CGRA_PERF_CNT_C0_ACTIVE_CYCLES - 4'b 1111, // index[23] CGRA_PERF_CNT_C0_STALL_CYCLES - 4'b 1111, // index[24] CGRA_PERF_CNT_C1_ACTIVE_CYCLES - 4'b 1111, // index[25] CGRA_PERF_CNT_C1_STALL_CYCLES - 4'b 1111, // index[26] CGRA_PERF_CNT_C2_ACTIVE_CYCLES - 4'b 1111, // index[27] CGRA_PERF_CNT_C2_STALL_CYCLES - 4'b 1111, // index[28] CGRA_PERF_CNT_C3_ACTIVE_CYCLES - 4'b 1111, // index[29] CGRA_PERF_CNT_C3_STALL_CYCLES - 4'b 1111, // index[30] CGRA_RESERVED30 - 4'b 1111 // index[31] CGRA_RESERVED31 - }; - -endpackage - diff --git a/hw/vendor/esl_epfl_cgra/rtl/cgra_reg_top.sv b/hw/vendor/esl_epfl_cgra/rtl/cgra_reg_top.sv deleted file mode 100644 index ebd8614e..00000000 --- a/hw/vendor/esl_epfl_cgra/rtl/cgra_reg_top.sv +++ /dev/null @@ -1,1339 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Top module auto-generated by `reggen` - - -`include "common_cells/assertions.svh" - -module cgra_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 7 -) ( - input clk_i, - input rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output cgra_reg_pkg::cgra_reg2hw_t reg2hw, // Write - input cgra_reg_pkg::cgra_hw2reg_t hw2reg, // Read - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import cgra_reg_pkg::* ; - - localparam int DW = 32; - localparam int DBW = DW/8; // Byte Width - - // register signals - logic reg_we; - logic reg_re; - logic [AW-1:0] reg_addr; - logic [DW-1:0] reg_wdata; - logic [DBW-1:0] reg_be; - logic [DW-1:0] reg_rdata; - logic reg_error; - - logic addrmiss, wr_err; - - logic [DW-1:0] reg_rdata_next; - - // Below register interface can be changed - reg_req_t reg_intf_req; - reg_rsp_t reg_intf_rsp; - - - assign reg_intf_req = reg_req_i; - assign reg_rsp_o = reg_intf_rsp; - - - assign reg_we = reg_intf_req.valid & reg_intf_req.write; - assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr; - assign reg_wdata = reg_intf_req.wdata; - assign reg_be = reg_intf_req.wstrb; - assign reg_intf_rsp.rdata = reg_rdata; - assign reg_intf_rsp.error = reg_error; - assign reg_intf_rsp.ready = 1'b1; - - assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err; - - - // Define SW related signals - // Format: __{wd|we|qs} - // or _{wd|we|qs} if field == 1 or 0 - logic [3:0] col_status_qs; - logic [31:0] slot0_ker_id_qs; - logic [31:0] slot0_ker_id_wd; - logic slot0_ker_id_we; - logic [31:0] slot1_ker_id_qs; - logic [31:0] slot1_ker_id_wd; - logic slot1_ker_id_we; - logic [31:0] slot0_ptr_in_c0_qs; - logic [31:0] slot0_ptr_in_c0_wd; - logic slot0_ptr_in_c0_we; - logic [31:0] slot0_ptr_out_c0_qs; - logic [31:0] slot0_ptr_out_c0_wd; - logic slot0_ptr_out_c0_we; - logic [31:0] slot0_ptr_in_c1_qs; - logic [31:0] slot0_ptr_in_c1_wd; - logic slot0_ptr_in_c1_we; - logic [31:0] slot0_ptr_out_c1_qs; - logic [31:0] slot0_ptr_out_c1_wd; - logic slot0_ptr_out_c1_we; - logic [31:0] slot0_ptr_in_c2_qs; - logic [31:0] slot0_ptr_in_c2_wd; - logic slot0_ptr_in_c2_we; - logic [31:0] slot0_ptr_out_c2_qs; - logic [31:0] slot0_ptr_out_c2_wd; - logic slot0_ptr_out_c2_we; - logic [31:0] slot0_ptr_in_c3_qs; - logic [31:0] slot0_ptr_in_c3_wd; - logic slot0_ptr_in_c3_we; - logic [31:0] slot0_ptr_out_c3_qs; - logic [31:0] slot0_ptr_out_c3_wd; - logic slot0_ptr_out_c3_we; - logic [31:0] slot1_ptr_in_c0_qs; - logic [31:0] slot1_ptr_in_c0_wd; - logic slot1_ptr_in_c0_we; - logic [31:0] slot1_ptr_out_c0_qs; - logic [31:0] slot1_ptr_out_c0_wd; - logic slot1_ptr_out_c0_we; - logic [31:0] slot1_ptr_in_c1_qs; - logic [31:0] slot1_ptr_in_c1_wd; - logic slot1_ptr_in_c1_we; - logic [31:0] slot1_ptr_out_c1_qs; - logic [31:0] slot1_ptr_out_c1_wd; - logic slot1_ptr_out_c1_we; - logic [31:0] slot1_ptr_in_c2_qs; - logic [31:0] slot1_ptr_in_c2_wd; - logic slot1_ptr_in_c2_we; - logic [31:0] slot1_ptr_out_c2_qs; - logic [31:0] slot1_ptr_out_c2_wd; - logic slot1_ptr_out_c2_we; - logic [31:0] slot1_ptr_in_c3_qs; - logic [31:0] slot1_ptr_in_c3_wd; - logic slot1_ptr_in_c3_we; - logic [31:0] slot1_ptr_out_c3_qs; - logic [31:0] slot1_ptr_out_c3_wd; - logic slot1_ptr_out_c3_we; - logic perf_cnt_enable_qs; - logic perf_cnt_enable_wd; - logic perf_cnt_enable_we; - logic perf_cnt_reset_qs; - logic perf_cnt_reset_wd; - logic perf_cnt_reset_we; - logic [31:0] perf_cnt_total_kernels_qs; - logic [31:0] perf_cnt_total_kernels_wd; - logic perf_cnt_total_kernels_we; - logic [31:0] perf_cnt_c0_active_cycles_qs; - logic [31:0] perf_cnt_c0_active_cycles_wd; - logic perf_cnt_c0_active_cycles_we; - logic [31:0] perf_cnt_c0_stall_cycles_qs; - logic [31:0] perf_cnt_c0_stall_cycles_wd; - logic perf_cnt_c0_stall_cycles_we; - logic [31:0] perf_cnt_c1_active_cycles_qs; - logic [31:0] perf_cnt_c1_active_cycles_wd; - logic perf_cnt_c1_active_cycles_we; - logic [31:0] perf_cnt_c1_stall_cycles_qs; - logic [31:0] perf_cnt_c1_stall_cycles_wd; - logic perf_cnt_c1_stall_cycles_we; - logic [31:0] perf_cnt_c2_active_cycles_qs; - logic [31:0] perf_cnt_c2_active_cycles_wd; - logic perf_cnt_c2_active_cycles_we; - logic [31:0] perf_cnt_c2_stall_cycles_qs; - logic [31:0] perf_cnt_c2_stall_cycles_wd; - logic perf_cnt_c2_stall_cycles_we; - logic [31:0] perf_cnt_c3_active_cycles_qs; - logic [31:0] perf_cnt_c3_active_cycles_wd; - logic perf_cnt_c3_active_cycles_we; - logic [31:0] perf_cnt_c3_stall_cycles_qs; - logic [31:0] perf_cnt_c3_stall_cycles_wd; - logic perf_cnt_c3_stall_cycles_we; - logic [31:0] reserved30_qs; - logic [31:0] reserved31_qs; - - // Register instances - // R[col_status]: V(False) - - prim_subreg #( - .DW (4), - .SWACCESS("RO"), - .RESVAL (4'h0) - ) u_col_status ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (hw2reg.col_status.de), - .d (hw2reg.col_status.d ), - - // to internal hardware - .qe (), - .q (reg2hw.col_status.q ), - - // to register interface (read) - .qs (col_status_qs) - ); - - - // R[slot0_ker_id]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ker_id ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ker_id_we), - .wd (slot0_ker_id_wd), - - // from internal hardware - .de (hw2reg.slot0_ker_id.de), - .d (hw2reg.slot0_ker_id.d ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ker_id.q ), - - // to register interface (read) - .qs (slot0_ker_id_qs) - ); - - - // R[slot1_ker_id]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ker_id ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ker_id_we), - .wd (slot1_ker_id_wd), - - // from internal hardware - .de (hw2reg.slot1_ker_id.de), - .d (hw2reg.slot1_ker_id.d ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ker_id.q ), - - // to register interface (read) - .qs (slot1_ker_id_qs) - ); - - - // R[slot0_ptr_in_c0]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_in_c0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_in_c0_we), - .wd (slot0_ptr_in_c0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_in_c0.q ), - - // to register interface (read) - .qs (slot0_ptr_in_c0_qs) - ); - - - // R[slot0_ptr_out_c0]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_out_c0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_out_c0_we), - .wd (slot0_ptr_out_c0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_out_c0.q ), - - // to register interface (read) - .qs (slot0_ptr_out_c0_qs) - ); - - - // R[slot0_ptr_in_c1]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_in_c1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_in_c1_we), - .wd (slot0_ptr_in_c1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_in_c1.q ), - - // to register interface (read) - .qs (slot0_ptr_in_c1_qs) - ); - - - // R[slot0_ptr_out_c1]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_out_c1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_out_c1_we), - .wd (slot0_ptr_out_c1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_out_c1.q ), - - // to register interface (read) - .qs (slot0_ptr_out_c1_qs) - ); - - - // R[slot0_ptr_in_c2]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_in_c2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_in_c2_we), - .wd (slot0_ptr_in_c2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_in_c2.q ), - - // to register interface (read) - .qs (slot0_ptr_in_c2_qs) - ); - - - // R[slot0_ptr_out_c2]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_out_c2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_out_c2_we), - .wd (slot0_ptr_out_c2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_out_c2.q ), - - // to register interface (read) - .qs (slot0_ptr_out_c2_qs) - ); - - - // R[slot0_ptr_in_c3]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_in_c3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_in_c3_we), - .wd (slot0_ptr_in_c3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_in_c3.q ), - - // to register interface (read) - .qs (slot0_ptr_in_c3_qs) - ); - - - // R[slot0_ptr_out_c3]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot0_ptr_out_c3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot0_ptr_out_c3_we), - .wd (slot0_ptr_out_c3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot0_ptr_out_c3.q ), - - // to register interface (read) - .qs (slot0_ptr_out_c3_qs) - ); - - - // R[slot1_ptr_in_c0]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_in_c0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_in_c0_we), - .wd (slot1_ptr_in_c0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_in_c0.q ), - - // to register interface (read) - .qs (slot1_ptr_in_c0_qs) - ); - - - // R[slot1_ptr_out_c0]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_out_c0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_out_c0_we), - .wd (slot1_ptr_out_c0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_out_c0.q ), - - // to register interface (read) - .qs (slot1_ptr_out_c0_qs) - ); - - - // R[slot1_ptr_in_c1]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_in_c1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_in_c1_we), - .wd (slot1_ptr_in_c1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_in_c1.q ), - - // to register interface (read) - .qs (slot1_ptr_in_c1_qs) - ); - - - // R[slot1_ptr_out_c1]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_out_c1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_out_c1_we), - .wd (slot1_ptr_out_c1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_out_c1.q ), - - // to register interface (read) - .qs (slot1_ptr_out_c1_qs) - ); - - - // R[slot1_ptr_in_c2]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_in_c2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_in_c2_we), - .wd (slot1_ptr_in_c2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_in_c2.q ), - - // to register interface (read) - .qs (slot1_ptr_in_c2_qs) - ); - - - // R[slot1_ptr_out_c2]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_out_c2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_out_c2_we), - .wd (slot1_ptr_out_c2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_out_c2.q ), - - // to register interface (read) - .qs (slot1_ptr_out_c2_qs) - ); - - - // R[slot1_ptr_in_c3]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_in_c3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_in_c3_we), - .wd (slot1_ptr_in_c3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_in_c3.q ), - - // to register interface (read) - .qs (slot1_ptr_in_c3_qs) - ); - - - // R[slot1_ptr_out_c3]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_slot1_ptr_out_c3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (slot1_ptr_out_c3_we), - .wd (slot1_ptr_out_c3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.slot1_ptr_out_c3.q ), - - // to register interface (read) - .qs (slot1_ptr_out_c3_qs) - ); - - - // R[perf_cnt_enable]: V(False) - - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_perf_cnt_enable ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_enable_we), - .wd (perf_cnt_enable_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_enable.q ), - - // to register interface (read) - .qs (perf_cnt_enable_qs) - ); - - - // R[perf_cnt_reset]: V(False) - - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_perf_cnt_reset ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_reset_we), - .wd (perf_cnt_reset_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_reset.de), - .d (hw2reg.perf_cnt_reset.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_reset.q ), - - // to register interface (read) - .qs (perf_cnt_reset_qs) - ); - - - // R[perf_cnt_total_kernels]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_total_kernels ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_total_kernels_we), - .wd (perf_cnt_total_kernels_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_total_kernels.de), - .d (hw2reg.perf_cnt_total_kernels.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_total_kernels.q ), - - // to register interface (read) - .qs (perf_cnt_total_kernels_qs) - ); - - - // R[perf_cnt_c0_active_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c0_active_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c0_active_cycles_we), - .wd (perf_cnt_c0_active_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c0_active_cycles.de), - .d (hw2reg.perf_cnt_c0_active_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c0_active_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c0_active_cycles_qs) - ); - - - // R[perf_cnt_c0_stall_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c0_stall_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c0_stall_cycles_we), - .wd (perf_cnt_c0_stall_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c0_stall_cycles.de), - .d (hw2reg.perf_cnt_c0_stall_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c0_stall_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c0_stall_cycles_qs) - ); - - - // R[perf_cnt_c1_active_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c1_active_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c1_active_cycles_we), - .wd (perf_cnt_c1_active_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c1_active_cycles.de), - .d (hw2reg.perf_cnt_c1_active_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c1_active_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c1_active_cycles_qs) - ); - - - // R[perf_cnt_c1_stall_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c1_stall_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c1_stall_cycles_we), - .wd (perf_cnt_c1_stall_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c1_stall_cycles.de), - .d (hw2reg.perf_cnt_c1_stall_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c1_stall_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c1_stall_cycles_qs) - ); - - - // R[perf_cnt_c2_active_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c2_active_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c2_active_cycles_we), - .wd (perf_cnt_c2_active_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c2_active_cycles.de), - .d (hw2reg.perf_cnt_c2_active_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c2_active_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c2_active_cycles_qs) - ); - - - // R[perf_cnt_c2_stall_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c2_stall_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c2_stall_cycles_we), - .wd (perf_cnt_c2_stall_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c2_stall_cycles.de), - .d (hw2reg.perf_cnt_c2_stall_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c2_stall_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c2_stall_cycles_qs) - ); - - - // R[perf_cnt_c3_active_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c3_active_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c3_active_cycles_we), - .wd (perf_cnt_c3_active_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c3_active_cycles.de), - .d (hw2reg.perf_cnt_c3_active_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c3_active_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c3_active_cycles_qs) - ); - - - // R[perf_cnt_c3_stall_cycles]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_perf_cnt_c3_stall_cycles ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (perf_cnt_c3_stall_cycles_we), - .wd (perf_cnt_c3_stall_cycles_wd), - - // from internal hardware - .de (hw2reg.perf_cnt_c3_stall_cycles.de), - .d (hw2reg.perf_cnt_c3_stall_cycles.d ), - - // to internal hardware - .qe (), - .q (reg2hw.perf_cnt_c3_stall_cycles.q ), - - // to register interface (read) - .qs (perf_cnt_c3_stall_cycles_qs) - ); - - - // R[reserved30]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RO"), - .RESVAL (32'h0) - ) u_reserved30 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.reserved30.q ), - - // to register interface (read) - .qs (reserved30_qs) - ); - - - // R[reserved31]: V(False) - - prim_subreg #( - .DW (32), - .SWACCESS("RO"), - .RESVAL (32'h0) - ) u_reserved31 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.reserved31.q ), - - // to register interface (read) - .qs (reserved31_qs) - ); - - - - - logic [31:0] addr_hit; - always_comb begin - addr_hit = '0; - addr_hit[ 0] = (reg_addr == CGRA_COL_STATUS_OFFSET); - addr_hit[ 1] = (reg_addr == CGRA_SLOT0_KER_ID_OFFSET); - addr_hit[ 2] = (reg_addr == CGRA_SLOT1_KER_ID_OFFSET); - addr_hit[ 3] = (reg_addr == CGRA_SLOT0_PTR_IN_C0_OFFSET); - addr_hit[ 4] = (reg_addr == CGRA_SLOT0_PTR_OUT_C0_OFFSET); - addr_hit[ 5] = (reg_addr == CGRA_SLOT0_PTR_IN_C1_OFFSET); - addr_hit[ 6] = (reg_addr == CGRA_SLOT0_PTR_OUT_C1_OFFSET); - addr_hit[ 7] = (reg_addr == CGRA_SLOT0_PTR_IN_C2_OFFSET); - addr_hit[ 8] = (reg_addr == CGRA_SLOT0_PTR_OUT_C2_OFFSET); - addr_hit[ 9] = (reg_addr == CGRA_SLOT0_PTR_IN_C3_OFFSET); - addr_hit[10] = (reg_addr == CGRA_SLOT0_PTR_OUT_C3_OFFSET); - addr_hit[11] = (reg_addr == CGRA_SLOT1_PTR_IN_C0_OFFSET); - addr_hit[12] = (reg_addr == CGRA_SLOT1_PTR_OUT_C0_OFFSET); - addr_hit[13] = (reg_addr == CGRA_SLOT1_PTR_IN_C1_OFFSET); - addr_hit[14] = (reg_addr == CGRA_SLOT1_PTR_OUT_C1_OFFSET); - addr_hit[15] = (reg_addr == CGRA_SLOT1_PTR_IN_C2_OFFSET); - addr_hit[16] = (reg_addr == CGRA_SLOT1_PTR_OUT_C2_OFFSET); - addr_hit[17] = (reg_addr == CGRA_SLOT1_PTR_IN_C3_OFFSET); - addr_hit[18] = (reg_addr == CGRA_SLOT1_PTR_OUT_C3_OFFSET); - addr_hit[19] = (reg_addr == CGRA_PERF_CNT_ENABLE_OFFSET); - addr_hit[20] = (reg_addr == CGRA_PERF_CNT_RESET_OFFSET); - addr_hit[21] = (reg_addr == CGRA_PERF_CNT_TOTAL_KERNELS_OFFSET); - addr_hit[22] = (reg_addr == CGRA_PERF_CNT_C0_ACTIVE_CYCLES_OFFSET); - addr_hit[23] = (reg_addr == CGRA_PERF_CNT_C0_STALL_CYCLES_OFFSET); - addr_hit[24] = (reg_addr == CGRA_PERF_CNT_C1_ACTIVE_CYCLES_OFFSET); - addr_hit[25] = (reg_addr == CGRA_PERF_CNT_C1_STALL_CYCLES_OFFSET); - addr_hit[26] = (reg_addr == CGRA_PERF_CNT_C2_ACTIVE_CYCLES_OFFSET); - addr_hit[27] = (reg_addr == CGRA_PERF_CNT_C2_STALL_CYCLES_OFFSET); - addr_hit[28] = (reg_addr == CGRA_PERF_CNT_C3_ACTIVE_CYCLES_OFFSET); - addr_hit[29] = (reg_addr == CGRA_PERF_CNT_C3_STALL_CYCLES_OFFSET); - addr_hit[30] = (reg_addr == CGRA_RESERVED30_OFFSET); - addr_hit[31] = (reg_addr == CGRA_RESERVED31_OFFSET); - end - - assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; - - // Check sub-word write is permitted - always_comb begin - wr_err = (reg_we & - ((addr_hit[ 0] & (|(CGRA_PERMIT[ 0] & ~reg_be))) | - (addr_hit[ 1] & (|(CGRA_PERMIT[ 1] & ~reg_be))) | - (addr_hit[ 2] & (|(CGRA_PERMIT[ 2] & ~reg_be))) | - (addr_hit[ 3] & (|(CGRA_PERMIT[ 3] & ~reg_be))) | - (addr_hit[ 4] & (|(CGRA_PERMIT[ 4] & ~reg_be))) | - (addr_hit[ 5] & (|(CGRA_PERMIT[ 5] & ~reg_be))) | - (addr_hit[ 6] & (|(CGRA_PERMIT[ 6] & ~reg_be))) | - (addr_hit[ 7] & (|(CGRA_PERMIT[ 7] & ~reg_be))) | - (addr_hit[ 8] & (|(CGRA_PERMIT[ 8] & ~reg_be))) | - (addr_hit[ 9] & (|(CGRA_PERMIT[ 9] & ~reg_be))) | - (addr_hit[10] & (|(CGRA_PERMIT[10] & ~reg_be))) | - (addr_hit[11] & (|(CGRA_PERMIT[11] & ~reg_be))) | - (addr_hit[12] & (|(CGRA_PERMIT[12] & ~reg_be))) | - (addr_hit[13] & (|(CGRA_PERMIT[13] & ~reg_be))) | - (addr_hit[14] & (|(CGRA_PERMIT[14] & ~reg_be))) | - (addr_hit[15] & (|(CGRA_PERMIT[15] & ~reg_be))) | - (addr_hit[16] & (|(CGRA_PERMIT[16] & ~reg_be))) | - (addr_hit[17] & (|(CGRA_PERMIT[17] & ~reg_be))) | - (addr_hit[18] & (|(CGRA_PERMIT[18] & ~reg_be))) | - (addr_hit[19] & (|(CGRA_PERMIT[19] & ~reg_be))) | - (addr_hit[20] & (|(CGRA_PERMIT[20] & ~reg_be))) | - (addr_hit[21] & (|(CGRA_PERMIT[21] & ~reg_be))) | - (addr_hit[22] & (|(CGRA_PERMIT[22] & ~reg_be))) | - (addr_hit[23] & (|(CGRA_PERMIT[23] & ~reg_be))) | - (addr_hit[24] & (|(CGRA_PERMIT[24] & ~reg_be))) | - (addr_hit[25] & (|(CGRA_PERMIT[25] & ~reg_be))) | - (addr_hit[26] & (|(CGRA_PERMIT[26] & ~reg_be))) | - (addr_hit[27] & (|(CGRA_PERMIT[27] & ~reg_be))) | - (addr_hit[28] & (|(CGRA_PERMIT[28] & ~reg_be))) | - (addr_hit[29] & (|(CGRA_PERMIT[29] & ~reg_be))) | - (addr_hit[30] & (|(CGRA_PERMIT[30] & ~reg_be))) | - (addr_hit[31] & (|(CGRA_PERMIT[31] & ~reg_be))))); - end - - assign slot0_ker_id_we = addr_hit[1] & reg_we & !reg_error; - assign slot0_ker_id_wd = reg_wdata[31:0]; - - assign slot1_ker_id_we = addr_hit[2] & reg_we & !reg_error; - assign slot1_ker_id_wd = reg_wdata[31:0]; - - assign slot0_ptr_in_c0_we = addr_hit[3] & reg_we & !reg_error; - assign slot0_ptr_in_c0_wd = reg_wdata[31:0]; - - assign slot0_ptr_out_c0_we = addr_hit[4] & reg_we & !reg_error; - assign slot0_ptr_out_c0_wd = reg_wdata[31:0]; - - assign slot0_ptr_in_c1_we = addr_hit[5] & reg_we & !reg_error; - assign slot0_ptr_in_c1_wd = reg_wdata[31:0]; - - assign slot0_ptr_out_c1_we = addr_hit[6] & reg_we & !reg_error; - assign slot0_ptr_out_c1_wd = reg_wdata[31:0]; - - assign slot0_ptr_in_c2_we = addr_hit[7] & reg_we & !reg_error; - assign slot0_ptr_in_c2_wd = reg_wdata[31:0]; - - assign slot0_ptr_out_c2_we = addr_hit[8] & reg_we & !reg_error; - assign slot0_ptr_out_c2_wd = reg_wdata[31:0]; - - assign slot0_ptr_in_c3_we = addr_hit[9] & reg_we & !reg_error; - assign slot0_ptr_in_c3_wd = reg_wdata[31:0]; - - assign slot0_ptr_out_c3_we = addr_hit[10] & reg_we & !reg_error; - assign slot0_ptr_out_c3_wd = reg_wdata[31:0]; - - assign slot1_ptr_in_c0_we = addr_hit[11] & reg_we & !reg_error; - assign slot1_ptr_in_c0_wd = reg_wdata[31:0]; - - assign slot1_ptr_out_c0_we = addr_hit[12] & reg_we & !reg_error; - assign slot1_ptr_out_c0_wd = reg_wdata[31:0]; - - assign slot1_ptr_in_c1_we = addr_hit[13] & reg_we & !reg_error; - assign slot1_ptr_in_c1_wd = reg_wdata[31:0]; - - assign slot1_ptr_out_c1_we = addr_hit[14] & reg_we & !reg_error; - assign slot1_ptr_out_c1_wd = reg_wdata[31:0]; - - assign slot1_ptr_in_c2_we = addr_hit[15] & reg_we & !reg_error; - assign slot1_ptr_in_c2_wd = reg_wdata[31:0]; - - assign slot1_ptr_out_c2_we = addr_hit[16] & reg_we & !reg_error; - assign slot1_ptr_out_c2_wd = reg_wdata[31:0]; - - assign slot1_ptr_in_c3_we = addr_hit[17] & reg_we & !reg_error; - assign slot1_ptr_in_c3_wd = reg_wdata[31:0]; - - assign slot1_ptr_out_c3_we = addr_hit[18] & reg_we & !reg_error; - assign slot1_ptr_out_c3_wd = reg_wdata[31:0]; - - assign perf_cnt_enable_we = addr_hit[19] & reg_we & !reg_error; - assign perf_cnt_enable_wd = reg_wdata[0]; - - assign perf_cnt_reset_we = addr_hit[20] & reg_we & !reg_error; - assign perf_cnt_reset_wd = reg_wdata[0]; - - assign perf_cnt_total_kernels_we = addr_hit[21] & reg_we & !reg_error; - assign perf_cnt_total_kernels_wd = reg_wdata[31:0]; - - assign perf_cnt_c0_active_cycles_we = addr_hit[22] & reg_we & !reg_error; - assign perf_cnt_c0_active_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c0_stall_cycles_we = addr_hit[23] & reg_we & !reg_error; - assign perf_cnt_c0_stall_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c1_active_cycles_we = addr_hit[24] & reg_we & !reg_error; - assign perf_cnt_c1_active_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c1_stall_cycles_we = addr_hit[25] & reg_we & !reg_error; - assign perf_cnt_c1_stall_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c2_active_cycles_we = addr_hit[26] & reg_we & !reg_error; - assign perf_cnt_c2_active_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c2_stall_cycles_we = addr_hit[27] & reg_we & !reg_error; - assign perf_cnt_c2_stall_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c3_active_cycles_we = addr_hit[28] & reg_we & !reg_error; - assign perf_cnt_c3_active_cycles_wd = reg_wdata[31:0]; - - assign perf_cnt_c3_stall_cycles_we = addr_hit[29] & reg_we & !reg_error; - assign perf_cnt_c3_stall_cycles_wd = reg_wdata[31:0]; - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (1'b1) - addr_hit[0]: begin - reg_rdata_next[3:0] = col_status_qs; - end - - addr_hit[1]: begin - reg_rdata_next[31:0] = slot0_ker_id_qs; - end - - addr_hit[2]: begin - reg_rdata_next[31:0] = slot1_ker_id_qs; - end - - addr_hit[3]: begin - reg_rdata_next[31:0] = slot0_ptr_in_c0_qs; - end - - addr_hit[4]: begin - reg_rdata_next[31:0] = slot0_ptr_out_c0_qs; - end - - addr_hit[5]: begin - reg_rdata_next[31:0] = slot0_ptr_in_c1_qs; - end - - addr_hit[6]: begin - reg_rdata_next[31:0] = slot0_ptr_out_c1_qs; - end - - addr_hit[7]: begin - reg_rdata_next[31:0] = slot0_ptr_in_c2_qs; - end - - addr_hit[8]: begin - reg_rdata_next[31:0] = slot0_ptr_out_c2_qs; - end - - addr_hit[9]: begin - reg_rdata_next[31:0] = slot0_ptr_in_c3_qs; - end - - addr_hit[10]: begin - reg_rdata_next[31:0] = slot0_ptr_out_c3_qs; - end - - addr_hit[11]: begin - reg_rdata_next[31:0] = slot1_ptr_in_c0_qs; - end - - addr_hit[12]: begin - reg_rdata_next[31:0] = slot1_ptr_out_c0_qs; - end - - addr_hit[13]: begin - reg_rdata_next[31:0] = slot1_ptr_in_c1_qs; - end - - addr_hit[14]: begin - reg_rdata_next[31:0] = slot1_ptr_out_c1_qs; - end - - addr_hit[15]: begin - reg_rdata_next[31:0] = slot1_ptr_in_c2_qs; - end - - addr_hit[16]: begin - reg_rdata_next[31:0] = slot1_ptr_out_c2_qs; - end - - addr_hit[17]: begin - reg_rdata_next[31:0] = slot1_ptr_in_c3_qs; - end - - addr_hit[18]: begin - reg_rdata_next[31:0] = slot1_ptr_out_c3_qs; - end - - addr_hit[19]: begin - reg_rdata_next[0] = perf_cnt_enable_qs; - end - - addr_hit[20]: begin - reg_rdata_next[0] = perf_cnt_reset_qs; - end - - addr_hit[21]: begin - reg_rdata_next[31:0] = perf_cnt_total_kernels_qs; - end - - addr_hit[22]: begin - reg_rdata_next[31:0] = perf_cnt_c0_active_cycles_qs; - end - - addr_hit[23]: begin - reg_rdata_next[31:0] = perf_cnt_c0_stall_cycles_qs; - end - - addr_hit[24]: begin - reg_rdata_next[31:0] = perf_cnt_c1_active_cycles_qs; - end - - addr_hit[25]: begin - reg_rdata_next[31:0] = perf_cnt_c1_stall_cycles_qs; - end - - addr_hit[26]: begin - reg_rdata_next[31:0] = perf_cnt_c2_active_cycles_qs; - end - - addr_hit[27]: begin - reg_rdata_next[31:0] = perf_cnt_c2_stall_cycles_qs; - end - - addr_hit[28]: begin - reg_rdata_next[31:0] = perf_cnt_c3_active_cycles_qs; - end - - addr_hit[29]: begin - reg_rdata_next[31:0] = perf_cnt_c3_stall_cycles_qs; - end - - addr_hit[30]: begin - reg_rdata_next[31:0] = reserved30_qs; - end - - addr_hit[31]: begin - reg_rdata_next[31:0] = reserved31_qs; - end - - default: begin - reg_rdata_next = '1; - end - endcase - end - - // Unused signal tieoff - - // wdata / byte enable are not always fully used - // add a blanket unused statement to handle lint waivers - logic unused_wdata; - logic unused_be; - assign unused_wdata = ^reg_wdata; - assign unused_be = ^reg_be; - - // Assertions for Register Interface - `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) - -endmodule diff --git a/hw/vendor/esl_epfl_cgra/rtl/peripheral_regs.sv b/hw/vendor/esl_epfl_cgra/rtl/peripheral_regs.sv deleted file mode 100644 index f138560a..00000000 --- a/hw/vendor/esl_epfl_cgra/rtl/peripheral_regs.sv +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2022 EPFL -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - -module peripheral_regs - import cgra_pkg::*; - import reg_pkg::*; -( - input logic clk_i, - input logic rst_ni, - input logic acc_ack_i, - input logic [ N_SLOTS_LOG2-1:0] c_id_req_clear_i, - input logic [ N_COL-1:0] col_stall_i, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - input logic [ N_COL-1:0] acc_req_i, - input logic [ N_COL-1:0] acc_end_i, - output logic [ N_COL-1:0] col_status_o, - output logic [KER_CONF_N_REG_LOG2-1:0] core_ker_id_o [0:N_SLOTS-1], - output logic [ DP_WIDTH-1:0] core_rd_ptr_o [0:N_SLOTS-1][0:MAX_COL_REQ-1], - output logic [ DP_WIDTH-1:0] core_wr_ptr_o [0:N_SLOTS-1][0:MAX_COL_REQ-1] -); - - import cgra_reg_pkg::*; - - cgra_reg2hw_t reg2hw; - cgra_hw2reg_t hw2reg; - - logic [N_COL-1:0] col_status; - logic perf_cnt_en; - logic perf_cnt_reset; - - assign col_status_o = col_status; - - assign perf_cnt_en = reg2hw.perf_cnt_enable.q; - assign perf_cnt_reset = reg2hw.perf_cnt_reset.q; - - - // Columns' read and write pointers - always_comb - begin - core_ker_id_o[0] = reg2hw.slot0_ker_id.q[KER_CONF_N_REG_LOG2-1:0]; - core_ker_id_o[1] = reg2hw.slot1_ker_id.q[KER_CONF_N_REG_LOG2-1:0]; - - core_rd_ptr_o[0][0] = reg2hw.slot0_ptr_in_c0.q; - core_wr_ptr_o[0][0] = reg2hw.slot0_ptr_out_c0.q; - core_rd_ptr_o[0][1] = reg2hw.slot0_ptr_in_c1.q; - core_wr_ptr_o[0][1] = reg2hw.slot0_ptr_out_c1.q; - core_rd_ptr_o[0][2] = reg2hw.slot0_ptr_in_c2.q; - core_wr_ptr_o[0][2] = reg2hw.slot0_ptr_out_c2.q; - core_rd_ptr_o[0][3] = reg2hw.slot0_ptr_in_c3.q; - core_wr_ptr_o[0][3] = reg2hw.slot0_ptr_out_c3.q; - - core_rd_ptr_o[1][0] = reg2hw.slot1_ptr_in_c0.q; - core_wr_ptr_o[1][0] = reg2hw.slot1_ptr_out_c0.q; - core_rd_ptr_o[1][1] = reg2hw.slot1_ptr_in_c1.q; - core_wr_ptr_o[1][1] = reg2hw.slot1_ptr_out_c1.q; - core_rd_ptr_o[1][2] = reg2hw.slot1_ptr_in_c2.q; - core_wr_ptr_o[1][2] = reg2hw.slot1_ptr_out_c2.q; - core_rd_ptr_o[1][3] = reg2hw.slot1_ptr_in_c3.q; - core_wr_ptr_o[1][3] = reg2hw.slot1_ptr_out_c3.q; - end - - // Reset/update performance counters - assign hw2reg.perf_cnt_total_kernels.de = perf_cnt_reset | (perf_cnt_en & acc_ack_i); - assign hw2reg.perf_cnt_total_kernels.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_total_kernels.q + 1; - // Column 0 - assign hw2reg.perf_cnt_c0_active_cycles.de = perf_cnt_reset | (perf_cnt_en & (col_status[0] | acc_req_i[0])); - assign hw2reg.perf_cnt_c0_active_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c0_active_cycles.q + 1; - assign hw2reg.perf_cnt_c0_stall_cycles.de = perf_cnt_reset | (perf_cnt_en & col_stall_i[0]); - assign hw2reg.perf_cnt_c0_stall_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c0_stall_cycles.q + 1; - // Column 1 - assign hw2reg.perf_cnt_c1_active_cycles.de = perf_cnt_reset | (perf_cnt_en & (col_status[1] | acc_req_i[1])); - assign hw2reg.perf_cnt_c1_active_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c1_active_cycles.q + 1; - assign hw2reg.perf_cnt_c1_stall_cycles.de = perf_cnt_reset | (perf_cnt_en & col_stall_i[1]); - assign hw2reg.perf_cnt_c1_stall_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c1_stall_cycles.q + 1; - // Column 2 - assign hw2reg.perf_cnt_c2_active_cycles.de = perf_cnt_reset | (perf_cnt_en & (col_status[2] | acc_req_i[2])); - assign hw2reg.perf_cnt_c2_active_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c2_active_cycles.q + 1; - assign hw2reg.perf_cnt_c2_stall_cycles.de = perf_cnt_reset | (perf_cnt_en & col_stall_i[2]); - assign hw2reg.perf_cnt_c2_stall_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c2_stall_cycles.q + 1; - // Column 3 - assign hw2reg.perf_cnt_c3_active_cycles.de = perf_cnt_reset | (perf_cnt_en & (col_status[3] | acc_req_i[3])); - assign hw2reg.perf_cnt_c3_active_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c3_active_cycles.q + 1; - assign hw2reg.perf_cnt_c3_stall_cycles.de = perf_cnt_reset | (perf_cnt_en & col_stall_i[3]); - assign hw2reg.perf_cnt_c3_stall_cycles.d = perf_cnt_reset == 1'b1 ? '0 : reg2hw.perf_cnt_c3_stall_cycles.q + 1; - // Disable reset - assign hw2reg.perf_cnt_reset.de = perf_cnt_reset; - assign hw2reg.perf_cnt_reset.d = '0; - - // Clear kernel ID request - assign hw2reg.slot0_ker_id.de = acc_ack_i | ~c_id_req_clear_i; - assign hw2reg.slot0_ker_id.d = '0; - assign hw2reg.slot1_ker_id.de = acc_ack_i | c_id_req_clear_i; - assign hw2reg.slot1_ker_id.d = '0; - - // Update CGRA column status: - // 0 - Column is free - // 1 - Column is used - assign col_status = reg2hw.col_status.q; - assign hw2reg.col_status.de = ((|acc_req_i) & acc_ack_i) | (|acc_end_i); - assign hw2reg.col_status.d = ((|acc_req_i) & acc_ack_i) == 1'b1 ? (col_status | acc_req_i) : (col_status & ~acc_end_i); - - cgra_reg_top #( - .reg_req_t(reg_req_t), - .reg_rsp_t(reg_rsp_t) - ) cgra_reg_top_i ( - .clk_i, - .rst_ni, - .reg_req_i, - .reg_rsp_o, - .reg2hw, - .hw2reg, - .devmode_i(1'b1) - ); - -endmodule diff --git a/hw/vendor/esl_epfl_cgra/sim/cgra_sram_wrapper.sv b/hw/vendor/esl_epfl_cgra/sim/cgra_sram_wrapper.sv index 407afa08..e61bf806 100644 --- a/hw/vendor/esl_epfl_cgra/sim/cgra_sram_wrapper.sv +++ b/hw/vendor/esl_epfl_cgra/sim/cgra_sram_wrapper.sv @@ -22,7 +22,7 @@ module cgra_sram_wrapper #( input logic [AddrWidth-1:0] addr_i, // request address input logic [ 31:0] wdata_i, // write data input logic [ 3:0] be_i, // write byte enable - input logic set_retentive_i, + input logic set_retentive_ni, // output ports output logic [ 31:0] rdata_o // read data ); diff --git a/hw/vendor/esl_epfl_cgra/sw/cgra_regs.h b/hw/vendor/esl_epfl_cgra/sw/cgra_regs.h deleted file mode 100644 index e9a87251..00000000 --- a/hw/vendor/esl_epfl_cgra/sw/cgra_regs.h +++ /dev/null @@ -1,125 +0,0 @@ -// Generated register defines for cgra - -// Copyright information found in source file: -// Copyright EPFL contributors. - -// Licensing information found in source file: -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#ifndef _CGRA_REG_DEFS_ -#define _CGRA_REG_DEFS_ - -#ifdef __cplusplus -extern "C" { -#endif -// Register width -#define CGRA_PARAM_REG_WIDTH 32 - -// CGRA columns status (0:free, 1:used) -#define CGRA_COL_STATUS_REG_OFFSET 0x0 -#define CGRA_COL_STATUS_COL_STATUS_MASK 0xf -#define CGRA_COL_STATUS_COL_STATUS_OFFSET 0 -#define CGRA_COL_STATUS_COL_STATUS_FIELD \ - ((bitfield_field32_t) { .mask = CGRA_COL_STATUS_COL_STATUS_MASK, .index = CGRA_COL_STATUS_COL_STATUS_OFFSET }) - -// Slot 0 kernel ID -#define CGRA_SLOT0_KER_ID_REG_OFFSET 0x4 - -// Slot 1 kernel ID -#define CGRA_SLOT1_KER_ID_REG_OFFSET 0x8 - -// Slot 0 input data pointer for first column used -#define CGRA_SLOT0_PTR_IN_C0_REG_OFFSET 0xc - -// Slot 0 output data pointer for first column used -#define CGRA_SLOT0_PTR_OUT_C0_REG_OFFSET 0x10 - -// Slot 0 input data pointer for second column used -#define CGRA_SLOT0_PTR_IN_C1_REG_OFFSET 0x14 - -// Slot 0 Output data pointer for second column used -#define CGRA_SLOT0_PTR_OUT_C1_REG_OFFSET 0x18 - -// Slot 0 input data pointer for third column used -#define CGRA_SLOT0_PTR_IN_C2_REG_OFFSET 0x1c - -// Slot 0 output data pointer for first column used -#define CGRA_SLOT0_PTR_OUT_C2_REG_OFFSET 0x20 - -// Slot 0 input data pointer for fourth column used -#define CGRA_SLOT0_PTR_IN_C3_REG_OFFSET 0x24 - -// Slot 1 output data pointer for fourth column used -#define CGRA_SLOT0_PTR_OUT_C3_REG_OFFSET 0x28 - -// Slot 1 input data pointer for first column used -#define CGRA_SLOT1_PTR_IN_C0_REG_OFFSET 0x2c - -// Slot 1 output data pointer for first column used -#define CGRA_SLOT1_PTR_OUT_C0_REG_OFFSET 0x30 - -// Slot 1 input data pointer for second column used -#define CGRA_SLOT1_PTR_IN_C1_REG_OFFSET 0x34 - -// Slot 1 Output data pointer for second column used -#define CGRA_SLOT1_PTR_OUT_C1_REG_OFFSET 0x38 - -// Slot 1 input data pointer for third column used -#define CGRA_SLOT1_PTR_IN_C2_REG_OFFSET 0x3c - -// Slot 1 output data pointer for first column used -#define CGRA_SLOT1_PTR_OUT_C2_REG_OFFSET 0x40 - -// Slot 1 input data pointer for fourth column used -#define CGRA_SLOT1_PTR_IN_C3_REG_OFFSET 0x44 - -// Slot 1 output data pointer for fourth column used -#define CGRA_SLOT1_PTR_OUT_C3_REG_OFFSET 0x48 - -// Enable performance counters -#define CGRA_PERF_CNT_ENABLE_REG_OFFSET 0x4c -#define CGRA_PERF_CNT_ENABLE_PERF_CNT_ENABLE_BIT 0 - -// Reset performance counters -#define CGRA_PERF_CNT_RESET_REG_OFFSET 0x50 -#define CGRA_PERF_CNT_RESET_PERF_CNT_RESET_BIT 0 - -// Total number of kernels executed (all columns) -#define CGRA_PERF_CNT_TOTAL_KERNELS_REG_OFFSET 0x54 - -// Number of active cycles (configuration+execution)) of column 0 -#define CGRA_PERF_CNT_C0_ACTIVE_CYCLES_REG_OFFSET 0x58 - -// Number of stall cycles during execution of column 0 -#define CGRA_PERF_CNT_C0_STALL_CYCLES_REG_OFFSET 0x5c - -// Number of active cycles (configuration+execution)) of column 1 -#define CGRA_PERF_CNT_C1_ACTIVE_CYCLES_REG_OFFSET 0x60 - -// Number of stall cycles during execution of column 1 -#define CGRA_PERF_CNT_C1_STALL_CYCLES_REG_OFFSET 0x64 - -// Number of active cycles (configuration+execution) )of column 2 -#define CGRA_PERF_CNT_C2_ACTIVE_CYCLES_REG_OFFSET 0x68 - -// Number of stall cycles during execution of column 2 -#define CGRA_PERF_CNT_C2_STALL_CYCLES_REG_OFFSET 0x6c - -// Number of active cycles (configuration+execution) of column 3 -#define CGRA_PERF_CNT_C3_ACTIVE_CYCLES_REG_OFFSET 0x70 - -// Number of stall cycles during execution of column 3 -#define CGRA_PERF_CNT_C3_STALL_CYCLES_REG_OFFSET 0x74 - -// Reserved -#define CGRA_RESERVED30_REG_OFFSET 0x78 - -// Reserved -#define CGRA_RESERVED31_REG_OFFSET 0x7c - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // _CGRA_REG_DEFS_ -// End generated register defines for cgra \ No newline at end of file diff --git a/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py b/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py new file mode 100644 index 00000000..75586fca --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py @@ -0,0 +1,186 @@ +# FFT OUTPUT SPLIT OPS instructions DEPREDECATED + +instructions.append(["NEXT RC"]) + +# RC1_0 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["RF2", "CONST", "SADD", "RF2", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + + +# RC1_1 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF2", "CONST", "SSUB", "RF2", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +################################################################################################# +################################################################################################# +################################################################################################# + +instructions.append(["NEXT RC"]) + +# RC2_0 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF3", "RCT", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCB", "OUT_D", "IN1", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCT", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "EXIT", "RF1", "OFF", "OUT_F", "0"]) + + +# RC2_1 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF3", "RCT", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCL", "OUT_D", "FXP_ADD", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCL", "RCB", "FXP_SUB", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF2", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +################################################################################################# +################################################################################################# +################################################################################################# + +instructions.append(["NEXT RC"]) + +# RC3_0 +# PROLOGUE +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SSUB", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF2", "CONST", "SSUB", "RF2", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCB", "RF1", "SWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + + +# RC3_1 +# PROLOGUE +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SSUB", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "IN1", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF3", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCT", "RF1", "SWI", "RF1", "OFF", "OUT_F", "0"]) + +################################################################################################# +################################################################################################# +################################################################################################# + +instructions.append(["NEXT RC"]) + +# RC4_0 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["RF2", "RCB", "FXP_SUB", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCT", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RCB", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) + + +# RC4_1 +# PROLOGUE +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) +instructions.append(["DATA", "OUT_D", "LWD", "RF3", "ON", "OUT_F", "0"]) + +# ITERATION LOOP +instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) +instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF2", "CONST", "SADD", "RF2", "ON", "OUT_F", "4"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF4", "CONST", "SADD", "RF4", "ON", "OUT_F", "1"]) +instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) +instructions.append(["RF4", "RF3", "BLT", "RF1", "OFF", "OUT_F", "6"]) + + +################################################################################################# +################################################################################################# +################################################################################################# + +kernel_col_needed = "0011" +row_st_add = 58 +n_instructions = 14 diff --git a/hw/vendor/esl_epfl_cgra/utilities/cgra_bitsream_gen.py b/hw/vendor/esl_epfl_cgra/util/cgra_bitstream_gen.py.tpl similarity index 84% rename from hw/vendor/esl_epfl_cgra/utilities/cgra_bitsream_gen.py rename to hw/vendor/esl_epfl_cgra/util/cgra_bitstream_gen.py.tpl index da42ef9e..442e93a7 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/cgra_bitsream_gen.py +++ b/hw/vendor/esl_epfl_cgra/util/cgra_bitstream_gen.py.tpl @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # Copyright EPFL contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 @@ -84,6 +86,7 @@ def return_indices_of_a(a, b, name = ''): sys.exit("ERROR instruction: " + str(b) + " is not a valid command (not in " + name + " list)") +<%text> ########################################################################## # _____ _____ _____ _____ ____ _ _ ______ _____ _____ # # / ____/ ____| __ \ /\ / ____/ __ \| \ | | ____|_ _/ ____| # @@ -93,22 +96,34 @@ def return_indices_of_a(a, b, name = ''): # \_____\_____|_| \_/_/ \_\ \_____\____/|_| \_|_| |_____\_____| # # # ########################################################################## +\ + +CGRA_N_COL = ${cgra_num_columns} +CGRA_N_ROW = ${cgra_num_rows} -CGRA_N_COL = 4 -CGRA_N_ROW = 4 +CGRA_MAX_COL = ${cgra_max_columns} -RCS_NUM_CREG = 32; +RCS_NUM_CREG = ${cgra_rcs_num_instr}; RCS_NUM_CREG_LOG2 = ceil(log(RCS_NUM_CREG,2)); -CGRA_IMEM_N_LINE = 128 -CGRA_IMEM_NL_LOG2 = ceil(log(CGRA_IMEM_N_LINE,2)) +CGRA_CMEM_BK_DEPTH = ${cgra_cmem_bk_depth} +CGRA_CMEM_BK_DEPTH_LOG2 = ceil(log(CGRA_CMEM_BK_DEPTH,2)) # Memory holding the kernel configuration words (KMEM) # Max possible number of kernel -CGRA_KMEM_N_KER = 16 +CGRA_KMEM_DEPTH = ${cgra_kmem_depth} # Kernel configuration word width -CGRA_KMEM_WIDTH = CGRA_N_COL + CGRA_IMEM_NL_LOG2 + RCS_NUM_CREG_LOG2 +CGRA_KMEM_WIDTH = CGRA_MAX_COL + CGRA_CMEM_BK_DEPTH_LOG2 + RCS_NUM_CREG_LOG2 +# Check the parameters are in the expected range +if CGRA_KMEM_WIDTH > 32: + print('ERROR: kernel configuration word width > 32 bits') +if CGRA_CMEM_BK_DEPTH < (CGRA_MAX_COL*RCS_NUM_CREG): + print('WARNING: context memory cannot hold the maximum kernel size') +if ${cgra_max_columns} > CGRA_N_COL: + print('ERROR: maximum number of columns is larger than the actual number of columns') + +<%text> ################################################################# # _____ _____ _____ _____ ____ _ _ _____ _____ _____ # # | __ \ / ____|/ ____| / ____/ __ \| \ | | ___|_ _/ ____| # @@ -118,6 +133,7 @@ def return_indices_of_a(a, b, name = ''): # |_| \_\\_____|_____/ \_____\____/|_| \_|_| |_____\_____| # # # ################################################################# +\ RCS_MUXA_BITS = 4 RCS_MUXB_BITS = 4 @@ -127,7 +143,11 @@ def return_indices_of_a(a, b, name = ''): RCS_MUXFLAG_BITS = 3 RCS_IMM_BITS = 13 -CGRA_IMEM_WIDTH = RCS_MUXA_BITS+RCS_MUXB_BITS+RCS_ALU_OP_BITS+RCS_RF_WADD_BITS+RCS_RF_WE_BITS+RCS_MUXFLAG_BITS+RCS_IMM_BITS +CGRA_CMEM_WIDTH = RCS_MUXA_BITS+RCS_MUXB_BITS+RCS_ALU_OP_BITS+RCS_RF_WADD_BITS+RCS_RF_WE_BITS+RCS_MUXFLAG_BITS+RCS_IMM_BITS + +# This could be changed but for now 32 bits are expected +if CGRA_CMEM_WIDTH != 32: + print('ERROR: instructions (configuration words) width not equal to 32') muxA_list = ['ZERO', 'SELF', 'RCL', 'RCR', 'RCT', 'RCB', 'R0', 'R1', 'R2', 'R3', 'IMM'] muxB_list = ['ZERO', 'SELF', 'RCL', 'RCR', 'RCT', 'RCB', 'R0', 'R1', 'R2', 'R3', 'IMM'] @@ -149,6 +169,7 @@ def return_indices_of_a(a, b, name = ''): rcs_nop_instr = ['ZERO', 'ZERO', 'NOP', '-', 'SELF', '0'] +<%text> ##################################################################################### # _ _______ _____ _____ ____ _ _ _____ __ ______ _____ _____ # # | |/ / ___| __ \ / ____/ __ \| \ | | ___| \ \ / / __ \| __ \| __ \ # @@ -158,25 +179,28 @@ def return_indices_of_a(a, b, name = ''): # |_|\_\_____|_| \_\ \_____\____/|_| \_|_| \/ \/ \____/|_| \_\_____/ # # # ##################################################################################### +\ ker_null_conf = get_bin(0, CGRA_KMEM_WIDTH) +<%text> ##################################################################################### +\ -rcs_imem_file = '../bitsream/cgra_imem.bit' -ker_kmem_file = '../bitsream/cgra_kmem.bit' +rcs_imem_file = '../bitstream/cgra_imem.bit' +ker_kmem_file = '../bitstream/cgra_kmem.bit' -if not os.path.exists('../bitsream'): - os.mkdir('../bitsream') +if not os.path.exists('../bitstream'): + os.mkdir('../bitstream') open(rcs_imem_file, 'w') open(ker_kmem_file, 'w') -rcs_logger = logfunc.log2file(rcs_imem_file, CGRA_IMEM_WIDTH + 4) # + 0b<>, +rcs_logger = logfunc.log2file(rcs_imem_file, CGRA_CMEM_WIDTH + 4) # + 0b<>, ker_logger = logfunc.log2file(ker_kmem_file, CGRA_KMEM_WIDTH) -rcs_instructions = [[rcs_nop_instr for _ in range(CGRA_IMEM_N_LINE)] for _ in range (CGRA_N_ROW)] -ker_conf_words = [ker_null_conf for _ in range(CGRA_KMEM_N_KER)] +rcs_instructions = [[rcs_nop_instr for _ in range(CGRA_CMEM_BK_DEPTH)] for _ in range (CGRA_N_ROW)] +ker_conf_words = [ker_null_conf for _ in range(CGRA_KMEM_DEPTH)] # First entry is always null ker_conf_words[0] = ker_null_conf @@ -210,19 +234,19 @@ def return_indices_of_a(a, b, name = ''): # PRINT STATS print("CGRA conf. word width :", CGRA_KMEM_WIDTH) -print("CGRA instruction width :", CGRA_IMEM_WIDTH) +print("CGRA instruction width :", CGRA_CMEM_WIDTH) print("CGRA number of kernels :", ker_next_id-1) print("-------------------------------------") # Check instruction memory is large enough -if ker_start_add > CGRA_IMEM_N_LINE: +if ker_start_add > CGRA_CMEM_BK_DEPTH: print("ERROR: TOO MANY INSTRUCTIONS FOR CGRA MEMORY") else: - print("INFO: {}/{} CGRA INSTRUCTIONS".format(ker_start_add, CGRA_IMEM_N_LINE)); + print("INFO: {}/{} CGRA INSTRUCTIONS".format(ker_start_add, CGRA_CMEM_BK_DEPTH)); print("-------------------------------------") -for i in range(0,CGRA_KMEM_N_KER): +for i in range(0,CGRA_KMEM_DEPTH): # ker_logger.log_line(ker_conf_words[i]) ker_logger.log_line(hex(int(ker_conf_words[i],2))) # print(ker_conf_words[i]) diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_check_size.py b/hw/vendor/esl_epfl_cgra/util/instructions_check_size.py new file mode 100644 index 00000000..a0680ce5 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/instructions_check_size.py @@ -0,0 +1,33 @@ +# +# Check CGRA size is correctly configured +# + +ker_col_needed = 1 +ker_num_instr = 6 + +ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ + get_bin(ker_start_add, RCS_NUM_CREG_LOG2) +\ + get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) + +# Save current start address +start_add = ker_start_add +# Update start address and ID for next kernel +ker_start_add = ker_start_add + ker_num_instr*ker_col_needed +ker_next_id = ker_next_id+1 + +# Used for multi-column kernels +k = ker_num_instr + +################################################################################################# +############################################## RC0 ############################################## +################################################################################################# + +# COLUMN-0 +# PROLOGUE +rcs_instructions[0][start_add+0] = [ "-", "-", "LWD", "-", "-", "4"] +rcs_instructions[0][start_add+1] = [ "RCT", "ZERO", "SADD", "-", "-", "-"] # move +rcs_instructions[0][start_add+2] = [ "RCL", "ZERO", "SADD", "-", "-", "-"] # move +rcs_instructions[0][start_add+3] = ["SELF", "-", "SWD", "-", "-", "4"] +rcs_instructions[0][start_add+4] = rcs_nop_instr +rcs_instructions[0][start_add+5] = [ "-", "-", "EXIT", "-", "-", "-"] + diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_max.py b/hw/vendor/esl_epfl_cgra/util/instructions_dbl_max.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_max.py rename to hw/vendor/esl_epfl_cgra/util/instructions_dbl_max.py index a3595c5d..a7fd679f 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_max.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_dbl_max.py @@ -40,7 +40,7 @@ # EPILOGUE rcs_instructions[0][start_add+10] = rcs_nop_instr rcs_instructions[0][start_add+11] = rcs_nop_instr -rcs_instructions[0][start_add+12] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[0][start_add+12] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[0][start_add+13] = [ "-", "-", "EXIT", "-", "-", "-"] ################################################################################################# @@ -49,7 +49,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+ 1] = rcs_nop_instr rcs_instructions[1][start_add+ 2] = [ "-", "R2", "LWI", "R0", "-", "-"] @@ -63,7 +63,7 @@ rcs_instructions[1][start_add+ 9] = rcs_nop_instr # EPILOGUE -rcs_instructions[1][start_add+10] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[1][start_add+10] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[1][start_add+11] = rcs_nop_instr rcs_instructions[1][start_add+12] = rcs_nop_instr rcs_instructions[1][start_add+13] = rcs_nop_instr @@ -89,7 +89,7 @@ # EPILOGUE rcs_instructions[2][start_add+10] = rcs_nop_instr -rcs_instructions[2][start_add+11] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[2][start_add+11] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[2][start_add+12] = rcs_nop_instr rcs_instructions[2][start_add+13] = rcs_nop_instr @@ -100,7 +100,7 @@ # COLUMN-0 # PROLOGUE rcs_instructions[3][start_add+ 0] = [ "IMM", "ZERO", "SADD", "R0", "-", "-1"] # move -rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R3", "-", "-"] +rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R3", "-", "4"] rcs_instructions[3][start_add+ 2] = rcs_nop_instr # ITERATION LOOP diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_min.py b/hw/vendor/esl_epfl_cgra/util/instructions_dbl_min.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_min.py rename to hw/vendor/esl_epfl_cgra/util/instructions_dbl_min.py index dfaf1280..d68ef12b 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_dbl_min.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_dbl_min.py @@ -40,7 +40,7 @@ # EPILOGUE rcs_instructions[0][start_add+10] = rcs_nop_instr rcs_instructions[0][start_add+11] = rcs_nop_instr -rcs_instructions[0][start_add+12] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[0][start_add+12] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[0][start_add+13] = [ "-", "-", "EXIT", "-", "-", "-"] ################################################################################################# @@ -49,7 +49,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+ 1] = rcs_nop_instr rcs_instructions[1][start_add+ 2] = [ "-", "R2", "LWI", "R0", "-", "-"] @@ -63,7 +63,7 @@ rcs_instructions[1][start_add+ 9] = rcs_nop_instr # EPILOGUE -rcs_instructions[1][start_add+10] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[1][start_add+10] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[1][start_add+11] = rcs_nop_instr rcs_instructions[1][start_add+12] = rcs_nop_instr rcs_instructions[1][start_add+13] = rcs_nop_instr @@ -89,7 +89,7 @@ # EPILOGUE rcs_instructions[2][start_add+10] = rcs_nop_instr -rcs_instructions[2][start_add+11] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[2][start_add+11] = [ "R0", "-", "SWD", "-", "-", "4"] rcs_instructions[2][start_add+12] = rcs_nop_instr rcs_instructions[2][start_add+13] = rcs_nop_instr @@ -100,7 +100,7 @@ # COLUMN-0 # PROLOGUE rcs_instructions[3][start_add+ 0] = [ "IMM", "ZERO", "SADD", "R0", "-", "-1"] # move -rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R3", "-", "-"] +rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R3", "-", "4"] rcs_instructions[3][start_add+ 2] = rcs_nop_instr # ITERATION LOOP diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_fft_bitrev.py b/hw/vendor/esl_epfl_cgra/util/instructions_fft_bitrev.py new file mode 100644 index 00000000..0e7cb32a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/instructions_fft_bitrev.py @@ -0,0 +1,103 @@ +# +# FFT input bit reversal reordering instructions (manual mapping) +# + +ker_col_needed = 1 +ker_num_instr = 11 + +ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ + get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ + get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) + +# Save current start address +start_add = ker_start_add +# Update start address and ID for next kernel +ker_start_add = ker_start_add + ker_num_instr*ker_col_needed +ker_next_id = ker_next_id+1 + +# Used for multi-column kernels +k = ker_num_instr + +################################################################################################# +############################################## RC0 ############################################## +################################################################################################# + +# COLUMN-0 +# PROLOGUE +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[0][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] +rcs_instructions[0][start_add+ 2] = rcs_nop_instr +rcs_instructions[0][start_add+ 3] = [ "R0", "RCB", "SADD", "R0", "-", "-"] + +# ITERATION LOOP +rcs_instructions[0][start_add+ 4] = [ "-", "R0", "LWI", "R2", "-", "-"] +rcs_instructions[0][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "8"] +rcs_instructions[0][start_add+ 6] = rcs_nop_instr +rcs_instructions[0][start_add+ 7] = rcs_nop_instr + +rcs_instructions[0][start_add+ 8] = [ "RCB", "IMM", "SLT", "-", "-", "2"] +rcs_instructions[0][start_add+ 9] = [ "R1", "SELF", "SADD", "-", "-", "-"] +rcs_instructions[0][start_add+10] = [ "R2", "SELF", "SWI", "-", "-", "-"] + +################################################################################################# +############################################## RC1 ############################################## +################################################################################################# + +# COLUMN-0 +# PROLOGUE +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[1][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] +rcs_instructions[1][start_add+ 2] = [ "RCB", "IMM", "SLT", "-", "-", "2"] +rcs_instructions[1][start_add+ 3] = [ "R0", "SELF", "SADD", "R0", "-", "-"] + +# ITERATION LOOP +rcs_instructions[1][start_add+ 4] = [ "-", "R0", "LWI", "R2", "-", "-"] +rcs_instructions[1][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "8"] +rcs_instructions[1][start_add+ 6] = [ "R3", "IMM", "SLT", "-", "-", "1"] +rcs_instructions[1][start_add+ 7] = ["SELF", "RCB", "LOR", "R3", "-", "-"] + +rcs_instructions[1][start_add+ 8] = ["ZERO", "ZERO", "SADD", "R3", "-", "-"] # R3=0 +rcs_instructions[1][start_add+ 9] = [ "RCT", "R1", "SADD", "-", "-", "-"] +rcs_instructions[1][start_add+10] = [ "R2", "SELF", "SWI", "-", "-", "-"] + +################################################################################################# +############################################## RC2 ############################################## +################################################################################################# + +# COLUMN-0 +# PROLOGUE +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R1", "-", "4"] +rcs_instructions[2][start_add+ 1] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[2][start_add+ 2] = rcs_nop_instr +rcs_instructions[2][start_add+ 3] = rcs_nop_instr + +# ITERATION LOOP +rcs_instructions[2][start_add+ 4] = ["ZERO", "R0", "SADD", "R2", "-", "-"] # R2=R0 +rcs_instructions[2][start_add+ 5] = rcs_nop_instr +rcs_instructions[2][start_add+ 6] = [ "R2", "IMM", "LAND", "-", "-", "1"] +rcs_instructions[2][start_add+ 7] = [ "R2", "IMM", "SRT", "R2", "-", "1"] + +rcs_instructions[2][start_add+ 8] = [ "R0", "IMM", "SADD", "R0", "-", "1"] +rcs_instructions[2][start_add+ 9] = rcs_nop_instr +rcs_instructions[2][start_add+10] = [ "R0", "R1", "BLT", "-", "-", "4"] + +################################################################################################# +############################################## RC3 ############################################## +################################################################################################# + +# COLUMN-0 +# PROLOGUE +rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[3][start_add+ 1] = rcs_nop_instr +rcs_instructions[3][start_add+ 2] = rcs_nop_instr +rcs_instructions[3][start_add+ 3] = rcs_nop_instr + +# ITERATION LOOP +rcs_instructions[3][start_add+ 4] = ["ZERO", "ZERO", "SADD", "R1", "-", "-"] # R1=0 +rcs_instructions[3][start_add+ 5] = rcs_nop_instr +rcs_instructions[3][start_add+ 6] = [ "R1", "IMM", "SADD", "R1", "-", "1"] +rcs_instructions[3][start_add+ 7] = [ "R1", "R0", "BLT", "-", "-", "6"] + +rcs_instructions[3][start_add+ 8] = rcs_nop_instr +rcs_instructions[3][start_add+ 9] = rcs_nop_instr +rcs_instructions[3][start_add+10] = [ "-", "-", "EXIT", "-", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx.py b/hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx.py rename to hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx.py index 5695005b..cec59b04 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx.py @@ -24,7 +24,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[0][start_add+ 1] = [ "IMM", "ZERO", "SADD", "R3", "-", "4"] rcs_instructions[0][start_add+ 2] = rcs_nop_instr @@ -75,7 +75,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+ 1] = [ "RCB", "IMM", "SLT", "R1", "-", "1"] rcs_instructions[1][start_add+ 2] = ["ZERO", "ZERO", "BEQ", "-", "-", "9"] @@ -99,7 +99,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+k+ 1] = [ "RCB", "ZERO", "SADD", "-", "-", "-"] rcs_instructions[1][start_add+k+ 2] = rcs_nop_instr @@ -126,7 +126,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "-", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "-", "-", "4"] rcs_instructions[2][start_add+ 1] = ["ZERO", "IMM", "SSUB", "R1", "-", "1"] rcs_instructions[2][start_add+ 2] = [ "RCT", "IMM", "SRT", "R0", "-", "2"] @@ -150,7 +150,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[2][start_add+k+ 1] = ["ZERO", "RCB", "SADD", "R1", "-", "-"] rcs_instructions[2][start_add+k+ 2] = rcs_nop_instr @@ -201,7 +201,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "-", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "-", "-", "4"] rcs_instructions[3][start_add+k+ 1] = ["ZERO", "IMM", "SADD", "R2", "-", "1"] rcs_instructions[3][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R0", "-", "1"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx_forever.py b/hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx_forever.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx_forever.py rename to hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx_forever.py index 3384c22e..b3ee7dd8 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_cplx_forever.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_fft_cplx_forever.py @@ -24,7 +24,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[0][start_add+ 1] = [ "IMM", "ZERO", "SADD", "R3", "-", "4"] rcs_instructions[0][start_add+ 2] = rcs_nop_instr @@ -77,7 +77,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+ 1] = [ "RCB", "IMM", "SLT", "R1", "-", "1"] rcs_instructions[1][start_add+ 2] = ["ZERO", "ZERO", "BEQ", "-", "-", "9"] @@ -102,7 +102,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[1][start_add+k+ 1] = [ "RCB", "ZERO", "SADD", "-", "-", "-"] rcs_instructions[1][start_add+k+ 2] = rcs_nop_instr @@ -130,7 +130,7 @@ # COLUMN-0 # PROLOGUE -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[2][start_add+ 1] = ["ZERO", "IMM", "SSUB", "R1", "-", "1"] rcs_instructions[2][start_add+ 2] = [ "RCT", "IMM", "SRT", "R0", "-", "2"] @@ -155,7 +155,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R2", "-", "4"] rcs_instructions[2][start_add+k+ 1] = ["ZERO", "RCB", "SADD", "R1", "-", "-"] rcs_instructions[2][start_add+k+ 2] = rcs_nop_instr @@ -208,7 +208,7 @@ # COLUMN-1 # PROLOGUE -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[3][start_add+k+ 1] = ["ZERO", "IMM", "SADD", "R2", "-", "1"] rcs_instructions[3][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R0", "-", "1"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_func_test.py b/hw/vendor/esl_epfl_cgra/util/instructions_func_test.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_func_test.py rename to hw/vendor/esl_epfl_cgra/util/instructions_func_test.py index 3d2a5054..8c0acb1c 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_func_test.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_func_test.py @@ -23,8 +23,8 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[0][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[0][start_add+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[0][start_add+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -57,8 +57,8 @@ rcs_instructions[0][start_add+31] = [ "-", "-", "EXIT", "-", "-", "-"] # COLUMN-1 -rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[0][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[0][start_add+k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[0][start_add+k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -91,8 +91,8 @@ rcs_instructions[0][start_add+k+31] = [ "IMM", "ZERO", "SADD", "R3", "-", "-13"] # move # COLUMN-2 -rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[0][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[0][start_add+2*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+2*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[0][start_add+2*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -125,8 +125,8 @@ rcs_instructions[0][start_add+2*k+31] = rcs_nop_instr # COLUMN-3 -rcs_instructions[0][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[0][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[0][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[0][start_add+3*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+3*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[0][start_add+3*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -164,8 +164,8 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[1][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[1][start_add+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[1][start_add+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -198,8 +198,8 @@ rcs_instructions[1][start_add+31] = rcs_nop_instr # COLUMN-1 -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[1][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[1][start_add+k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[1][start_add+k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -232,8 +232,8 @@ rcs_instructions[1][start_add+k+31] = rcs_nop_instr # COLUMN-2 -rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[1][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[1][start_add+2*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+2*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[1][start_add+2*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -266,8 +266,8 @@ rcs_instructions[1][start_add+2*k+31] = rcs_nop_instr # COLUMN-3 -rcs_instructions[1][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[1][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[1][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[1][start_add+3*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+3*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[1][start_add+3*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -304,8 +304,8 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[2][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[2][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[2][start_add+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[2][start_add+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -338,8 +338,8 @@ rcs_instructions[2][start_add+31] = rcs_nop_instr # COLUMN-1 -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[2][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[2][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[2][start_add+k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[2][start_add+k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -372,8 +372,8 @@ rcs_instructions[2][start_add+k+31] = rcs_nop_instr # COLUMN-2 -rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[2][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[2][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[2][start_add+2*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+2*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[2][start_add+2*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -406,8 +406,8 @@ rcs_instructions[2][start_add+2*k+31] = rcs_nop_instr # COLUMN-3 -rcs_instructions[2][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[2][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[2][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[2][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[2][start_add+3*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+3*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[2][start_add+3*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -444,8 +444,8 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[3][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[3][start_add+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[3][start_add+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -478,8 +478,8 @@ rcs_instructions[3][start_add+31] = rcs_nop_instr # COLUMN-1 -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[3][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[3][start_add+k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[3][start_add+k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[3][start_add+k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -512,8 +512,8 @@ rcs_instructions[3][start_add+k+31] = rcs_nop_instr # COLUMN-2 -rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[3][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[3][start_add+2*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[3][start_add+2*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+2*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[3][start_add+2*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] @@ -546,8 +546,8 @@ rcs_instructions[3][start_add+2*k+31] = rcs_nop_instr # COLUMN-3 -rcs_instructions[3][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[3][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] +rcs_instructions[3][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] +rcs_instructions[3][start_add+3*k+ 1] = [ "-", "-", "LWD", "R1", "-", "4"] rcs_instructions[3][start_add+3*k+ 2] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+3*k+ 3] = [ "RCB", "R2", "SADD", "R2", "-", "-"] rcs_instructions[3][start_add+3*k+ 4] = [ "R2", "RCT", "SSUB", "R3", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py b/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py new file mode 100644 index 00000000..5c236c82 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py @@ -0,0 +1,87 @@ +# +# MAX_PEAK search instructions DEPREDECATED +# + +ker_col_needed = 1 +ker_num_instr = 11 + +ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ + get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ + get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) + +# Save current start address +start_add = ker_start_add +# Update start address and ID for next kernel +ker_start_add = ker_start_add + ker_num_instr*ker_col_needed +ker_next_id = ker_next_id+1 + +# Used for multi-column kernels +k = ker_num_instr + +################################################################################################# +############################################## RC0 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[0][start_add+ 0] = rcs_nop_instr +rcs_instructions[0][start_add+ 1] = rcs_nop_instr +rcs_instructions[0][start_add+ 2] = ["SRAM", "-", "LWD", "R1", "-", "-"] +rcs_instructions[0][start_add+ 3] = ["SRAM", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+ 4] = rcs_nop_instr +rcs_instructions[0][start_add+ 5] = [ "R2", "R1", "SSUB", "-", "-", "-"] +rcs_instructions[0][start_add+ 6] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] +rcs_instructions[0][start_add+ 7] = [ "R2", "PREV", "BSFA", "R2", "RCB", "-"] +rcs_instructions[0][start_add+ 8] = [ "R0", "-", "INA", "R1", "-", "-"] +rcs_instructions[0][start_add+ 9] = rcs_nop_instr +rcs_instructions[0][start_add+10] = [ "R2", "-", "SWD", "-", "-", "-"] + +################################################################################################# +############################################## RC1 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[1][start_add+ 0] = rcs_nop_instr +rcs_instructions[1][start_add+ 1] = ["SRAM", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+ 2] = [ "-", "IMM", "INB", "R1", "-", "-1"] +rcs_instructions[1][start_add+ 3] = [ "RCT", "-", "INA", "R3", "-", "-"] +rcs_instructions[1][start_add+ 4] = [ "R3", "R0", "SSUB", "-", "-", "-"] +rcs_instructions[1][start_add+ 5] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] +rcs_instructions[1][start_add+ 6] = [ "RCB", "PREV", "SADD", "-", "-", "-"] +rcs_instructions[1][start_add+ 7] = rcs_nop_instr +rcs_instructions[1][start_add+ 8] = [ "R3", "-", "INA", "R0", "-", "-"] +rcs_instructions[1][start_add+ 9] = rcs_nop_instr +rcs_instructions[1][start_add+10] = rcs_nop_instr + +################################################################################################# +############################################## RC2 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[2][start_add+ 0] = rcs_nop_instr +rcs_instructions[2][start_add+ 1] = rcs_nop_instr +rcs_instructions[2][start_add+ 2] = [ "-", "IMM", "INB", "R1", "-", "-1"] +rcs_instructions[2][start_add+ 3] = ["SRAM", "-", "INA", "-", "-", "-"] +rcs_instructions[2][start_add+ 4] = [ "RCB", "PREV", "SSUB", "-", "-", "-"] +rcs_instructions[2][start_add+ 5] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] +rcs_instructions[2][start_add+ 6] = [ "RCT", "PREV", "SADD", "-", "-", "-"] +rcs_instructions[2][start_add+ 7] = rcs_nop_instr +rcs_instructions[2][start_add+ 8] = rcs_nop_instr +rcs_instructions[2][start_add+ 9] = rcs_nop_instr +rcs_instructions[2][start_add+10] = [ "-", "-", "EXIT", "-", "-", "-"] + +################################################################################################# +############################################## RC3 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[3][start_add+ 0] = ["SRAM", "-", "LWD", "R3", "-", "-"] +rcs_instructions[3][start_add+ 1] = rcs_nop_instr +rcs_instructions[3][start_add+ 2] = ["SRAM", "-", "INA", "R1", "-", "-"] +rcs_instructions[3][start_add+ 3] = [ "R1", "-", "INA", "-", "-", "-"] +rcs_instructions[3][start_add+ 4] = [ "RCB", "-", "INA", "R1", "-", "-"] +rcs_instructions[3][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "1"] +rcs_instructions[3][start_add+ 6] = [ "R0", "R2", "BSFA", "-", "RCB", "-"] +rcs_instructions[3][start_add+ 7] = [ "R2", "PREV", "BSFA", "R2", "RCT", "-"] +rcs_instructions[3][start_add+ 8] = [ "R0", "R3", "BLT", "-", "-", "3"] +rcs_instructions[3][start_add+ 9] = [ "R2", "-", "SWD", "-", "-", "-"] +rcs_instructions[3][start_add+10] = rcs_nop_instr diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py b/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py new file mode 100644 index 00000000..2669aa8d --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py @@ -0,0 +1,83 @@ +# +# MIN_MAX_CIRCULAR search instructions (manual mapping) DEPREDECATED +# + +ker_col_needed = 1 +ker_num_instr = 10 + +ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ + get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ + get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) + +# Save current start address +start_add = ker_start_add +# Update start address and ID for next kernel +ker_start_add = ker_start_add + ker_num_instr*ker_col_needed +ker_next_id = ker_next_id+1 + +# Used for multi-column kernels +k = ker_num_instr + +################################################################################################# +############################################## RC0 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[0][start_add+ 0] = rcs_nop_instr +rcs_instructions[0][start_add+ 1] = [ "RCB", "IMM", "SLT", "R3", "-", "2"] +rcs_instructions[0][start_add+ 2] = [ "RCB", "IMM", "SLT", "R1", "-", "2"] +rcs_instructions[0][start_add+ 3] = ["SRAM", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+ 4] = [ "R0", "R1", "SADD", "-", "-", "-"] +rcs_instructions[0][start_add+ 5] = [ "R1", "IMM", "SADD", "-", "-", "4"] +rcs_instructions[0][start_add+ 6] = [ "R3", "PREV", "LAND", "R1", "-", "-"] +rcs_instructions[0][start_add+ 7] = [ "R0", "R1", "SADD", "-", "-", "-"] +rcs_instructions[0][start_add+ 8] = rcs_nop_instr +rcs_instructions[0][start_add+ 9] = rcs_nop_instr + +################################################################################################# +############################################## RC1 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[1][start_add+ 0] = ["SRAM", "-", "LWD", "-", "-", "-"] +rcs_instructions[1][start_add+ 1] = ["SRAM", "-", "LWD", "-", "-", "-"] +rcs_instructions[1][start_add+ 2] = ["SRAM", "-", "LWD", "R3", "-", "-"] +rcs_instructions[1][start_add+ 3] = rcs_nop_instr +rcs_instructions[1][start_add+ 4] = rcs_nop_instr +rcs_instructions[1][start_add+ 5] = ["SRAM", "RCT", "LWI", "-", "-", "-"] +rcs_instructions[1][start_add+ 6] = [ "R0", "IMM", "SADD", "R0", "-", "1"] +rcs_instructions[1][start_add+ 7] = [ "R0", "R3", "BLT", "-", "-", "5"] +rcs_instructions[1][start_add+ 8] = rcs_nop_instr +rcs_instructions[1][start_add+ 9] = rcs_nop_instr + +################################################################################################# +############################################## RC2 ############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[2][start_add+ 0] = rcs_nop_instr +rcs_instructions[2][start_add+ 1] = rcs_nop_instr +rcs_instructions[2][start_add+ 2] = rcs_nop_instr +rcs_instructions[2][start_add+ 3] = rcs_nop_instr +rcs_instructions[2][start_add+ 4] = rcs_nop_instr +rcs_instructions[2][start_add+ 5] = ["SRAM", "-", "INA", "R1", "-", "-"] +rcs_instructions[2][start_add+ 6] = [ "R0", "R1", "SSUB", "-", "-", "-"] +rcs_instructions[2][start_add+ 7] = [ "R1", "R0", "BSFA", "R0", "PREV", "-"] +rcs_instructions[2][start_add+ 8] = [ "R0", "-", "SWD", "-", "-", "-"] +rcs_instructions[2][start_add+ 9] = [ "-", "-", "EXIT", "-", "-", "-"] + +################################################################################################# +############################################## RC03############################################## +################################################################################################# + +# COLUMN-0 +rcs_instructions[3][start_add+ 0] = rcs_nop_instr +rcs_instructions[3][start_add+ 1] = rcs_nop_instr +rcs_instructions[3][start_add+ 2] = rcs_nop_instr +rcs_instructions[3][start_add+ 3] = rcs_nop_instr +rcs_instructions[3][start_add+ 4] = rcs_nop_instr +rcs_instructions[3][start_add+ 5] = ["SRAM", "-", "INA", "R1", "-", "-"] +rcs_instructions[3][start_add+ 6] = [ "R0", "R1", "SSUB", "-", "-", "-"] +rcs_instructions[3][start_add+ 7] = [ "R0", "R1", "BSFA", "R0", "PREV", "-"] +rcs_instructions[3][start_add+ 8] = rcs_nop_instr +rcs_instructions[3][start_add+ 9] = [ "R0", "-", "SWD", "-", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_100percent.py b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_100percent.py similarity index 97% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_100percent.py rename to hw/vendor/esl_epfl_cgra/util/instructions_while_loop_100percent.py index 83b705d1..d4a22242 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_100percent.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_100percent.py @@ -23,7 +23,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -33,7 +33,7 @@ rcs_instructions[0][start_add+ 7] = [ "-", "-", "EXIT", "-", "-", "-"] # COLUMN-1 -rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -43,7 +43,7 @@ rcs_instructions[0][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+2*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -53,7 +53,7 @@ rcs_instructions[0][start_add+2*k+ 7] = rcs_nop_instr # COLUMN-3 -rcs_instructions[0][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+3*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+3*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+3*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -67,7 +67,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -77,7 +77,7 @@ rcs_instructions[1][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -87,7 +87,7 @@ rcs_instructions[1][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+2*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -97,7 +97,7 @@ rcs_instructions[1][start_add+2*k+ 7] = rcs_nop_instr # COLUMN-3 -rcs_instructions[1][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+3*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+3*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+3*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -111,7 +111,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -121,7 +121,7 @@ rcs_instructions[2][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -131,7 +131,7 @@ rcs_instructions[2][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+2*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -141,7 +141,7 @@ rcs_instructions[2][start_add+2*k+ 7] = rcs_nop_instr # COLUMN-3 -rcs_instructions[2][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+3*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+3*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+3*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -155,7 +155,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -165,7 +165,7 @@ rcs_instructions[3][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -175,7 +175,7 @@ rcs_instructions[3][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+2*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -186,7 +186,7 @@ # COLUMN-3 -rcs_instructions[3][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+3*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+3*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+3*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+3*k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_50percent.py b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_50percent.py similarity index 98% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_50percent.py rename to hw/vendor/esl_epfl_cgra/util/instructions_while_loop_50percent.py index 2867debf..361955e0 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_50percent.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_50percent.py @@ -23,7 +23,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -33,7 +33,7 @@ rcs_instructions[0][start_add+ 7] = [ "-", "-", "EXIT", "-", "-", "-"] # COLUMN-1 -rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -67,7 +67,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -77,7 +77,7 @@ rcs_instructions[1][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -111,7 +111,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -121,7 +121,7 @@ rcs_instructions[2][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -155,7 +155,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -165,7 +165,7 @@ rcs_instructions[3][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_75percent.py b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_75percent.py similarity index 97% rename from hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_75percent.py rename to hw/vendor/esl_epfl_cgra/util/instructions_while_loop_75percent.py index eba2c310..daab0386 100644 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_while_loop_75percent.py +++ b/hw/vendor/esl_epfl_cgra/util/instructions_while_loop_75percent.py @@ -23,7 +23,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -33,7 +33,7 @@ rcs_instructions[0][start_add+ 7] = [ "-", "-", "EXIT", "-", "-", "-"] # COLUMN-1 -rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -43,7 +43,7 @@ rcs_instructions[0][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[0][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[0][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[0][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[0][start_add+2*k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -67,7 +67,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -77,7 +77,7 @@ rcs_instructions[1][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -87,7 +87,7 @@ rcs_instructions[1][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[1][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[1][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[1][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[1][start_add+2*k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -111,7 +111,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -121,7 +121,7 @@ rcs_instructions[2][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -131,7 +131,7 @@ rcs_instructions[2][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[2][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[2][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[2][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[2][start_add+2*k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] @@ -155,7 +155,7 @@ ################################################################################################# # COLUMN-0 -rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -165,7 +165,7 @@ rcs_instructions[3][start_add+ 7] = rcs_nop_instr # COLUMN-1 -rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+k+ 3] = [ "RCB", "R2", "SMUL", "R2", "-", "-"] @@ -175,7 +175,7 @@ rcs_instructions[3][start_add+k+ 7] = rcs_nop_instr # COLUMN-2 -rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] +rcs_instructions[3][start_add+2*k+ 0] = [ "-", "-", "LWD", "R0", "-", "4"] rcs_instructions[3][start_add+2*k+ 1] = [ "-", "R0", "LWI", "R2", "-", "-"] rcs_instructions[3][start_add+2*k+ 2] = ["ZERO", "IMM", "SADD", "R1", "-", "123"] rcs_instructions[3][start_add+2*k+ 3] = [ "RCT", "R2", "SMUL", "R2", "-", "-"] diff --git a/hw/vendor/esl_epfl_cgra/utilities/log2file.py b/hw/vendor/esl_epfl_cgra/util/log2file.py similarity index 100% rename from hw/vendor/esl_epfl_cgra/utilities/log2file.py rename to hw/vendor/esl_epfl_cgra/util/log2file.py diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/README.md b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/README.md new file mode 100644 index 00000000..ea244dc6 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/README.md @@ -0,0 +1,113 @@ +# Register generator `reggen` and `regtool` + +The utility script `regtool.py` and collateral under `reggen` are Python +tools to read register descriptions in Hjson and generate various output +formats. The tool can output HTML documentation, standard JSON, compact +standard JSON (whitespace removed) and Hjson. The example commands assume +`$REPO_TOP` is set to the toplevel directory of the repository. + +### Setup + +If packages have not previously been installed you will need to set a +few things up. First use `pip3` to install some required packages: + +```console +$ pip3 install --user hjson +$ pip3 install --user mistletoe +$ pip3 install --user mako +``` + +### Register JSON Format + +For details on the register JSON format, see the +[register tool documentation]({{< relref "doc/rm/register_tool/index.md" >}}). +To ensure things stay up to date, the register JSON format information +is documented by the tool itself. +The documentation can be generated by running the following commands: + +```console +$ cd $REPO_TOP/util +$ ./build_docs.py +``` +Under the hood, the `build_docs.py` tool will automatically use the `reggen` +tool to produce Markdown and processing that into HTML. + +### Examples using standalone regtool + +Normally for documentation the `build_docs.py` tool will automatically +use `reggen`. The script `regtool.py` provides a standalone way to run +`reggen`. See the +[register tool documentation]({{< relref "doc/rm/register_tool/index.md" >}}) +for details about how to invoke the tool. + +The following shows an example of how to generate RTL from a register +description: + +```console +$ cd $REPO_TOP/util +$ mkdir /tmp/rtl +$ ./regtool.py -r -t /tmp/rtl ../hw/ip/uart/data/uart.hjson +$ ls /tmp/rtl + uart_reg_pkg.sv uart_reg_top.sv +``` + +The following shows an example of how to generate a DV UVM class from +a register description: + +```console +$ cd $REPO_TOP/util +$ mkdir /tmp/dv +$ ./regtool.py -s -t /tmp/dv ../hw/ip/uart/data/uart.hjson +$ ls /tmp/dv + uart_ral_pkg.sv +``` + +By default, the generated block, register and field models are derived from +`dv_base_reg` classes provided at `hw/dv/sv/dv_base_reg`. If required, the user +can supply the `--dv-base-prefix my_base` switch to have the models derive from +a custom, user-defined RAL classes instead: + +```console +$ cd $REPO_TOP/util +$ mkdir /tmp/dv +$ ./regtool.py -s -t /tmp/dv ../hw/ip/uart/data/uart.hjson \ + --dv-base-prefix my_base +$ ls /tmp/dv + uart_ral_pkg.sv +``` + +This makes the following assumptions: +- A FuseSoC core file aggregating the `my_base` RAL classes with the VLNV + name `lowrisc:dv:my_base_reg` is provided in the cores search path. +- These custom classes are derived from the corresponding `dv_base_reg` classes + and have the following names: + - `my_base_reg_pkg.sv`: The RAL package that includes the below sources + - `my_base_reg_block.sv`: The register block abstraction + - `my_base_reg.sv`: The register abstraction + - `my_base_reg_field.sv`: The register field abstraction + - `my_base_mem.sv`: The memory abstraction +- If any of the above class specializations is not needed, it can be + `typedef`'ed in `my_base_reg_pkg`: + ```systemverilog + package my_base_reg_pkg; + import dv_base_reg_pkg::*; + typedef dv_base_reg_field my_base_reg_field; + typedef dv_base_mem my_base_mem; + `include "my_base_reg.sv" + `include "my_base_reg_block.sv" + endpackage + ``` + +The following shows an example of how to generate a FPV csr read write assertion +module from a register description: + +```console +$ cd $REPO_TOP/util +$ mkdir /tmp/fpv/vip +$ ./regtool.py -f -t /tmp/fpv/vip ../hw/ip/uart/data/uart.hjson +$ ls /tmp/fpv + uart_csr_assert_fpv.sv +``` + +If the target directory is not specified, the tool creates the DV file +under the `hw/ip/{module}/dv/` directory. diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/__init__.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/access.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/access.py new file mode 100644 index 00000000..286fc87b --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/access.py @@ -0,0 +1,121 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Enumerated types for fields +Generated by validation, used by backends +""" + +from enum import Enum + +from .lib import check_str + + +class JsonEnum(Enum): + def for_json(x) -> str: + return str(x) + + +class SwWrAccess(JsonEnum): + WR = 1 + NONE = 2 + + +class SwRdAccess(JsonEnum): + RD = 1 + RC = 2 # Special handling for port + NONE = 3 + + +class SwAccess(JsonEnum): + RO = 1 + RW = 2 + WO = 3 + W1C = 4 + W1S = 5 + W0C = 6 + RC = 7 + R0W1C = 8 + NONE = 9 + + +class HwAccess(JsonEnum): + HRO = 1 + HRW = 2 + HWO = 3 + NONE = 4 # No access allowed + + +# swaccess permitted values +# text description, access enum, wr access enum, rd access enum, ok in window +SWACCESS_PERMITTED = { + 'none': ("No access", # noqa: E241 + SwAccess.NONE, SwWrAccess.NONE, SwRdAccess.NONE, False), # noqa: E241 + 'ro': ("Read Only", # noqa: E241 + SwAccess.RO, SwWrAccess.NONE, SwRdAccess.RD, True), # noqa: E241 + 'rc': ("Read Only, reading clears", # noqa: E241 + SwAccess.RC, SwWrAccess.WR, SwRdAccess.RC, False), # noqa: E241 + 'rw': ("Read/Write", # noqa: E241 + SwAccess.RW, SwWrAccess.WR, SwRdAccess.RD, True), # noqa: E241 + 'r0w1c': ("Read zero, Write with 1 clears", # noqa: E241 + SwAccess.W1C, SwWrAccess.WR, SwRdAccess.NONE, False), # noqa: E241 + 'rw1s': ("Read, Write with 1 sets", # noqa: E241 + SwAccess.W1S, SwWrAccess.WR, SwRdAccess.RD, False), # noqa: E241 + 'rw1c': ("Read, Write with 1 clears", # noqa: E241 + SwAccess.W1C, SwWrAccess.WR, SwRdAccess.RD, False), # noqa: E241 + 'rw0c': ("Read, Write with 0 clears", # noqa: E241 + SwAccess.W0C, SwWrAccess.WR, SwRdAccess.RD, False), # noqa: E241 + 'wo': ("Write Only", # noqa: E241 + SwAccess.WO, SwWrAccess.WR, SwRdAccess.NONE, True) # noqa: E241 +} + +# hwaccess permitted values +HWACCESS_PERMITTED = { + 'hro': ("Read Only", HwAccess.HRO), + 'hrw': ("Read/Write", HwAccess.HRW), + 'hwo': ("Write Only", HwAccess.HWO), + 'none': ("No Access Needed", HwAccess.NONE) +} + + +class SWAccess: + def __init__(self, where: str, raw: object): + self.key = check_str(raw, 'swaccess for {}'.format(where)) + try: + self.value = SWACCESS_PERMITTED[self.key] + except KeyError: + raise ValueError('Unknown swaccess key, {}, for {}.' + .format(self.key, where)) from None + + def dv_rights(self) -> str: + if self.key in ['none', 'ro', 'rc']: + return "RO" + elif self.key in ['rw', 'r0w1c', 'rw1s', 'rw1c', 'rw0c']: + return "RW" + else: + assert self.key == 'wo' + return "WO" + + def swrd(self) -> SwRdAccess: + return self.value[3] + + def allows_read(self) -> bool: + return self.value[3] != SwRdAccess.NONE + + def allows_write(self) -> bool: + return self.value[2] == SwWrAccess.WR + + +class HWAccess: + def __init__(self, where: str, raw: object): + self.key = check_str(raw, 'hwaccess for {}'.format(where)) + try: + self.value = HWACCESS_PERMITTED[self.key] + except KeyError: + raise ValueError('Unknown hwaccess key, {}, for {}.' + .format(self.key, where)) from None + + def allows_read(self) -> bool: + return self.key in ['hro', 'hrw'] + + def allows_write(self) -> bool: + return self.key in ['hrw', 'hwo'] diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/alert.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/alert.py new file mode 100644 index 00000000..a23ff491 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/alert.py @@ -0,0 +1,54 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, List + +from .bits import Bits +from .signal import Signal +from .lib import check_keys, check_name, check_str, check_list + + +class Alert(Signal): + def __init__(self, name: str, desc: str, bit: int, fatal: bool): + super().__init__(name, desc, Bits(bit, bit)) + self.bit = bit + self.fatal = fatal + + @staticmethod + def from_raw(what: str, + lsb: int, + raw: object) -> 'Alert': + rd = check_keys(raw, what, ['name', 'desc'], []) + + name = check_name(rd['name'], 'name field of ' + what) + desc = check_str(rd['desc'], 'desc field of ' + what) + + # Make sense of the alert name, which should be prefixed with recov_ or + # fatal_. + pfx = name.split('_')[0] + if pfx == 'recov': + fatal = False + elif pfx == 'fatal': + fatal = True + else: + raise ValueError('Invalid name field of {}: alert names must be ' + 'prefixed with "recov_" or "fatal_". Saw {!r}.' + .format(what, name)) + + return Alert(name, desc, lsb, fatal) + + @staticmethod + def from_raw_list(what: str, raw: object) -> List['Alert']: + ret = [] + for idx, entry in enumerate(check_list(raw, what)): + entry_what = 'entry {} of {}'.format(idx, what) + alert = Alert.from_raw(entry_what, idx, entry) + ret.append(alert) + return ret + + def _asdict(self) -> Dict[str, object]: + return { + 'name': self.name, + 'desc': self.desc, + } diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bits.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bits.py new file mode 100644 index 00000000..c8d48f70 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bits.py @@ -0,0 +1,87 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Support code for bit ranges in reggen''' + +from typing import Tuple + +from .lib import check_str +from .params import ReggenParams + + +class Bits: + def __init__(self, msb: int, lsb: int): + assert 0 <= lsb <= msb + self.msb = msb + self.lsb = lsb + + def bitmask(self) -> int: + return (1 << (self.msb + 1)) - (1 << self.lsb) + + def width(self) -> int: + return 1 + self.msb - self.lsb + + def max_value(self) -> int: + return (1 << self.width()) - 1 + + def extract_field(self, reg_val: int) -> int: + return (reg_val & self.bitmask()) >> self.lsb + + @staticmethod + def from_raw(where: str, + reg_width: int, + params: ReggenParams, + raw: object) -> 'Bits': + # Bits should be specified as msb:lsb or as just a single bit index. + if isinstance(raw, int): + msb = raw + lsb = raw + else: + str_val = check_str(raw, 'bits field for {}'.format(where)) + msb, lsb = Bits._parse_str(where, params, str_val) + + # Check that the bit indices look sensible + if msb < lsb: + raise ValueError('msb for {} is {}: less than {}, the msb.' + .format(where, msb, lsb)) + if lsb < 0: + raise ValueError('lsb for {} is {}, which is negative.' + .format(where, lsb)) + if msb >= reg_width: + raise ValueError("msb for {} is {}, which doesn't fit in {} bits." + .format(where, msb, reg_width)) + + return Bits(msb, lsb) + + @staticmethod + def _parse_str(where: str, + params: ReggenParams, + str_val: str) -> Tuple[int, int]: + try: + idx = int(str_val) + return (idx, idx) + except ValueError: + # Doesn't look like an integer. Never mind: try msb:lsb + pass + + parts = str_val.split(':') + if len(parts) != 2: + raise ValueError('bits field for {} is not an ' + 'integer or of the form msb:lsb. Saw {!r}.' + .format(where, str_val)) + return (params.expand(parts[0], + 'msb of bits field for {}'.format(where)), + params.expand(parts[1], + 'lsb of bits field for {}'.format(where))) + + def make_translated(self, bit_offset: int) -> 'Bits': + assert 0 <= bit_offset + return Bits(self.msb + bit_offset, self.lsb + bit_offset) + + def as_str(self) -> str: + if self.lsb == self.msb: + return str(self.lsb) + else: + assert self.lsb < self.msb + return '{}:{}'.format(self.msb, self.lsb) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bus_interfaces.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bus_interfaces.py new file mode 100644 index 00000000..37c5818e --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/bus_interfaces.py @@ -0,0 +1,187 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Code representing a list of bus interfaces for a block''' +from enum import Enum +from typing import Dict, List, Optional, Tuple + +from .inter_signal import InterSignal +from .lib import check_list, check_keys, check_str, check_optional_str + +class BusProtocol(Enum): + TLUL = "tlul" + REG_IFACE = "reg_iface" + + @classmethod + def has_value(cls, v): + return v in cls._value2member_map_ + + +class BusInterfaces: + def __init__(self, + has_unnamed_host: bool, + named_hosts: List[str], + has_unnamed_device: bool, + named_devices: List[str], + interface_list: List[Dict]): + assert has_unnamed_device or named_devices + assert len(named_hosts) == len(set(named_hosts)) + assert len(named_devices) == len(set(named_devices)) + + self.has_unnamed_host = has_unnamed_host + self.named_hosts = named_hosts + self.has_unnamed_device = has_unnamed_device + self.named_devices = named_devices + self.interface_list = interface_list + + @staticmethod + def from_raw(raw: object, where: str) -> 'BusInterfaces': + has_unnamed_host = False + named_hosts = [] + interface_list = [] + + has_unnamed_device = False + named_devices = [] + + for idx, raw_entry in enumerate(check_list(raw, where)): + entry_what = 'entry {} of {}'.format(idx + 1, where) + ed = check_keys(raw_entry, entry_what, + ['protocol', 'direction'], + ['name']) + + protocol = check_str(ed['protocol'], + 'protocol field of ' + entry_what) + if not BusProtocol.has_value(protocol): + raise ValueError('Unknown protocol {!r} at {}' + .format(protocol, entry_what)) + + direction = check_str(ed['direction'], + 'direction field of ' + entry_what) + if direction not in ['device', 'host']: + raise ValueError('Unknown interface direction {!r} at {}' + .format(direction, entry_what)) + + name = check_optional_str(ed.get('name'), + 'name field of ' + entry_what) + + if direction == 'host': + if name is None: + if has_unnamed_host: + raise ValueError('Multiple un-named host ' + 'interfaces at {}' + .format(where)) + has_unnamed_host = True + else: + if name in named_hosts: + raise ValueError('Duplicate host interface ' + 'with name {!r} at {}' + .format(name, where)) + named_hosts.append(name) + else: + if name is None: + if has_unnamed_device: + raise ValueError('Multiple un-named device ' + 'interfaces at {}' + .format(where)) + has_unnamed_device = True + else: + if name in named_devices: + raise ValueError('Duplicate device interface ' + 'with name {!r} at {}' + .format(name, where)) + named_devices.append(name) + interface_list.append({'name': name, 'protocol': BusProtocol(protocol), 'is_host': direction=='host'}) + + if not (has_unnamed_device or named_devices): + raise ValueError('No device interface at ' + where) + + return BusInterfaces(has_unnamed_host, named_hosts, + has_unnamed_device, named_devices, interface_list) + + def has_host(self) -> bool: + return bool(self.has_unnamed_host or self.named_hosts) + + def _interfaces(self) -> List[Tuple[bool, Optional[str]]]: + ret = [] # type: List[Tuple[bool, Optional[str]]] + if self.has_unnamed_host: + ret.append((True, None)) + for name in self.named_hosts: + ret.append((True, name)) + + if self.has_unnamed_device: + ret.append((False, None)) + for name in self.named_devices: + ret.append((False, name)) + + return ret + + @staticmethod + def _if_dict(is_host: bool, name: Optional[str]) -> Dict[str, object]: + ret = { + 'protocol': 'tlul', + 'direction': 'host' if is_host else 'device' + } # type: Dict[str, object] + + if name is not None: + ret['name'] = name + + return ret + + def as_dicts(self) -> List[Dict[str, object]]: + return [BusInterfaces._if_dict(is_host, name) + for is_host, name in self._interfaces()] + + def get_port_name(self, is_host: bool, name: Optional[str]) -> str: + if is_host: + tl_suffix = 'tl_h' + else: + tl_suffix = 'tl_d' if self.has_host() else 'tl' + + return (tl_suffix if name is None + else '{}_{}'.format(name, tl_suffix)) + + def get_port_names(self, inc_hosts: bool, inc_devices: bool) -> List[str]: + ret = [] + for is_host, name in self._interfaces(): + if not (inc_hosts if is_host else inc_devices): + continue + ret.append(self.get_port_name(is_host, name)) + return ret + + def _if_inter_signal(self, + is_host: bool, + name: Optional[str]) -> InterSignal: + return InterSignal(self.get_port_name(is_host, name), + None, 'tl', 'tlul_pkg', 'req_rsp', 'rsp', 1, None) + + def inter_signals(self) -> List[InterSignal]: + return [self._if_inter_signal(is_host, name) + for is_host, name in self._interfaces()] + + def has_interface(self, is_host: bool, name: Optional[str]) -> bool: + if is_host: + if name is None: + return self.has_unnamed_host + else: + return name in self.named_hosts + else: + if name is None: + return self.has_unnamed_device + else: + return name in self.named_devices + + def find_port_name(self, is_host: bool, name: Optional[str]) -> str: + '''Look up the given host/name pair and return its port name. + + Raises a KeyError if there is no match. + + ''' + if not self.has_interface(is_host, name): + called = ('with no name' + if name is None else 'called {!r}'.format(name)) + raise KeyError('There is no {} bus interface {}.' + .format('host' if is_host else 'device', + called)) + + return self.get_port_name(is_host, name) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/enum_entry.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/enum_entry.py new file mode 100644 index 00000000..fe1e9ecd --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/enum_entry.py @@ -0,0 +1,35 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict + +from .lib import check_keys, check_str, check_int + +REQUIRED_FIELDS = { + 'name': ['s', "name of the member of the enum"], + 'desc': ['t', "description when field has this value"], + 'value': ['d', "value of this member of the enum"] +} + + +class EnumEntry: + def __init__(self, where: str, max_val: int, raw: object): + rd = check_keys(raw, where, + list(REQUIRED_FIELDS.keys()), + []) + + self.name = check_str(rd['name'], 'name field of {}'.format(where)) + self.desc = check_str(rd['desc'], 'desc field of {}'.format(where)) + self.value = check_int(rd['value'], 'value field of {}'.format(where)) + if not (0 <= self.value <= max_val): + raise ValueError("value for {} is {}, which isn't representable " + "in the field (representable range: 0 .. {})." + .format(where, self.value, max_val)) + + def _asdict(self) -> Dict[str, object]: + return { + 'name': self.name, + 'desc': self.desc, + 'value': str(self.value) + } diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/field.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/field.py new file mode 100644 index 00000000..a2beb735 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/field.py @@ -0,0 +1,291 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, List, Optional + +from .access import SWAccess, HWAccess +from .bits import Bits +from .enum_entry import EnumEntry +from .lib import (check_keys, check_str, check_name, + check_list, check_str_list, check_xint) +from .params import ReggenParams + +REQUIRED_FIELDS = { + 'bits': ['b', "bit or bit range (msb:lsb)"] +} + +OPTIONAL_FIELDS = { + 'name': ['s', "name of the field"], + 'desc': ['t', "description of field (required if the field has a name)"], + 'swaccess': [ + 's', "software access permission, copied from " + "register if not provided in field. " + "(Tool adds if not provided.)" + ], + 'hwaccess': [ + 's', "hardware access permission, copied from " + "register if not prvided in field. " + "(Tool adds if not provided.)" + ], + 'resval': [ + 'x', "reset value, comes from register resval " + "if not provided in field. Zero if neither " + "are provided and the field is readable, " + "x if neither are provided and the field " + "is wo. Must match if both are provided." + ], + 'enum': ['l', "list of permitted enumeration groups"], + 'tags': [ + 's', + "tags for the field, followed by the format 'tag_name:item1:item2...'" + ] +} + + +class Field: + def __init__(self, + name: str, + desc: Optional[str], + tags: List[str], + swaccess: SWAccess, + hwaccess: HWAccess, + hwqe: bool, + hwre: bool, + bits: Bits, + resval: Optional[int], + enum: Optional[List[EnumEntry]]): + self.name = name + self.desc = desc + self.tags = tags + self.swaccess = swaccess + self.hwaccess = hwaccess + self.hwqe = hwqe + self.hwre = hwre + self.bits = bits + self.resval = resval + self.enum = enum + + @staticmethod + def from_raw(reg_name: str, + field_idx: int, + num_fields: int, + default_swaccess: SWAccess, + default_hwaccess: HWAccess, + reg_resval: Optional[int], + reg_width: int, + reg_hwqe: bool, + reg_hwre: bool, + params: ReggenParams, + raw: object) -> 'Field': + where = 'field {} of {} register'.format(field_idx, reg_name) + rd = check_keys(raw, where, + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + raw_name = rd.get('name') + if raw_name is None: + name = ('field{}'.format(field_idx + 1) + if num_fields > 1 else reg_name) + else: + name = check_name(raw_name, 'name of {}'.format(where)) + + raw_desc = rd.get('desc') + if raw_desc is None and raw_name is not None: + raise ValueError('Missing desc field for {}' + .format(where)) + if raw_desc is None: + desc = None + else: + desc = check_str(raw_desc, 'desc field for {}'.format(where)) + + tags = check_str_list(rd.get('tags', []), + 'tags for {}'.format(where)) + + raw_swaccess = rd.get('swaccess') + if raw_swaccess is not None: + swaccess = SWAccess(where, raw_swaccess) + else: + swaccess = default_swaccess + + raw_hwaccess = rd.get('hwaccess') + if raw_hwaccess is not None: + hwaccess = HWAccess(where, raw_hwaccess) + else: + hwaccess = default_hwaccess + + bits = Bits.from_raw(where, reg_width, params, rd['bits']) + + raw_resval = rd.get('resval') + if raw_resval is None: + # The field doesn't define a reset value. Use bits from reg_resval + # if it's defined, otherwise None (which means "x"). + if reg_resval is None: + resval = None + else: + resval = bits.extract_field(reg_resval) + else: + # The field does define a reset value. It should be an integer or + # 'x'. In the latter case, we set resval to None (as above). + resval = check_xint(raw_resval, 'resval field for {}'.format(where)) + if resval is None: + # We don't allow a field to be explicitly 'x' on reset but for + # the containing register to have a reset value. + if reg_resval is not None: + raise ValueError('resval field for {} is "x", but the ' + 'register defines a resval as well.' + .format(where)) + else: + # Check that the reset value is representable with bits + if not (0 <= resval <= bits.max_value()): + raise ValueError("resval field for {} is {}, which " + "isn't representable as an unsigned " + "{}-bit integer." + .format(where, resval, bits.width())) + + # If the register had a resval, check this value matches it. + if reg_resval is not None: + resval_from_reg = bits.extract_field(reg_resval) + if resval != resval_from_reg: + raise ValueError('resval field for {} is {}, but the ' + 'register defines a resval as well, ' + 'where bits {}:{} would give {}.' + .format(where, resval, + bits.msb, bits.lsb, + resval_from_reg)) + + raw_enum = rd.get('enum') + if raw_enum is None: + enum = None + else: + enum = [] + raw_entries = check_list(raw_enum, + 'enum field for {}'.format(where)) + enum_val_to_name = {} # type: Dict[int, str] + for idx, raw_entry in enumerate(raw_entries): + entry = EnumEntry('entry {} in enum list for {}' + .format(idx + 1, where), + bits.max_value(), + raw_entry) + if entry.value in enum_val_to_name: + raise ValueError('In {}, duplicate enum entries for ' + 'value {} ({} and {}).' + .format(where, + entry.value, + enum_val_to_name[entry.value], + entry.name)) + enum.append(entry) + enum_val_to_name[entry.value] = entry.name + + return Field(name, desc, tags, + swaccess, hwaccess, + reg_hwqe, reg_hwre, bits, resval, enum) + + def has_incomplete_enum(self) -> bool: + return (self.enum is not None and + len(self.enum) != 1 + self.bits.max_value()) + + def get_n_bits(self, hwext: bool, bittype: List[str]) -> int: + '''Get the size of this field in bits + + bittype should be a list of the types of signals to count. The elements + should come from the following list: + + - 'q': A signal for the value of the field. Only needed if HW can read + its contents. + + - 'd': A signal for the next value of the field. Only needed if HW can + write its contents. + + - 'qe': A write enable signal for bus accesses. Only needed if HW can + read the field's contents and the field has the hwqe flag. + + - 're': A read enable signal for bus accesses. Only needed if HW can + read the field's contents and the field has the hwre flag. + + - 'de': A write enable signal for hardware accesses. Only needed if HW + can write the field's contents and the register data is stored in the + register block (true if the hwext flag is false). + + ''' + n_bits = 0 + if "q" in bittype and self.hwaccess.allows_read(): + n_bits += self.bits.width() + if "d" in bittype and self.hwaccess.allows_write(): + n_bits += self.bits.width() + if "qe" in bittype and self.hwaccess.allows_read(): + n_bits += int(self.hwqe) + if "re" in bittype and self.hwaccess.allows_read(): + n_bits += int(self.hwre) + if "de" in bittype and self.hwaccess.allows_write(): + n_bits += int(not hwext) + return n_bits + + def make_multi(self, + reg_width: int, + min_reg_idx: int, + max_reg_idx: int, + cname: str, + creg_idx: int, + stripped: bool) -> List['Field']: + assert 0 <= min_reg_idx <= max_reg_idx + + # Check that we won't overflow reg_width. We assume that the LSB should + # be preserved: if msb=5, lsb=2 then the replicated copies will be + # [5:2], [11:8] etc. + num_copies = 1 + max_reg_idx - min_reg_idx + field_width = self.bits.msb + 1 + + if field_width * num_copies > reg_width: + raise ValueError('Cannot replicate field {} {} times: the ' + 'resulting width would be {}, but the register ' + 'width is just {}.' + .format(self.name, num_copies, + field_width * num_copies, reg_width)) + + desc = ('For {}{}'.format(cname, creg_idx) + if stripped else self.desc) + enum = None if stripped else self.enum + + ret = [] + for reg_idx in range(min_reg_idx, max_reg_idx + 1): + name = '{}_{}'.format(self.name, reg_idx) + + bit_offset = field_width * (reg_idx - min_reg_idx) + bits = (self.bits + if bit_offset == 0 + else self.bits.make_translated(bit_offset)) + + ret.append(Field(name, desc, + self.tags, self.swaccess, self.hwaccess, + self.hwqe, self.hwre, bits, self.resval, enum)) + + return ret + + def make_suffixed(self, suffix: str, + cname: str, + creg_idx: int, + stripped: bool) -> 'Field': + desc = ('For {}{}'.format(cname, creg_idx) + if stripped else self.desc) + enum = None if stripped else self.enum + + return Field(self.name + suffix, + desc, self.tags, self.swaccess, self.hwaccess, + self.hwqe, self.hwre, self.bits, self.resval, enum) + + def _asdict(self) -> Dict[str, object]: + rd = { + 'bits': self.bits.as_str(), + 'name': self.name, + 'swaccess': self.swaccess.key, + 'hwaccess': self.hwaccess.key, + 'resval': 'x' if self.resval is None else str(self.resval), + 'tags': self.tags + } # type: Dict[str, object] + + if self.desc is not None: + rd['desc'] = self.desc + if self.enum is not None: + rd['enum'] = self.enum + return rd diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/fpv_csr.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/fpv_csr.sv.tpl new file mode 100644 index 00000000..01f20c73 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/fpv_csr.sv.tpl @@ -0,0 +1,177 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// FPV CSR read and write assertions auto-generated by `reggen` containing data structure +// Do Not Edit directly +// TODO: This automation currently only support register without HW write access +<% + from reggen import (gen_fpv) + from reggen.register import Register + + from topgen import lib + + lblock = block.name.lower() + use_reg_iface = any([interface['protocol'] == BusProtocol.REG_IFACE and not interace['is_host'] for interface in block.bus_interfaces.interface_list]) + + # This template shouldn't be instantiated if the device interface + # doesn't actually have any registers. + assert rb.flat_regs + +%>\ +<%def name="construct_classes(block)">\ + +% if use_reg_iface: +`include "common_cells/assertions.svh" +% else: +`include "prim_assert.sv" +% endif +`ifdef UVM + import uvm_pkg::*; +`endif + +// Block: ${lblock} +module ${mod_base}_csr_assert_fpv import tlul_pkg::*; + import top_pkg::*;( + input clk_i, + input rst_ni, + + // tile link ports + input tl_h2d_t h2d, + input tl_d2h_t d2h +); +<% + addr_width = rb.get_addr_width() + addr_msb = addr_width - 1 + hro_regs_list = [r for r in rb.flat_regs if not r.hwaccess.allows_write()] + num_hro_regs = len(hro_regs_list) + hro_map = {r.offset: (idx, r) for idx, r in enumerate(hro_regs_list)} +%>\ + +// Currently FPV csr assertion only support HRO registers. +% if num_hro_regs > 0: +`ifndef VERILATOR +`ifndef SYNTHESIS + + parameter bit[3:0] MAX_A_SOURCE = 10; // used for FPV only to reduce runtime + + typedef struct packed { + logic [TL_DW-1:0] wr_data; + logic [TL_AW-1:0] addr; + logic wr_pending; + logic rd_pending; + } pend_item_t; + + bit disable_sva; + + // mask register to convert byte to bit + logic [TL_DW-1:0] a_mask_bit; + + assign a_mask_bit[7:0] = h2d.a_mask[0] ? '1 : '0; + assign a_mask_bit[15:8] = h2d.a_mask[1] ? '1 : '0; + assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0; + assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0; + + bit [${addr_msb}-2:0] hro_idx; // index for exp_vals + bit [${addr_msb}:0] normalized_addr; + + // Map register address with hro_idx in exp_vals array. + always_comb begin: decode_hro_addr_to_idx + unique case (pend_trans[d2h.d_source].addr) +% for idx, r in hro_map.values(): + ${r.offset}: hro_idx <= ${idx}; +% endfor + // If the register is not a HRO register, the write data will all update to this default idx. + default: hro_idx <= ${num_hro_regs + 1}; + endcase + end + + // store internal expected values for HW ReadOnly registers + logic [TL_DW-1:0] exp_vals[${num_hro_regs + 1}]; + + `ifdef FPV_ON + pend_item_t [MAX_A_SOURCE:0] pend_trans; + `else + pend_item_t [2**TL_AIW-1:0] pend_trans; + `endif + + // normalized address only take the [${addr_msb}:2] address from the TLUL a_address + assign normalized_addr = {h2d.a_address[${addr_msb}:2], 2'b0}; + +% if num_hro_regs > 0: + // for write HRO registers, store the write data into exp_vals + always_ff @(negedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + pend_trans <= '0; + % for hro_reg in hro_regs_list: + exp_vals[${hro_map.get(hro_reg.offset)[0]}] <= ${hro_reg.resval}; + % endfor + end else begin + if (h2d.a_valid && d2h.a_ready) begin + pend_trans[h2d.a_source].addr <= normalized_addr; + if (h2d.a_opcode inside {PutFullData, PutPartialData}) begin + pend_trans[h2d.a_source].wr_data <= h2d.a_data & a_mask_bit; + pend_trans[h2d.a_source].wr_pending <= 1'b1; + end else if (h2d.a_opcode == Get) begin + pend_trans[h2d.a_source].rd_pending <= 1'b1; + end + end + if (d2h.d_valid) begin + if (pend_trans[d2h.d_source].wr_pending == 1) begin + if (!d2h.d_error) begin + exp_vals[hro_idx] <= pend_trans[d2h.d_source].wr_data; + end + pend_trans[d2h.d_source].wr_pending <= 1'b0; + end + if (h2d.d_ready && pend_trans[d2h.d_source].rd_pending == 1) begin + pend_trans[d2h.d_source].rd_pending <= 1'b0; + end + end + end + end + + // for read HRO registers, assert read out values by access policy and exp_vals + % for hro_reg in hro_regs_list: +<% + r_name = hro_reg.name.lower() + reg_addr = hro_reg.offset + reg_addr_hex = format(reg_addr, 'x') + regwen = hro_reg.regwen + reg_mask = 0 + + for f in hro_reg.get_field_list(): + f_access = f.swaccess.key.lower() + if f_access == "rw" and regwen == None: + reg_mask = reg_mask | f.bits.bitmask() +%>\ + % if reg_mask != 0: +<% reg_mask_hex = format(reg_mask, 'x') %>\ + `ASSERT(${r_name}_rd_A, d2h.d_valid && pend_trans[d2h.d_source].rd_pending && + pend_trans[d2h.d_source].addr == ${addr_width}'h${reg_addr_hex} |-> + d2h.d_error || + (d2h.d_data & 'h${reg_mask_hex}) == (exp_vals[${hro_map.get(reg_addr)[0]}] & 'h${reg_mask_hex})) + + % endif + % endfor +% endif + + // This FPV only assumption is to reduce the FPV runtime. + `ASSUME_FPV(TlulSource_M, h2d.a_source >= 0 && h2d.a_source <= MAX_A_SOURCE, clk_i, !rst_ni) + + `ifdef UVM + initial forever begin + bit csr_assert_en; + uvm_config_db#(bit)::wait_modified(null, "%m", "csr_assert_en"); + if (!uvm_config_db#(bit)::get(null, "%m", "csr_assert_en", csr_assert_en)) begin + `uvm_fatal("csr_assert", "Can't find csr_assert_en") + end + disable_sva = !csr_assert_en; + end + `endif + +`endif +`endif +% endif +endmodule +\ +${construct_classes(block)} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cfg_html.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cfg_html.py new file mode 100644 index 00000000..0bb44d3d --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cfg_html.py @@ -0,0 +1,113 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +""" +Generate HTML documentation from Block +""" + +from typing import TextIO + +from .ip_block import IpBlock +from .html_helpers import render_td +from .signal import Signal + + +def genout(outfile: TextIO, msg: str) -> None: + outfile.write(msg) + + +def name_width(x: Signal) -> str: + if x.bits.width() == 1: + return x.name + + return '{}[{}:0]'.format(x.name, x.bits.msb) + + +def gen_kv(outfile: TextIO, key: str, value: str) -> None: + genout(outfile, + '

{}: {}

\n'.format(key, value)) + + +def gen_cfg_html(cfgs: IpBlock, outfile: TextIO) -> None: + rnames = cfgs.get_rnames() + + ot_server = 'https://docs.opentitan.org' + comport_url = ot_server + '/doc/rm/comportability_specification' + genout(outfile, + '

Referring to the Comportable guideline for ' + 'peripheral device functionality, the module ' + '{mod_name} has the following hardware ' + 'interfaces defined.

\n' + .format(url=comport_url, mod_name=cfgs.name)) + + # clocks + gen_kv(outfile, + 'Primary Clock', + '{}'.format(cfgs.clock_signals[0])) + if len(cfgs.clock_signals) > 1: + other_clocks = ['{}'.format(clk) + for clk in cfgs.clock_signals[1:]] + gen_kv(outfile, 'Other Clocks', ', '.join(other_clocks)) + else: + gen_kv(outfile, 'Other Clocks', 'none') + + # bus interfaces + dev_ports = ['{}'.format(port) + for port in cfgs.bus_interfaces.get_port_names(False, True)] + assert dev_ports + gen_kv(outfile, 'Bus Device Interfaces (TL-UL)', ', '.join(dev_ports)) + + host_ports = ['{}'.format(port) + for port in cfgs.bus_interfaces.get_port_names(True, False)] + if host_ports: + gen_kv(outfile, 'Bus Host Interfaces (TL-UL)', ', '.join(host_ports)) + else: + gen_kv(outfile, 'Bus Host Interfaces (TL-UL)', 'none') + + # IO + ios = ([('input', x) for x in cfgs.xputs[1]] + + [('output', x) for x in cfgs.xputs[2]] + + [('inout', x) for x in cfgs.xputs[0]]) + if ios: + genout(outfile, "

Peripheral Pins for Chip IO:

\n") + genout( + outfile, "" + + "" + + "\n") + for direction, x in ios: + genout(outfile, + '{}' + .format(name_width(x), + direction, + render_td(x.desc, rnames, None))) + genout(outfile, "
Pin namedirectionDescription
{}{}
\n") + else: + genout(outfile, "

Peripheral Pins for Chip IO: none

\n") + + if not cfgs.interrupts: + genout(outfile, "

Interrupts: none

\n") + else: + genout(outfile, "

Interrupts:

\n") + genout( + outfile, "" + + "\n") + for x in cfgs.interrupts: + genout(outfile, + '{}' + .format(name_width(x), + render_td(x.desc, rnames, None))) + genout(outfile, "
Interrupt NameDescription
{}
\n") + + if not cfgs.alerts: + genout(outfile, "

Security Alerts: none

\n") + else: + genout(outfile, "

Security Alerts:

\n") + genout( + outfile, "" + + "\n") + for x in cfgs.alerts: + genout(outfile, + '{}' + .format(x.name, + render_td(x.desc, rnames, None))) + genout(outfile, "
Alert NameDescription
{}
\n") diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cheader.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cheader.py new file mode 100644 index 00000000..f68bd396 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_cheader.py @@ -0,0 +1,439 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +""" +Generate C header from validated register JSON tree +""" + +import io +import logging as log +import sys +import textwrap +import warnings +from typing import List, Optional, Set, TextIO + + +from .field import Field +from .ip_block import IpBlock +from .params import LocalParam +from .register import Register +from .multi_register import MultiRegister +from .signal import Signal +from .window import Window + + +def genout(outfile: TextIO, msg: str) -> None: + outfile.write(msg) + +def to_snake_case(s: str) -> str: + val = [] + for i, ch in enumerate(s): + if i > 0 and ch.isupper(): + val.append('_') + val.append(ch) + return ''.join(val) + +def as_define(s: str) -> str: + s = s.upper() + r = '' + for i in range(0, len(s)): + r += s[i] if s[i].isalnum() else '_' + return r + + +def first_line(s: str) -> str: + """Returns the first line of a multi-line string""" + return s.splitlines()[0] + + +def format_comment(s: str) -> str: + """Formats a string to comment wrapped to an 80 character line width + + Returns wrapped string including newline and // comment characters. + """ + return '\n'.join( + textwrap.wrap( + s, width=77, initial_indent='// ', subsequent_indent='// ')) + '\n' + + +def gen_define(name: str, + args: List[str], + body: str, + existing_defines: Set[str], + indent: str = ' ') -> str: + r"""Produces a #define string, will split into two lines if a single line + has a width greater than 80 characters. Result includes newline. + + Arguments: + name - Name of the #define + args - List of arguments for the define, provide an empty list if there are + none + body - Body of the #define + existing_defines - set of already generated define names. + Error if `name` is in `existing_defines`. + indent - Gives string to prepend on any new lines produced by + wrapping (default ' ') + + Example result: + name = 'A_MACRO' + args = ['arg1', 'arg2'], + body = 'arg1 + arg2 + 10' + + #define A_MACRO(arg1, arg2) arg1 + arg2 + 10 + + When the macro is wrapped the break happens after the argument list (or + macro name if there is no argument list + + #define A_MACRO(arg1, arg2) \ + arg1 + arg2 + 10 + + """ + + if name in existing_defines: + log.error("Duplicate #define for " + name) + sys.exit(1) + + if len(args) != 0: + define_declare = '#define ' + name + '(' + ', '.join(args) + ')' + else: + define_declare = '#define ' + name + + oneline_define = define_declare + ' ' + body + + existing_defines.add(name) + + if len(oneline_define) <= 80: + return oneline_define + '\n' + + return define_declare + ' \\\n' + indent + body + '\n' + + +def gen_cdefine_register(outstr: TextIO, + reg: Register, + comp: str, + width: int, + rnames: Set[str], + existing_defines: Set[str]) -> None: + rname = reg.name + offset = reg.offset + + genout(outstr, format_comment(first_line(reg.desc))) + defname = as_define(comp + '_' + rname) + genout( + outstr, + gen_define(defname + '_REG_OFFSET', [], hex(offset), existing_defines)) + + for field in reg.fields: + dname = defname + '_' + as_define(field.name) + field_width = field.bits.width() + + if field_width == 1: + # single bit + genout( + outstr, + gen_define(dname + '_BIT', [], str(field.bits.lsb), + existing_defines)) + else: + # multiple bits (unless it is the whole register) + if field_width != width: + mask = field.bits.bitmask() >> field.bits.lsb + genout( + outstr, + gen_define(dname + '_MASK', [], hex(mask), + existing_defines)) + genout( + outstr, + gen_define(dname + '_OFFSET', [], str(field.bits.lsb), + existing_defines)) + genout( + outstr, + gen_define( + dname + '_FIELD', [], + '((bitfield_field32_t) {{ .mask = {dname}_MASK, .index = {dname}_OFFSET }})' + .format(dname=dname), existing_defines)) + if field.enum is not None: + for enum in field.enum: + ename = as_define(enum.name) + value = hex(enum.value) + genout( + outstr, + gen_define( + defname + '_' + as_define(field.name) + + '_VALUE_' + ename, [], value, existing_defines)) + genout(outstr, '\n') + return + + +def gen_cdefine_window(outstr: TextIO, + win: Window, + comp: str, + regwidth: int, + rnames: Set[str], + existing_defines: Set[str]) -> None: + offset = win.offset + + genout(outstr, format_comment('Memory area: ' + first_line(win.desc))) + defname = as_define(comp + '_' + win.name) + genout( + outstr, + gen_define(defname + '_REG_OFFSET', [], hex(offset), existing_defines)) + items = win.items + genout( + outstr, + gen_define(defname + '_SIZE_WORDS', [], str(items), existing_defines)) + items = items * (regwidth // 8) + genout( + outstr, + gen_define(defname + '_SIZE_BYTES', [], str(items), existing_defines)) + + wid = win.validbits + if (wid != regwidth): + mask = (1 << wid) - 1 + genout(outstr, + gen_define(defname + '_MASK ', [], hex(mask), existing_defines)) + + +def gen_cdefines_module_param(outstr: TextIO, + param: LocalParam, + module_name: str, + existing_defines: Set[str]) -> None: + # Presently there is only one type (int), however if the new types are + # added, they potentially need to be handled differently. + known_types = ["int"] + if param.param_type not in known_types: + warnings.warn("Cannot generate a module define of type {}" + .format(param.param_type)) + return + + if param.desc is not None: + genout(outstr, format_comment(first_line(param.desc))) + # Heuristic: if the name already has underscores, it's already snake_case, + # otherwise, assume StudlyCaps and covert it to snake_case. + param_name = param.name if '_' in param.name else to_snake_case(param.name) + define_name = as_define(module_name + '_PARAM_' + param_name) + if param.param_type == "int": + define = gen_define(define_name, [], param.value, + existing_defines) + + genout(outstr, define) + genout(outstr, '\n') + + +def gen_cdefines_module_params(outstr: TextIO, + module_data: IpBlock, + module_name: str, + register_width: int, + existing_defines: Set[str]) -> None: + module_params = module_data.params + + for param in module_params.get_localparams(): + gen_cdefines_module_param(outstr, param, module_name, existing_defines) + + genout(outstr, format_comment(first_line("Register width"))) + define_name = as_define(module_name + '_PARAM_REG_WIDTH') + define = gen_define(define_name, [], str(register_width), existing_defines) + genout(outstr, define) + genout(outstr, '\n') + + +def gen_multireg_field_defines(outstr: TextIO, + regname: str, + field: Field, + subreg_num: int, + regwidth: int, + existing_defines: Set[str]) -> None: + field_width = field.bits.width() + fields_per_reg = regwidth // field_width + + define_name = regname + '_' + as_define(field.name + "_FIELD_WIDTH") + define = gen_define(define_name, [], str(field_width), existing_defines) + genout(outstr, define) + + define_name = regname + '_' + as_define(field.name + "_FIELDS_PER_REG") + define = gen_define(define_name, [], str(fields_per_reg), existing_defines) + genout(outstr, define) + + define_name = regname + "_MULTIREG_COUNT" + define = gen_define(define_name, [], str(subreg_num), existing_defines) + genout(outstr, define) + + genout(outstr, '\n') + + +def gen_cdefine_multireg(outstr: TextIO, + multireg: MultiRegister, + component: str, + regwidth: int, + rnames: Set[str], + existing_defines: Set[str]) -> None: + comment = multireg.reg.desc + " (common parameters)" + genout(outstr, format_comment(first_line(comment))) + if len(multireg.reg.fields) == 1: + regname = as_define(component + '_' + multireg.reg.name) + gen_multireg_field_defines(outstr, regname, multireg.reg.fields[0], + len(multireg.regs), regwidth, existing_defines) + else: + log.warn("Non-homogeneous multireg " + multireg.reg.name + + " skip multireg specific data generation.") + + for subreg in multireg.regs: + gen_cdefine_register(outstr, subreg, component, regwidth, rnames, + existing_defines) + + +def gen_cdefines_interrupt_field(outstr: TextIO, + interrupt: Signal, + component: str, + regwidth: int, + existing_defines: Set[str]) -> None: + fieldlsb = interrupt.bits.lsb + iname = interrupt.name + defname = as_define(component + '_INTR_COMMON_' + iname) + + if interrupt.bits.width() == 1: + # single bit + genout( + outstr, + gen_define(defname + '_BIT', [], str(fieldlsb), existing_defines)) + else: + # multiple bits (unless it is the whole register) + if interrupt.bits.width() != regwidth: + mask = interrupt.bits.msb >> fieldlsb + genout( + outstr, + gen_define(defname + '_MASK', [], hex(mask), existing_defines)) + genout( + outstr, + gen_define(defname + '_OFFSET', [], str(fieldlsb), + existing_defines)) + genout( + outstr, + gen_define( + defname + '_FIELD', [], + '((bitfield_field32_t) {{ .mask = {dname}_MASK, .index = {dname}_OFFSET }})' + .format(dname=defname), existing_defines)) + + +def gen_cdefines_interrupts(outstr: TextIO, + block: IpBlock, + component: str, + regwidth: int, + existing_defines: Set[str]) -> None: + # If no_auto_intr_regs is true, then we do not generate common defines, + # because the bit offsets for a particular interrupt may differ between + # the interrupt enable/state/test registers. + if block.no_auto_intr: + return + + genout(outstr, format_comment(first_line("Common Interrupt Offsets"))) + for intr in block.interrupts: + gen_cdefines_interrupt_field(outstr, intr, component, regwidth, + existing_defines) + genout(outstr, '\n') + + +def gen_cdefines(block: IpBlock, + outfile: TextIO, + src_lic: Optional[str], + src_copy: str) -> int: + rnames = block.get_rnames() + + outstr = io.StringIO() + + # This tracks the defines that have been generated so far, so we + # can error if we attempt to duplicate a definition + existing_defines = set() # type: Set[str] + + gen_cdefines_module_params(outstr, block, block.name, block.regwidth, + existing_defines) + + gen_cdefines_interrupts(outstr, block, block.name, block.regwidth, + existing_defines) + + for rb in block.reg_blocks.values(): + for x in rb.entries: + if isinstance(x, Register): + gen_cdefine_register(outstr, x, block.name, block.regwidth, rnames, + existing_defines) + continue + + if isinstance(x, MultiRegister): + gen_cdefine_multireg(outstr, x, block.name, block.regwidth, rnames, + existing_defines) + continue + + if isinstance(x, Window): + gen_cdefine_window(outstr, x, block.name, block.regwidth, + rnames, existing_defines) + continue + + generated = outstr.getvalue() + outstr.close() + + genout(outfile, '// Generated register defines for ' + block.name + '\n\n') + if src_copy != '': + genout(outfile, '// Copyright information found in source file:\n') + genout(outfile, '// ' + src_copy + '\n\n') + if src_lic is not None: + genout(outfile, '// Licensing information found in source file:\n') + for line in src_lic.splitlines(): + genout(outfile, '// ' + line + '\n') + genout(outfile, '\n') + + # Header Include Guard + genout(outfile, '#ifndef _' + as_define(block.name) + '_REG_DEFS_\n') + genout(outfile, '#define _' + as_define(block.name) + '_REG_DEFS_\n\n') + + # Header Extern Guard (so header can be used from C and C++) + genout(outfile, '#ifdef __cplusplus\n') + genout(outfile, 'extern "C" {\n') + genout(outfile, '#endif\n') + + genout(outfile, generated) + + # Header Extern Guard + genout(outfile, '#ifdef __cplusplus\n') + genout(outfile, '} // extern "C"\n') + genout(outfile, '#endif\n') + + # Header Include Guard + genout(outfile, '#endif // _' + as_define(block.name) + '_REG_DEFS_\n') + + genout(outfile, '// End generated register defines for ' + block.name) + + return 0 + + +def test_gen_define() -> None: + basic_oneline = '#define MACRO_NAME body\n' + assert gen_define('MACRO_NAME', [], 'body', set()) == basic_oneline + + basic_oneline_with_args = '#define MACRO_NAME(arg1, arg2) arg1 + arg2\n' + assert (gen_define('MACRO_NAME', ['arg1', 'arg2'], 'arg1 + arg2', + set()) == basic_oneline_with_args) + + long_macro_name = 'A_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_LONG_MACRO_NAME' + + multiline = ('#define ' + long_macro_name + ' \\\n' + + ' a_fairly_long_body + something_else + 10\n') + + assert (gen_define(long_macro_name, [], + 'a_fairly_long_body + something_else + 10', + set()) == multiline) + + multiline_with_args = ('#define ' + long_macro_name + + '(arg1, arg2, arg3) \\\n' + + ' a_fairly_long_body + arg1 + arg2 + arg3\n') + + assert (gen_define(long_macro_name, ['arg1', 'arg2', 'arg3'], + 'a_fairly_long_body + arg1 + arg2 + arg3', + set()) == multiline_with_args) + + multiline_with_args_big_indent = ( + '#define ' + long_macro_name + '(arg1, arg2, arg3) \\\n' + + ' a_fairly_long_body + arg1 + arg2 + arg3\n') + + assert (gen_define(long_macro_name, ['arg1', 'arg2', 'arg3'], + 'a_fairly_long_body + arg1 + arg2 + arg3', + set(), + indent=' ') == multiline_with_args_big_indent) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_dv.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_dv.py new file mode 100644 index 00000000..d2d054ad --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_dv.py @@ -0,0 +1,108 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +'''Generate DV code for an IP block''' + +import logging as log +import os +from typing import List + +import yaml + +from mako import exceptions # type: ignore +from mako.lookup import TemplateLookup # type: ignore +from pkg_resources import resource_filename + +from .ip_block import IpBlock +from .register import Register +from .window import Window + + +def bcname(esc_if_name: str) -> str: + '''Get the name of the dv_base_reg_block subclass for this device interface''' + return esc_if_name + "_reg_block" + + +def rcname(esc_if_name: str, r: Register) -> str: + '''Get the name of the dv_base_reg subclass for this register''' + return '{}_reg_{}'.format(esc_if_name, r.name.lower()) + + +def mcname(esc_if_name: str, m: Window) -> str: + '''Get the name of the dv_base_mem subclass for this memory''' + return '{}_mem_{}'.format(esc_if_name, m.name.lower()) + + +def miname(m: Window) -> str: + '''Get the lower-case name of a memory block''' + return m.name.lower() + + +def gen_core_file(outdir: str, + lblock: str, + dv_base_prefix: str, + paths: List[str]) -> None: + depends = ["lowrisc:dv:dv_base_reg"] + if dv_base_prefix and dv_base_prefix != "dv_base": + depends.append("lowrisc:dv:{}_reg".format(dv_base_prefix)) + + # Generate a fusesoc core file that points at the files we've just + # generated. + core_data = { + 'name': "lowrisc:dv:{}_ral_pkg".format(lblock), + 'filesets': { + 'files_dv': { + 'depend': depends, + 'files': paths, + 'file_type': 'systemVerilogSource' + }, + }, + 'targets': { + 'default': { + 'filesets': [ + 'files_dv', + ], + }, + }, + } + core_file_path = os.path.join(outdir, lblock + '_ral_pkg.core') + with open(core_file_path, 'w') as core_file: + core_file.write('CAPI=2:\n') + yaml.dump(core_data, core_file, encoding='utf-8') + + +def gen_dv(block: IpBlock, dv_base_prefix: str, outdir: str) -> int: + '''Generate DV files for an IpBlock''' + + lookup = TemplateLookup(directories=[resource_filename('reggen', '.')]) + uvm_reg_tpl = lookup.get_template('uvm_reg.sv.tpl') + + # Generate the RAL package(s). For a device interface with no name we + # generate the package "_ral_pkg" (writing to _ral_pkg.sv). + # In any other case, we also need the interface name, giving + # __ral_pkg. + generated = [] + + lblock = block.name.lower() + for if_name, rb in block.reg_blocks.items(): + hier_path = '' if block.hier_path is None else block.hier_path + '.' + if_suffix = '' if if_name is None else '_' + if_name.lower() + mod_base = lblock + if_suffix + reg_block_path = hier_path + 'u_reg' + if_suffix + + file_name = mod_base + '_ral_pkg.sv' + generated.append(file_name) + reg_top_path = os.path.join(outdir, file_name) + with open(reg_top_path, 'w', encoding='UTF-8') as fout: + try: + fout.write(uvm_reg_tpl.render(rb=rb, + block=block, + esc_if_name=mod_base, + reg_block_path=reg_block_path, + dv_base_prefix=dv_base_prefix)) + except: # noqa F722 for template Exception handling + log.error(exceptions.text_error_template().render()) + return 1 + + gen_core_file(outdir, lblock, dv_base_prefix, generated) + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_fpv.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_fpv.py new file mode 100644 index 00000000..e6e6d7d3 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_fpv.py @@ -0,0 +1,81 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# # Lint as: python3 +# +"""Generate FPV CSR read and write assertions from IpBlock +""" + +import logging as log +import os.path + +import yaml +from mako import exceptions +from mako.template import Template +from pkg_resources import resource_filename + +from .ip_block import IpBlock + + +def gen_fpv(block: IpBlock, outdir): + # Read Register templates + fpv_csr_tpl = Template( + filename=resource_filename('reggen', 'fpv_csr.sv.tpl')) + + # Generate a module with CSR assertions for each device interface. For a + # device interface with no name, we generate _csr_assert_fpv. For a + # named interface, we generate __csr_assert_fpv. + lblock = block.name.lower() + generated = [] + for if_name, rb in block.reg_blocks.items(): + if not rb.flat_regs: + # No registers to check! + continue + + if if_name is None: + mod_base = lblock + else: + mod_base = lblock + '_' + if_name.lower() + + mod_name = mod_base + '_csr_assert_fpv' + filename = mod_name + '.sv' + generated.append(filename) + reg_top_path = os.path.join(outdir, filename) + with open(reg_top_path, 'w', encoding='UTF-8') as fout: + try: + fout.write(fpv_csr_tpl.render(block=block, + mod_base=mod_base, + if_name=if_name, + rb=rb)) + except: # noqa F722 for template Exception handling + log.error(exceptions.text_error_template().render()) + return 1 + + # Generate a fusesoc core file that points at the files we've just + # generated. + core_data = { + 'name': "lowrisc:fpv:{}_csr_assert".format(lblock), + 'filesets': { + 'files_dv': { + 'depend': [ + "lowrisc:tlul:headers", + "lowrisc:prim:assert", + ], + 'files': generated, + 'file_type': 'systemVerilogSource' + }, + }, + 'targets': { + 'default': { + 'filesets': [ + 'files_dv', + ], + }, + }, + } + core_file_path = os.path.join(outdir, lblock + '_csr_assert_fpv.core') + with open(core_file_path, 'w') as core_file: + core_file.write('CAPI=2:\n') + yaml.dump(core_data, core_file, encoding='utf-8') + + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_html.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_html.py new file mode 100644 index 00000000..e8c427b1 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_html.py @@ -0,0 +1,325 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +""" +Generate HTML documentation from IpBlock +""" + +from typing import Set, TextIO + +from .ip_block import IpBlock +from .html_helpers import expand_paras, render_td +from .multi_register import MultiRegister +from .reg_block import RegBlock +from .register import Register +from .window import Window + + +def genout(outfile: TextIO, msg: str) -> None: + outfile.write(msg) + + +# Generation of HTML table with register bit-field summary picture +# Max 16-bit wide on one line + + +def gen_tbl_row(outfile: TextIO, msb: int, width: int, close: bool) -> None: + if (close): + genout(outfile, "\n") + genout(outfile, "") + for x in range(msb, msb - width, -1): + genout(outfile, "" + str(x) + "") + + genout(outfile, "") + + +def gen_html_reg_pic(outfile: TextIO, reg: Register, width: int) -> None: + + if (width > 32): + bsize = 3 + nextbit = 63 + hdrbits = 16 + nextline = 48 + elif (width > 16): + bsize = 3 + nextbit = 31 + hdrbits = 16 + nextline = 16 + elif (width > 8): + bsize = 3 + nextbit = 15 + nextline = 0 + hdrbits = 16 + else: + bsize = 12 + nextbit = 7 + nextline = 0 + hdrbits = 8 + + genout(outfile, "") + gen_tbl_row(outfile, nextbit, hdrbits, False) + + for field in reversed(reg.fields): + fieldlsb = field.bits.lsb + fieldwidth = field.bits.width() + fieldmsb = field.bits.msb + fname = field.name + + while nextbit > fieldmsb: + if (nextbit >= nextline) and (fieldmsb < nextline): + spans = nextbit - (nextline - 1) + else: + spans = nextbit - fieldmsb + genout( + outfile, "\n") + if (nextbit >= nextline) and (fieldmsb < nextline): + nextbit = nextline - 1 + gen_tbl_row(outfile, nextbit, hdrbits, True) + nextline = nextline - 16 + else: + nextbit = fieldmsb + + while (fieldmsb >= nextline) and (fieldlsb < nextline): + spans = fieldmsb - (nextline - 1) + genout( + outfile, "\n") + fname = "..." + field.name + fieldwidth = fieldwidth - spans + fieldmsb = nextline - 1 + nextline = nextline - 16 + gen_tbl_row(outfile, fieldmsb, hdrbits, True) + + namelen = len(fname) + if namelen == 0 or fname == ' ': + fname = " " + if (namelen > bsize * fieldwidth): + usestyle = (" style=\"font-size:" + str( + (bsize * 100 * fieldwidth) / namelen) + "%\"") + else: + usestyle = "" + + genout( + outfile, "\n") + + if (fieldlsb == nextline) and nextline > 0: + gen_tbl_row(outfile, nextline - 1, hdrbits, True) + nextline = nextline - 16 + + nextbit = fieldlsb - 1 + while (nextbit > 0): + spans = nextbit - (nextline - 1) + genout(outfile, + "\n") + nextbit = nextline - 1 + if (nextline > 0): + gen_tbl_row(outfile, nextline - 1, hdrbits, True) + nextline = nextline - 16 + + genout(outfile, "
 " + + fname + "..." + fname + " 
") + + +# Generation of HTML table with header, register picture and details + + +def gen_html_register(outfile: TextIO, + reg: Register, + comp: str, + width: int, + rnames: Set[str]) -> None: + rname = reg.name + offset = reg.offset + regwen_div = '' + if reg.regwen is not None: + regwen_div = ('
Register enable = {}
\n' + .format(reg.regwen)) + + desc_paras = expand_paras(reg.desc, rnames) + desc_head = desc_paras[0] + desc_body = desc_paras[1:] + + genout(outfile, + '\n' + ' \n' + ' \n' + ' \n' + .format(lrname=rname.lower(), + comp=comp, + rname=rname, + off=offset, + desc=desc_head, + resval=reg.resval, + mask=reg.resmask, + wen=regwen_div)) + if desc_body: + genout(outfile, + '' + .format(''.join(desc_body))) + + genout(outfile, "\n") + + genout(outfile, "") + genout(outfile, "") + genout(outfile, "") + genout(outfile, "") + genout(outfile, "") + nextbit = 0 + fcount = 0 + + for field in reg.fields: + fcount += 1 + fname = field.name + + fieldlsb = field.bits.lsb + if fieldlsb > nextbit: + genout(outfile, "") + genout(outfile, "") + genout(outfile, "") + genout( + outfile, "") + genout(outfile, "") + + # Collect up any description and enum table + desc_parts = [] + + if field.desc is not None: + desc_parts += expand_paras(field.desc, rnames) + + if field.enum is not None: + desc_parts.append('
\n' + '
{comp}.{rname} @ {off:#x}
\n' + '
{desc}
\n' + '
Reset default = {resval:#x}, mask {mask:#x}
\n' + '{wen}' + '
{}
") + gen_html_reg_pic(outfile, reg, width) + genout(outfile, "
BitsTypeResetNameDescription
") + if (nextbit == (fieldlsb - 1)): + genout(outfile, str(nextbit)) + else: + genout(outfile, str(fieldlsb - 1) + ":" + str(nextbit)) + genout(outfile, + "Reserved
" + field.bits.as_str() + "" + field.swaccess.key + "" + + ('x' if field.resval is None else hex(field.resval)) + + "" + fname + "
') + for enum in field.enum: + enum_desc_paras = expand_paras(enum.desc, rnames) + desc_parts.append('' + '' + '' + '' + '\n' + .format(val=enum.value, + name=enum.name, + desc=''.join(enum_desc_paras))) + desc_parts.append('
{val}{name}{desc}
') + if field.has_incomplete_enum(): + desc_parts.append("

Other values are reserved.

") + + genout(outfile, + '{}'.format(''.join(desc_parts))) + nextbit = fieldlsb + field.bits.width() + + genout(outfile, "\n
\n") + + +def gen_html_window(outfile: TextIO, + win: Window, + comp: str, + regwidth: int, + rnames: Set[str]) -> None: + wname = win.name or '(unnamed window)' + offset = win.offset + genout(outfile, + '\n' + ' \n' + ' \n' + ' \n' + .format(comp=comp, + wname=wname, + lwname=wname.lower(), + off=offset, + items=win.items, + swaccess=win.swaccess.key, + byte_writes=('' if win.byte_write else 'not '))) + genout(outfile, '{}'.format(render_td(win.desc, rnames, 'regde'))) + genout(outfile, "
\n' + '
{comp}.{wname} @ + {off:#x}
\n' + '
{items} item {swaccess} window
\n' + '
Byte writes are {byte_writes}supported
\n' + '
') + genout(outfile, '') + wid = win.validbits + + for x in range(regwidth - 1, -1, -1): + if x == regwidth - 1 or x == wid - 1 or x == 0: + genout(outfile, '') + else: + genout(outfile, '') + genout(outfile, '') + tblmax = win.items - 1 + for x in [0, 1, 2, tblmax - 1, tblmax]: + if x == 2: + genout( + outfile, '') + else: + genout( + outfile, '') + if wid < regwidth: + genout( + outfile, '\n') + genout( + outfile, + '\n') + else: + genout( + outfile, '\n') + genout(outfile, '') + genout(outfile, '
' + str(x) + '
 ...
+' + + hex(offset + x * (regwidth // 8)) + '   
') + genout(outfile, + '
\n
\n") + + +def gen_html_reg_block(outfile: TextIO, + rb: RegBlock, + comp: str, + width: int, + rnames: Set[str]) -> None: + for x in rb.entries: + if isinstance(x, Register): + gen_html_register(outfile, x, comp, width, rnames) + elif isinstance(x, MultiRegister): + for reg in x.regs: + gen_html_register(outfile, reg, comp, width, rnames) + else: + assert isinstance(x, Window) + gen_html_window(outfile, x, comp, width, rnames) + + +def gen_html(block: IpBlock, outfile: TextIO) -> int: + rnames = block.get_rnames() + + assert block.reg_blocks + # Handle the case where there's just one interface + if len(block.reg_blocks) == 1: + rb = list(block.reg_blocks.values())[0] + gen_html_reg_block(outfile, rb, block.name, block.regwidth, rnames) + return 0 + + # Handle the case where there is more than one device interface and, + # correspondingly, more than one reg block. + for iface_name, rb in block.reg_blocks.items(): + iface_desc = ('device interface {}'.format(iface_name) + if iface_name is not None + else 'the unnamed device interface') + genout(outfile, + '

Registers visible under {}

'.format(iface_desc)) + gen_html_reg_block(outfile, rb, block.name, block.regwidth, rnames) + + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_json.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_json.py new file mode 100644 index 00000000..c593cc1c --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_json.py @@ -0,0 +1,34 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Generate JSON/compact JSON/Hjson from register JSON tree +""" + +import hjson + + +def gen_json(obj, outfile, format): + if format == 'json': + hjson.dumpJSON(obj, + outfile, + ensure_ascii=False, + use_decimal=True, + indent=' ', + for_json=True) + elif format == 'compact': + hjson.dumpJSON(obj, + outfile, + ensure_ascii=False, + for_json=True, + use_decimal=True, + separators=(',', ':')) + elif format == 'hjson': + hjson.dump(obj, + outfile, + ensure_ascii=False, + for_json=True, + use_decimal=True) + else: + raise ValueError('Invalid JSON format ' + format) + + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_rtl.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_rtl.py new file mode 100644 index 00000000..14c9b4ba --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_rtl.py @@ -0,0 +1,136 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Generate SystemVerilog designs from IpBlock object""" + +import logging as log +import os +from typing import Dict, Optional, Tuple + +from mako import exceptions # type: ignore +from mako.template import Template # type: ignore +from pkg_resources import resource_filename + +from .ip_block import IpBlock +from .multi_register import MultiRegister +from .reg_base import RegBase +from .register import Register + + +def escape_name(name: str) -> str: + return name.lower().replace(' ', '_') + + +def make_box_quote(msg: str, indent: str = ' ') -> str: + hr = indent + ('/' * (len(msg) + 6)) + middle = indent + '// ' + msg + ' //' + return '\n'.join([hr, middle, hr]) + + +def _get_awparam_name(iface_name: Optional[str]) -> str: + return (iface_name or 'Iface').capitalize() + 'Aw' + + +def get_addr_widths(block: IpBlock) -> Dict[Optional[str], Tuple[str, int]]: + '''Return the address widths for the device interfaces + + Returns a dictionary keyed by interface name whose values are pairs: + (paramname, width) where paramname is IfaceAw for an unnamed interface and + FooAw for an interface called foo. This is constructed in the same order as + block.reg_blocks. + + If there is a single device interface and that interface is unnamed, use + the more general parameter name "BlockAw". + + ''' + assert block.reg_blocks + if len(block.reg_blocks) == 1 and None in block.reg_blocks: + return {None: ('BlockAw', block.reg_blocks[None].get_addr_width())} + + return {name: (_get_awparam_name(name), rb.get_addr_width()) + for name, rb in block.reg_blocks.items()} + + +def get_type_name_pfx(block: IpBlock, iface_name: Optional[str]) -> str: + return block.name.lower() + ('' if iface_name is None + else '_{}'.format(iface_name.lower())) + + +def get_r0(reg: RegBase) -> Register: + '''Get a Register representing an entry in the RegBase''' + if isinstance(reg, Register): + return reg + else: + assert isinstance(reg, MultiRegister) + return reg.reg + + +def get_iface_tx_type(block: IpBlock, + iface_name: Optional[str], + hw2reg: bool) -> str: + x2x = 'hw2reg' if hw2reg else 'reg2hw' + pfx = get_type_name_pfx(block, iface_name) + return '_'.join([pfx, x2x, 't']) + + +def get_reg_tx_type(block: IpBlock, reg: RegBase, hw2reg: bool) -> str: + '''Get the name of the hw2reg or reg2hw type for reg''' + if isinstance(reg, Register): + r0 = reg + type_suff = 'reg_t' + else: + assert isinstance(reg, MultiRegister) + r0 = reg.reg + type_suff = 'mreg_t' + + x2x = 'hw2reg' if hw2reg else 'reg2hw' + return '_'.join([block.name.lower(), + x2x, + r0.name.lower(), + type_suff]) + + +def gen_rtl(block: IpBlock, outdir: str) -> int: + # Read Register templates + reg_top_tpl = Template( + filename=resource_filename('reggen', 'reg_top.sv.tpl')) + reg_pkg_tpl = Template( + filename=resource_filename('reggen', 'reg_pkg.sv.tpl')) + + # Generate _reg_pkg.sv + # + # This defines the various types used to interface between the *_reg_top + # module(s) and the block itself. + reg_pkg_path = os.path.join(outdir, block.name.lower() + "_reg_pkg.sv") + with open(reg_pkg_path, 'w', encoding='UTF-8') as fout: + try: + fout.write(reg_pkg_tpl.render(block=block)) + except: # noqa F722 for template Exception handling + log.error(exceptions.text_error_template().render()) + return 1 + + # Generate the register block implementation(s). For a device interface + # with no name we generate the register module "_reg_top" (writing + # to _reg_top.sv). In any other case, we also need the interface + # name, giving __reg_top. + lblock = block.name.lower() + for if_name, rb in block.reg_blocks.items(): + if if_name is None: + mod_base = lblock + else: + mod_base = lblock + '_' + if_name.lower() + + mod_name = mod_base + '_reg_top' + reg_top_path = os.path.join(outdir, mod_name + '.sv') + with open(reg_top_path, 'w', encoding='UTF-8') as fout: + try: + fout.write(reg_top_tpl.render(block=block, + mod_base=mod_base, + mod_name=mod_name, + if_name=if_name, + rb=rb)) + except: # noqa F722 for template Exception handling + log.error(exceptions.text_error_template().render()) + return 1 + + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_selfdoc.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_selfdoc.py new file mode 100644 index 00000000..5f38404a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/gen_selfdoc.py @@ -0,0 +1,306 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +""" +Generates the documentation for the register tool + +""" +from .access import SWACCESS_PERMITTED, HWACCESS_PERMITTED +from reggen import (validate, + ip_block, enum_entry, field, + register, multi_register, window) + + +def genout(outfile, msg): + outfile.write(msg) + + +doc_intro = """ + + + +The tables describe each key and the type of the value. The following +types are used: + +Type | Description +---- | ----------- +""" + +swaccess_intro = """ + +Register fields are tagged using the swaccess key to describe the +permitted access and side-effects. This key must have one of these +values: + +""" + +hwaccess_intro = """ + +Register fields are tagged using the hwaccess key to describe the +permitted access from hardware logic and side-effects. This key must +have one of these values: + +""" + +top_example = """ +The basic structure of a register definition file is thus: + +```hjson +{ + name: "GP", + regwidth: "32", + registers: [ + // register definitions... + ] +} + +``` + +""" + +register_example = """ + +The basic register definition group will follow this pattern: + +```hjson + { name: "REGA", + desc: "Description of register", + swaccess: "rw", + resval: "42", + fields: [ + // bit field definitions... + ] + } +``` + +The name and brief description are required. If the swaccess key is +provided it describes the access pattern that will be used by all +bitfields in the register that do not override with their own swaccess +key. This is a useful shortcut because in most cases a register will +have the same access restrictions for all fields. The reset value of +the register may also be provided here or in the individual fields. If +it is provided in both places then they must match, if it is provided +in neither place then the reset value defaults to zero for all except +write-only fields when it defaults to x. + +""" + +field_example = """ + +Field names should be relatively short because they will be used +frequently (and need to fit in the register layout picture!) The field +description is expected to be longer and will most likely make use of +the Hjson ability to include multi-line strings. An example with three +fields: + +```hjson + fields: [ + { bits: "15:0", + name: "RXS", + desc: ''' + Last 16 oversampled values of RX. These are captured at 16x the baud + rate clock. This is a shift register with the most recent bit in + bit 0 and the oldest in bit 15. Only valid when ENRXS is set. + ''' + } + { bits: "16", + name: "ENRXS", + desc: ''' + If this bit is set the receive oversampled data is collected + in the RXS field. + ''' + } + {bits: "20:19", name: "TXILVL", + desc: "Trigger level for TX interrupts", + resval: "2", + enum: [ + { value: "0", name: "txlvl1", desc: "1 character" }, + { value: "1", name: "txlvl4", desc: "4 characters" }, + { value: "2", name: "txlvl8", desc: "8 characters" }, + { value: "3", name: "txlvl16", desc: "16 characters" } + ] + } + ] +``` + +In all of these the swaccess parameter is inherited from the register +level, and will be added so this key is always available to the +backend. The RXS and ENRXS will default to zero reset value (unless +something different is provided for the register) and will have the +key added, but TXILVL expicitly sets its reset value as 2. + +The missing bits 17 and 18 will be treated as reserved by the tool, as +will any bits between 21 and the maximum in the register. + +The TXILVL is an example using an enumeration to specify all valid +values for the field. In this case all possible values are described, +if the list is incomplete then the field is marked with the rsvdenum +key so the backend can take appropriate action. (If the enum field is +more than 7 bits then the checking is not done.) + +""" + +offset_intro = """ + +""" + +multi_intro = """ + +The multireg expands on the register required fields and will generate +a list of the generated registers (that contain all required and +generated keys for an actual register). + +""" + +window_intro = """ + +A window defines an open region of the register space that can be used +for things that are not registers (for example access to a buffer ram). + +""" + +regwen_intro = """ + +Registers can protect themselves from software writes by using the +register attribute regwen. When not an emptry string (the default +value), regwen indicates that another register must be true in order +to allow writes to this register. This is useful for the prevention +of software modification. The register-enable register (call it +REGWEN) must be one bit in width, and should default to 1 and be rw1c +for preferred security control. This allows all writes to proceed +until at some point software disables future modifications by clearing +REGWEN. An error is reported if REGWEN does not exist, contains more +than one bit, is not `rw1c` or does not default to 1. One REGWEN can +protect multiple registers. The REGWEN register must precede those +registers that refer to it in the .hjson register list. An example: + +```hjson + { name: "REGWEN", + desc: "Register write enable for a bank of registers", + swaccess: "rw1c", + fields: [ { bits: "0", resval: "1" } ] + } + { name: "REGA", + swaccess: "rw", + regwen: "REGWEN", + ... + } + { name: "REGB", + swaccess: "rw", + regwen: "REGWEN", + ... + } +``` +""" + +doc_tail = """ + +(end of output generated by `regtool.py --doc`) + +""" + + +def doc_tbl_head(outfile, use): + if use is not None: + genout(outfile, "\nKey | Kind | Type | Description of Value\n") + genout(outfile, "--- | ---- | ---- | --------------------\n") + else: + genout(outfile, "\nKey | Description\n") + genout(outfile, "--- | -----------\n") + + +def doc_tbl_line(outfile, key, use, desc): + if use is not None: + desc_key, desc_txt = desc + val_type = (validate.val_types[desc_key][0] + if desc_key is not None else None) + else: + assert isinstance(desc, str) + val_type = None + desc_txt = desc + + if val_type is not None: + genout( + outfile, '{} | {} | {} | {}\n'.format(key, validate.key_use[use], + val_type, desc_txt)) + else: + genout(outfile, key + " | " + desc_txt + "\n") + + +def document(outfile): + genout(outfile, doc_intro) + for x in validate.val_types: + genout( + outfile, + validate.val_types[x][0] + " | " + validate.val_types[x][1] + "\n") + + genout(outfile, swaccess_intro) + doc_tbl_head(outfile, None) + for key, value in SWACCESS_PERMITTED.items(): + doc_tbl_line(outfile, key, None, value[0]) + + genout(outfile, hwaccess_intro) + doc_tbl_head(outfile, None) + for key, value in HWACCESS_PERMITTED.items(): + doc_tbl_line(outfile, key, None, value[0]) + + genout( + outfile, "\n\nThe top level of the JSON is a group containing " + "the following keys:\n") + doc_tbl_head(outfile, 1) + for k, v in ip_block.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + for k, v in ip_block.OPTIONAL_FIELDS.items(): + doc_tbl_line(outfile, k, 'o', v) + genout(outfile, top_example) + + genout( + outfile, "\n\nThe list of registers includes register definition " + "groups containing the following keys:\n") + doc_tbl_head(outfile, 1) + for k, v in register.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + for k, v in register.OPTIONAL_FIELDS.items(): + doc_tbl_line(outfile, k, 'o', v) + genout(outfile, register_example) + + genout( + outfile, "\n\nIn the fields list each field definition is a group " + "itself containing the following keys:\n") + doc_tbl_head(outfile, 1) + for k, v in field.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + for k, v in field.OPTIONAL_FIELDS.items(): + doc_tbl_line(outfile, k, 'o', v) + genout(outfile, field_example) + + genout(outfile, "\n\nDefinitions in an enumeration group contain:\n") + doc_tbl_head(outfile, 1) + for k, v in enum_entry.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + + genout( + outfile, "\n\nThe list of registers may include single entry groups " + "to control the offset, open a window or generate registers:\n") + doc_tbl_head(outfile, 1) + for x in validate.list_optone: + doc_tbl_line(outfile, x, 'o', validate.list_optone[x]) + + genout(outfile, offset_intro) + genout(outfile, regwen_intro) + + genout(outfile, window_intro) + doc_tbl_head(outfile, 1) + for k, v in window.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + for k, v in window.OPTIONAL_FIELDS.items(): + doc_tbl_line(outfile, k, 'o', v) + + genout(outfile, multi_intro) + doc_tbl_head(outfile, 1) + for k, v in multi_register.REQUIRED_FIELDS.items(): + doc_tbl_line(outfile, k, 'r', v) + for k, v in multi_register.OPTIONAL_FIELDS.items(): + doc_tbl_line(outfile, k, 'o', v) + + genout(outfile, doc_tail) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/html_helpers.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/html_helpers.py new file mode 100644 index 00000000..8c828ee2 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/html_helpers.py @@ -0,0 +1,83 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import re +from typing import List, Match, Optional, Set + + +def expand_paras(s: str, rnames: Set[str]) -> List[str]: + '''Expand a description field to HTML. + + This supports a sort of simple pseudo-markdown. Supported Markdown + features: + + - Separate paragraphs on a blank line + - **bold** and *italicised* text + - Back-ticks for pre-formatted text + + We also generate links to registers when a name is prefixed with a double + exclamation mark. For example, if there is a register FOO then !!FOO or + !!FOO.field will generate a link to that register. + + Returns a list of rendered paragraphs + + ''' + # Start by splitting into paragraphs. The regex matches a newline followed + # by one or more lines that just contain whitespace. Then render each + # paragraph with the _expand_paragraph worker function. + paras = [_expand_paragraph(paragraph.strip(), rnames) + for paragraph in re.split(r'\n(?:\s*\n)+', s)] + + # There will always be at least one paragraph (splitting an empty string + # gives ['']) + assert paras + return paras + + +def _expand_paragraph(s: str, rnames: Set[str]) -> str: + '''Expand a single paragraph, as described in _get_desc_paras''' + def fieldsub(match: Match[str]) -> str: + base = match.group(1).partition('.')[0].lower() + if base in rnames: + if match.group(1)[-1] == ".": + return ('' + + match.group(1)[:-1] + '.') + else: + return ('' + + match.group(1) + '') + log.warn('!!' + match.group(1).partition('.')[0] + + ' not found in register list.') + return match.group(0) + + # Split out pre-formatted text. Because the call to re.split has a capture + # group in the regex, we get an odd number of results. Elements with even + # indices are "normal text". Those with odd indices are the captured text + # between the back-ticks. + code_split = re.split(r'`([^`]+)`', s) + expanded_parts = [] + + for idx, part in enumerate(code_split): + if idx & 1: + # Text contained in back ticks + expanded_parts.append('{}'.format(part)) + continue + + part = re.sub(r"!!([A-Za-z0-9_.]+)", fieldsub, part) + part = re.sub(r"(?s)\*\*(.+?)\*\*", r'\1', part) + part = re.sub(r"\*([^*]+?)\*", r'\1', part) + expanded_parts.append(part) + + return '

{}

'.format(''.join(expanded_parts)) + + +def render_td(s: str, rnames: Set[str], td_class: Optional[str]) -> str: + '''Expand a description field and put it in a . + + Returns a string. See _get_desc_paras for the format that gets expanded. + + ''' + desc_paras = expand_paras(s, rnames) + class_attr = '' if td_class is None else ' class="{}"'.format(td_class) + return '{}'.format(class_attr, ''.join(desc_paras)) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/inter_signal.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/inter_signal.py new file mode 100644 index 00000000..cf27d511 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/inter_signal.py @@ -0,0 +1,81 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, Optional + +from .lib import (check_keys, check_name, + check_str, check_optional_str, check_int) + + +class InterSignal: + def __init__(self, + name: str, + desc: Optional[str], + struct: str, + package: Optional[str], + signal_type: str, + act: str, + width: int, + default: Optional[str]): + assert 0 < width + self.name = name + self.desc = desc + self.struct = struct + self.package = package + self.signal_type = signal_type + self.act = act + self.width = width + self.default = default + + @staticmethod + def from_raw(what: str, raw: object) -> 'InterSignal': + rd = check_keys(raw, what, + ['name', 'struct', 'type', 'act'], + ['desc', 'package', 'width', 'default']) + + name = check_name(rd['name'], 'name field of ' + what) + + r_desc = rd.get('desc') + if r_desc is None: + desc = None + else: + desc = check_str(r_desc, 'desc field of ' + what) + + struct = check_str(rd['struct'], 'struct field of ' + what) + + r_package = rd.get('package') + if r_package is None or r_package == '': + package = None + else: + package = check_name(r_package, 'package field of ' + what) + + signal_type = check_name(rd['type'], 'type field of ' + what) + act = check_name(rd['act'], 'act field of ' + what) + width = check_int(rd.get('width', 1), 'width field of ' + what) + if width <= 0: + raise ValueError('width field of {} is not positive.'.format(what)) + + default = check_optional_str(rd.get('default'), + 'default field of ' + what) + + return InterSignal(name, desc, struct, package, + signal_type, act, width, default) + + def _asdict(self) -> Dict[str, object]: + ret = {'name': self.name} # type: Dict[str, object] + if self.desc is not None: + ret['desc'] = self.desc + ret['struct'] = self.struct + if self.package is not None: + ret['package'] = self.package + ret['type'] = self.signal_type + ret['act'] = self.act + ret['width'] = self.width + if self.default is not None: + ret['default'] = self.default + + return ret + + def as_dict(self) -> Dict[str, object]: + return self._asdict() diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/ip_block.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/ip_block.py new file mode 100644 index 00000000..5865d04a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/ip_block.py @@ -0,0 +1,365 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Code representing an IP block for reggen''' + +from typing import Dict, List, Optional, Sequence, Set, Tuple + +import hjson # type: ignore + +from .alert import Alert +from .bus_interfaces import BusInterfaces +from .inter_signal import InterSignal +from .lib import (check_keys, check_name, check_int, check_bool, + check_list, check_optional_str, check_name_list) +from .params import ReggenParams, LocalParam +from .reg_block import RegBlock +from .signal import Signal + + +REQUIRED_FIELDS = { + 'name': ['s', "name of the component"], + 'clock_primary': ['s', "name of the primary clock"], + 'bus_interfaces': ['l', "bus interfaces for the device"], + 'registers': [ + 'l', + "list of register definition groups and " + "offset control groups" + ] +} + +OPTIONAL_FIELDS = { + 'alert_list': ['lnw', "list of peripheral alerts"], + 'available_inout_list': ['lnw', "list of available peripheral inouts"], + 'available_input_list': ['lnw', "list of available peripheral inputs"], + 'available_output_list': ['lnw', "list of available peripheral outputs"], + 'hier_path': [ + None, + 'additional hierarchy path before the reg block instance' + ], + 'interrupt_list': ['lnw', "list of peripheral interrupts"], + 'inter_signal_list': ['l', "list of inter-module signals"], + 'no_auto_alert_regs': [ + 's', "Set to true to suppress automatic " + "generation of alert test registers. " + "Defaults to true if no alert_list is present. " + "Otherwise this defaults to false. " + ], + 'no_auto_intr_regs': [ + 's', "Set to true to suppress automatic " + "generation of interrupt registers. " + "Defaults to true if no interrupt_list is present. " + "Otherwise this defaults to false. " + ], + 'other_clock_list': ['l', "list of other chip clocks needed"], + 'other_reset_list': ['l', "list of other resets"], + 'param_list': ['lp', "list of parameters of the IP"], + 'regwidth': ['d', "width of registers in bits (default 32)"], + 'reset_primary': ['s', "primary reset used by the module"], + 'reset_request_list': ['l', 'list of signals requesting reset'], + 'scan': ['pb', 'Indicates the module have `scanmode_i`'], + 'scan_reset': ['pb', 'Indicates the module have `scan_rst_ni`'], + 'scan_en': ['pb', 'Indicates the module has `scan_en_i`'], + 'SPDX-License-Identifier': [ + 's', "License ientifier (if using pure json) " + "Only use this if unable to put this " + "information in a comment at the top of the " + "file." + ], + 'wakeup_list': ['lnw', "list of peripheral wakeups"] +} + + +class IpBlock: + def __init__(self, + name: str, + regwidth: int, + params: ReggenParams, + reg_blocks: Dict[Optional[str], RegBlock], + interrupts: Sequence[Signal], + no_auto_intr: bool, + alerts: List[Alert], + no_auto_alert: bool, + scan: bool, + inter_signals: List[InterSignal], + bus_interfaces: BusInterfaces, + hier_path: Optional[str], + clock_signals: List[str], + reset_signals: List[str], + xputs: Tuple[Sequence[Signal], + Sequence[Signal], + Sequence[Signal]], + wakeups: Sequence[Signal], + reset_requests: Sequence[Signal], + scan_reset: bool, + scan_en: bool): + assert reg_blocks + assert clock_signals + assert reset_signals + + # Check that register blocks are in bijection with device interfaces + reg_block_names = reg_blocks.keys() + dev_if_names = [] # type: List[Optional[str]] + dev_if_names += bus_interfaces.named_devices + if bus_interfaces.has_unnamed_device: + dev_if_names.append(None) + assert set(reg_block_names) == set(dev_if_names) + + self.name = name + self.regwidth = regwidth + self.reg_blocks = reg_blocks + self.params = params + self.interrupts = interrupts + self.no_auto_intr = no_auto_intr + self.alerts = alerts + self.no_auto_alert = no_auto_alert + self.scan = scan + self.inter_signals = inter_signals + self.bus_interfaces = bus_interfaces + self.hier_path = hier_path + self.clock_signals = clock_signals + self.reset_signals = reset_signals + self.xputs = xputs + self.wakeups = wakeups + self.reset_requests = reset_requests + self.scan_reset = scan_reset + self.scan_en = scan_en + + @staticmethod + def from_raw(param_defaults: List[Tuple[str, str]], + raw: object, + where: str) -> 'IpBlock': + + rd = check_keys(raw, 'block at ' + where, + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + name = check_name(rd['name'], 'name of block at ' + where) + + what = '{} block at {}'.format(name, where) + + r_regwidth = rd.get('regwidth') + if r_regwidth is None: + regwidth = 32 + else: + regwidth = check_int(r_regwidth, 'regwidth field of ' + what) + if regwidth <= 0: + raise ValueError('Invalid regwidth field for {}: ' + '{} is not positive.' + .format(what, regwidth)) + + params = ReggenParams.from_raw('parameter list for ' + what, + rd.get('param_list', [])) + try: + params.apply_defaults(param_defaults) + except (ValueError, KeyError) as err: + raise ValueError('Failed to apply defaults to params: {}' + .format(err)) from None + + init_block = RegBlock(regwidth, params) + + interrupts = Signal.from_raw_list('interrupt_list for block {}' + .format(name), + rd.get('interrupt_list', [])) + alerts = Alert.from_raw_list('alert_list for block {}' + .format(name), + rd.get('alert_list', [])) + + no_auto_intr = check_bool(rd.get('no_auto_intr_regs', not interrupts), + 'no_auto_intr_regs field of ' + what) + + no_auto_alert = check_bool(rd.get('no_auto_alert_regs', not alerts), + 'no_auto_alert_regs field of ' + what) + + if interrupts and not no_auto_intr: + if interrupts[-1].bits.msb >= regwidth: + raise ValueError("Interrupt list for {} is too wide: " + "msb is {}, which doesn't fit with a " + "regwidth of {}." + .format(what, + interrupts[-1].bits.msb, regwidth)) + init_block.make_intr_regs(interrupts) + + if alerts: + if not no_auto_alert: + if len(alerts) > regwidth: + raise ValueError("Interrupt list for {} is too wide: " + "{} alerts don't fit with a regwidth of {}." + .format(what, len(alerts), regwidth)) + init_block.make_alert_regs(alerts) + + # Generate a NumAlerts parameter + existing_param = params.get('NumAlerts') + if existing_param is not None: + if ((not isinstance(existing_param, LocalParam) or + existing_param.param_type != 'int' or + existing_param.value != str(len(alerts)))): + raise ValueError('Conflicting definition of NumAlerts ' + 'parameter.') + else: + params.add(LocalParam(name='NumAlerts', + desc='Number of alerts', + param_type='int', + value=str(len(alerts)))) + + scan = check_bool(rd.get('scan', False), 'scan field of ' + what) + + reg_blocks = RegBlock.build_blocks(init_block, rd['registers']) + + r_inter_signals = check_list(rd.get('inter_signal_list', []), + 'inter_signal_list field') + inter_signals = [ + InterSignal.from_raw('entry {} of the inter_signal_list field' + .format(idx + 1), + entry) + for idx, entry in enumerate(r_inter_signals) + ] + + bus_interfaces = (BusInterfaces. + from_raw(rd['bus_interfaces'], + 'bus_interfaces field of ' + where)) + inter_signals += bus_interfaces.inter_signals() + + hier_path = check_optional_str(rd.get('hier_path', None), + 'hier_path field of ' + what) + + clock_primary = check_name(rd['clock_primary'], + 'clock_primary field of ' + what) + other_clock_list = check_name_list(rd.get('other_clock_list', []), + 'other_clock_list field of ' + what) + clock_signals = [clock_primary] + other_clock_list + + reset_primary = check_name(rd.get('reset_primary', 'rst_ni'), + 'reset_primary field of ' + what) + other_reset_list = check_name_list(rd.get('other_reset_list', []), + 'other_reset_list field of ' + what) + reset_signals = [reset_primary] + other_reset_list + + xputs = ( + Signal.from_raw_list('available_inout_list for block ' + name, + rd.get('available_inout_list', [])), + Signal.from_raw_list('available_input_list for block ' + name, + rd.get('available_input_list', [])), + Signal.from_raw_list('available_output_list for block ' + name, + rd.get('available_output_list', [])) + ) + wakeups = Signal.from_raw_list('wakeup_list for block ' + name, + rd.get('wakeup_list', [])) + rst_reqs = Signal.from_raw_list('reset_request_list for block ' + name, + rd.get('reset_request_list', [])) + + scan_reset = check_bool(rd.get('scan_reset', False), + 'scan_reset field of ' + what) + + scan_en = check_bool(rd.get('scan_en', False), + 'scan_en field of ' + what) + + # Check that register blocks are in bijection with device interfaces + reg_block_names = reg_blocks.keys() + dev_if_names = [] # type: List[Optional[str]] + dev_if_names += bus_interfaces.named_devices + if bus_interfaces.has_unnamed_device: + dev_if_names.append(None) + if set(reg_block_names) != set(dev_if_names): + raise ValueError("IP block {} defines device interfaces, named {} " + "but its registers don't match (they are keyed " + "by {})." + .format(name, dev_if_names, + list(reg_block_names))) + + return IpBlock(name, regwidth, params, reg_blocks, + interrupts, no_auto_intr, alerts, no_auto_alert, + scan, inter_signals, bus_interfaces, + hier_path, clock_signals, reset_signals, xputs, + wakeups, rst_reqs, scan_reset, scan_en) + + @staticmethod + def from_text(txt: str, + param_defaults: List[Tuple[str, str]], + where: str) -> 'IpBlock': + '''Load an IpBlock from an hjson description in txt''' + return IpBlock.from_raw(param_defaults, + hjson.loads(txt, use_decimal=True), + where) + + @staticmethod + def from_path(path: str, + param_defaults: List[Tuple[str, str]]) -> 'IpBlock': + '''Load an IpBlock from an hjson description in a file at path''' + with open(path, 'r', encoding='utf-8') as handle: + return IpBlock.from_text(handle.read(), param_defaults, + 'file at {!r}'.format(path)) + + def _asdict(self) -> Dict[str, object]: + ret = { + 'name': self.name, + 'regwidth': self.regwidth + } + if len(self.reg_blocks) == 1 and None in self.reg_blocks: + ret['registers'] = self.reg_blocks[None].as_dicts() + else: + ret['registers'] = {k: v.as_dicts() + for k, v in self.reg_blocks.items()} + + ret['param_list'] = self.params.as_dicts() + ret['interrupt_list'] = self.interrupts + ret['no_auto_intr_regs'] = self.no_auto_intr + ret['alert_list'] = self.alerts + ret['no_auto_alert_regs'] = self.no_auto_alert + ret['scan'] = self.scan + ret['inter_signal_list'] = self.inter_signals + ret['bus_interfaces'] = self.bus_interfaces.as_dicts() + + if self.hier_path is not None: + ret['hier_path'] = self.hier_path + + ret['clock_primary'] = self.clock_signals[0] + if len(self.clock_signals) > 1: + ret['other_clock_list'] = self.clock_signals[1:] + + ret['reset_primary'] = self.reset_signals[0] + if len(self.reset_signals) > 1: + ret['other_reset_list'] = self.reset_signals[1:] + + inouts, inputs, outputs = self.xputs + if inouts: + ret['available_inout_list'] = inouts + if inputs: + ret['available_input_list'] = inputs + if outputs: + ret['available_output_list'] = outputs + + if self.wakeups: + ret['wakeup_list'] = self.wakeups + if self.reset_requests: + ret['reset_request_list'] = self.reset_requests + + ret['scan_reset'] = self.scan_reset + ret['scan_en'] = self.scan_en + + return ret + + def get_rnames(self) -> Set[str]: + ret = set() # type: Set[str] + for rb in self.reg_blocks.values(): + ret = ret.union(set(rb.name_to_offset.keys())) + return ret + + def get_signals_as_list_of_dicts(self) -> List[Dict]: + '''Look up and return signal by name''' + result = [] + for iodir, xput in zip(('inout', 'input', 'output'), self.xputs): + for sig in xput: + result.append(sig.as_nwt_dict(iodir)) + return result + + def get_signal_by_name_as_dict(self, name: str) -> Dict: + '''Look up and return signal by name''' + sig_list = self.get_signals_as_list_of_dicts() + for sig in sig_list: + if sig['name'] == name: + return sig + else: + raise ValueError("Signal {} does not exist in IP block {}" + .format(name, self.name)) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/lib.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/lib.py new file mode 100644 index 00000000..d72ef3d3 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/lib.py @@ -0,0 +1,262 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Parsing support code for reggen''' + +import re +from typing import Dict, List, Optional, cast + + +# Names that are prohibited (used as reserved keywords in systemverilog) +_VERILOG_KEYWORDS = { + 'alias', 'always', 'always_comb', 'always_ff', 'always_latch', 'and', + 'assert', 'assign', 'assume', 'automatic', 'before', 'begin', 'bind', + 'bins', 'binsof', 'bit', 'break', 'buf', 'bufif0', 'bufif1', 'byte', + 'case', 'casex', 'casez', 'cell', 'chandle', 'class', 'clocking', 'cmos', + 'config', 'const', 'constraint', 'context', 'continue', 'cover', + 'covergroup', 'coverpoint', 'cross', 'deassign', 'default', 'defparam', + 'design', 'disable', 'dist', 'do', 'edge', 'else', 'end', 'endcase', + 'endclass', 'endclocking', 'endconfig', 'endfunction', 'endgenerate', + 'endgroup', 'endinterface', 'endmodule', 'endpackage', 'endprimitive', + 'endprogram', 'endproperty', 'endspecify', 'endsequence', 'endtable', + 'endtask', 'enum', 'event', 'expect', 'export', 'extends', 'extern', + 'final', 'first_match', 'for', 'force', 'foreach', 'forever', 'fork', + 'forkjoin', 'function', 'generate', 'genvar', 'highz0', 'highz1', 'if', + 'iff', 'ifnone', 'ignore_bins', 'illegal_bins', 'import', 'incdir', + 'include', 'initial', 'inout', 'input', 'inside', 'instance', 'int', + 'integer', 'interface', 'intersect', 'join', 'join_any', 'join_none', + 'large', 'liblist', 'library', 'local', 'localparam', 'logic', 'longint', + 'macromodule', 'matches', 'medium', 'modport', 'module', 'nand', 'negedge', + 'new', 'nmos', 'nor', 'noshowcancelled', 'not', 'notif0', 'notif1', 'null', + 'or', 'output', 'package', 'packed', 'parameter', 'pmos', 'posedge', + 'primitive', 'priority', 'program', 'property', 'protected', 'pull0', + 'pull1', 'pulldown', 'pullup', 'pulsestyle_onevent', 'pulsestyle_ondetect', + 'pure', 'rand', 'randc', 'randcase', 'randsequence', 'rcmos', 'real', + 'realtime', 'ref', 'reg', 'release', 'repeat', 'return', 'rnmos', 'rpmos', + 'rtran', 'rtranif0', 'rtranif1', 'scalared', 'sequence', 'shortint', + 'shortreal', 'showcancelled', 'signed', 'small', 'solve', 'specify', + 'specparam', 'static', 'string', 'strong0', 'strong1', 'struct', 'super', + 'supply0', 'supply1', 'table', 'tagged', 'task', 'this', 'throughout', + 'time', 'timeprecision', 'timeunit', 'tran', 'tranif0', 'tranif1', 'tri', + 'tri0', 'tri1', 'triand', 'trior', 'trireg', 'type', 'typedef', 'union', + 'unique', 'unsigned', 'use', 'uwire', 'var', 'vectored', 'virtual', 'void', + 'wait', 'wait_order', 'wand', 'weak0', 'weak1', 'while', 'wildcard', + 'wire', 'with', 'within', 'wor', 'xnor', 'xor' +} + + +def check_str_dict(obj: object, what: str) -> Dict[str, object]: + if not isinstance(obj, dict): + raise ValueError("{} is expected to be a dict, but was actually a {}." + .format(what, type(obj).__name__)) + + for key in obj: + if not isinstance(key, str): + raise ValueError('{} has a key {!r}, which is not a string.' + .format(what, key)) + + return cast(Dict[str, object], obj) + + +def check_keys(obj: object, + what: str, + required_keys: List[str], + optional_keys: List[str]) -> Dict[str, object]: + '''Check that obj is a dict object with the expected keys + + If not, raise a ValueError; the what argument names the object. + + ''' + od = check_str_dict(obj, what) + + allowed = set() + missing = [] + for key in required_keys: + assert key not in allowed + allowed.add(key) + if key not in od: + missing.append(key) + + for key in optional_keys: + assert key not in allowed + allowed.add(key) + + unexpected = [] + for key in od: + if key not in allowed: + unexpected.append(key) + + if missing or unexpected: + mstr = ('The following required fields were missing: {}.' + .format(', '.join(missing)) if missing else '') + ustr = ('The following unexpected fields were found: {}.' + .format(', '.join(unexpected)) if unexpected else '') + raise ValueError("{} doesn't have the right keys. {}{}{}" + .format(what, + mstr, + ' ' if mstr and ustr else '', + ustr)) + + return od + + +def check_str(obj: object, what: str) -> str: + '''Check that the given object is a string + + If not, raise a ValueError; the what argument names the object. + + ''' + if not isinstance(obj, str): + raise ValueError('{} is of type {}, not a string.' + .format(what, type(obj).__name__)) + return obj + + +def check_name(obj: object, what: str) -> str: + '''Check that obj is a string that's a valid name. + + If not, raise a ValueError; the what argument names the object. + + ''' + as_str = check_str(obj, what) + + # Allow the usual symbol constituents (alphanumeric plus underscore; no + # leading numbers) + if not re.match(r'[a-zA-Z_][a-zA-Z_0-9]*$', as_str): + raise ValueError("{} is {!r}, which isn't a valid symbol in " + "C / Verilog, so isn't allowed as a name." + .format(what, as_str)) + + # Also check that this isn't a reserved word. + if as_str in _VERILOG_KEYWORDS: + raise ValueError("{} is {!r}, which is a reserved word in " + "SystemVerilog, so isn't allowed as a name." + .format(what, as_str)) + + return as_str + + +def check_bool(obj: object, what: str) -> bool: + '''Check that obj is a bool or a string that parses to a bool. + + If not, raise a ValueError; the what argument names the object. + + ''' + if isinstance(obj, str): + as_bool = { + 'true': True, + 'false': False, + '1': True, + '0': False + }.get(obj.lower()) + if as_bool is None: + raise ValueError('{} is {!r}, which cannot be parsed as a bool.' + .format(what, obj)) + return as_bool + + if obj is True or obj is False: + return obj + + raise ValueError('{} is of type {}, not a bool.' + .format(what, type(obj).__name__)) + + +def check_list(obj: object, what: str) -> List[object]: + '''Check that the given object is a list + + If not, raise a ValueError; the what argument names the object. + + ''' + if not isinstance(obj, list): + raise ValueError('{} is of type {}, not a list.' + .format(what, type(obj).__name__)) + return obj + + +def check_str_list(obj: object, what: str) -> List[str]: + '''Check that the given object is a list of strings + + If not, raise a ValueError; the what argument names the object. + + ''' + lst = check_list(obj, what) + for idx, elt in enumerate(lst): + if not isinstance(elt, str): + raise ValueError('Element {} of {} is of type {}, ' + 'not a string.' + .format(idx, what, type(elt).__name__)) + return cast(List[str], lst) + + +def check_name_list(obj: object, what: str) -> List[str]: + '''Check that the given object is a list of valid names + + If not, raise a ValueError; the what argument names the object. + + ''' + lst = check_list(obj, what) + for idx, elt in enumerate(lst): + check_name(elt, 'Element {} of {}'.format(idx + 1, what)) + + return cast(List[str], lst) + + +def check_int(obj: object, what: str) -> int: + '''Check that obj is an integer or a string that parses to an integer. + + If not, raise a ValueError; the what argument names the object. + + ''' + if isinstance(obj, int): + return obj + + if isinstance(obj, str): + try: + return int(obj, 0) + except ValueError: + raise ValueError('{} is {!r}, which cannot be parsed as an int.' + .format(what, obj)) from None + + raise ValueError('{} is of type {}, not an integer.' + .format(what, type(obj).__name__)) + + +def check_xint(obj: object, what: str) -> Optional[int]: + '''Check that obj is an integer, a string that parses to an integer or "x". + + On success, return an integer value if there is one or None if the value + was 'x'. On failure, raise a ValueError; the what argument names the + object. + + ''' + if isinstance(obj, int): + return obj + + if isinstance(obj, str): + if obj == 'x': + return None + try: + return int(obj, 0) + except ValueError: + raise ValueError('{} is {!r}, which is not "x", ' + 'nor can it be parsed as an int.' + .format(what, obj)) from None + + raise ValueError('{} is of type {}, not an integer.' + .format(what, type(obj).__name__)) + + +def check_optional_str(obj: object, what: str) -> Optional[str]: + '''Check that obj is a string or None''' + return None if obj is None else check_str(obj, what) + + +def get_basename(name: str) -> str: + '''Strip trailing _number (used as multireg suffix) from name''' + # TODO: This is a workaround, should solve this as part of parsing a + # multi-reg. + match = re.search(r'_[0-9]+$', name) + assert match + assert match.start() > 0 + return name[0:match.start()] diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/multi_register.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/multi_register.py new file mode 100644 index 00000000..82c86677 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/multi_register.py @@ -0,0 +1,142 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, List + +from reggen import register +from .field import Field +from .lib import check_keys, check_str, check_name, check_bool +from .params import ReggenParams +from .reg_base import RegBase +from .register import Register + +REQUIRED_FIELDS = { + 'name': ['s', "base name of the registers"], + 'desc': ['t', "description of the registers"], + 'count': [ + 's', "number of instances to generate." + " This field can be integer or string matching" + " from param_list." + ], + 'cname': [ + 's', "base name for each instance, mostly" + " useful for referring to instance in messages." + ], + 'fields': [ + 'l', "list of register field description" + " groups. Describes bit positions used for" + " base instance." + ] +} +OPTIONAL_FIELDS = register.OPTIONAL_FIELDS.copy() +OPTIONAL_FIELDS.update({ + 'regwen_multi': [ + 'pb', "If true, regwen term increments" + " along with current multireg count." + ], + 'compact': [ + 'pb', "If true, allow multireg compacting." + "If false, do not compact." + ] +}) + + +class MultiRegister(RegBase): + def __init__(self, + offset: int, + addrsep: int, + reg_width: int, + params: ReggenParams, + raw: object): + super().__init__(offset) + + rd = check_keys(raw, 'multireg', + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + # Now that we've checked the schema of rd, we make a "reg" version of + # it that removes any fields that are allowed by MultiRegister but + # aren't allowed by Register. We'll pass that to the register factory + # method. + reg_allowed_keys = (set(register.REQUIRED_FIELDS.keys()) | + set(register.OPTIONAL_FIELDS.keys())) + reg_rd = {key: value + for key, value in rd.items() + if key in reg_allowed_keys} + self.reg = Register.from_raw(reg_width, offset, params, reg_rd) + + self.cname = check_name(rd['cname'], + 'cname field of multireg {}' + .format(self.reg.name)) + + self.regwen_multi = check_bool(rd.get('regwen_multi', False), + 'regwen_multi field of multireg {}' + .format(self.reg.name)) + + default_compact = True if len(self.reg.fields) == 1 else False + self.compact = check_bool(rd.get('compact', default_compact), + 'compact field of multireg {}' + .format(self.reg.name)) + if self.compact and len(self.reg.fields) > 1: + raise ValueError('Multireg {} sets the compact flag ' + 'but has multiple fields.' + .format(self.reg.name)) + + count_str = check_str(rd['count'], + 'count field of multireg {}' + .format(self.reg.name)) + self.count = params.expand(count_str, + 'count field of multireg ' + self.reg.name) + if self.count <= 0: + raise ValueError("Multireg {} has a count of {}, " + "which isn't positive." + .format(self.reg.name, self.count)) + + # Generate the registers that this multireg expands into. Here, a + # "creg" is a "compacted register", which might contain multiple actual + # registers. + if self.compact: + assert len(self.reg.fields) == 1 + width_per_reg = self.reg.fields[0].bits.msb + 1 + assert width_per_reg <= reg_width + regs_per_creg = reg_width // width_per_reg + else: + regs_per_creg = 1 + + self.regs = [] + creg_count = (self.count + regs_per_creg - 1) // regs_per_creg + for creg_idx in range(creg_count): + min_reg_idx = regs_per_creg * creg_idx + max_reg_idx = min(min_reg_idx + regs_per_creg, self.count) - 1 + creg_offset = offset + creg_idx * addrsep + + reg = self.reg.make_multi(reg_width, + creg_offset, creg_idx, creg_count, + self.regwen_multi, self.compact, + min_reg_idx, max_reg_idx, self.cname) + self.regs.append(reg) + + def next_offset(self, addrsep: int) -> int: + return self.offset + len(self.regs) * addrsep + + def get_n_bits(self, bittype: List[str] = ["q"]) -> int: + return sum(reg.get_n_bits(bittype) for reg in self.regs) + + def get_field_list(self) -> List[Field]: + ret = [] + for reg in self.regs: + ret += reg.get_field_list() + return ret + + def is_homogeneous(self) -> bool: + return self.reg.is_homogeneous() + + def _asdict(self) -> Dict[str, object]: + rd = self.reg._asdict() + rd['count'] = str(self.count) + rd['cname'] = self.cname + rd['regwen_multi'] = str(self.regwen_multi) + rd['compact'] = str(self.compact) + + return {'multireg': rd} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/params.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/params.py new file mode 100644 index 00000000..b7a6adcb --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/params.py @@ -0,0 +1,341 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import re +from collections.abc import MutableMapping +from typing import Dict, List, Optional, Tuple + +from .lib import check_keys, check_str, check_int, check_bool, check_list + +REQUIRED_FIELDS = { + 'name': ['s', "name of the item"], +} + +OPTIONAL_FIELDS = { + 'desc': ['s', "description of the item"], + 'type': ['s', "item type. int by default"], + 'default': ['s', "item default value"], + 'local': ['pb', "to be localparam"], + 'expose': ['pb', "to be exposed to top"], + 'randcount': [ + 's', "number of bits to randomize in the parameter. 0 by default." + ], + 'randtype': ['s', "type of randomization to perform. none by default"], +} + + +class BaseParam: + def __init__(self, name: str, desc: Optional[str], param_type: str): + self.name = name + self.desc = desc + self.param_type = param_type + + def apply_default(self, value: str) -> None: + if self.param_type[:3] == 'int': + check_int(value, + 'default value for parameter {} ' + '(which has type {})' + .format(self.name, self.param_type)) + self.default = value + + def as_dict(self) -> Dict[str, object]: + rd = {} # type: Dict[str, object] + rd['name'] = self.name + if self.desc is not None: + rd['desc'] = self.desc + rd['type'] = self.param_type + return rd + + +class LocalParam(BaseParam): + def __init__(self, + name: str, + desc: Optional[str], + param_type: str, + value: str): + super().__init__(name, desc, param_type) + self.value = value + + def expand_value(self, when: str) -> int: + try: + return int(self.value, 0) + except ValueError: + raise ValueError("When {}, the {} value expanded as " + "{}, which doesn't parse as an integer." + .format(when, self.name, self.value)) from None + + def as_dict(self) -> Dict[str, object]: + rd = super().as_dict() + rd['local'] = True + rd['default'] = self.value + return rd + + +class Parameter(BaseParam): + def __init__(self, + name: str, + desc: Optional[str], + param_type: str, + default: str, + expose: bool): + super().__init__(name, desc, param_type) + self.default = default + self.expose = expose + + def as_dict(self) -> Dict[str, object]: + rd = super().as_dict() + rd['default'] = self.default + rd['expose'] = 'true' if self.expose else 'false' + return rd + + +class RandParameter(BaseParam): + def __init__(self, + name: str, + desc: Optional[str], + param_type: str, + randcount: int, + randtype: str): + assert randcount > 0 + assert randtype in ['perm', 'data'] + super().__init__(name, desc, param_type) + self.randcount = randcount + self.randtype = randtype + + def apply_default(self, value: str) -> None: + raise ValueError('Cannot apply a default value of {!r} to ' + 'parameter {}: it is a random netlist constant.' + .format(self.name, value)) + + def as_dict(self) -> Dict[str, object]: + rd = super().as_dict() + rd['randcount'] = self.randcount + rd['randtype'] = self.randtype + return rd + + +def _parse_parameter(where: str, raw: object) -> BaseParam: + rd = check_keys(raw, where, + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + # TODO: Check if PascalCase or ALL_CAPS + name = check_str(rd['name'], 'name field of ' + where) + + r_desc = rd.get('desc') + if r_desc is None: + desc = None + else: + desc = check_str(r_desc, 'desc field of ' + where) + + # TODO: We should probably check that any register called RndCnstFoo has + # randtype and randcount. + if name.lower().startswith('rndcnst') and 'randtype' in rd: + # This is a random netlist constant and should be parsed as a + # RandParameter. + randtype = check_str(rd.get('randtype', 'none'), + 'randtype field of ' + where) + if randtype not in ['perm', 'data']: + raise ValueError('At {}, parameter {} has a name that implies it ' + 'is a random netlist constant, which means it ' + 'must specify a randtype of "perm" or "data", ' + 'rather than {!r}.' + .format(where, name, randtype)) + + r_randcount = rd.get('randcount') + if r_randcount is None: + raise ValueError('At {}, the random netlist constant {} has no ' + 'randcount field.' + .format(where, name)) + randcount = check_int(r_randcount, 'randcount field of ' + where) + if randcount <= 0: + raise ValueError('At {}, the random netlist constant {} has a ' + 'randcount of {}, which is not positive.' + .format(where, name, randcount)) + + r_type = rd.get('type') + if r_type is None: + raise ValueError('At {}, parameter {} has no type field (which is ' + 'required for random netlist constants).' + .format(where, name)) + param_type = check_str(r_type, 'type field of ' + where) + + local = check_bool(rd.get('local', 'false'), 'local field of ' + where) + if local: + raise ValueError('At {}, the parameter {} specifies local = true, ' + 'meaning that it is a localparam. This is ' + 'incompatible with being a random netlist ' + 'constant (how would it be set?)' + .format(where, name)) + + r_default = rd.get('default') + if r_default is not None: + raise ValueError('At {}, the parameter {} specifies a value for ' + 'the "default" field. This is incompatible with ' + 'being a random netlist constant: the value will ' + 'be set by the random generator.' + .format(where, name)) + + expose = check_bool(rd.get('expose', 'false'), + 'expose field of ' + where) + if expose: + raise ValueError('At {}, the parameter {} specifies expose = ' + 'true, meaning that the parameter is exposed to ' + 'the top-level. This is incompatible with being ' + 'a random netlist constant.' + .format(where, name)) + + return RandParameter(name, desc, param_type, randcount, randtype) + + # This doesn't have a name like a random netlist constant. Check that it + # doesn't define randcount or randtype. + for fld in ['randcount', 'randtype']: + if fld in rd: + raise ValueError("At {where}, the parameter {name} specifies " + "{fld} but the name doesn't look like a random " + "netlist constant. To use {fld}, prefix the name " + "with RndCnst." + .format(where=where, name=name, fld=fld)) + + r_type = rd.get('type') + if r_type is None: + param_type = 'int' + else: + param_type = check_str(r_type, 'type field of ' + where) + + local = check_bool(rd.get('local', 'true'), 'local field of ' + where) + expose = check_bool(rd.get('expose', 'false'), 'expose field of ' + where) + + r_default = rd.get('default') + if r_default is None: + raise ValueError('At {}, the {} param has no default field.' + .format(where, name)) + else: + default = check_str(r_default, 'default field of ' + where) + if param_type[:3] == 'int': + check_int(default, + 'default field of {}, (an integer parameter)' + .format(name)) + + if local: + if expose: + raise ValueError('At {}, the localparam {} cannot be exposed to ' + 'the top-level.' + .format(where, name)) + return LocalParam(name, desc, param_type, value=default) + else: + return Parameter(name, desc, param_type, default, expose) + + +class Params(MutableMapping): + def __init__(self) -> None: + self.by_name = {} # type: Dict[str, BaseParam] + + def __getitem__(self, key): + return self.by_name[key] + + def __delitem__(self, key): + del self.by_name[key] + + def __setitem__(self, key, value): + self.by_name[key] = value + + def __iter__(self): + return iter(self.by_name) + + def __len__(self): + return len(self.by_name) + + def __repr__(self): + return f"{type(self).__name__}({self.by_name})" + + def add(self, param: BaseParam) -> None: + assert param.name not in self.by_name + self.by_name[param.name] = param + + def apply_defaults(self, defaults: List[Tuple[str, str]]) -> None: + for idx, (key, value) in enumerate(defaults): + param = self.by_name[key] + if param is None: + raise KeyError('Cannot find parameter ' + '{} to set default value.' + .format(key)) + + param.apply_default(value) + + def _expand_one(self, value: str, when: str) -> int: + # Check whether value is already an integer: if so, return that. + try: + return int(value, 0) + except ValueError: + pass + + param = self.by_name.get(value) + if param is None: + raise ValueError('Cannot find a parameter called {} when {}. ' + 'Known parameters: {}.' + .format(value, + when, + ', '.join(self.by_name.keys()))) + + # Only allow localparams in the expansion (because otherwise we're at + # the mercy of whatever instantiates the block). + if not isinstance(param, LocalParam): + raise ValueError("When {}, {} is a not a local parameter." + .format(when, value)) + + return param.expand_value(when) + + def expand(self, value: str, where: str) -> int: + # Here, we want to support arithmetic expressions with + and -. We + # don't support other operators, or parentheses (so can parse with just + # a regex). + # + # Use re.split, capturing the operators. This turns e.g. "a + b-c" into + # ['a ', '+', ' b', '-', 'c']. If there's a leading operator ("+a"), + # the first element of the results is an empty string. This means + # elements with odd positions are always operators and elements with + # even positions are values. + acc = 0 + is_neg = False + + for idx, tok in enumerate(re.split(r'([+-])', value)): + if idx == 0 and not tok: + continue + if idx % 2: + is_neg = (tok == '-') + continue + + term = self._expand_one(tok.strip(), + 'expanding term {} of {}' + .format(idx // 2, where)) + acc += -term if is_neg else term + + return acc + + def as_dicts(self) -> List[Dict[str, object]]: + return [p.as_dict() for p in self.by_name.values()] + + +class ReggenParams(Params): + @staticmethod + def from_raw(where: str, raw: object) -> 'ReggenParams': + ret = ReggenParams() + rl = check_list(raw, where) + for idx, r_param in enumerate(rl): + entry_where = 'entry {} in {}'.format(idx + 1, where) + param = _parse_parameter(entry_where, r_param) + if param.name in ret: + raise ValueError('At {}, found a duplicate parameter with ' + 'name {}.' + .format(entry_where, param.name)) + ret.add(param) + return ret + + def get_localparams(self) -> List[LocalParam]: + ret = [] + for param in self.by_name.values(): + if isinstance(param, LocalParam): + ret.append(param) + return ret diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_base.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_base.py new file mode 100644 index 00000000..eb88b463 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_base.py @@ -0,0 +1,45 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import List + +from .field import Field + + +class RegBase: + '''An abstract class inherited by Register and MultiRegister + + This represents a block of one or more registers with a base address. + + ''' + def __init__(self, offset: int): + self.offset = offset + + def get_n_bits(self, bittype: List[str]) -> int: + '''Get the size of this register / these registers in bits + + See Field.get_n_bits() for the precise meaning of bittype. + + ''' + raise NotImplementedError() + + def get_field_list(self) -> List[Field]: + '''Get an ordered list of the fields in the register(s) + + Registers are ordered from low to high address. Within a register, + fields are ordered as Register.fields: from LSB to MSB. + + ''' + raise NotImplementedError() + + def is_homogeneous(self) -> bool: + '''True if every field in the block is identical + + For a single register, this is true if it only has one field. For a + multireg, it is true if the generating register has just one field. + Note that if the compact flag is set, the generated registers might + have multiple (replicated) fields. + + ''' + raise NotImplementedError() diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_block.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_block.py new file mode 100644 index 00000000..30a4f747 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_block.py @@ -0,0 +1,431 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Code representing the registers, windows etc. for a block''' + +import re +from typing import Callable, Dict, List, Optional, Sequence, Union + +from .alert import Alert +from .access import SWAccess, HWAccess +from .field import Field +from .signal import Signal +from .lib import check_int, check_list, check_str_dict, check_str +from .multi_register import MultiRegister +from .params import ReggenParams +from .register import Register +from .window import Window + + +class RegBlock: + def __init__(self, reg_width: int, params: ReggenParams): + + self._addrsep = (reg_width + 7) // 8 + self._reg_width = reg_width + self._params = params + + self.offset = 0 + self.multiregs = [] # type: List[MultiRegister] + self.registers = [] # type: List[Register] + self.windows = [] # type: List[Window] + + # Boolean indication whether ANY window in regblock has data integrity passthrough + self.has_data_intg_passthru = False + + # A list of all registers, expanding multiregs, ordered by offset + self.flat_regs = [] # type: List[Register] + + # A list of registers and multiregisters (unexpanded) + self.all_regs = [] # type: List[Union[Register, MultiRegister]] + + # A list with everything in order + self.entries = [] # type: List[object] + + # A dict of named entries, mapping name to offset + self.name_to_offset = {} # type: Dict[str, int] + + # A dict of all registers (expanding multiregs), mapping name to the + # register object + self.name_to_flat_reg = {} # type: Dict[str, Register] + + # A list of all write enable names + self.wennames = [] # type: List[str] + + @staticmethod + def build_blocks(block: 'RegBlock', + raw: object) -> Dict[Optional[str], 'RegBlock']: + '''Build a dictionary of blocks for a 'registers' field in the hjson + + There are two different syntaxes we might see here. The simple syntax + just consists of a list of entries (register, multireg, window, + skipto). If we see that, each entry gets added to init_block and then + we return {None: init_block}. + + The more complicated syntax is a dictionary. This parses from hjson as + an OrderedDict which we walk in document order. Entries from the first + key/value pair in the dictionary will be added to init_block. Later + key/value pairs start empty RegBlocks. The return value is a dictionary + mapping the keys we saw to their respective RegBlocks. + + ''' + if isinstance(raw, list): + # This is the simple syntax + block.add_raw_registers(raw, 'registers field at top-level') + return {None: block} + + # This is the more complicated syntax + if not isinstance(raw, dict): + raise ValueError('registers field at top-level is ' + 'neither a list or a dictionary.') + + ret = {} # type: Dict[Optional[str], RegBlock] + for idx, (r_key, r_val) in enumerate(raw.items()): + if idx > 0: + block = RegBlock(block._reg_width, block._params) + + rb_key = check_str(r_key, + 'the key for item {} of ' + 'the registers dictionary at top-level' + .format(idx + 1)) + rb_val = check_list(r_val, + 'the value for item {} of ' + 'the registers dictionary at top-level' + .format(idx + 1)) + + block.add_raw_registers(rb_val, + 'item {} of the registers ' + 'dictionary at top-level' + .format(idx + 1)) + block.validate() + + assert rb_key not in ret + ret[rb_key] = block + + return ret + + def add_raw_registers(self, raw: object, what: str) -> None: + rl = check_list(raw, 'registers field at top-level') + for entry_idx, entry_raw in enumerate(rl): + where = ('entry {} of the top-level registers field' + .format(entry_idx + 1)) + self.add_raw(where, entry_raw) + + def add_raw(self, where: str, raw: object) -> None: + entry = check_str_dict(raw, where) + + handlers = { + 'register': self._handle_register, + 'reserved': self._handle_reserved, + 'skipto': self._handle_skipto, + 'window': self._handle_window, + 'multireg': self._handle_multireg + } + + entry_type = 'register' + entry_body = entry # type: object + + for t in ['reserved', 'skipto', 'window', 'multireg']: + t_body = entry.get(t) + if t_body is not None: + # Special entries look like { window: { ... } }, so if we + # get a hit, this should be the only key in entry. Note + # that this also checks that nothing has more than one + # entry type. + if len(entry) != 1: + other_keys = [k for k in entry if k != t] + assert other_keys + raise ValueError('At offset {:#x}, {} has key {}, which ' + 'should give its type. But it also has ' + 'other keys too: {}.' + .format(self.offset, + where, t, ', '.join(other_keys))) + entry_type = t + entry_body = t_body + + entry_where = ('At offset {:#x}, {}, type {!r}' + .format(self.offset, where, entry_type)) + + handlers[entry_type](entry_where, entry_body) + + def _handle_register(self, where: str, body: object) -> None: + reg = Register.from_raw(self._reg_width, + self.offset, self._params, body) + self.add_register(reg) + + def _handle_reserved(self, where: str, body: object) -> None: + nreserved = check_int(body, 'body of ' + where) + if nreserved <= 0: + raise ValueError('Reserved count in {} is {}, ' + 'which is not positive.' + .format(where, nreserved)) + + self.offset += self._addrsep * nreserved + + def _handle_skipto(self, where: str, body: object) -> None: + skipto = check_int(body, 'body of ' + where) + if skipto < self.offset: + raise ValueError('Destination of skipto in {} is {:#x}, ' + 'is less than the current offset, {:#x}.' + .format(where, skipto, self.offset)) + if skipto % self._addrsep: + raise ValueError('Destination of skipto in {} is {:#x}, ' + 'not a multiple of addrsep, {:#x}.' + .format(where, skipto, self._addrsep)) + self.offset = skipto + + def _handle_window(self, where: str, body: object) -> None: + window = Window.from_raw(self.offset, + self._reg_width, self._params, body) + if window.name is not None: + lname = window.name.lower() + if lname in self.name_to_offset: + raise ValueError('Window {} (at offset {:#x}) has the ' + 'same name as something at offset {:#x}.' + .format(window.name, window.offset, + self.name_to_offset[lname])) + self.add_window(window) + + def _handle_multireg(self, where: str, body: object) -> None: + mr = MultiRegister(self.offset, + self._addrsep, self._reg_width, self._params, body) + for reg in mr.regs: + lname = reg.name.lower() + if lname in self.name_to_offset: + raise ValueError('Multiregister {} (at offset {:#x}) expands ' + 'to a register with name {} (at offset ' + '{:#x}), but this already names something at ' + 'offset {:#x}.' + .format(mr.reg.name, mr.reg.offset, + reg.name, reg.offset, + self.name_to_offset[lname])) + self._add_flat_reg(reg) + self.name_to_offset[lname] = reg.offset + + self.multiregs.append(mr) + self.all_regs.append(mr) + self.entries.append(mr) + self.offset = mr.next_offset(self._addrsep) + + def add_register(self, reg: Register) -> None: + assert reg.offset == self.offset + + lname = reg.name.lower() + if lname in self.name_to_offset: + raise ValueError('Register {} (at offset {:#x}) has the same ' + 'name as something at offset {:#x}.' + .format(reg.name, reg.offset, + self.name_to_offset[lname])) + self._add_flat_reg(reg) + self.name_to_offset[lname] = reg.offset + + self.registers.append(reg) + self.all_regs.append(reg) + self.entries.append(reg) + self.offset = reg.next_offset(self._addrsep) + + if reg.regwen is not None and reg.regwen not in self.wennames: + self.wennames.append(reg.regwen) + + def _add_flat_reg(self, reg: Register) -> None: + # The first assertion is checked at the call site (where we can print + # out a nicer message for multiregs). The second assertion should be + # implied by the first. + assert reg.name not in self.name_to_offset + assert reg.name not in self.name_to_flat_reg + + self.flat_regs.append(reg) + self.name_to_flat_reg[reg.name.lower()] = reg + + def add_window(self, window: Window) -> None: + if window.name is not None: + lname = window.name.lower() + assert lname not in self.name_to_offset + self.name_to_offset[lname] = window.offset + + self.windows.append(window) + self.entries.append(window) + assert self.offset <= window.offset + self.offset = window.next_offset(self._addrsep) + + self.has_data_intg_passthru |= window.data_intg_passthru + + def validate(self) -> None: + '''Run this to check consistency after all registers have been added''' + + # Check that every write-enable register has a good name, a valid reset + # value, and valid access permissions. + for wenname in self.wennames: + # check the REGWEN naming convention + if re.fullmatch(r'(.+_)*REGWEN(_[0-9]+)?', wenname) is None: + raise ValueError("Regwen name {} must have the suffix '_REGWEN'" + .format(wenname)) + + wen_reg = self.name_to_flat_reg.get(wenname.lower()) + if wen_reg is None: + raise ValueError('One or more registers use {} as a ' + 'write-enable, but there is no such register.' + .format(wenname)) + + # If the REGWEN bit is SW controlled, check that the register + # defaults to enabled. If this bit is read-only by SW and hence + # hardware controlled, we do not enforce this requirement. + if wen_reg.swaccess.key != "ro" and not wen_reg.resval: + raise ValueError('One or more registers use {} as a ' + 'write-enable. Since it is SW-controlled ' + 'it should have a nonzero reset value.' + .format(wenname)) + + if wen_reg.swaccess.key == "rw0c": + # The register is software managed: all good! + continue + + if wen_reg.swaccess.key == "ro" and wen_reg.hwaccess.key == "hwo": + # The register is hardware managed: that's fine too. + continue + + raise ValueError('One or more registers use {} as a write-enable. ' + 'However, it has invalid access permissions ' + '({} / {}). It should either have swaccess=RW0C ' + 'or have swaccess=RO and hwaccess=HWO.' + .format(wenname, + wen_reg.swaccess.key, + wen_reg.hwaccess.key)) + + def get_n_bits(self, bittype: List[str] = ["q"]) -> int: + '''Returns number of bits in registers in this block. + + This includes those expanded from multiregs. See Field.get_n_bits for a + description of the bittype argument. + + ''' + return sum(reg.get_n_bits(bittype) for reg in self.flat_regs) + + def as_dicts(self) -> List[object]: + entries = [] # type: List[object] + offset = 0 + for entry in self.entries: + assert (isinstance(entry, Register) or + isinstance(entry, MultiRegister) or + isinstance(entry, Window)) + + next_off = entry.offset + assert offset <= next_off + res_bytes = next_off - offset + if res_bytes: + assert res_bytes % self._addrsep == 0 + entries.append({'reserved': res_bytes // self._addrsep}) + + entries.append(entry) + offset = entry.next_offset(self._addrsep) + + return entries + + _FieldFormatter = Callable[[bool, str], str] + + def _add_intr_alert_reg(self, + signals: Sequence[Signal], + reg_name: str, + reg_desc: str, + field_desc_fmt: Optional[Union[str, _FieldFormatter]], + swaccess: str, + hwaccess: str, + is_testreg: bool, + reg_tags: List[str]) -> None: + swaccess_obj = SWAccess('RegBlock._make_intr_alert_reg()', swaccess) + hwaccess_obj = HWAccess('RegBlock._make_intr_alert_reg()', hwaccess) + + fields = [] + for signal in signals: + if field_desc_fmt is None: + field_desc = signal.desc + elif isinstance(field_desc_fmt, str): + field_desc = field_desc_fmt + else: + width = signal.bits.width() + field_desc = field_desc_fmt(width > 1, signal.name) + + fields.append(Field(signal.name, + field_desc or signal.desc, + tags=[], + swaccess=swaccess_obj, + hwaccess=hwaccess_obj, + hwqe=is_testreg, + hwre=False, + bits=signal.bits, + resval=0, + enum=None)) + + reg = Register(self.offset, + reg_name, + reg_desc, + swaccess_obj, + hwaccess_obj, + hwext=is_testreg, + hwqe=is_testreg, + hwre=False, + regwen=None, + tags=reg_tags, + resval=None, + shadowed=False, + fields=fields, + update_err_alert=None, + storage_err_alert=None) + self.add_register(reg) + + def make_intr_regs(self, interrupts: Sequence[Signal]) -> None: + assert interrupts + assert interrupts[-1].bits.msb < self._reg_width + + self._add_intr_alert_reg(interrupts, + 'INTR_STATE', + 'Interrupt State Register', + None, + 'rw1c', + 'hrw', + False, + # intr_state csr is affected by writes to + # other csrs - skip write-check + ["excl:CsrNonInitTests:CsrExclWriteCheck"]) + self._add_intr_alert_reg(interrupts, + 'INTR_ENABLE', + 'Interrupt Enable Register', + lambda w, n: ('Enable interrupt when ' + '{}!!INTR_STATE.{} is set.' + .format('corresponding bit in ' + if w else '', + n)), + 'rw', + 'hro', + False, + []) + self._add_intr_alert_reg(interrupts, + 'INTR_TEST', + 'Interrupt Test Register', + lambda w, n: ('Write 1 to force ' + '{}!!INTR_STATE.{} to 1.' + .format('corresponding bit in ' + if w else '', + n)), + 'wo', + 'hro', + True, + # intr_test csr is WO so reads back 0s + ["excl:CsrNonInitTests:CsrExclWrite"]) + + def make_alert_regs(self, alerts: List[Alert]) -> None: + assert alerts + assert len(alerts) < self._reg_width + self._add_intr_alert_reg(alerts, + 'ALERT_TEST', + 'Alert Test Register', + ('Write 1 to trigger ' + 'one alert event of this kind.'), + 'wo', + 'hro', + True, + []) + + def get_addr_width(self) -> int: + '''Calculate the number of bits to address every byte of the block''' + return (self.offset - 1).bit_length() diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_html.css b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_html.css new file mode 100644 index 00000000..4cb48edb --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_html.css @@ -0,0 +1,74 @@ +/* Stylesheet for reggen HTML register output */ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +table.regpic { + width: 95%; + border-collapse: collapse; + margin-left:auto; + margin-right:auto; + table-layout:fixed; +} + +table.regdef { + border: 1px solid black; + width: 80%; + border-collapse: collapse; + margin-left:auto; + margin-right:auto; + table-layout:auto; +} + +table.regdef th { + border: 1px solid black; + font-family: sans-serif; + +} + +td.bitnum { + font-size: 60%; + text-align: center; +} + +td.unused { + border: 1px solid black; + background-color: gray; +} + +td.fname { + border: 1px solid black; + text-align: center; + font-family: sans-serif; +} + + +td.regbits, td.regperm, td.regrv { + border: 1px solid black; + text-align: center; + font-family: sans-serif; +} + +td.regde, td.regfn { + border: 1px solid black; +} + +table.cfgtable { + border: 1px solid black; + width: 80%; + border-collapse: collapse; + margin-left:auto; + margin-right:auto; + table-layout:auto; +} + +table.cfgtable th { + border: 1px solid black; + font-family: sans-serif; + font-weight: bold; +} + +table.cfgtable td { + border: 1px solid black; + font-family: sans-serif; +} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_pkg.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_pkg.sv.tpl new file mode 100644 index 00000000..1c5520a5 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_pkg.sv.tpl @@ -0,0 +1,347 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure +<% + from topgen import lib # TODO: Split lib to common lib module + + from reggen.access import HwAccess, SwRdAccess, SwWrAccess + from reggen.register import Register + from reggen.multi_register import MultiRegister + + from reggen import gen_rtl + + localparams = block.params.get_localparams() + + addr_widths = gen_rtl.get_addr_widths(block) + + lblock = block.name.lower() + ublock = lblock.upper() + + def reg_pfx(reg): + return '{}_{}'.format(ublock, reg.name.upper()) + + def reg_resname(reg): + return '{}_RESVAL'.format(reg_pfx(reg)) + + def field_resname(reg, field): + return '{}_{}_RESVAL'.format(reg_pfx(reg), field.name.upper()) + +%>\ +<%def name="typedefs_for_iface(iface_name, iface_desc, for_iface, rb)">\ +<% + hdr = gen_rtl.make_box_quote('Typedefs for registers' + for_iface) +%>\ +% for r in rb.all_regs: + % if r.get_n_bits(["q"]): + % if hdr: + +${hdr} + % endif +<% + r0 = gen_rtl.get_r0(r) + hdr = None +%>\ + + typedef struct packed { + % if r.is_homogeneous(): + ## If we have a homogeneous register or multireg, there is just one field + ## (possibly replicated many times). The typedef is for one copy of that + ## field. +<% + field = r.get_field_list()[0] + field_q_width = field.get_n_bits(r0.hwext, ['q']) + field_q_bits = lib.bitarray(field_q_width, 2) +%>\ + logic ${field_q_bits} q; + % if field.hwqe: + logic qe; + % endif + % if field.hwre or (r0.shadowed and r0.hwext): + logic re; + % endif + % if r0.shadowed and not r0.hwext: + logic err_update; + logic err_storage; + % endif + % else: + ## We are inhomogeneous, which means there is more than one different + ## field. Generate a reg2hw typedef that packs together all the fields of + ## the register. + % for f in r0.fields: + % if f.get_n_bits(r0.hwext, ["q"]) >= 1: +<% + field_q_width = f.get_n_bits(r0.hwext, ['q']) + field_q_bits = lib.bitarray(field_q_width, 2) + + struct_name = f.name.lower() +%>\ + struct packed { + logic ${field_q_bits} q; + % if f.hwqe: + logic qe; + % endif + % if f.hwre or (r0.shadowed and r0.hwext): + logic re; + % endif + % if r0.shadowed and not r0.hwext: + logic err_update; + logic err_storage; + % endif + } ${struct_name}; + %endif + %endfor + %endif + } ${gen_rtl.get_reg_tx_type(block, r, False)}; + %endif +% endfor +% for r in rb.all_regs: + % if r.get_n_bits(["d"]): + % if hdr: + +${hdr} + % endif +<% + r0 = gen_rtl.get_r0(r) + hdr = None +%>\ + + typedef struct packed { + % if r.is_homogeneous(): + ## If we have a homogeneous register or multireg, there is just one field + ## (possibly replicated many times). The typedef is for one copy of that + ## field. +<% + field = r.get_field_list()[0] + field_d_width = field.get_n_bits(r0.hwext, ['d']) + field_d_bits = lib.bitarray(field_d_width, 2) +%>\ + logic ${field_d_bits} d; + % if not r0.hwext: + logic de; + % endif + % else: + ## We are inhomogeneous, which means there is more than one different + ## field. Generate a hw2reg typedef that packs together all the fields of + ## the register. + % for f in r0.fields: + % if f.get_n_bits(r0.hwext, ["d"]) >= 1: +<% + field_d_width = f.get_n_bits(r0.hwext, ['d']) + field_d_bits = lib.bitarray(field_d_width, 2) + + struct_name = f.name.lower() +%>\ + struct packed { + logic ${field_d_bits} d; + % if not r0.hwext: + logic de; + % endif + } ${struct_name}; + %endif + %endfor + %endif + } ${gen_rtl.get_reg_tx_type(block, r, True)}; + % endif +% endfor +\ +<%def name="reg2hw_for_iface(iface_name, iface_desc, for_iface, rb)">\ +<% +nbits = rb.get_n_bits(["q", "qe", "re"]) +packbit = 0 +%>\ +% if nbits > 0: + + // Register -> HW type${for_iface} + typedef struct packed { +% for r in rb.all_regs: + % if r.get_n_bits(["q"]): +<% + r0 = gen_rtl.get_r0(r) + struct_type = gen_rtl.get_reg_tx_type(block, r, False) + struct_width = r0.get_n_bits(['q', 'qe', 're']) + + if isinstance(r, MultiRegister): + struct_type += " [{}:0]".format(r.count - 1) + struct_width *= r.count + + msb = nbits - packbit - 1 + lsb = msb - struct_width + 1 + packbit += struct_width +%>\ + ${struct_type} ${r0.name.lower()}; // [${msb}:${lsb}] + % endif +% endfor + } ${gen_rtl.get_iface_tx_type(block, iface_name, False)}; +% endif +\ +<%def name="hw2reg_for_iface(iface_name, iface_desc, for_iface, rb)">\ +<% +nbits = rb.get_n_bits(["d", "de"]) +packbit = 0 +%>\ +% if nbits > 0: + + // HW -> register type${for_iface} + typedef struct packed { +% for r in rb.all_regs: + % if r.get_n_bits(["d"]): +<% + r0 = gen_rtl.get_r0(r) + struct_type = gen_rtl.get_reg_tx_type(block, r, True) + struct_width = r0.get_n_bits(['d', 'de']) + + if isinstance(r, MultiRegister): + struct_type += " [{}:0]".format(r.count - 1) + struct_width *= r.count + + msb = nbits - packbit - 1 + lsb = msb - struct_width + 1 + packbit += struct_width +%>\ + ${struct_type} ${r0.name.lower()}; // [${msb}:${lsb}] + % endif +% endfor + } ${gen_rtl.get_iface_tx_type(block, iface_name, True)}; +% endif +\ +<%def name="offsets_for_iface(iface_name, iface_desc, for_iface, rb)">\ +% if not rb.flat_regs: +<% return STOP_RENDERING %> +% endif + + // Register offsets${for_iface} +<% +aw_name, aw = addr_widths[iface_name] +%>\ +% for r in rb.flat_regs: +<% +value = "{}'h {:x}".format(aw, r.offset) +%>\ + parameter logic [${aw_name}-1:0] ${reg_pfx(r)}_OFFSET = ${value}; +% endfor +\ +<%def name="hwext_resvals_for_iface(iface_name, iface_desc, for_iface, rb)">\ +<% + hwext_regs = [r for r in rb.flat_regs if r.hwext] +%>\ +% if hwext_regs: + + // Reset values for hwext registers and their fields${for_iface} + % for reg in hwext_regs: +<% + reg_width = reg.get_width() + reg_msb = reg_width - 1 + reg_resval = "{}'h {:x}".format(reg_width, reg.resval) +%>\ + parameter logic [${reg_msb}:0] ${reg_resname(reg)} = ${reg_resval}; + % for field in reg.fields: + % if field.resval is not None: +<% + field_width = field.bits.width() + field_msb = field_width - 1 + field_resval = "{}'h {:x}".format(field_width, field.resval) +%>\ + parameter logic [${field_msb}:0] ${field_resname(reg, field)} = ${field_resval}; + % endif + % endfor + % endfor +% endif +\ +<%def name="windows_for_iface(iface_name, iface_desc, for_iface, rb)">\ +% if rb.windows: +<% + aw_name, aw = addr_widths[iface_name] +%>\ + + // Window parameters${for_iface} +% for i,w in enumerate(rb.windows): +<% + win_pfx = '{}_{}'.format(ublock, w.name.upper()) + base_txt_val = "{}'h {:x}".format(aw, w.offset) + size_txt_val = "'h {:x}".format(w.size_in_bytes) + + offset_type = 'logic [{}-1:0]'.format(aw_name) + size_type = 'int unsigned' + max_type_len = max(len(offset_type), len(size_type)) + + offset_type += ' ' * (max_type_len - len(offset_type)) + size_type += ' ' * (max_type_len - len(size_type)) + +%>\ + parameter ${offset_type} ${win_pfx}_OFFSET = ${base_txt_val}; + parameter ${size_type} ${win_pfx}_SIZE = ${size_txt_val}; +% endfor +% endif +\ +<%def name="reg_data_for_iface(iface_name, iface_desc, for_iface, rb)">\ +% if rb.flat_regs: +<% + lpfx = gen_rtl.get_type_name_pfx(block, iface_name) + upfx = lpfx.upper() + idx_len = len("{}".format(len(rb.flat_regs) - 1)) +%>\ + + // Register index${for_iface} + typedef enum int { +% for r in rb.flat_regs: + ${ublock}_${r.name.upper()}${"" if loop.last else ","} +% endfor + } ${lpfx}_id_e; + + // Register width information to check illegal writes${for_iface} + parameter logic [3:0] ${upfx}_PERMIT [${len(rb.flat_regs)}] = '{ + % for i, r in enumerate(rb.flat_regs): +<% + index_str = "{}".format(i).rjust(idx_len) + width = r.get_width() + if width > 24: + mask = '1111' + elif width > 16: + mask = '0111' + elif width > 8: + mask = '0011' + else: + mask = '0001' + + comma = ',' if i < len(rb.flat_regs) - 1 else ' ' +%>\ + 4'b ${mask}${comma} // index[${index_str}] ${ublock}_${r.name.upper()} + % endfor + }; +% endif +\ + +package ${lblock}_reg_pkg; +% if localparams: + + // Param list +% for param in localparams: + parameter ${param.param_type} ${param.name} = ${param.value}; +% endfor +% endif + + // Address widths within the block +% for param_name, width in addr_widths.values(): + parameter int ${param_name} = ${width}; +% endfor +<% + just_default = len(block.reg_blocks) == 1 and None in block.reg_blocks +%>\ +% for iface_name, rb in block.reg_blocks.items(): +<% + iface_desc = iface_name or 'default' + for_iface = '' if just_default else ' for {} interface'.format(iface_desc) +%>\ +${typedefs_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${reg2hw_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${hw2reg_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${offsets_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${hwext_resvals_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${windows_for_iface(iface_name, iface_desc, for_iface, rb)}\ +${reg_data_for_iface(iface_name, iface_desc, for_iface, rb)}\ +% endfor + +endpackage + diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_top.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_top.sv.tpl new file mode 100644 index 00000000..4cd9036a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/reg_top.sv.tpl @@ -0,0 +1,712 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` +<% + from reggen import gen_rtl + from reggen.access import HwAccess, SwRdAccess, SwWrAccess + from reggen.lib import get_basename + from reggen.register import Register + from reggen.multi_register import MultiRegister + from reggen.ip_block import IpBlock + from reggen.bus_interfaces import BusProtocol + + num_wins = len(rb.windows) + num_wins_width = ((num_wins+1).bit_length()) - 1 + num_reg_dsp = 1 if rb.all_regs else 0 + num_dsp = num_wins + num_reg_dsp + regs_flat = rb.flat_regs + max_regs_char = len("{}".format(len(regs_flat) - 1)) + addr_width = rb.get_addr_width() + + lblock = block.name.lower() + ublock = lblock.upper() + + u_mod_base = mod_base.upper() + + reg2hw_t = gen_rtl.get_iface_tx_type(block, if_name, False) + hw2reg_t = gen_rtl.get_iface_tx_type(block, if_name, True) + + # Calculate whether we're going to need an AW parameter. We use it if there + # are any registers (obviously). We also use it if there are any windows that + # don't start at zero and end at 1 << addr_width (see the "addr_checks" + # calculation below for where that comes from). + needs_aw = (bool(regs_flat) or + num_wins > 1 or + rb.windows and ( + rb.windows[0].offset != 0 or + rb.windows[0].size_in_bytes != (1 << addr_width))) + + # Check if the interface protocol is reg_interface + use_reg_iface = any([interface['protocol'] == BusProtocol.REG_IFACE and not interface['is_host'] for interface in block.bus_interfaces.interface_list]) + reg_intf_req = "reg_req_t" + reg_intf_rsp = "reg_rsp_t" + + common_data_intg_gen = 0 if rb.has_data_intg_passthru else 1 + adapt_data_intg_gen = 1 if rb.has_data_intg_passthru else 0 + assert common_data_intg_gen != adapt_data_intg_gen +%> + +% if use_reg_iface: +`include "common_cells/assertions.svh" +% else: +`include "prim_assert.sv" +% endif + +module ${mod_name} \ +% if use_reg_iface: +#( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = ${addr_width} +) \ +% else: + % if needs_aw: +#( + parameter int AW = ${addr_width} +) \ + % endif +% endif +( + input clk_i, + input rst_ni, +% if use_reg_iface: + input ${reg_intf_req} reg_req_i, + output ${reg_intf_rsp} reg_rsp_o, +% else: + input tlul_pkg::tl_h2d_t tl_i, + output tlul_pkg::tl_d2h_t tl_o, +% endif +% if num_wins != 0: + + // Output port for window +% if use_reg_iface: + output ${reg_intf_req} [${num_wins}-1:0] reg_req_win_o, + input ${reg_intf_rsp} [${num_wins}-1:0] reg_rsp_win_i, +% else: + output tlul_pkg::tl_h2d_t tl_win_o [${num_wins}], + input tlul_pkg::tl_d2h_t tl_win_i [${num_wins}], +% endif + +% endif + // To HW +% if rb.get_n_bits(["q","qe","re"]): + output ${lblock}_reg_pkg::${reg2hw_t} reg2hw, // Write +% endif +% if rb.get_n_bits(["d","de"]): + input ${lblock}_reg_pkg::${hw2reg_t} hw2reg, // Read +% endif + +% if not use_reg_iface: + // Integrity check errors + output logic intg_err_o, +% endif + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import ${lblock}_reg_pkg::* ; + +% if rb.all_regs: + localparam int DW = ${block.regwidth}; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [AW-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + +% if use_reg_iface: + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; +% else: + tlul_pkg::tl_h2d_t tl_reg_h2d; + tlul_pkg::tl_d2h_t tl_reg_d2h; +% endif +% endif + +% if not use_reg_iface: + // incoming payload check + logic intg_err; + tlul_cmd_intg_chk u_chk ( + .tl_i, + .err_o(intg_err) + ); + + logic intg_err_q; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + intg_err_q <= '0; + end else if (intg_err) begin + intg_err_q <= 1'b1; + end + end + + // integrity error output is permanent and should be used for alert generation + // register errors are transactional + assign intg_err_o = intg_err_q | intg_err; + + // outgoing integrity generation + tlul_pkg::tl_d2h_t tl_o_pre; + tlul_rsp_intg_gen #( + .EnableRspIntgGen(1), + .EnableDataIntgGen(${common_data_intg_gen}) + ) u_rsp_intg_gen ( + .tl_i(tl_o_pre), + .tl_o + ); +% endif + +% if num_dsp == 1: + ## Either no windows (and just registers) or no registers and only + ## one window. + % if num_wins == 0: + % if use_reg_iface: + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + % else: + assign tl_reg_h2d = tl_i; + assign tl_o_pre = tl_reg_d2h; + % endif + % else: + % if use_reg_iface: + assign reg_req_win_o = reg_req_i; + assign reg_rsp_o = reg_rsp_win_i + % else: + assign tl_win_o[0] = tl_i; + assign tl_o_pre = tl_win_i[0]; + % endif + % endif +% else: + logic [${num_wins_width-1}:0] reg_steer; + + % if use_reg_iface: + ${reg_intf_req} [${num_dsp}-1:0] reg_intf_demux_req; + ${reg_intf_rsp} [${num_dsp}-1:0] reg_intf_demux_rsp; + + // demux connection + assign reg_intf_req = reg_intf_demux_req[${num_wins}]; + assign reg_intf_demux_rsp[${num_wins}] = reg_intf_rsp; + + % for i,t in enumerate(block.wins): + assign reg_req_win_o[${i}] = reg_intf_demux_req[${i}]; + assign reg_intf_demux_rsp[${i}] = reg_rsp_win_i[${i}]; + % endfor + + // Create Socket_1n + reg_demux #( + .NoPorts (${num_dsp}), + .req_t (${reg_intf_req}), + .rsp_t (${reg_intf_rsp}) + ) i_reg_demux ( + .clk_i, + .rst_ni, + .in_req_i (reg_req_i), + .in_rsp_o (reg_rsp_o), + .out_req_o (reg_intf_demux_req), + .out_rsp_i (reg_intf_demux_rsp), + .in_select_i (reg_steer) + ); + + % else: + tlul_pkg::tl_h2d_t tl_socket_h2d [${num_dsp}]; + tlul_pkg::tl_d2h_t tl_socket_d2h [${num_dsp}]; + + // socket_1n connection + % if rb.all_regs: + assign tl_reg_h2d = tl_socket_h2d[${num_wins}]; + assign tl_socket_d2h[${num_wins}] = tl_reg_d2h; + + % endif + % for i,t in enumerate(rb.windows): + assign tl_win_o[${i}] = tl_socket_h2d[${i}]; + % if common_data_intg_gen == 0 and rb.windows[i].data_intg_passthru == False: + ## If there are multiple windows, and not every window has data integrity + ## passthrough, we must generate data integrity for it here. + tlul_rsp_intg_gen #( + .EnableRspIntgGen(0), + .EnableDataIntgGen(1) + ) u_win${i}_data_intg_gen ( + .tl_i(tl_win_i[${i}]), + .tl_o(tl_socket_d2h[${i}]) + ); + % else: + assign tl_socket_d2h[${i}] = tl_win_i[${i}]; + % endif + % endfor + + // Create Socket_1n + tlul_socket_1n #( + .N (${num_dsp}), + .HReqPass (1'b1), + .HRspPass (1'b1), + .DReqPass ({${num_dsp}{1'b1}}), + .DRspPass ({${num_dsp}{1'b1}}), + .HReqDepth (4'h0), + .HRspDepth (4'h0), + .DReqDepth ({${num_dsp}{4'h0}}), + .DRspDepth ({${num_dsp}{4'h0}}) + ) u_socket ( + .clk_i, + .rst_ni, + .tl_h_i (tl_i), + .tl_h_o (tl_o_pre), + .tl_d_o (tl_socket_h2d), + .tl_d_i (tl_socket_d2h), + .dev_select_i (reg_steer) + ); + % endif + + // Create steering logic + always_comb begin + reg_steer = ${num_dsp-1}; // Default set to register + + // TODO: Can below codes be unique case () inside ? + % for i,w in enumerate(rb.windows): +<% + base_addr = w.offset + limit_addr = w.offset + w.size_in_bytes + if use_reg_iface: + hi_check = 'reg_req_i.addr[AW-1:0] < {}'.format(limit_addr) + else: + hi_check = 'tl_i.a_address[AW-1:0] < {}'.format(limit_addr) + addr_checks = [] + if base_addr > 0: + if use_reg_iface: + addr_checks.append('reg_req_i.addr[AW-1:0] >= {}'.format(base_addr)) + else: + addr_checks.append('tl_i.a_address[AW-1:0] >= {}'.format(base_addr)) + if limit_addr < 2**addr_width: + if use_reg_iface: + addr_checks.append('reg_req_i.addr[AW-1:0] < {}'.format(limit_addr)) + else: + addr_checks.append('tl_i.a_address[AW-1:0] < {}'.format(limit_addr)) + + addr_test = ' && '.join(addr_checks) +%>\ + % if addr_test: + if (${addr_test}) begin + % endif + reg_steer = ${i}; + % if addr_test: + end + % endif + % endfor + % if not use_reg_iface: + if (intg_err) begin + reg_steer = ${num_dsp-1}; + end + % endif + end +% endif +% if rb.all_regs: + + +% if use_reg_iface: + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; +% else: + tlul_adapter_reg #( + .RegAw(AW), + .RegDw(DW), + .EnableDataIntgGen(${adapt_data_intg_gen}) + ) u_reg_if ( + .clk_i, + .rst_ni, + + .tl_i (tl_reg_h2d), + .tl_o (tl_reg_d2h), + + .we_o (reg_we), + .re_o (reg_re), + .addr_o (reg_addr), + .wdata_o (reg_wdata), + .be_o (reg_be), + .rdata_i (reg_rdata), + .error_i (reg_error) + ); +% endif + + assign reg_rdata = reg_rdata_next ; +% if use_reg_iface: + assign reg_error = (devmode_i & addrmiss) | wr_err; +% else: + assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err; +% endif + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + % for r in regs_flat: + % if len(r.fields) == 1: +${sig_gen(r.fields[0], r.name.lower(), r.hwext, r.shadowed)}\ + % else: + % for f in r.fields: +${sig_gen(f, r.name.lower() + "_" + f.name.lower(), r.hwext, r.shadowed)}\ + % endfor + % endif + % endfor + + // Register instances + % for r in rb.all_regs: + ######################## multiregister ########################### + % if isinstance(r, MultiRegister): +<% + k = 0 +%> + % for sr in r.regs: + // Subregister ${k} of Multireg ${r.reg.name.lower()} + // R[${sr.name.lower()}]: V(${str(sr.hwext)}) + % if len(sr.fields) == 1: +<% + f = sr.fields[0] + finst_name = sr.name.lower() + fsig_name = r.reg.name.lower() + "[%d]" % k + k = k + 1 +%> +${finst_gen(f, finst_name, fsig_name, sr.hwext, sr.regwen, sr.shadowed)} + % else: + % for f in sr.fields: +<% + finst_name = sr.name.lower() + "_" + f.name.lower() + if r.is_homogeneous(): + fsig_name = r.reg.name.lower() + "[%d]" % k + k = k + 1 + else: + fsig_name = r.reg.name.lower() + "[%d]" % k + "." + get_basename(f.name.lower()) +%> + // F[${f.name.lower()}]: ${f.bits.msb}:${f.bits.lsb} +${finst_gen(f, finst_name, fsig_name, sr.hwext, sr.regwen, sr.shadowed)} + % endfor +<% + if not r.is_homogeneous(): + k += 1 +%> + % endif + ## for: mreg_flat + % endfor +######################## register with single field ########################### + % elif len(r.fields) == 1: + // R[${r.name.lower()}]: V(${str(r.hwext)}) +<% + f = r.fields[0] + finst_name = r.name.lower() + fsig_name = r.name.lower() +%> +${finst_gen(f, finst_name, fsig_name, r.hwext, r.regwen, r.shadowed)} +######################## register with multiple fields ########################### + % else: + // R[${r.name.lower()}]: V(${str(r.hwext)}) + % for f in r.fields: +<% + finst_name = r.name.lower() + "_" + f.name.lower() + fsig_name = r.name.lower() + "." + f.name.lower() +%> + // F[${f.name.lower()}]: ${f.bits.msb}:${f.bits.lsb} +${finst_gen(f, finst_name, fsig_name, r.hwext, r.regwen, r.shadowed)} + % endfor + % endif + + ## for: rb.all_regs + % endfor + + + logic [${len(regs_flat)-1}:0] addr_hit; + always_comb begin + addr_hit = '0; + % for i,r in enumerate(regs_flat): + addr_hit[${"{}".format(i).rjust(max_regs_char)}] = (reg_addr == ${ublock}_${r.name.upper()}_OFFSET); + % endfor + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + +% if regs_flat: +<% + # We want to signal wr_err if reg_be (the byte enable signal) is true for + # any bytes that aren't supported by a register. That's true if a + # addr_hit[i] and a bit is set in reg_be but not in *_PERMIT[i]. + + wr_err_terms = ['(addr_hit[{idx}] & (|({mod}_PERMIT[{idx}] & ~reg_be)))' + .format(idx=str(i).rjust(max_regs_char), + mod=u_mod_base) + for i in range(len(regs_flat))] + wr_err_expr = (' |\n' + (' ' * 15)).join(wr_err_terms) +%>\ + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + (${wr_err_expr})); + end +% else: + assign wr_error = 1'b0; +% endif\ + + % for i, r in enumerate(regs_flat): + % if len(r.fields) == 1: +${we_gen(r.fields[0], r.name.lower(), r.hwext, r.shadowed, i)}\ + % else: + % for f in r.fields: +${we_gen(f, r.name.lower() + "_" + f.name.lower(), r.hwext, r.shadowed, i)}\ + % endfor + % endif + % endfor + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + % for i, r in enumerate(regs_flat): + % if len(r.fields) == 1: + addr_hit[${i}]: begin +${rdata_gen(r.fields[0], r.name.lower())}\ + end + + % else: + addr_hit[${i}]: begin + % for f in r.fields: +${rdata_gen(f, r.name.lower() + "_" + f.name.lower())}\ + % endfor + end + + % endif + % endfor + default: begin + reg_rdata_next = '1; + end + endcase + end +% endif + + // Unused signal tieoff +% if rb.all_regs: + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; +% else: + // devmode_i is not used if there are no registers + logic unused_devmode; + assign unused_devmode = ^devmode_i; +% endif +% if rb.all_regs: + + // Assertions for Register Interface +% if not use_reg_iface: + `ASSERT_PULSE(wePulse, reg_we) + `ASSERT_PULSE(rePulse, reg_re) + + `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid) + + // this is formulated as an assumption such that the FPV testbenches do disprove this + // property by mistake + //`ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.chk_en == tlul_pkg::CheckDis) +% endif + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +% endif +endmodule +<%def name="str_bits_sv(bits)">\ +% if bits.msb != bits.lsb: +${bits.msb}:${bits.lsb}\ +% else: +${bits.msb}\ +% endif +\ +<%def name="str_arr_sv(bits)">\ +% if bits.msb != bits.lsb: +[${bits.msb-bits.lsb}:0] \ +% endif +\ +<%def name="sig_gen(field, sig_name, hwext, shadowed)">\ + % if field.swaccess.allows_read(): + logic ${str_arr_sv(field.bits)}${sig_name}_qs; + % endif + % if field.swaccess.allows_write(): + logic ${str_arr_sv(field.bits)}${sig_name}_wd; + logic ${sig_name}_we; + % endif + % if (field.swaccess.allows_read() and hwext) or shadowed: + logic ${sig_name}_re; + % endif +\ +<%def name="finst_gen(field, finst_name, fsig_name, hwext, regwen, shadowed)">\ + % if hwext: ## if hwext, instantiate prim_subreg_ext + prim_subreg_ext #( + .DW (${field.bits.width()}) + ) u_${finst_name} ( + % if field.swaccess.allows_read(): + .re (${finst_name}_re), + % else: + .re (1'b0), + % endif + % if field.swaccess.allows_write(): + % if regwen: + // qualified with register enable + .we (${finst_name}_we & ${regwen.lower()}_qs), + % else: + .we (${finst_name}_we), + % endif + .wd (${finst_name}_wd), + % else: + .we (1'b0), + .wd ('0), + % endif + % if field.hwaccess.allows_write(): + .d (hw2reg.${fsig_name}.d), + % else: + .d ('0), + % endif + % if field.hwre or shadowed: + .qre (reg2hw.${fsig_name}.re), + % else: + .qre (), + % endif + % if not field.hwaccess.allows_read(): + .qe (), + .q (), + % else: + % if field.hwqe: + .qe (reg2hw.${fsig_name}.qe), + % else: + .qe (), + % endif + .q (reg2hw.${fsig_name}.q ), + % endif + % if field.swaccess.allows_read(): + .qs (${finst_name}_qs) + % else: + .qs () + % endif + ); + % else: ## if not hwext, instantiate prim_subreg, prim_subreg_shadow or constant assign + % if ((not field.hwaccess.allows_read() and\ + not field.hwaccess.allows_write() and\ + field.swaccess.swrd() == SwRdAccess.RD and\ + not field.swaccess.allows_write())): + // constant-only read + assign ${finst_name}_qs = ${field.bits.width()}'h${"%x" % (field.resval or 0)}; + % else: ## not hwext not constant + % if not shadowed: + prim_subreg #( + % else: + prim_subreg_shadow #( + % endif + .DW (${field.bits.width()}), + .SWACCESS("${field.swaccess.value[1].name.upper()}"), + .RESVAL (${field.bits.width()}'h${"%x" % (field.resval or 0)}) + ) u_${finst_name} ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + % if shadowed: + .re (${finst_name}_re), + % endif + % if field.swaccess.allows_write(): ## non-RO types + % if regwen: + // from register interface (qualified with register enable) + .we (${finst_name}_we & ${regwen.lower()}_qs), + % else: + // from register interface + .we (${finst_name}_we), + % endif + .wd (${finst_name}_wd), + % else: ## RO types + .we (1'b0), + .wd ('0 ), + % endif + + // from internal hardware + % if field.hwaccess.allows_write(): + .de (hw2reg.${fsig_name}.de), + .d (hw2reg.${fsig_name}.d ), + % else: + .de (1'b0), + .d ('0 ), + % endif + + // to internal hardware + % if not field.hwaccess.allows_read(): + .qe (), + .q (), + % else: + % if field.hwqe: + .qe (reg2hw.${fsig_name}.qe), + % else: + .qe (), + % endif + .q (reg2hw.${fsig_name}.q ), + % endif + + % if not shadowed: + % if field.swaccess.allows_read(): + // to register interface (read) + .qs (${finst_name}_qs) + % else: + .qs () + % endif + % else: + % if field.swaccess.allows_read(): + // to register interface (read) + .qs (${finst_name}_qs), + % else: + .qs (), + % endif + + // Shadow register error conditions + .err_update (reg2hw.${fsig_name}.err_update ), + .err_storage (reg2hw.${fsig_name}.err_storage) + % endif + ); + % endif ## end non-constant prim_subreg + % endif +\ +<%def name="we_gen(field, sig_name, hwext, shadowed, idx)">\ +<% + needs_we = field.swaccess.allows_write() + needs_re = (field.swaccess.allows_read() and hwext) or shadowed + space = '\n' if needs_we or needs_re else '' +%>\ +${space}\ +% if needs_we: + % if field.swaccess.swrd() != SwRdAccess.RC: + assign ${sig_name}_we = addr_hit[${idx}] & reg_we & !reg_error; + assign ${sig_name}_wd = reg_wdata[${str_bits_sv(field.bits)}]; + % else: + ## Generate WE based on read request, read should clear + assign ${sig_name}_we = addr_hit[${idx}] & reg_re & !reg_error; + assign ${sig_name}_wd = '1; + % endif +% endif +% if needs_re: + assign ${sig_name}_re = addr_hit[${idx}] & reg_re & !reg_error; +% endif +\ +<%def name="rdata_gen(field, sig_name)">\ +% if field.swaccess.allows_read(): + reg_rdata_next[${str_bits_sv(field.bits)}] = ${sig_name}_qs; +% else: + reg_rdata_next[${str_bits_sv(field.bits)}] = '0; +% endif +\ diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/register.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/register.py new file mode 100644 index 00000000..24f73d02 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/register.py @@ -0,0 +1,375 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, List, Optional + +from .access import SWAccess, HWAccess +from .field import Field +from .lib import (check_keys, check_str, check_name, check_bool, + check_list, check_str_list, check_int) +from .params import ReggenParams +from .reg_base import RegBase + +REQUIRED_FIELDS = { + 'name': ['s', "name of the register"], + 'desc': ['t', "description of the register"], + 'fields': ['l', "list of register field description groups"] +} + +OPTIONAL_FIELDS = { + 'swaccess': [ + 's', + "software access permission to use for " + "fields that don't specify swaccess" + ], + 'hwaccess': [ + 's', + "hardware access permission to use for " + "fields that don't specify hwaccess" + ], + 'hwext': [ + 's', + "'true' if the register is stored outside " + "of the register module" + ], + 'hwqe': [ + 's', + "'true' if hardware uses 'q' enable signal, " + "which is latched signal of software write pulse." + ], + 'hwre': [ + 's', + "'true' if hardware uses 're' signal, " + "which is latched signal of software read pulse." + ], + 'regwen': [ + 's', + "if register is write-protected by another register, that " + "register name should be given here. empty-string for no register " + "write protection" + ], + 'resval': [ + 'd', + "reset value of full register (default 0)" + ], + 'tags': [ + 's', + "tags for the register, following the format 'tag_name:item1:item2...'" + ], + 'shadowed': [ + 's', + "'true' if the register is shadowed" + ], + 'update_err_alert': [ + 's', + "alert that will be triggered if " + "this shadowed register has update error" + ], + 'storage_err_alert': [ + 's', + "alert that will be triggered if " + "this shadowed register has storage error" + ] +} + + +class Register(RegBase): + '''Code representing a register for reggen''' + def __init__(self, + offset: int, + name: str, + desc: str, + swaccess: SWAccess, + hwaccess: HWAccess, + hwext: bool, + hwqe: bool, + hwre: bool, + regwen: Optional[str], + tags: List[str], + resval: Optional[int], + shadowed: bool, + fields: List[Field], + update_err_alert: Optional[str], + storage_err_alert: Optional[str]): + super().__init__(offset) + self.name = name + self.desc = desc + + self.swaccess = swaccess + self.hwaccess = hwaccess + + self.hwext = hwext + if self.hwext and self.hwaccess.key == 'hro' and self.sw_readable(): + raise ValueError('hwext flag for {} register is set, but ' + 'hwaccess is hro and the register value ' + 'is readable by software mode ({}).' + .format(self.name, self.swaccess.key)) + + self.hwqe = hwqe + if self.hwext and not self.hwqe and self.sw_writable(): + raise ValueError('The {} register has hwext set and is writable ' + 'by software (mode {}), so must also have hwqe ' + 'enabled.' + .format(self.name, self.swaccess.key)) + + self.hwre = hwre + if self.hwre and not self.hwext: + raise ValueError('The {} register specifies hwre but not hwext.' + .format(self.name)) + + self.regwen = regwen + self.tags = tags + + self.shadowed = shadowed + sounds_shadowy = self.name.lower().endswith('_shadowed') + if self.shadowed and not sounds_shadowy: + raise ValueError("Register {} has the shadowed flag but its name " + "doesn't end with the _shadowed suffix." + .format(self.name)) + elif sounds_shadowy and not self.shadowed: + raise ValueError("Register {} has a name ending in _shadowed, but " + "the shadowed flag is not set." + .format(self.name)) + + # Take a copy of fields and then sort by bit index + assert fields + self.fields = fields.copy() + self.fields.sort(key=lambda field: field.bits.lsb) + + # Index fields by name and check for duplicates + self.name_to_field = {} # type: Dict[str, Field] + for field in self.fields: + if field.name in self.name_to_field: + raise ValueError('Register {} has duplicate fields called {}.' + .format(self.name, field.name)) + self.name_to_field[field.name] = field + + # Check that field bits are disjoint + bits_used = 0 + for field in self.fields: + field_mask = field.bits.bitmask() + if bits_used & field_mask: + raise ValueError('Register {} has non-disjoint fields: ' + '{} uses bits {:#x} used by other fields.' + .format(self.name, field.name, + bits_used & field_mask)) + + # Compute a reset value and mask from our constituent fields. + self.resval = 0 + self.resmask = 0 + for field in self.fields: + self.resval |= (field.resval or 0) << field.bits.lsb + self.resmask |= field.bits.bitmask() + + # If the register defined a reset value, make sure it matches. We've + # already checked that each field matches, but we still need to make + # sure there weren't any bits unaccounted for. + if resval is not None and self.resval != resval: + raise ValueError('Register {} specifies a reset value of {:#x} but ' + 'collecting reset values across its fields yields ' + '{:#x}.' + .format(self.name, resval, self.resval)) + + self.update_err_alert = update_err_alert + self.storage_err_alert = storage_err_alert + + @staticmethod + def from_raw(reg_width: int, + offset: int, + params: ReggenParams, + raw: object) -> 'Register': + rd = check_keys(raw, 'register', + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + name = check_name(rd['name'], 'name of register') + desc = check_str(rd['desc'], 'desc for {} register'.format(name)) + + swaccess = SWAccess('{} register'.format(name), + rd.get('swaccess', 'none')) + hwaccess = HWAccess('{} register'.format(name), + rd.get('hwaccess', 'hro')) + + hwext = check_bool(rd.get('hwext', False), + 'hwext flag for {} register'.format(name)) + + hwqe = check_bool(rd.get('hwqe', False), + 'hwqe flag for {} register'.format(name)) + + hwre = check_bool(rd.get('hwre', False), + 'hwre flag for {} register'.format(name)) + + raw_regwen = rd.get('regwen', '') + if not raw_regwen: + regwen = None + else: + regwen = check_name(raw_regwen, + 'regwen for {} register'.format(name)) + + tags = check_str_list(rd.get('tags', []), + 'tags for {} register'.format(name)) + + raw_resval = rd.get('resval') + if raw_resval is None: + resval = None + else: + resval = check_int(raw_resval, + 'resval for {} register'.format(name)) + if not 0 <= resval < (1 << reg_width): + raise ValueError('resval for {} register is {}, ' + 'not an unsigned {}-bit number.' + .format(name, resval, reg_width)) + + shadowed = check_bool(rd.get('shadowed', False), + 'shadowed flag for {} register' + .format(name)) + + raw_fields = check_list(rd['fields'], + 'fields for {} register'.format(name)) + if not raw_fields: + raise ValueError('Register {} has no fields.'.format(name)) + fields = [Field.from_raw(name, + idx, + len(raw_fields), + swaccess, + hwaccess, + resval, + reg_width, + hwqe, + hwre, + params, + rf) + for idx, rf in enumerate(raw_fields)] + + raw_uea = rd.get('update_err_alert') + if raw_uea is None: + update_err_alert = None + else: + update_err_alert = check_name(raw_uea, + 'update_err_alert for {} register' + .format(name)) + + raw_sea = rd.get('storage_err_alert') + if raw_sea is None: + storage_err_alert = None + else: + storage_err_alert = check_name(raw_sea, + 'storage_err_alert for {} register' + .format(name)) + + return Register(offset, name, desc, swaccess, hwaccess, + hwext, hwqe, hwre, regwen, + tags, resval, shadowed, fields, + update_err_alert, storage_err_alert) + + def next_offset(self, addrsep: int) -> int: + return self.offset + addrsep + + def sw_readable(self) -> bool: + return self.swaccess.key not in ['wo', 'r0w1c'] + + def sw_writable(self) -> bool: + return self.swaccess.key != 'ro' + + def dv_rights(self) -> str: + return self.swaccess.dv_rights() + + def get_n_bits(self, bittype: List[str]) -> int: + return sum(field.get_n_bits(self.hwext, bittype) + for field in self.fields) + + def get_field_list(self) -> List[Field]: + return self.fields + + def is_homogeneous(self) -> bool: + return len(self.fields) == 1 + + def get_width(self) -> int: + '''Get the width of the fields in the register in bits + + This counts dead space between and below fields, so it's calculated as + one more than the highest msb. + + ''' + # self.fields is ordered by (increasing) LSB, so we can find the MSB of + # the register by taking the MSB of the last field. + return 1 + self.fields[-1].bits.msb + + def make_multi(self, + reg_width: int, + offset: int, + creg_idx: int, + creg_count: int, + regwen_multi: bool, + compact: bool, + min_reg_idx: int, + max_reg_idx: int, + cname: str) -> 'Register': + '''Generate a numbered, packed version of the register''' + assert 0 <= creg_idx < creg_count + assert 0 <= min_reg_idx <= max_reg_idx + assert compact or (min_reg_idx == max_reg_idx) + + new_name = ('{}_{}'.format(self.name, creg_idx) + if creg_count > 1 + else self.name) + + if self.regwen is None or not regwen_multi or creg_count == 1: + new_regwen = self.regwen + else: + new_regwen = '{}_{}'.format(self.regwen, creg_idx) + + strip_field = creg_idx > 0 + + if compact: + # Compacting multiple registers into a single "compacted" register. + # This is only supported if we have exactly one field (checked at + # the call-site) + assert len(self.fields) == 1 + new_fields = self.fields[0].make_multi(reg_width, + min_reg_idx, max_reg_idx, + cname, creg_idx, + strip_field) + else: + # No compacting going on, but we still choose to rename the fields + # to match the registers + assert creg_idx == min_reg_idx + new_fields = [field.make_suffixed('_{}'.format(creg_idx), + cname, creg_idx, strip_field) + for field in self.fields] + + # Don't specify a reset value for the new register. Any reset value + # defined for the original register will have propagated to its fields, + # so when we combine them here, the Register constructor can compute a + # reset value for us (which might well be different from self.resval if + # we've replicated fields). + new_resval = None + + return Register(offset, new_name, self.desc, + self.swaccess, self.hwaccess, + self.hwext, self.hwqe, self.hwre, new_regwen, + self.tags, new_resval, self.shadowed, new_fields, + self.update_err_alert, self.storage_err_alert) + + def _asdict(self) -> Dict[str, object]: + rd = { + 'name': self.name, + 'desc': self.desc, + 'fields': self.fields, + 'swaccess': self.swaccess.key, + 'hwaccess': self.hwaccess.key, + 'hwext': str(self.hwext), + 'hwqe': str(self.hwqe), + 'hwre': str(self.hwre), + 'tags': self.tags, + 'shadowed': str(self.shadowed), + } + if self.regwen is not None: + rd['regwen'] = self.regwen + if self.update_err_alert is not None: + rd['update_err_alert'] = self.update_err_alert + if self.storage_err_alert is not None: + rd['storage_err_alert'] = self.storage_err_alert + + return rd diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/signal.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/signal.py new file mode 100644 index 00000000..bd4d6a33 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/signal.py @@ -0,0 +1,63 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, Sequence + +from .bits import Bits +from .lib import check_keys, check_name, check_str, check_int, check_list + + +class Signal: + def __init__(self, name: str, desc: str, bits: Bits): + self.name = name + self.desc = desc + self.bits = bits + + @staticmethod + def from_raw(what: str, lsb: int, raw: object) -> 'Signal': + rd = check_keys(raw, what, + ['name', 'desc'], + ['width']) + + name = check_name(rd['name'], 'name field of ' + what) + desc = check_str(rd['desc'], 'desc field of ' + what) + width = check_int(rd.get('width', 1), 'width field of ' + what) + if width <= 0: + raise ValueError('The width field of signal {} ({}) ' + 'has value {}, but should be positive.' + .format(name, what, width)) + + bits = Bits(lsb + width - 1, lsb) + + return Signal(name, desc, bits) + + @staticmethod + def from_raw_list(what: str, raw: object) -> Sequence['Signal']: + lsb = 0 + ret = [] + for idx, entry in enumerate(check_list(raw, what)): + entry_what = 'entry {} of {}'.format(idx, what) + interrupt = Signal.from_raw(entry_what, lsb, entry) + ret.append(interrupt) + lsb += interrupt.bits.width() + return ret + + def _asdict(self) -> Dict[str, object]: + return { + 'name': self.name, + 'desc': self.desc, + 'width': str(self.bits.width()) + } + + def as_nwt_dict(self, type_field: str) -> Dict[str, object]: + '''Return a view of the signal as a dictionary + + The dictionary has fields "name", "width" and "type", the last + of which comes from the type_field argument. Used for topgen + integration. + + ''' + return {'name': self.name, + 'width': self.bits.width(), + 'type': type_field} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg.sv.tpl new file mode 100644 index 00000000..9d8d9dc7 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg.sv.tpl @@ -0,0 +1,14 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// UVM Registers auto-generated by `reggen` containing data structure +## +## +## We use functions from uvm_reg_base.sv.tpl to define +## per-device-interface code. +## +<%namespace file="uvm_reg_base.sv.tpl" import="*"/>\ +## +## +${make_ral_pkg(dv_base_prefix, block.regwidth, reg_block_path, rb, esc_if_name)} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg_base.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg_base.sv.tpl new file mode 100644 index 00000000..d1da4f4f --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/uvm_reg_base.sv.tpl @@ -0,0 +1,431 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +<%! + from reggen import gen_dv + from reggen.access import HwAccess, SwRdAccess, SwWrAccess +%> +## +## +## make_ral_pkg +## ============ +## +## Generate the RAL package for a device interface. +## +## dv_base_prefix a string naming the base register type. If it is FOO, +## then we will inherit from FOO_reg (assumed to +## be a subclass of uvm_reg). +## +## reg_width an integer giving the width of registers in bits +## +## reg_block_path the hierarchical path to the relevant register block in the +## design +## +## rb a RegBlock object +## +## esc_if_name a string giving the full, escaped, interface name. For +## a device interface called FOO on block BAR, +## this will be bar__foo. For an unnamed interface +## on block BAR, this will be just bar. +## +<%def name="make_ral_pkg(dv_base_prefix, reg_width, reg_block_path, rb, esc_if_name)">\ +package ${esc_if_name}_ral_pkg; +${make_ral_pkg_hdr(dv_base_prefix, [])} + +${make_ral_pkg_fwd_decls(esc_if_name, rb.flat_regs, rb.windows)} +% for reg in rb.flat_regs: + +${make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg)} +% endfor +% for window in rb.windows: + +${make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)} +% endfor + +<% + reg_block_name = gen_dv.bcname(esc_if_name) +%>\ + class ${reg_block_name} extends ${dv_base_prefix}_reg_block; +% if rb.flat_regs: + // registers +% for r in rb.flat_regs: + rand ${gen_dv.rcname(esc_if_name, r)} ${r.name.lower()}; +% endfor +% endif +% if rb.windows: + // memories +% for window in rb.windows: + rand ${gen_dv.mcname(esc_if_name, window)} ${gen_dv.miname(window)}; +% endfor +% endif + + `uvm_object_utils(${reg_block_name}) + + function new(string name = "${reg_block_name}", + int has_coverage = UVM_NO_COVERAGE); + super.new(name, has_coverage); + endfunction : new + + virtual function void build(uvm_reg_addr_t base_addr, + csr_excl_item csr_excl = null); + // create default map + this.default_map = create_map(.name("default_map"), + .base_addr(base_addr), + .n_bytes(${reg_width//8}), + .endian(UVM_LITTLE_ENDIAN)); + if (csr_excl == null) begin + csr_excl = csr_excl_item::type_id::create("csr_excl"); + this.csr_excl = csr_excl; + end +% if rb.flat_regs: + set_hdl_path_root("tb.dut", "BkdrRegPathRtl"); + set_hdl_path_root("tb.dut", "BkdrRegPathRtlCommitted"); + set_hdl_path_root("tb.dut", "BkdrRegPathRtlShadow"); + // create registers +% for r in rb.flat_regs: +<% + reg_name = r.name.lower() + reg_right = r.dv_rights() + reg_offset = "{}'h{:x}".format(reg_width, r.offset) + reg_tags = r.tags + reg_shadowed = r.shadowed + + type_id_indent = ' ' * (len(reg_name) + 4) +%>\ + ${reg_name} = (${gen_dv.rcname(esc_if_name, r)}:: + ${type_id_indent}type_id::create("${reg_name}")); + ${reg_name}.configure(.blk_parent(this)); + ${reg_name}.build(csr_excl); + default_map.add_reg(.rg(${reg_name}), + .offset(${reg_offset}), + .rights("${reg_right}")); +% if reg_shadowed: + ${reg_name}.set_is_shadowed(); +% endif +% if reg_tags: + // create register tags +% for reg_tag in reg_tags: +<% + tag = reg_tag.split(":") +%>\ +% if tag[0] == "excl": + csr_excl.add_excl(${reg_name}.get_full_name(), ${tag[2]}, ${tag[1]}); +% endif +% endfor +% endif +% endfor +<% + any_regwen = False + for r in rb.flat_regs: + if r.regwen: + any_regwen = True + break +%>\ +% if any_regwen: + // assign locked reg to its regwen reg +% for r in rb.flat_regs: +% if r.regwen: +% for reg in rb.flat_regs: +% if r.regwen.lower() == reg.name.lower(): + ${r.regwen.lower()}.add_lockable_reg_or_fld(${r.name.lower()}); +<% break %>\ +% elif reg.name.lower() in r.regwen.lower(): +% for field in reg.get_field_list(): +% if r.regwen.lower() == (reg.name.lower() + "_" + field.name.lower()): + ${r.regwen.lower()}.${field.name.lower()}.add_lockable_reg_or_fld(${r.name.lower()}); +<% break %>\ +% endif +% endfor +% endif +% endfor +% endif +% endfor +% endif +% endif +${make_ral_pkg_window_instances(reg_width, esc_if_name, rb)} + endfunction : build + endclass : ${reg_block_name} + +endpackage +\ +## +## +## make_ral_pkg_hdr +## ================ +## +## Generate the header for a RAL package +## +## dv_base_prefix as for make_ral_pkg +## +## deps a list of names for packages that should be explicitly +## imported +## +<%def name="make_ral_pkg_hdr(dv_base_prefix, deps)">\ + // dep packages + import uvm_pkg::*; + import dv_base_reg_pkg::*; +% if dv_base_prefix != "dv_base": + import ${dv_base_prefix}_reg_pkg::*; +% endif +% for dep in deps: + import ${dep}::*; +% endfor + + // macro includes + `include "uvm_macros.svh"\ +\ +## +## +## make_ral_pkg_fwd_decls +## ====================== +## +## Generate the forward declarations for a RAL package +## +## esc_if_name as for make_ral_pkg +## +## flat_regs a list of Register objects (expanding multiregs) +## +## windows a list of Window objects +## +<%def name="make_ral_pkg_fwd_decls(esc_if_name, flat_regs, windows)">\ + // Forward declare all register/memory/block classes +% for r in flat_regs: + typedef class ${gen_dv.rcname(esc_if_name, r)}; +% endfor +% for w in windows: + typedef class ${gen_dv.mcname(esc_if_name, w)}; +% endfor + typedef class ${gen_dv.bcname(esc_if_name)};\ +\ +## +## +## make_ral_pkg_reg_class +## ====================== +## +## Generate the classes for a register inside a RAL package +## +## dv_base_prefix as for make_ral_pkg +## +## reg_width as for make_ral_pkg +## +## esc_if_name as for make_ral_pkg +## +## reg_block_path as for make_ral_pkg +## +## reg a Register object +<%def name="make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg)">\ +<% + reg_name = reg.name.lower() + + is_ext = reg.hwext + for field in reg.fields: + if (field.hwaccess.value[1] == HwAccess.NONE and + field.swaccess.swrd() == SwRdAccess.RD and + not field.swaccess.allows_write()): + is_ext = 1 + + class_name = gen_dv.rcname(esc_if_name, reg) +%>\ + class ${class_name} extends ${dv_base_prefix}_reg; + // fields +% for f in reg.fields: + rand ${dv_base_prefix}_reg_field ${f.name.lower()}; +% endfor + + `uvm_object_utils(${class_name}) + + function new(string name = "${class_name}", + int unsigned n_bits = ${reg_width}, + int has_coverage = UVM_NO_COVERAGE); + super.new(name, n_bits, has_coverage); + endfunction : new + + virtual function void build(csr_excl_item csr_excl = null); + // create fields +% for field in reg.fields: +<% + if len(reg.fields) == 1: + reg_field_name = reg_name + else: + reg_field_name = reg_name + "_" + field.name.lower() +%>\ +${_create_reg_field(dv_base_prefix, reg_width, reg_block_path, reg.shadowed, reg.hwext, reg_field_name, field)} +% endfor +% if reg.shadowed and reg.hwext: +<% + shadowed_reg_path = '' + for tag in reg.tags: + parts = tag.split(':') + if parts[0] == 'shadowed_reg_path': + shadowed_reg_path = parts[1] + + if not shadowed_reg_path: + print("ERROR: ext shadow_reg does not have tags for shadowed_reg_path!") + assert 0 + + bit_idx = reg.fields[-1].bits.msb + 1 + +%>\ + add_update_err_alert("${reg.update_err_alert}"); + add_storage_err_alert("${reg.storage_err_alert}"); + add_hdl_path_slice("${shadowed_reg_path}.committed_reg.q", + 0, ${bit_idx}, 0, "BkdrRegPathRtlCommitted"); + add_hdl_path_slice("${shadowed_reg_path}.shadow_reg.q", + 0, ${bit_idx}, 0, "BkdrRegPathRtlShadow"); +% endif +% if is_ext: + set_is_ext_reg(1); +% endif + endfunction : build + endclass : ${class_name}\ +\ +## +## +## _create_reg_field +## ================= +## +## Generate the code that creates a uvm_reg_field object for a field +## in a register. +## +## dv_base_prefix as for make_ral_pkg +## +## reg_width as for make_ral_pkg +## +## reg_block_path as for make_ral_pkg +## +## shadowed true if the field's register is shadowed +## +## hwext true if the field's register is hwext +## +## reg_field_name a string with the name to give the field in the HDL +## +## field a Field object +<%def name="_create_reg_field(dv_base_prefix, reg_width, reg_block_path, shadowed, hwext, reg_field_name, field)">\ +<% + field_size = field.bits.width() + if field.swaccess.key == "r0w1c": + field_access = "W1C" + else: + field_access = field.swaccess.value[1].name + + if not field.hwaccess.allows_write(): + field_volatile = 0 + else: + field_volatile = 1 + field_tags = field.tags + + fname = field.name.lower() + type_id_indent = ' ' * (len(fname) + 4) +%>\ + ${fname} = (${dv_base_prefix}_reg_field:: + ${type_id_indent}type_id::create("${fname}")); + ${fname}.configure( + .parent(this), + .size(${field_size}), + .lsb_pos(${field.bits.lsb}), + .access("${field_access}"), + .volatile(${field_volatile}), + .reset(${reg_width}'h${format(field.resval or 0, 'x')}), + .has_reset(1), + .is_rand(1), + .individually_accessible(1)); + ${fname}.set_original_access("${field_access}"); +% if ((field.hwaccess.value[1] == HwAccess.NONE and\ + field.swaccess.swrd() == SwRdAccess.RD and\ + not field.swaccess.allows_write())): + // constant reg + add_hdl_path_slice("${reg_block_path}.${reg_field_name}_qs", + ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl"); +% else: + add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.q${"s" if hwext else ""}", + ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl"); +% endif +% if shadowed and not hwext: + add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.committed_reg.q", + ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlCommitted"); + add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.shadow_reg.q", + ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlShadow"); +% endif +% if field_tags: + // create field tags +% for field_tag in field_tags: +<% + tag = field_tag.split(":") +%>\ +% if tag[0] == "excl": + csr_excl.add_excl(${field.name.lower()}.get_full_name(), ${tag[2]}, ${tag[1]}); +% endif +% endfor +% endif +\ +## +## +## make_ral_pkg_window_class +## ========================= +## +## Generate the classes for a window inside a RAL package +## +## dv_base_prefix as for make_ral_pkg +## +## esc_if_name as for make_ral_pkg +## +## window a Window object +<%def name="make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)">\ +<% + mem_name = window.name.lower() + mem_right = window.swaccess.dv_rights() + mem_n_bits = window.validbits + mem_size = window.items + + class_name = gen_dv.mcname(esc_if_name, window) +%>\ + class ${class_name} extends ${dv_base_prefix}_mem; + + `uvm_object_utils(${class_name}) + + function new(string name = "${class_name}", + longint unsigned size = ${mem_size}, + int unsigned n_bits = ${mem_n_bits}, + string access = "${mem_right}", + int has_coverage = UVM_NO_COVERAGE); + super.new(name, size, n_bits, access, has_coverage); +% if window.byte_write: + set_mem_partial_write_support(1); +% endif + endfunction : new + + endclass : ${class_name} +\ +## +## +## make_ral_pkg_window_instances +## ============================= +## +## Generate the classes for a window inside a RAL package +## +## reg_width as for make_ral_pkg +## +## esc_if_name as for make_ral_pkg +## +## rb a RegBlock object +## +<%def name="make_ral_pkg_window_instances(reg_width, esc_if_name, rb)">\ +% if rb.windows: + + // create memories +% for w in rb.windows: +<% + mem_name = w.name.lower() + mem_right = w.swaccess.dv_rights() + mem_offset = "{}'h{:x}".format(reg_width, w.offset) + mem_n_bits = w.validbits + mem_size = w.items +%>\ + ${mem_name} = ${gen_dv.mcname(esc_if_name, w)}::type_id::create("${mem_name}"); + ${mem_name}.configure(.parent(this)); + default_map.add_mem(.mem(${mem_name}), + .offset(${mem_offset}), + .rights("${mem_right}")); +% endfor +% endif +\ diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/validate.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/validate.py new file mode 100644 index 00000000..e1cea7fa --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/validate.py @@ -0,0 +1,155 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +""" +Register JSON validation +""" + +import logging as log + + +# validating version of int(x, 0) +# returns int value, error flag +# if error flag is True value will be zero +def check_int(x, err_prefix, suppress_err_msg=False): + if isinstance(x, int): + return x, False + if x[0] == '0' and len(x) > 2: + if x[1] in 'bB': + validch = '01' + elif x[1] in 'oO': + validch = '01234567' + elif x[1] in 'xX': + validch = '0123456789abcdefABCDEF' + else: + if not suppress_err_msg: + log.error(err_prefix + + ": int must start digit, 0b, 0B, 0o, 0O, 0x or 0X") + return 0, True + for c in x[2:]: + if c not in validch: + if not suppress_err_msg: + log.error(err_prefix + ": Bad character " + c + " in " + x) + return 0, True + else: + if not x.isdecimal(): + if not suppress_err_msg: + log.error(err_prefix + ": Number not valid int " + x) + return 0, True + return int(x, 0), False + + +def check_bool(x, err_prefix): + """check_bool checks if input 'x' is one of the list: + "true", "false" + + It returns value as Bool type and Error condition. + """ + if isinstance(x, bool): + # if Bool returns as it is + return x, False + if not x.lower() in ["true", "false"]: + log.error(err_prefix + ": Bad field value " + x) + return False, True + else: + return (x.lower() == "true"), False + + +def check_ln(obj, x, withwidth, err_prefix): + error = 0 + if not isinstance(obj[x], list): + log.error(err_prefix + ' element ' + x + ' not a list') + return 1 + for y in obj[x]: + error += check_keys(y, ln_required, ln_optional if withwidth else {}, + {}, err_prefix + ' element ' + x) + if withwidth: + if 'width' in y: + w, err = check_int(y['width'], err_prefix + ' width in ' + x) + if err: + error += 1 + w = 1 + else: + w = 1 + y['width'] = str(w) + + return error + + +def check_keys(obj, required_keys, optional_keys, added_keys, err_prefix): + error = 0 + for x in required_keys: + if x not in obj: + error += 1 + log.error(err_prefix + " missing required key " + x) + for x in obj: + type = None + if x in required_keys: + type = required_keys[x][0] + elif x in optional_keys: + type = optional_keys[x][0] + elif x not in added_keys: + log.warning(err_prefix + " contains extra key " + x) + if type is not None: + if type[:2] == 'ln': + error += check_ln(obj, x, type == 'lnw', err_prefix) + + return error + + +val_types = { + 'd': ["int", "integer (binary 0b, octal 0o, decimal, hex 0x)"], + 'x': ["xint", "x for undefined otherwise int"], + 'b': [ + "bitrange", "bit number as decimal integer, " + "or bit-range as decimal integers msb:lsb" + ], + 'l': ["list", "comma separated list enclosed in `[]`"], + 'ln': [ + "name list", 'comma separated list enclosed in `[]` of ' + 'one or more groups that have just name and dscr keys.' + ' e.g. `{ name: "name", desc: "description"}`' + ], + 'lnw': ["name list+", 'name list that optionally contains a width'], + 'lp': ["parameter list", 'parameter list having default value optionally'], + 'g': ["group", "comma separated group of key:value enclosed in `{}`"], + 'lg': [ + "list of group", "comma separated group of key:value enclosed in `{}`" + " the second entry of the list is the sub group format" + ], + 's': ["string", "string, typically short"], + 't': [ + "text", "string, may be multi-line enclosed in `'''` " + "may use `**bold**`, `*italic*` or `!!Reg` markup" + ], + 'T': ["tuple", "tuple enclosed in ()"], + 'pi': ["python int", "Native Python type int (generated)"], + 'pb': ["python Bool", "Native Python type Bool (generated)"], + 'pl': ["python list", "Native Python type list (generated)"], + 'pe': ["python enum", "Native Python type enum (generated)"] +} + +# ln type has list of groups with only name and description +# (was called "subunit" in cfg_validate) +ln_required = { + 'name': ['s', "name of the item"], + 'desc': ['s', "description of the item"], +} +ln_optional = { + 'width': ['d', "bit width of the item (if not 1)"], +} + +# Registers list may have embedded keys +list_optone = { + 'reserved': ['d', "number of registers to reserve space for"], + 'skipto': ['d', "set next register offset to value"], + 'window': [ + 'g', "group defining an address range " + "for something other than standard registers" + ], + 'multireg': + ['g', "group defining registers generated " + "from a base instance."] +} + +key_use = {'r': "required", 'o': "optional", 'a': "added by tool"} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/version.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/version.py new file mode 100644 index 00000000..3539c460 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/version.py @@ -0,0 +1,24 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +r"""Standard version printing +""" +import os +import subprocess +import sys + +import pkg_resources # part of setuptools + + +def show_and_exit(clitool, packages): + util_path = os.path.dirname(os.path.realpath(clitool)) + os.chdir(util_path) + ver = subprocess.run( + ["git", "describe", "--always", "--dirty", "--broken"], + stdout=subprocess.PIPE).stdout.strip().decode('ascii') + if (ver == ''): + ver = 'not found (not in Git repository?)' + sys.stderr.write(clitool + " Git version " + ver + '\n') + for p in packages: + sys.stderr.write(p + ' ' + pkg_resources.require(p)[0].version + '\n') + exit(0) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/window.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/window.py new file mode 100644 index 00000000..d4355c88 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/reggen/window.py @@ -0,0 +1,169 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict + +from .access import SWAccess +from .lib import check_keys, check_str, check_bool, check_int +from .params import ReggenParams + + +REQUIRED_FIELDS = { + 'name': ['s', "name of the window"], + 'desc': ['t', "description of the window"], + 'items': ['d', "size in fieldaccess width words of the window"], + 'swaccess': ['s', "software access permitted"], +} + +# TODO potential for additional optional to give more type info? +# eg sram-hw-port: "none", "sync", "async" +OPTIONAL_FIELDS = { + 'data-intg-passthru': [ + 's', "True if the window has data integrity pass through. " + "Defaults to false if not present." + ], + 'byte-write': [ + 's', "True if byte writes are supported. " + "Defaults to false if not present." + ], + 'validbits': [ + 'd', "Number of valid data bits within " + "regwidth sized word. " + "Defaults to regwidth. If " + "smaller than the regwidth then in each " + "word of the window bits " + "[regwidth-1:validbits] are unused and " + "bits [validbits-1:0] are valid." + ], + 'unusual': [ + 's', "True if window has unusual parameters " + "(set to prevent Unusual: errors)." + "Defaults to false if not present." + ] +} + + +class Window: + '''A class representing a memory window''' + def __init__(self, + name: str, + desc: str, + unusual: bool, + byte_write: bool, + data_intg_passthru: bool, + validbits: int, + items: int, + size_in_bytes: int, + offset: int, + swaccess: SWAccess): + assert 0 < validbits + assert 0 < items <= size_in_bytes + + self.name = name + self.desc = desc + self.unusual = unusual + self.byte_write = byte_write + self.data_intg_passthru = data_intg_passthru + self.validbits = validbits + self.items = items + self.size_in_bytes = size_in_bytes + self.offset = offset + self.swaccess = swaccess + + # Check that offset has been adjusted so that the first item in the + # window has all zeros in the low bits. + po2_size = 1 << (self.size_in_bytes - 1).bit_length() + assert not (offset & (po2_size - 1)) + + @staticmethod + def from_raw(offset: int, + reg_width: int, + params: ReggenParams, + raw: object) -> 'Window': + rd = check_keys(raw, 'window', + list(REQUIRED_FIELDS.keys()), + list(OPTIONAL_FIELDS.keys())) + + wind_desc = 'window at offset {:#x}'.format(offset) + name = check_str(rd['name'], wind_desc) + wind_desc = '{!r} {}'.format(name, wind_desc) + + desc = check_str(rd['desc'], 'desc field for ' + wind_desc) + + unusual = check_bool(rd.get('unusual', False), + 'unusual field for ' + wind_desc) + byte_write = check_bool(rd.get('byte-write', False), + 'byte-write field for ' + wind_desc) + data_intg_passthru = check_bool(rd.get('data-intg-passthru', False), + 'data-intg-passthru field for ' + wind_desc) + + validbits = check_int(rd.get('validbits', reg_width), + 'validbits field for ' + wind_desc) + if validbits <= 0: + raise ValueError('validbits field for {} is not positive.' + .format(wind_desc)) + if validbits > reg_width: + raise ValueError('validbits field for {} is {}, ' + 'which is greater than {}, the register width.' + .format(wind_desc, validbits, reg_width)) + + r_items = check_str(rd['items'], 'items field for ' + wind_desc) + items = params.expand(r_items, 'items field for ' + wind_desc) + if items <= 0: + raise ValueError("Items field for {} is {}, " + "which isn't positive." + .format(wind_desc, items)) + + assert reg_width % 8 == 0 + size_in_bytes = items * (reg_width // 8) + + # Round size_in_bytes up to the next power of 2. The calculation is + # like clog2 calculations in SystemVerilog, where we start with the + # last index, rather than the number of elements. + assert size_in_bytes > 0 + po2_size = 1 << (size_in_bytes - 1).bit_length() + + # A size that isn't a power of 2 is not allowed unless the unusual flag + # is set. + if po2_size != size_in_bytes and not unusual: + raise ValueError('Items field for {} is {}, which gives a size of ' + '{} bytes. This is not a power of 2 (next power ' + 'of 2 is {}). If you want to do this even so, ' + 'set the "unusual" flag.' + .format(wind_desc, items, + size_in_bytes, po2_size)) + + # Adjust offset if necessary to make sure the base address of the first + # item in the window has all zeros in the low bits. + addr_mask = po2_size - 1 + if offset & addr_mask: + offset = (offset | addr_mask) + 1 + offset = offset + + swaccess = SWAccess(wind_desc, rd['swaccess']) + if not (swaccess.value[4] or unusual): + raise ValueError('swaccess field for {} is {}, which is an ' + 'unusual access type for a window. If you want ' + 'to do this, set the "unusual" flag.' + .format(wind_desc, swaccess.key)) + + return Window(name, desc, unusual, byte_write, data_intg_passthru, + validbits, items, size_in_bytes, offset, swaccess) + + def next_offset(self, addrsep: int) -> int: + return self.offset + self.size_in_bytes + + def _asdict(self) -> Dict[str, object]: + rd = { + 'desc': self.desc, + 'items': self.items, + 'swaccess': self.swaccess.key, + 'byte-write': self.byte_write, + 'validbits': self.validbits, + 'unusual': self.unusual + } + if self.name is not None: + rd['name'] = self.name + + return {'window': rd} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/regtool.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/regtool.py new file mode 100644 index 00000000..f1501bd0 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/regtool.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Command-line tool to validate and convert register hjson + +""" +import argparse +import logging as log +import re +import sys +from pathlib import PurePath + +from reggen import (gen_cheader, gen_dv, gen_fpv, gen_html, + gen_json, gen_rtl, gen_selfdoc, version) +from reggen.ip_block import IpBlock + +DESC = """regtool, generate register info from Hjson source""" + +USAGE = ''' + regtool [options] + regtool [options] + regtool (-h | --help) + regtool (-V | --version) +''' + + +def main(): + verbose = 0 + + parser = argparse.ArgumentParser( + prog="regtool", + formatter_class=argparse.RawDescriptionHelpFormatter, + usage=USAGE, + description=DESC) + parser.add_argument('input', + nargs='?', + metavar='file', + type=argparse.FileType('r'), + default=sys.stdin, + help='input file in Hjson type') + parser.add_argument('-d', + action='store_true', + help='Output register documentation (html)') + parser.add_argument('--cdefines', + '-D', + action='store_true', + help='Output C defines header') + parser.add_argument('--doc', + action='store_true', + help='Output source file documentation (gfm)') + parser.add_argument('-j', + action='store_true', + help='Output as formatted JSON') + parser.add_argument('-c', action='store_true', help='Output as JSON') + parser.add_argument('-r', + action='store_true', + help='Output as SystemVerilog RTL') + parser.add_argument('-s', + action='store_true', + help='Output as UVM Register class') + parser.add_argument('-f', + action='store_true', + help='Output as FPV CSR rw assertion module') + parser.add_argument('--outdir', + '-t', + help='Target directory for generated RTL; ' + 'tool uses ../rtl if blank.') + parser.add_argument('--dv-base-prefix', + default='dv_base', + help='Prefix for the DV register classes from which ' + 'the register models are derived.') + parser.add_argument('--outfile', + '-o', + type=argparse.FileType('w'), + default=sys.stdout, + help='Target filename for json, html, gfm.') + parser.add_argument('--verbose', + '-v', + action='store_true', + help='Verbose and run validate twice') + parser.add_argument('--param', + '-p', + type=str, + default="", + help='''Change the Parameter values. + Only integer value is supported. + You can add multiple param arguments. + + Format: ParamA=ValA;ParamB=ValB + ''') + parser.add_argument('--version', + '-V', + action='store_true', + help='Show version') + parser.add_argument('--novalidate', + action='store_true', + help='Skip validate, just output json') + + args = parser.parse_args() + + if args.version: + version.show_and_exit(__file__, ["Hjson", "Mako"]) + + verbose = args.verbose + if (verbose): + log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG) + else: + log.basicConfig(format="%(levelname)s: %(message)s") + + # Entries are triples of the form (arg, (format, dirspec)). + # + # arg is the name of the argument that selects the format. format is the + # name of the format. dirspec is None if the output is a single file; if + # the output needs a directory, it is a default path relative to the source + # file (used when --outdir is not given). + arg_to_format = [('j', ('json', None)), ('c', ('compact', None)), + ('d', ('html', None)), ('doc', ('doc', None)), + ('r', ('rtl', 'rtl')), ('s', ('dv', 'dv')), + ('f', ('fpv', 'fpv/vip')), ('cdefines', ('cdh', None))] + format = None + dirspec = None + for arg_name, spec in arg_to_format: + if getattr(args, arg_name): + if format is not None: + log.error('Multiple output formats specified on ' + 'command line ({} and {}).'.format(format, spec[0])) + sys.exit(1) + format, dirspec = spec + if format is None: + format = 'hjson' + + infile = args.input + + # Split parameters into key=value pairs. + raw_params = args.param.split(';') if args.param else [] + params = [] + for idx, raw_param in enumerate(raw_params): + tokens = raw_param.split('=') + if len(tokens) != 2: + raise ValueError('Entry {} in list of parameter defaults to ' + 'apply is {!r}, which is not of the form ' + 'param=value.' + .format(idx, raw_param)) + params.append((tokens[0], tokens[1])) + + # Define either outfile or outdir (but not both), depending on the output + # format. + outfile = None + outdir = None + if dirspec is None: + if args.outdir is not None: + log.error('The {} format expects an output file, ' + 'not an output directory.'.format(format)) + sys.exit(1) + + outfile = args.outfile + else: + if args.outfile is not sys.stdout: + log.error('The {} format expects an output directory, ' + 'not an output file.'.format(format)) + sys.exit(1) + + if args.outdir is not None: + outdir = args.outdir + elif infile is not sys.stdin: + outdir = str(PurePath(infile.name).parents[1].joinpath(dirspec)) + else: + # We're using sys.stdin, so can't infer an output directory name + log.error( + 'The {} format writes to an output directory, which ' + 'cannot be inferred automatically if the input comes ' + 'from stdin. Use --outdir to specify it manually.'.format( + format)) + sys.exit(1) + + if format == 'doc': + with outfile: + gen_selfdoc.document(outfile) + exit(0) + + srcfull = infile.read() + + try: + obj = IpBlock.from_text(srcfull, params, infile.name) + except ValueError as err: + log.error(str(err)) + exit(1) + + if args.novalidate: + with outfile: + gen_json.gen_json(obj, outfile, format) + outfile.write('\n') + else: + if format == 'rtl': + return gen_rtl.gen_rtl(obj, outdir) + if format == 'dv': + return gen_dv.gen_dv(obj, args.dv_base_prefix, outdir) + if format == 'fpv': + return gen_fpv.gen_fpv(obj, outdir) + src_lic = None + src_copy = '' + found_spdx = None + found_lunder = None + copy = re.compile(r'.*(copyright.*)|(.*\(c\).*)', re.IGNORECASE) + spdx = re.compile(r'.*(SPDX-License-Identifier:.+)') + lunder = re.compile(r'.*(Licensed under.+)', re.IGNORECASE) + for line in srcfull.splitlines(): + mat = copy.match(line) + if mat is not None: + src_copy += mat.group(1) + mat = spdx.match(line) + if mat is not None: + found_spdx = mat.group(1) + mat = lunder.match(line) + if mat is not None: + found_lunder = mat.group(1) + if found_lunder: + src_lic = found_lunder + if found_spdx: + src_lic += '\n' + found_spdx + + with outfile: + if format == 'html': + return gen_html.gen_html(obj, outfile) + elif format == 'cdh': + return gen_cheader.gen_cdefines(obj, outfile, src_lic, src_copy) + else: + return gen_json.gen_json(obj, outfile, format) + + outfile.write('\n') + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/__init__.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/__init__.py new file mode 100644 index 00000000..d8a34008 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/__init__.py @@ -0,0 +1,8 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +from .lib import get_hjsonobj_xbars, search_ips # noqa: F401 +# noqa: F401 These functions are used in topgen.py +from .merge import amend_clocks, merge_top # noqa: F401 +from .validate import validate_top, check_flash # noqa: F401 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/c.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/c.py new file mode 100644 index 00000000..58760a37 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/c.py @@ -0,0 +1,444 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""This contains a class which is used to help generate `top_{name}.h` and +`top_{name}.h`. +""" +from collections import OrderedDict +from typing import Dict, List, Optional, Tuple + +from mako.template import Template + +from .lib import get_base_and_size, Name + +from reggen.ip_block import IpBlock + + +class MemoryRegion(object): + def __init__(self, name: Name, base_addr: int, size_bytes: int): + assert isinstance(base_addr, int) + self.name = name + self.base_addr = base_addr + self.size_bytes = size_bytes + self.size_words = (size_bytes + 3) // 4 + + def base_addr_name(self): + return self.name + Name(["base", "addr"]) + + def offset_name(self): + return self.name + Name(["offset"]) + + def size_bytes_name(self): + return self.name + Name(["size", "bytes"]) + + def size_words_name(self): + return self.name + Name(["size", "words"]) + + +class CEnum(object): + def __init__(self, name): + self.name = name + self.enum_counter = 0 + self.finalized = False + + self.constants = [] + + def add_constant(self, constant_name, docstring=""): + assert not self.finalized + + full_name = self.name + constant_name + + value = self.enum_counter + self.enum_counter += 1 + + self.constants.append((full_name, value, docstring)) + + return full_name + + def add_last_constant(self, docstring=""): + assert not self.finalized + + full_name = self.name + Name(["last"]) + + _, last_val, _ = self.constants[-1] + + self.constants.append((full_name, last_val, r"\internal " + docstring)) + self.finalized = True + + def render(self): + template = ("typedef enum ${enum.name.as_snake_case()} {\n" + "% for name, value, docstring in enum.constants:\n" + " ${name.as_c_enum()} = ${value}, /**< ${docstring} */\n" + "% endfor\n" + "} ${enum.name.as_c_type()};") + return Template(template).render(enum=self) + + +class CArrayMapping(object): + def __init__(self, name, output_type_name): + self.name = name + self.output_type_name = output_type_name + + self.mapping = OrderedDict() + + def add_entry(self, in_name, out_name): + self.mapping[in_name] = out_name + + def render_declaration(self): + template = ( + "extern const ${mapping.output_type_name.as_c_type()}\n" + " ${mapping.name.as_snake_case()}[${len(mapping.mapping)}];") + return Template(template).render(mapping=self) + + def render_definition(self): + template = ( + "const ${mapping.output_type_name.as_c_type()}\n" + " ${mapping.name.as_snake_case()}[${len(mapping.mapping)}] = {\n" + "% for in_name, out_name in mapping.mapping.items():\n" + " [${in_name.as_c_enum()}] = ${out_name.as_c_enum()},\n" + "% endfor\n" + "};\n") + return Template(template).render(mapping=self) + + +class TopGenC: + def __init__(self, top_info, name_to_block: Dict[str, IpBlock]): + self.top = top_info + self._top_name = Name(["top"]) + Name.from_snake_case(top_info["name"]) + self._name_to_block = name_to_block + + # The .c file needs the .h file's relative path, store it here + self.header_path = None + + self._init_plic_targets() + self._init_plic_mapping() + self._init_alert_mapping() + self._init_pinmux_mapping() + self._init_pwrmgr_wakeups() + self._init_rstmgr_sw_rsts() + self._init_pwrmgr_reset_requests() + self._init_clkmgr_clocks() + + def devices(self) -> List[Tuple[Tuple[str, Optional[str]], MemoryRegion]]: + '''Return a list of MemoryRegion objects for devices on the bus + + The list returned is pairs (full_if, region) where full_if is itself a + pair (inst_name, if_name). inst_name is the name of some IP block + instantiation. if_name is the name of the interface (may be None). + region is a MemoryRegion object representing the device. + + ''' + ret = [] # type: List[Tuple[Tuple[str, Optional[str]], MemoryRegion]] + for inst in self.top['module']: + block = self._name_to_block[inst['type']] + for if_name, rb in block.reg_blocks.items(): + full_if = (inst['name'], if_name) + full_if_name = Name.from_snake_case(full_if[0]) + if if_name is not None: + full_if_name += Name.from_snake_case(if_name) + + name = self._top_name + full_if_name + base, size = get_base_and_size(self._name_to_block, + inst, if_name) + + region = MemoryRegion(name, base, size) + ret.append((full_if, region)) + + return ret + + def memories(self): + return [(m["name"], + MemoryRegion(self._top_name + Name.from_snake_case(m["name"]), + int(m["base_addr"], 0), + int(m["size"], 0))) + for m in self.top["memory"]] + + def _init_plic_targets(self): + enum = CEnum(self._top_name + Name(["plic", "target"])) + + for core_id in range(int(self.top["num_cores"])): + enum.add_constant(Name(["ibex", str(core_id)]), + docstring="Ibex Core {}".format(core_id)) + + enum.add_last_constant("Final PLIC target") + + self.plic_targets = enum + + def _init_plic_mapping(self): + """We eventually want to generate a mapping from interrupt id to the + source peripheral. + + In order to do so, we generate two enums (one for interrupts, one for + sources), and store the generated names in a dictionary that represents + the mapping. + + PLIC Interrupt ID 0 corresponds to no interrupt, and so no peripheral, + so we encode that in the enum as "unknown". + + The interrupts have to be added in order, with "none" first, to ensure + that they get the correct mapping to their PLIC id, which is used for + addressing the right registers and bits. + """ + sources = CEnum(self._top_name + Name(["plic", "peripheral"])) + interrupts = CEnum(self._top_name + Name(["plic", "irq", "id"])) + plic_mapping = CArrayMapping( + self._top_name + Name(["plic", "interrupt", "for", "peripheral"]), + sources.name) + + unknown_source = sources.add_constant(Name(["unknown"]), + docstring="Unknown Peripheral") + none_irq_id = interrupts.add_constant(Name(["none"]), + docstring="No Interrupt") + plic_mapping.add_entry(none_irq_id, unknown_source) + + # When we generate the `interrupts` enum, the only info we have about + # the source is the module name. We'll use `source_name_map` to map a + # short module name to the full name object used for the enum constant. + source_name_map = {} + + for name in self.top["interrupt_module"]: + source_name = sources.add_constant(Name.from_snake_case(name), + docstring=name) + source_name_map[name] = source_name + + sources.add_last_constant("Final PLIC peripheral") + + for intr in self.top["interrupt"]: + # Some interrupts are multiple bits wide. Here we deal with that by + # adding a bit-index suffix + if "width" in intr and int(intr["width"]) != 1: + for i in range(int(intr["width"])): + name = Name.from_snake_case(intr["name"]) + Name([str(i)]) + irq_id = interrupts.add_constant(name, + docstring="{} {}".format( + intr["name"], i)) + source_name = source_name_map[intr["module_name"]] + plic_mapping.add_entry(irq_id, source_name) + else: + name = Name.from_snake_case(intr["name"]) + irq_id = interrupts.add_constant(name, docstring=intr["name"]) + source_name = source_name_map[intr["module_name"]] + plic_mapping.add_entry(irq_id, source_name) + + interrupts.add_last_constant("The Last Valid Interrupt ID.") + + self.plic_sources = sources + self.plic_interrupts = interrupts + self.plic_mapping = plic_mapping + + def _init_alert_mapping(self): + """We eventually want to generate a mapping from alert id to the source + peripheral. + + In order to do so, we generate two enums (one for alerts, one for + sources), and store the generated names in a dictionary that represents + the mapping. + + Alert Handler has no concept of "no alert", unlike the PLIC. + + The alerts have to be added in order, to ensure that they get the + correct mapping to their alert id, which is used for addressing the + right registers and bits. + """ + sources = CEnum(self._top_name + Name(["alert", "peripheral"])) + alerts = CEnum(self._top_name + Name(["alert", "id"])) + alert_mapping = CArrayMapping( + self._top_name + Name(["alert", "for", "peripheral"]), + sources.name) + + # When we generate the `alerts` enum, the only info we have about the + # source is the module name. We'll use `source_name_map` to map a short + # module name to the full name object used for the enum constant. + source_name_map = {} + + for name in self.top["alert_module"]: + source_name = sources.add_constant(Name.from_snake_case(name), + docstring=name) + source_name_map[name] = source_name + + sources.add_last_constant("Final Alert peripheral") + + for alert in self.top["alert"]: + if "width" in alert and int(alert["width"]) != 1: + for i in range(int(alert["width"])): + name = Name.from_snake_case(alert["name"]) + Name([str(i)]) + irq_id = alerts.add_constant(name, + docstring="{} {}".format( + alert["name"], i)) + source_name = source_name_map[alert["module_name"]] + alert_mapping.add_entry(irq_id, source_name) + else: + name = Name.from_snake_case(alert["name"]) + alert_id = alerts.add_constant(name, docstring=alert["name"]) + source_name = source_name_map[alert["module_name"]] + alert_mapping.add_entry(alert_id, source_name) + + alerts.add_last_constant("The Last Valid Alert ID.") + + self.alert_sources = sources + self.alert_alerts = alerts + self.alert_mapping = alert_mapping + + def _init_pinmux_mapping(self): + """Generate C enums for addressing pinmux registers and in/out selects. + + Inputs/outputs are connected in the order the modules are listed in + the hjson under the "mio_modules" key. For each module, the corresponding + inouts are connected first, followed by either the inputs or the outputs. + + Inputs: + - Peripheral chooses register field (pinmux_peripheral_in) + - Insel chooses MIO input (pinmux_insel) + + Outputs: + - MIO chooses register field (pinmux_mio_out) + - Outsel chooses peripheral output (pinmux_outsel) + + Insel and outsel have some special values which are captured here too. + """ + pinmux_info = self.top['pinmux'] + pinout_info = self.top['pinout'] + + # Peripheral Inputs + peripheral_in = CEnum(self._top_name + + Name(['pinmux', 'peripheral', 'in'])) + i = 0 + for sig in pinmux_info['ios']: + if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'input']: + index = Name([str(sig['idx'])]) if sig['idx'] != -1 else Name([]) + name = Name.from_snake_case(sig['name']) + index + peripheral_in.add_constant(name, docstring='Peripheral Input {}'.format(i)) + i += 1 + + peripheral_in.add_last_constant('Last valid peripheral input') + + # Pinmux Input Selects + insel = CEnum(self._top_name + Name(['pinmux', 'insel'])) + insel.add_constant(Name(['constant', 'zero']), + docstring='Tie constantly to zero') + insel.add_constant(Name(['constant', 'one']), + docstring='Tie constantly to one') + i = 0 + for pad in pinout_info['pads']: + if pad['connection'] == 'muxed': + insel.add_constant(Name([pad['name']]), + docstring='MIO Pad {}'.format(i)) + i += 1 + insel.add_last_constant('Last valid insel value') + + # MIO Outputs + mio_out = CEnum(self._top_name + Name(['pinmux', 'mio', 'out'])) + i = 0 + for pad in pinout_info['pads']: + if pad['connection'] == 'muxed': + mio_out.add_constant(Name.from_snake_case(pad['name']), + docstring='MIO Pad {}'.format(i)) + i += 1 + mio_out.add_last_constant('Last valid mio output') + + # Pinmux Output Selects + outsel = CEnum(self._top_name + Name(['pinmux', 'outsel'])) + outsel.add_constant(Name(['constant', 'zero']), + docstring='Tie constantly to zero') + outsel.add_constant(Name(['constant', 'one']), + docstring='Tie constantly to one') + outsel.add_constant(Name(['constant', 'high', 'z']), + docstring='Tie constantly to high-Z') + i = 0 + for sig in pinmux_info['ios']: + if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'output']: + index = Name([str(sig['idx'])]) if sig['idx'] != -1 else Name([]) + name = Name.from_snake_case(sig['name']) + index + outsel.add_constant(name, docstring='Peripheral Output {}'.format(i)) + i += 1 + + outsel.add_last_constant('Last valid outsel value') + + self.pinmux_peripheral_in = peripheral_in + self.pinmux_insel = insel + self.pinmux_mio_out = mio_out + self.pinmux_outsel = outsel + + def _init_pwrmgr_wakeups(self): + enum = CEnum(self._top_name + + Name(["power", "manager", "wake", "ups"])) + + for signal in self.top["wakeups"]: + enum.add_constant( + Name.from_snake_case(signal["module"]) + + Name.from_snake_case(signal["name"])) + + enum.add_last_constant("Last valid pwrmgr wakeup signal") + + self.pwrmgr_wakeups = enum + + # Enumerates the positions of all software controllable resets + def _init_rstmgr_sw_rsts(self): + sw_rsts = [ + rst for rst in self.top["resets"]["nodes"] + if 'sw' in rst and rst['sw'] == 1 + ] + + enum = CEnum(self._top_name + + Name(["reset", "manager", "sw", "resets"])) + + for rst in sw_rsts: + enum.add_constant(Name.from_snake_case(rst["name"])) + + enum.add_last_constant("Last valid rstmgr software reset request") + + self.rstmgr_sw_rsts = enum + + def _init_pwrmgr_reset_requests(self): + enum = CEnum(self._top_name + + Name(["power", "manager", "reset", "requests"])) + + for signal in self.top["reset_requests"]: + enum.add_constant( + Name.from_snake_case(signal["module"]) + + Name.from_snake_case(signal["name"])) + + enum.add_last_constant("Last valid pwrmgr reset_request signal") + + self.pwrmgr_reset_requests = enum + + def _init_clkmgr_clocks(self): + """ + Creates CEnums for accessing the software-controlled clocks in the + design. + + The logic here matches the logic in topgen.py in how it instantiates the + clock manager with the described clocks. + + We differentiate "gateable" clocks and "hintable" clocks because the + clock manager has separate register interfaces for each group. + """ + + aon_clocks = set() + for src in self.top['clocks']['srcs'] + self.top['clocks'][ + 'derived_srcs']: + if src['aon'] == 'yes': + aon_clocks.add(src['name']) + + gateable_clocks = CEnum(self._top_name + Name(["gateable", "clocks"])) + hintable_clocks = CEnum(self._top_name + Name(["hintable", "clocks"])) + + # This replicates the behaviour in `topgen.py` in deriving `hints` and + # `sw_clocks`. + for group in self.top['clocks']['groups']: + for (name, source) in group['clocks'].items(): + if source not in aon_clocks: + # All these clocks start with `clk_` which is redundant. + clock_name = Name.from_snake_case(name).remove_part("clk") + docstring = "Clock {} in group {}".format( + name, group['name']) + if group["sw_cg"] == "yes": + gateable_clocks.add_constant(clock_name, docstring) + elif group["sw_cg"] == "hint": + hintable_clocks.add_constant(clock_name, docstring) + + gateable_clocks.add_last_constant("Last Valid Gateable Clock") + hintable_clocks.add_last_constant("Last Valid Hintable Clock") + + self.clkmgr_gateable_clocks = gateable_clocks + self.clkmgr_hintable_clocks = hintable_clocks diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/gen_dv.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/gen_dv.py new file mode 100644 index 00000000..5e2beaa1 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/gen_dv.py @@ -0,0 +1,46 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +from typing import Optional, Tuple + +from mako import exceptions # type: ignore +from mako.lookup import TemplateLookup # type: ignore +from pkg_resources import resource_filename + +from reggen.gen_dv import gen_core_file + +from .top import Top + + +def sv_base_addr(top: Top, if_name: Tuple[str, Optional[str]]) -> str: + '''Get the base address of a device interface in SV syntax''' + return "{}'h{:x}".format(top.regwidth, top.if_addrs[if_name]) + + +def gen_dv(top: Top, + dv_base_prefix: str, + outdir: str) -> int: + '''Generate DV RAL model for a Top''' + # Read template + lookup = TemplateLookup(directories=[resource_filename('topgen', '.'), + resource_filename('reggen', '.')]) + uvm_reg_tpl = lookup.get_template('top_uvm_reg.sv.tpl') + + # Expand template + try: + to_write = uvm_reg_tpl.render(top=top, + dv_base_prefix=dv_base_prefix) + except: # noqa: E722 + log.error(exceptions.text_error_template().render()) + return 1 + + # Dump to output file + dest_path = '{}/chip_ral_pkg.sv'.format(outdir) + with open(dest_path, 'w') as fout: + fout.write(to_write) + + gen_core_file(outdir, 'chip', dv_base_prefix, ['chip_ral_pkg.sv']) + + return 0 diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/intermodule.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/intermodule.py new file mode 100644 index 00000000..d1048c12 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/intermodule.py @@ -0,0 +1,1005 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import re +from collections import OrderedDict +from enum import Enum +from typing import Dict, List, Tuple + +from reggen.ip_block import IpBlock +from reggen.inter_signal import InterSignal +from reggen.validate import check_int +from topgen import lib + +IM_TYPES = ['uni', 'req_rsp'] +IM_ACTS = ['req', 'rsp', 'rcv'] +IM_VALID_TYPEACT = {'uni': ['req', 'rcv'], 'req_rsp': ['req', 'rsp']} +IM_CONN_TYPE = ['1-to-1', '1-to-N', 'broadcast'] + + +class ImType(Enum): + Uni = 1 + ReqRsp = 2 + + +class ImAct(Enum): + Req = 1 + Rsp = 2 + Rcv = 3 + + +class ImConn(Enum): + OneToOne = 1 # req <-> {rsp,rcv} with same width + OneToN = 2 # req width N <-> N x {rsp,rcv}s width 1 + Broadcast = 3 # req width 1 <-> N x rcvs width 1 + + +def intersignal_format(req: Dict) -> str: + """Determine the signal format of the inter-module connections + + @param[req] Request struct. It has instance name, package format + and etc. + """ + + # TODO: Handle array signal + result = "{req}_{struct}".format(req=req["inst_name"], struct=req["name"]) + + # check signal length if exceeds 100 + + # 7 : space + . + # 3 : _{i|o}( + # 6 : _{req|rsp}), + req_length = 7 + len(req["name"]) + 3 + len(result) + 6 + + if req_length > 100: + logmsg = "signal {0} length cannot be greater than 100" + log.warning(logmsg.format(result)) + log.warning("Please consider shorten the instance name") + return result + + +def get_suffixes(ims: OrderedDict) -> Tuple[str, str]: + """Get suffixes of the struct. + + TL-UL struct uses `h2d`, `d2h` suffixes for req, rsp pair. + """ + if ims["package"] == "tlul_pkg" and ims["struct"] == "tl": + return ("_h2d", "_d2h") + + return ("_req", "_rsp") + + +def add_intermodule_connection(obj: OrderedDict, req_m: str, req_s: str, + rsp_m: str, rsp_s: str): + """Add if doesn't exist the connection + + Add a connection into obj['inter_module']['connect'] dictionary if doesn't exist. + + Parameters: + obj: Top dictionary object + req_m: Requester module name + req_s: Requester signal name + rsp_m: Responder module name + rsp_s: Responder signal name + + Returns: + No return type for this function + """ + req_key = "{}.{}".format(req_m, req_s) + rsp_key = "{}.{}".format(rsp_m, rsp_s) + + connect = obj["inter_module"]["connect"] + if req_key in connect: + # check if rsp has data + if rsp_key in connect[req_key]: + return + req_key.append(rsp_key) + return + + # req_key is not in connect: + # check if rsp_key + if rsp_key in connect: + # check if rsp has data + if req_key in connect[rsp_key]: + return + rsp_key.append(req_key) + return + + # Add new key and connect + connect[req_key] = [rsp_key] + + +def autoconnect_xbar(topcfg: OrderedDict, + name_to_block: Dict[str, IpBlock], + xbar: OrderedDict) -> None: + # The crossbar is connecting to modules and memories in topcfg, plus + # possible external connections. Make indices for the modules and memories + # for quick lookup and add some assertions to make sure no name appears in + # multiple places. + name_to_module = {} + for mod in topcfg['module']: + assert mod['name'] not in name_to_module + if lib.is_inst(mod): + name_to_module[mod['name']] = mod + + name_to_memory = {} + for mem in topcfg['memory']: + assert mem['name'] not in name_to_memory + if lib.is_inst(mem): + name_to_memory[mem['name']] = mem + + # The names of modules and memories should be disjoint + assert not (set(name_to_module.keys()) & set(name_to_memory.keys())) + + external_names = (set(topcfg['inter_module']['top']) | + set(topcfg["inter_module"]["external"].keys())) + + ports = [x for x in xbar["nodes"] if x["type"] in ["host", "device"]] + for port in ports: + # Here, we expect port_name to either be a single identifier (in which + # case, it's taken as the name of some module or memory) to be a dotted + # pair MOD.INAME where MOD is the name of some module and INAME is the + # associated interface name. + name_parts = port['name'].split('.', 1) + port_base = name_parts[0] + port_iname = name_parts[1] if len(name_parts) > 1 else None + esc_name = port['name'].replace('.', '__') + + if port["xbar"]: + if port_iname is not None: + log.error('A crossbar connection may not ' + 'have a target of the form MOD.INAME (saw {!r})' + .format(port['name'])) + continue + + if port["type"] == "host": + # Skip as device will add connection + continue + + # Device port adds signal + add_intermodule_connection(obj=topcfg, + req_m=xbar["name"], + req_s="tl_" + esc_name, + rsp_m=esc_name, + rsp_s="tl_" + xbar["name"]) + continue # xbar port case + + port_mod = name_to_module.get(port_base) + port_mem = name_to_memory.get(port_base) + assert port_mod is None or port_mem is None + + if not (port_mod or port_mem): + # if not in module, memory, should be existed in top or ext field + module_key = "{}.tl_{}".format(xbar["name"], esc_name) + if module_key not in external_names: + log.error("Inter-module key {} cannot be found in module, " + "memory, top, or external lists.".format(module_key)) + + continue + + if port_iname is not None and port_mem is not None: + log.error('Cannot make connection for {!r}: the base of the name ' + 'points to a memory but memories do not support ' + 'interface names.' + .format(port['name'])) + + is_host = port['type'] == 'host' + + # If the hit is a module, it originally came from reggen (via + # merge.py's amend_ip() function). In this case, we should have a + # BusInterfaces object as well as a list of InterSignal objects. + # + # If not, this is a memory that will just have a dictionary of inter + # signals. + if port_mod is not None: + block = name_to_block[port_mod['type']] + try: + sig_name = block.bus_interfaces.find_port_name(is_host, + port_iname) + except KeyError: + log.error('Cannot make {} connection for {!r}: the base of ' + 'the target module has no matching bus interface.' + .format('host' if is_host else 'device', + port['name'])) + continue + else: + inter_signal_list = port_mem['inter_signal_list'] + act = 'req' if is_host else 'rsp' + matches = [ + x for x in inter_signal_list + if (x.get('package') == 'tlul_pkg' and + x['struct'] == 'tl' and + x['act'] == act) + ] + if not matches: + log.error('Cannot make {} connection for {!r}: the memory ' + 'has no signal with an action of {}.' + .format('host' if is_host else 'device', + port['name'], + act)) + continue + + assert len(matches) == 1 + sig_name = matches[0]['name'] + + add_intermodule_connection(obj=topcfg, + req_m=port_base, + req_s=sig_name, + rsp_m=xbar["name"], + rsp_s="tl_" + esc_name) + + +def autoconnect(topcfg: OrderedDict, name_to_block: Dict[str, IpBlock]): + """Matching the connection based on the naming rule + between {memory, module} <-> Xbar. + """ + + # Add xbar connection to the modules, memories + for xbar in topcfg["xbar"]: + autoconnect_xbar(topcfg, name_to_block, xbar) + + +def _get_default_name(sig, suffix): + """Generate default for a net if one does not already exist. + """ + + # The else case covers the scenario where neither package nor default is provided. + # Specifically, the interface is 'logic' and has no default value. + # In this situation, just return 0's + if sig['default']: + return sig['default'] + elif sig['package']: + return "{}::{}_DEFAULT".format(sig['package'], (sig["struct"] + suffix).upper()) + else: + return "'0" + + +def elab_intermodule(topcfg: OrderedDict): + """Check the connection of inter-module and categorize them + + In the top template, it uses updated inter_module fields to create + connections between the modules (incl. memories). This function is to + create and check the validity of the connections `inter_module` using IPs' + `inter_signal_list`. + """ + + list_of_intersignals = [] + + if "inter_signal" not in topcfg: + topcfg["inter_signal"] = OrderedDict() + + # Gather the inter_signal_list + instances = topcfg["module"] + topcfg["memory"] + topcfg["xbar"] + \ + topcfg["host"] + topcfg["port"] + + for x in instances: + old_isl = x.get('inter_signal_list') + if old_isl is None: + continue + + new_isl = [] + for entry in old_isl: + # Convert any InterSignal objects to the expected dictionary format. + sig = (entry.as_dict() + if isinstance(entry, InterSignal) + else entry.copy()) + + # Add instance name to the entry and add to list_of_intersignals + sig["inst_name"] = x["name"] + list_of_intersignals.append(sig) + new_isl.append(sig) + + x['inter_signal_list'] = new_isl + + # Add field to the topcfg + topcfg["inter_signal"]["signals"] = list_of_intersignals + + # TODO: Cross check Can be done here not in validate as ipobj is not + # available in validate + error = check_intermodule(topcfg, "Inter-module Check") + assert error == 0, "Inter-module validation is failed cannot move forward." + + # intermodule + definitions = [] + + # Check the originator + # As inter-module connection allow only 1:1, 1:N, or N:1, pick the most + # common signals. If a requester connects to multiple responders/receivers, + # the requester is main connector so that the definition becomes array. + # + # For example: + # inter_module: { + # 'connect': { + # 'pwr_mgr.pwrup': ['lc.pwrup', 'otp.pwrup'] + # } + # } + # The tool adds `struct [1:0] pwr_mgr_pwrup` + # It doesn't matter whether `pwr_mgr.pwrup` is requester or responder. + # If the key is responder type, then the connection is made in reverse, + # such that `lc.pwrup --> pwr_mgr.pwrup[0]` and + # `otp.pwrup --> pwr_mgr.pwrup[1]` + + uid = 0 # Unique connection ID across the top + + for req, rsps in topcfg["inter_module"]["connect"].items(): + log.info("{req} --> {rsps}".format(req=req, rsps=rsps)) + + # Split index + req_module, req_signal, req_index = filter_index(req) + + # get the module signal + req_struct = find_intermodule_signal(list_of_intersignals, req_module, + req_signal) + + # decide signal format based on the `key` + sig_name = intersignal_format(req_struct) + req_struct["top_signame"] = sig_name + + # Find package in req, rsps + if "package" in req_struct: + package = req_struct["package"] + else: + for rsp in rsps: + rsp_module, rsp_signal, rsp_index = filter_index(rsp) + rsp_struct = find_intermodule_signal(list_of_intersignals, + rsp_module, rsp_signal) + if "package" in rsp_struct: + package = rsp_struct["package"] + break + if not package: + package = "" + + # Add to definition + if req_struct["type"] == "req_rsp": + req_suffix, rsp_suffix = get_suffixes(req_struct) + req_default = _get_default_name(req_struct, req_suffix) + rsp_default = _get_default_name(req_struct, rsp_suffix) + + # based on the active direction of the req_struct, one of the directions does not + # need a default since it will be an output + if (req_struct["act"] == 'req'): + req_default = '' + else: + rsp_default = '' + + # Add two definitions + definitions.append( + OrderedDict([('package', package), + ('struct', req_struct["struct"] + req_suffix), + ('signame', sig_name + "_req"), + ('width', req_struct["width"]), + ('type', req_struct["type"]), + ('end_idx', req_struct["end_idx"]), + ('act', req_struct["act"]), + ('suffix', "req"), + ('default', req_default)])) + definitions.append( + OrderedDict([('package', package), + ('struct', req_struct["struct"] + rsp_suffix), + ('signame', sig_name + "_rsp"), + ('width', req_struct["width"]), + ('type', req_struct["type"]), + ('end_idx', req_struct["end_idx"]), + ('act', req_struct["act"]), + ('suffix', "rsp"), + ('default', rsp_default)])) + else: + # unidirection + default = _get_default_name(req_struct, "") + definitions.append( + OrderedDict([('package', package), + ('struct', req_struct["struct"]), + ('signame', sig_name), + ('width', req_struct["width"]), + ('type', req_struct["type"]), + ('end_idx', req_struct["end_idx"]), + ('act', req_struct["act"]), + ('suffix', ""), + ('default', default)])) + + req_struct["index"] = -1 + + for i, rsp in enumerate(rsps): + # Split index + rsp_module, rsp_signal, rsp_index = filter_index(rsp) + + rsp_struct = find_intermodule_signal(list_of_intersignals, + rsp_module, rsp_signal) + + # determine the signal name + + rsp_struct["top_signame"] = sig_name + if req_struct["type"] == "uni" and req_struct[ + "top_type"] == "broadcast": + rsp_struct["index"] = -1 + elif rsp_struct["width"] == req_struct["width"] and len(rsps) == 1: + rsp_struct["index"] = -1 + else: + rsp_struct["index"] = -1 if req_struct["width"] == 1 else i + + # Assume it is logic + # req_rsp doesn't allow logic + if req_struct["struct"] == "logic": + assert req_struct[ + "type"] != "req_rsp", "logic signal cannot have req_rsp type" + + # increase Unique ID + uid += 1 + + # TODO: Check unconnected port + if "top" not in topcfg["inter_module"]: + topcfg["inter_module"]["top"] = [] + + for s in topcfg["inter_module"]["top"]: + sig_m, sig_s, sig_i = filter_index(s) + assert sig_i == -1, 'top net connection should not use bit index' + sig = find_intermodule_signal(list_of_intersignals, sig_m, sig_s) + sig_name = intersignal_format(sig) + sig["top_signame"] = sig_name + if "index" not in sig: + sig["index"] = -1 + + if sig["type"] == "req_rsp": + req_suffix, rsp_suffix = get_suffixes(sig) + # Add two definitions + definitions.append( + OrderedDict([('package', sig["package"]), + ('struct', sig["struct"] + req_suffix), + ('signame', sig_name + "_req"), + ('width', sig["width"]), ('type', sig["type"]), + ('end_idx', -1), + ('default', sig["default"])])) + definitions.append( + OrderedDict([('package', sig["package"]), + ('struct', sig["struct"] + rsp_suffix), + ('signame', sig_name + "_rsp"), + ('width', sig["width"]), ('type', sig["type"]), + ('end_idx', -1), + ('default', sig["default"])])) + else: # if sig["type"] == "uni": + definitions.append( + OrderedDict([('package', sig["package"]), + ('struct', sig["struct"]), ('signame', sig_name), + ('width', sig["width"]), ('type', sig["type"]), + ('end_idx', -1), + ('default', sig["default"])])) + + topcfg["inter_module"].setdefault('external', []) + topcfg["inter_signal"].setdefault('external', []) + + for s, port in topcfg["inter_module"]["external"].items(): + sig_m, sig_s, sig_i = filter_index(s) + assert sig_i == -1, 'top net connection should not use bit index' + sig = find_intermodule_signal(list_of_intersignals, sig_m, sig_s) + + # To make netname `_o` or `_i` + sig['external'] = True + + sig_name = port if port != "" else intersignal_format(sig) + + # if top signame already defined, then a previous connection category + # is already connected to external pin. Sig name is only used for + # port definition + conn_type = False + if "top_signame" not in sig: + sig["top_signame"] = sig_name + else: + conn_type = True + + if "index" not in sig: + sig["index"] = -1 + + # Add the port definition to top external ports + index = sig["index"] + netname = sig["top_signame"] + if sig["type"] == "req_rsp": + req_suffix, rsp_suffix = get_suffixes(sig) + if sig["act"] == "req": + req_sigsuffix, rsp_sigsuffix = ("_o", "_i") + + else: + req_sigsuffix, rsp_sigsuffix = ("_i", "_o") + + topcfg["inter_signal"]["external"].append( + OrderedDict([('package', sig["package"]), + ('struct', sig["struct"] + req_suffix), + ('signame', sig_name + "_req" + req_sigsuffix), + ('width', sig["width"]), ('type', sig["type"]), + ('default', sig["default"]), + ('direction', + 'out' if sig['act'] == "req" else 'in'), + ('conn_type', conn_type), + ('index', index), + ('netname', netname + req_suffix)])) + topcfg["inter_signal"]["external"].append( + OrderedDict([('package', sig["package"]), + ('struct', sig["struct"] + rsp_suffix), + ('signame', sig_name + "_rsp" + rsp_sigsuffix), + ('width', sig["width"]), ('type', sig["type"]), + ('default', sig["default"]), + ('direction', + 'in' if sig['act'] == "req" else 'out'), + ('conn_type', conn_type), + ('index', index), + ('netname', netname + rsp_suffix)])) + else: # uni + if sig["act"] == "req": + sigsuffix = "_o" + else: + sigsuffix = "_i" + topcfg["inter_signal"]["external"].append( + OrderedDict([('package', sig.get("package", "")), + ('struct', sig["struct"]), + ('signame', sig_name + sigsuffix), + ('width', sig["width"]), ('type', sig["type"]), + ('default', sig["default"]), + ('direction', + 'out' if sig['act'] == "req" else 'in'), + ('conn_type', conn_type), + ('index', index), + ('netname', netname)])) + + for sig in topcfg["inter_signal"]["signals"]: + # Check if it exist in definitions + if "top_signame" in sig: + continue + + # Set index to -1 + sig["index"] = -1 + + # TODO: Handle the unconnected port rule + + if "definitions" not in topcfg["inter_signal"]: + topcfg["inter_signal"]["definitions"] = definitions + + +def filter_index(signame: str) -> Tuple[str, str, int]: + """If the signal has array indicator `[N]` then split and return name and + array index. If not, array index is -1. + + param signame module.sig{[N]} + + result (module_name, signal_name, array_index) + """ + m = re.match(r'(\w+)\.(\w+)(\[(\d+)\])*', signame) + + if not m: + # Cannot match the pattern + return "", "", -1 + + if m.group(3): + # array index is not None + return m.group(1), m.group(2), m.group(4) + + return m.group(1), m.group(2), -1 + + +def find_intermodule_signal(sig_list, m_name, s_name) -> Dict: + """Return the intermodule signal structure + """ + + filtered = [ + x for x in sig_list if x["name"] == s_name and x["inst_name"] == m_name + ] + + if len(filtered) == 1: + return filtered[0] + + log.error("Found {num} entry/entries for {m_name}.{s_name}:".format( + num=len(filtered), m_name=m_name, s_name=s_name)) + return None + + +# Validation +def check_intermodule_field(sig: OrderedDict, + prefix: str = "") -> Tuple[int, OrderedDict]: + error = 0 + + # type check + if sig["type"] not in IM_TYPES: + log.error("{prefix} Inter_signal {name} " + "type {type} is incorrect.".format(prefix=prefix, + name=sig["name"], + type=sig["type"])) + error += 1 + + if sig["act"] not in IM_ACTS: + log.error("{prefix} Inter_signal {name} " + "act {act} is incorrect.".format(prefix=prefix, + name=sig["name"], + act=sig["act"])) + error += 1 + + # Check if type and act are matched + if error == 0: + if sig["act"] not in IM_VALID_TYPEACT[sig['type']]: + log.error("{type} and {act} of {name} are not a valid pair." + "".format(type=sig['type'], + act=sig['act'], + name=sig['name'])) + error += 1 + # Check 'width' field + width = 1 + if "width" not in sig: + sig["width"] = 1 + elif not isinstance(sig["width"], int): + width, err = check_int(sig["width"], sig["name"]) + if err: + log.error("{prefix} Inter-module {inst}.{sig} 'width' " + "should be int type.".format(prefix=prefix, + inst=sig["inst_name"], + sig=sig["name"])) + error += 1 + else: + # convert to int value + sig["width"] = width + + # Add empty string if no explicit default for dangling pins is given. + # In that case, dangling pins of type struct will be tied to the default + # parameter in the corresponding package, and dangling pins of type logic + # will be tied off to '0. + if "default" not in sig: + sig["default"] = "" + + if "package" not in sig: + sig["package"] = "" + + return error, sig + + +def find_otherside_modules(topcfg: OrderedDict, m, + s) -> List[Tuple[str, str, str]]: + """Find far-end port based on given module and signal name + """ + # TODO: handle special cases + special_inst_names = { + ('main', 'tl_rom'): ('tl_adapter_rom', 'tl'), + ('main', 'tl_ram_main'): ('tl_adapter_ram_main', 'tl'), + ('main', 'tl_eflash'): ('tl_adapter_eflash', 'tl'), + ('peri', 'tl_ram_ret_aon'): ('tl_adapter_ram_ret_aon', 'tl'), + ('main', 'tl_corei'): ('rv_core_ibex', 'tl_i'), + ('main', 'tl_cored'): ('rv_core_ibex', 'tl_d'), + ('main', 'tl_dm_sba'): ('dm_top', 'tl_h'), + ('main', 'tl_debug_mem'): ('dm_top', 'tl_d'), + ('peri', 'tl_ast'): ('ast', 'tl') + } + special_result = special_inst_names.get((m, s)) + if special_result is not None: + return [('top', special_result[0], special_result[1])] + + signame = "{}.{}".format(m, s) + for req, rsps in topcfg["inter_module"]["connect"].items(): + if req.startswith(signame): + # return rsps after splitting module instance name and the port + result = [] + for rsp in rsps: + rsp_m, rsp_s, rsp_i = filter_index(rsp) + result.append(('connect', rsp_m, rsp_s)) + return result + + for rsp in rsps: + if signame == rsp: + req_m, req_s, req_i = filter_index(req) + return [('connect', req_m, req_s)] + + # if reaches here, it means either the format is wrong, or floating port. + log.error("`find_otherside_modules()`: " + "No such signal {}.{} exists.".format(m, s)) + return [] + + +def check_intermodule(topcfg: Dict, prefix: str) -> int: + if "inter_module" not in topcfg: + return 0 + + total_error = 0 + + for req, rsps in topcfg["inter_module"]["connect"].items(): + error = 0 + # checking the key, value are in correct format + # Allowed format + # 1. module.signal + # 2. module.signal[index] // Remember array is not yet supported + # // But allow in format checker + # + # Example: + # inter_module: { + # 'connect': { + # 'flash_ctrl.flash': ['eflash.flash_ctrl'], + # 'life_cycle.provision': ['debug_tap.dbg_en', 'dft_ctrl.en'], + # 'otp.pwr_hold': ['pwrmgr.peri[0]'], + # 'flash_ctrl.pwr_hold': ['pwrmgr.peri[1]'], + # } + # } + # + # If length of value list is > 1, then key should be array (width need to match) + # If key is format #2, then length of value list shall be 1 + # If one of the value is format #2, then the key should be 1 bit width and + # entries of value list should be 1 + req_m, req_s, req_i = filter_index(req) + + if req_s == "": + log.error( + "Cannot parse the inter-module signal key '{req}'".format( + req=req)) + error += 1 + + # Check rsps signal format is list + if not isinstance(rsps, list): + log.error("Value of key '{req}' should be a list".format(req=req)) + error += 1 + continue + + req_struct = find_intermodule_signal(topcfg["inter_signal"]["signals"], + req_m, req_s) + + err, req_struct = check_intermodule_field(req_struct) + error += err + + if req_i != -1 and len(rsps) != 1: + # Array format should have one entry + log.error( + "If key {req} has index, only one entry is allowed.".format( + req=req)) + error += 1 + + total_width = 0 + widths = [] + + # Check rsp format + for i, rsp in enumerate(rsps): + rsp_m, rsp_s, rsp_i = filter_index(rsp) + if rsp_s == "": + log.error( + "Cannot parse the inter-module signal key '{req}->{rsp}'". + format(req=req, rsp=rsp)) + error += 1 + + rsp_struct = find_intermodule_signal( + topcfg["inter_signal"]["signals"], rsp_m, rsp_s) + + err, rsp_struct = check_intermodule_field(rsp_struct) + error += err + + total_width += rsp_struct["width"] + widths.append(rsp_struct["width"]) + + # Type check + # If no package was declared, it is declared with an empty string + if not rsp_struct["package"]: + rsp_struct["package"] = req_struct.get("package", "") + elif req_struct["package"] != rsp_struct["package"]: + log.error( + "Inter-module package should be matched: " + "{req}->{rsp} exp({expected}), actual({actual})".format( + req=req_struct["name"], + rsp=rsp_struct["name"], + expected=req_struct["package"], + actual=rsp_struct["package"])) + error += 1 + if req_struct["type"] != rsp_struct["type"]: + log.error( + "Inter-module type should be matched: " + "{req}->{rsp} exp({expected}), actual({actual})".format( + req=req_struct["name"], + rsp=rsp_struct["name"], + expected=req_struct["type"], + actual=rsp_struct["type"])) + error += 1 + + # If len(rsps) is 1, then the width should be matched to req + if req_struct["width"] != 1: + if rsp_struct["width"] not in [1, req_struct["width"]]: + log.error( + "If req {req} is an array, " + "rsp {rsp} shall be non-array or array with same width" + .format(req=req, rsp=rsp)) + error += 1 + + elif rsp_i != -1: + # If rsp has index, req should be width 1 + log.error( + "If rsp {rsp} has an array index, only one-to-one map is allowed." + .format(rsp=rsp)) + error += 1 + + # Determine if broadcast or one-to-N + log.debug("Handling inter-sig {} {}".format(req_struct['name'], total_width)) + req_struct["end_idx"] = -1 + if req_struct["width"] > 1 or len(rsps) != 1: + # If req width is same to the every width of rsps ==> broadcast + if len(rsps) * [req_struct["width"]] == widths: + log.debug("broadcast type") + req_struct["top_type"] = "broadcast" + + # If req width is same as total width of rsps ==> one-to-N + elif req_struct["width"] == total_width: + log.debug("one-to-N type") + req_struct["top_type"] = "one-to-N" + + # one-to-N connection is not fully populated + elif req_struct["width"] > total_width: + log.debug("partial one-to-N type") + req_struct["top_type"] = "partial-one-to-N" + req_struct["end_idx"] = len(rsps) + + # If not, error + else: + log.error("'uni' type connection {req} should be either " + "OneToN or Broadcast".format(req=req)) + error += 1 + + elif req_struct["type"] == "uni": + # one-to-one connection + req_struct["top_type"] = "broadcast" + + # If req is array, it is not allowed to have partial connections. + # Doing for loop again here: Make code separate from other checker + # for easier maintenance + total_error += error + + if error != 0: + # Skip the check + continue + + for item in topcfg["inter_module"]["top"] + list( + topcfg["inter_module"]["external"].keys()): + sig_m, sig_s, sig_i = filter_index(item) + if sig_i != -1: + log.error("{item} cannot have index".format(item=item)) + total_error += 1 + + sig_struct = find_intermodule_signal(topcfg["inter_signal"]["signals"], + sig_m, sig_s) + err, sig_struct = check_intermodule_field(sig_struct) + total_error += err + + return total_error + + +# Template functions +def im_defname(obj: OrderedDict) -> str: + """return definition struct name + + e.g. flash_ctrl::flash_req_t + """ + if obj["package"] == "": + # should be logic + return "logic" + + return "{package}::{struct}_t".format(package=obj["package"], + struct=obj["struct"]) + + +def im_netname(sig: OrderedDict, + suffix: str = "", default_name=False) -> str: + """return top signal name with index + + It also adds suffix for external signal. + + The default name input forces function to return default name, even if object + has a connection. + """ + + # Basic check and add missing fields + err, obj = check_intermodule_field(sig) + assert not err + + # Floating signals + # TODO: Find smarter way to assign default? + if "top_signame" not in obj or default_name: + if obj["act"] == "req" and suffix == "req": + return "" + if obj["act"] == "rsp" and suffix == "rsp": + return "" + if obj["act"] == "req" and suffix == "rsp": + # custom default has been specified + if obj["default"]: + return obj["default"] + if obj["package"] == "tlul_pkg" and obj["struct"] == "tl": + return "{package}::{struct}_D2H_DEFAULT".format( + package=obj["package"], struct=obj["struct"].upper()) + return "{package}::{struct}_RSP_DEFAULT".format( + package=obj["package"], struct=obj["struct"].upper()) + if obj["act"] == "rsp" and suffix == "req": + # custom default has been specified + if obj["default"]: + return obj["default"] + if obj.get("package") == "tlul_pkg" and obj["struct"] == "tl": + return "{package}::{struct}_H2D_DEFAULT".format( + package=obj["package"], struct=obj["struct"].upper()) + # default is used for dangling ports in definitions. + # the struct name already has `_req` suffix + return "{package}::{struct}_REQ_DEFAULT".format( + package=obj.get("package", ''), struct=obj["struct"].upper()) + if obj["act"] == "rcv" and suffix == "" and obj["struct"] == "logic": + # custom default has been specified + if obj["default"]: + return obj["default"] + return "'0" + if obj["act"] == "rcv" and suffix == "": + # custom default has been specified + if obj["default"]: + return obj["default"] + return "{package}::{struct}_DEFAULT".format( + package=obj["package"], struct=obj["struct"].upper()) + + return "" + + # Connected signals + assert suffix in ["", "req", "rsp"] + + suffix_s = "_{suffix}".format(suffix=suffix) if suffix != "" else suffix + + # External signal handling + if "external" in obj and obj["external"]: + pairs = { + # act , suffix: additional suffix + ("req", "req"): "_o", + ("req", "rsp"): "_i", + ("rsp", "req"): "_i", + ("rsp", "rsp"): "_o", + ("req", ""): "_o", + ("rcv", ""): "_i" + } + suffix_s += pairs[(obj['act'], suffix)] + + return "{top_signame}{suffix}{index}".format( + top_signame=obj["top_signame"], + suffix=suffix_s, + index=lib.index(obj["index"])) + + +def im_portname(obj: OrderedDict, suffix: str = "") -> str: + """return IP's port name + + e.g signame_o for requester req signal + """ + act = obj['act'] + name = obj['name'] + + if suffix == "": + suffix_s = "_o" if act == "req" else "_i" + elif suffix == "req": + suffix_s = "_o" if act == "req" else "_i" + else: + suffix_s = "_o" if act == "rsp" else "_i" + + return name + suffix_s + + +def get_dangling_im_def(objs: OrderedDict) -> str: + """return partial inter-module definitions + + Dangling intermodule connections happen when a one-to-N assignment + is not fully populated. + + This can result in two types of dangling: + - outgoing requests not used + - incoming responses not driven + + The determination of which category we fall into follows similar rules + as those used by im_netname. + + When the direction of the net is the same as the active direction of the + the connecting module, it is "unused". + + When the direction of the net is opposite of the active direction of the + the connecting module, it is "undriven". + + As an example, edn is defined as "rsp" of a "req_rsp" pair. It is also used + as the "active" module in inter-module connection. If there are not enough + connecting modules, the 'req' line is undriven, while the 'rsp' line is + unused. + + """ + unused_def = [obj for obj in objs if obj['end_idx'] > 0 and + obj['act'] == obj['suffix']] + + undriven_def = [obj for obj in objs if obj['end_idx'] > 0 and + (obj['act'] == 'req' and obj['suffix'] == 'rsp' or + obj['act'] == 'rsp' and obj['suffix'] == 'req')] + + return unused_def, undriven_def diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/lib.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/lib.py new file mode 100644 index 00000000..a1354fdf --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/lib.py @@ -0,0 +1,497 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import re +import sys +from collections import OrderedDict +from copy import deepcopy +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +import hjson + +from reggen.ip_block import IpBlock + +# Ignore flake8 warning as the function is used in the template +# disable isort formating, as conflicting with flake8 +from .intermodule import find_otherside_modules # noqa : F401 # isort:skip +from .intermodule import im_portname, im_defname, im_netname # noqa : F401 # isort:skip +from .intermodule import get_dangling_im_def # noqa : F401 # isort:skip + + +class Name: + """ + We often need to format names in specific ways; this class does so. + + To simplify parsing and reassembling of name strings, this class + stores the name parts as a canonical list of strings internally + (in self.parts). + + The "from_*" functions parse and split a name string into the canonical + list, whereas the "as_*" functions reassemble the canonical list in the + format specified. + + For example, ex = Name.from_snake_case("example_name") gets split into + ["example", "name"] internally, and ex.as_camel_case() reassembles this + internal representation into "ExampleName". + """ + def __add__(self, other): + return Name(self.parts + other.parts) + + @staticmethod + def from_snake_case(input: str) -> 'Name': + return Name(input.split("_")) + + def __init__(self, parts: List[str]): + self.parts = parts + for p in parts: + assert len(p) > 0, "cannot add zero-length name piece" + + def as_snake_case(self) -> str: + return "_".join([p.lower() for p in self.parts]) + + def as_camel_case(self) -> str: + out = "" + for p in self.parts: + # If we're about to join two parts which would introduce adjacent + # numbers, put an underscore between them. + if out[-1:].isnumeric() and p[:1].isnumeric(): + out += "_" + p + else: + out += p.capitalize() + return out + + def as_c_define(self) -> str: + return "_".join([p.upper() for p in self.parts]) + + def as_c_enum(self) -> str: + return "k" + self.as_camel_case() + + def as_c_type(self) -> str: + return self.as_snake_case() + "_t" + + def remove_part(self, part_to_remove: str) -> "Name": + return Name([p for p in self.parts if p != part_to_remove]) + + +def is_ipcfg(ip: Path) -> bool: # return bool + log.info("IP Path: %s" % repr(ip)) + ip_name = ip.parents[1].name + hjson_name = ip.name + + log.info("IP Name(%s) and HJSON name (%s)" % (ip_name, hjson_name)) + + if ip_name + ".hjson" == hjson_name or ip_name + "_reg.hjson" == hjson_name: + return True + return False + + +def search_ips(ip_path): # return list of config files + # list the every Hjson file + p = ip_path.glob('*/data/*.hjson') + + # filter only ip_name/data/ip_name{_reg|''}.hjson + ips = [x for x in p if is_ipcfg(x)] + + log.info("Filtered-in IP files: %s" % repr(ips)) + return ips + + +def is_xbarcfg(xbar_obj): + if "type" in xbar_obj and xbar_obj["type"] == "xbar": + return True + + return False + + +def get_hjsonobj_xbars(xbar_path): + """ Search crossbars Hjson files from given path. + + Search every Hjson in the directory and check Hjson type. + It could be type: "top" or type: "xbar" + returns [(name, obj), ... ] + """ + p = xbar_path.glob('*.hjson') + try: + xbar_objs = [ + hjson.load(x.open('r'), + use_decimal=True, + object_pairs_hook=OrderedDict) for x in p + ] + except ValueError: + raise SystemExit(sys.exc_info()[1]) + + xbar_objs = [x for x in xbar_objs if is_xbarcfg(x)] + + return xbar_objs + + +def get_module_by_name(top, name): + """Search in top["module"] by name + """ + module = None + for m in top["module"]: + if m["name"] == name: + module = m + break + + return module + + +def intersignal_to_signalname(top, m_name, s_name) -> str: + + # TODO: Find the signal in the `inter_module_list` and get the correct signal name + + return "{m_name}_{s_name}".format(m_name=m_name, s_name=s_name) + + +def get_package_name_by_intermodule_signal(top, struct) -> str: + """Search inter-module signal package with the struct name + + For instance, if `flash_ctrl` has inter-module signal package, + this function returns the package name + """ + instances = top["module"] + top["memory"] + + intermodule_instances = [ + x["inter_signal_list"] for x in instances if "inter_signal_list" in x + ] + + for m in intermodule_instances: + if m["name"] == struct and "package" in m: + return m["package"] + return "" + + +def get_signal_by_name(module, name): + """Return the signal struct with the type input/output/inout + """ + result = None + for s in module["available_input_list"] + module[ + "available_output_list"] + module["available_inout_list"]: + if s["name"] == name: + result = s + break + + return result + + +def add_module_prefix_to_signal(signal, module): + """Add module prefix to module signal format { name: "sig_name", width: NN } + """ + result = deepcopy(signal) + + if "name" not in signal: + raise SystemExit("signal {} doesn't have name field".format(signal)) + + result["name"] = module + "_" + signal["name"] + result["module_name"] = module + + return result + + +def get_ms_name(name): + """Split module_name.signal_name to module_name , signal_name + """ + + tokens = name.split('.') + + if len(tokens) == 0: + raise SystemExit("This to be catched in validate.py") + + module = tokens[0] + signal = None + if len(tokens) == 2: + signal = tokens[1] + + return module, signal + + +def parse_pad_field(padstr): + """Parse PadName[NN...NN] or PadName[NN] or just PadName + """ + match = re.match(r'^([A-Za-z0-9_]+)(\[([0-9]+)(\.\.([0-9]+))?\]|)', padstr) + return match.group(1), match.group(3), match.group(5) + + +def get_pad_list(padstr): + pads = [] + + pad, first, last = parse_pad_field(padstr) + if first is None: + first = 0 + last = 0 + elif last is None: + last = first + first = int(first, 0) + last = int(last, 0) + # width = first - last + 1 + + for p in range(first, last + 1): + pads.append(OrderedDict([("name", pad), ("index", p)])) + + return pads + + +# Template functions +def ljust(x, width): + return "{:<{width}}".format(x, width=width) + + +def bitarray(d, width): + """Print Systemverilog bit array + + @param d the bit width of the signal + @param width max character width of the signal group + + For instance, if width is 4, the max d value in the signal group could be + 9999. If d is 2, then this function pads 3 spaces at the end of the bit + slice. + + "[1:0] " <- d:=2, width=4 + "[9999:0]" <- max d-1 value + + If d is 1, it means array slice isn't necessary. So it returns empty spaces + """ + + if d <= 0: + log.error("lib.bitarray: Given value {} is smaller than 1".format(d)) + raise ValueError + if d == 1: + return " " * (width + 4) # [x:0] needs 4 more space than char_width + + out = "[{}:0]".format(d - 1) + return out + (" " * (width - len(str(d)))) + + +def parameterize(text): + """Return the value wrapping with quote if not integer nor bits + """ + if re.match(r'(\d+\'[hdb]\s*[0-9a-f_A-F]+|[0-9]+)', text) is None: + return "\"{}\"".format(text) + + return text + + +def index(i: int) -> str: + """Return index if it is not -1 + """ + return "[{}]".format(i) if i != -1 else "" + + +def get_clk_name(clk): + """Return the appropriate clk name + """ + if clk == 'main': + return 'clk_i' + else: + return "clk_{}_i".format(clk) + + +def get_reset_path(reset, domain, reset_cfg): + """Return the appropriate reset path given name + """ + # find matching node for reset + node_match = [node for node in reset_cfg['nodes'] if node['name'] == reset] + assert len(node_match) == 1 + reset_type = node_match[0]['type'] + + # find matching path + hier_path = "" + if reset_type == "int": + log.debug("{} used as internal reset".format(reset["name"])) + else: + hier_path = reset_cfg['hier_paths'][reset_type] + + # find domain selection + domain_sel = '' + if reset_type not in ["ext", "int"]: + domain_sel = "[rstmgr_pkg::Domain{}Sel]".format(domain) + + reset_path = "" + if reset_type == "ext": + reset_path = reset + else: + reset_path = "{}rst_{}_n{}".format(hier_path, reset, domain_sel) + + return reset_path + + +def get_unused_resets(top): + """Return dict of unused resets and associated domain + """ + unused_resets = OrderedDict() + unused_resets = { + reset['name']: domain + for reset in top['resets']['nodes'] + for domain in top['power']['domains'] + if reset['type'] == 'top' and domain not in reset['domains'] + } + + log.debug("Unused resets are {}".format(unused_resets)) + return unused_resets + + +def is_templated(module): + """Returns an indication where a particular module is templated + """ + if "attr" not in module: + return False + elif module["attr"] in ["templated"]: + return True + else: + return False + + +def is_top_reggen(module): + """Returns an indication where a particular module is NOT templated + and requires top level specific reggen + """ + if "attr" not in module: + return False + elif module["attr"] in ["reggen_top", "reggen_only"]: + return True + else: + return False + + +def is_inst(module): + """Returns an indication where a particular module should be instantiated + in the top level + """ + top_level_module = False + top_level_mem = False + + if "attr" not in module: + top_level_module = True + elif module["attr"] in ["normal", "templated", "reggen_top"]: + top_level_module = True + elif module["attr"] in ["reggen_only"]: + top_level_module = False + else: + raise ValueError('Attribute {} in {} is not valid' + .format(module['attr'], module['name'])) + + if module['type'] in ['rom', 'ram_1p_scr', 'eflash']: + top_level_mem = True + + return top_level_mem or top_level_module + + +def get_base_and_size(name_to_block: Dict[str, IpBlock], + inst: Dict[str, object], + ifname: Optional[str]) -> Tuple[int, int]: + min_device_spacing = 0x1000 + + block = name_to_block.get(inst['type']) + if block is None: + # If inst isn't the instantiation of a block, it came from some memory. + # Memories have their sizes defined, so we can just look it up there. + bytes_used = int(inst['size'], 0) + + # Memories don't have multiple or named interfaces, so this will only + # work if ifname is None. + assert ifname is None + base_addr = inst['base_addr'] + + else: + # If inst is the instantiation of some block, find the register block + # that corresponds to ifname + rb = block.reg_blocks.get(ifname) + if rb is None: + log.error('Cannot connect to non-existent {} device interface ' + 'on {!r} (an instance of the {!r} block)' + .format('default' if ifname is None else repr(ifname), + inst['name'], block.name)) + bytes_used = 0 + else: + bytes_used = 1 << rb.get_addr_width() + + base_addr = inst['base_addrs'][ifname] + + # Round up to min_device_spacing if necessary + size_byte = max(bytes_used, min_device_spacing) + + if isinstance(base_addr, str): + base_addr = int(base_addr, 0) + else: + assert isinstance(base_addr, int) + + return (base_addr, size_byte) + + +def get_io_enum_literal(sig: Dict, prefix: str) -> str: + """Returns the DIO pin enum literal with value assignment""" + name = Name.from_snake_case(prefix) + Name.from_snake_case(sig["name"]) + # In this case, the signal is a multibit signal, and hence + # we have to make the signal index part of the parameter + # name to uniquify it. + if sig['width'] > 1: + name += Name([str(sig['idx'])]) + return name.as_camel_case() + + +def make_bit_concatenation(sig_name: str, + indices: List[int], + end_indent: int) -> str: + '''Return SV code for concatenating certain indices from a signal + + sig_name is the name of the signal and indices is a non-empty list of the + indices to use, MSB first. So + + make_bit_concatenation("foo", [0, 100, 20]) + + should give + + {foo[0], foo[100], foo[20]} + + Adjacent bits turn into a range select. For example: + + make_bit_concatenation("foo", [0, 1, 2]) + + should give + + foo[0:2] + + If there are multiple ranges, they are printed one to a line. end_indent + gives the indentation of the closing brace and the range selects in between + get indented to end_indent + 2. + + ''' + assert 0 <= end_indent + + ranges = [] + cur_range_start = indices[0] + cur_range_end = indices[0] + for idx in indices[1:]: + if idx == cur_range_end + 1 and cur_range_start <= cur_range_end: + cur_range_end += 1 + continue + if idx == cur_range_end - 1 and cur_range_start >= cur_range_end: + cur_range_end -= 1 + continue + ranges.append((cur_range_start, cur_range_end)) + cur_range_start = idx + cur_range_end = idx + ranges.append((cur_range_start, cur_range_end)) + + items = [] + for range_start, range_end in ranges: + if range_start == range_end: + select = str(range_start) + else: + select = '{}:{}'.format(range_start, range_end) + items.append('{}[{}]'.format(sig_name, select)) + + if len(items) == 1: + return items[0] + + item_indent = '\n' + (' ' * (end_indent + 2)) + + acc = ['{', item_indent, items[0]] + for item in items[1:]: + acc += [',', item_indent, item] + acc += ['\n', ' ' * end_indent, '}'] + return ''.join(acc) diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/merge.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/merge.py new file mode 100644 index 00000000..6c0a9cd4 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/merge.py @@ -0,0 +1,1081 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import logging as log +import random +from collections import OrderedDict +from copy import deepcopy +from math import ceil, log2 +from typing import Dict, List + +from topgen import c, lib +from reggen.ip_block import IpBlock +from reggen.params import LocalParam, Parameter, RandParameter + + +def _get_random_data_hex_literal(width): + """ Fetch 'width' random bits and return them as hex literal""" + width = int(width) + literal_str = hex(random.getrandbits(width)) + return literal_str + + +def _get_random_perm_hex_literal(numel): + """ Compute a random permutation of 'numel' elements and + return as packed hex literal""" + num_elements = int(numel) + width = int(ceil(log2(num_elements))) + idx = [x for x in range(num_elements)] + random.shuffle(idx) + literal_str = "" + for k in idx: + literal_str += format(k, '0' + str(width) + 'b') + # convert to hex for space efficiency + literal_str = hex(int(literal_str, 2)) + return literal_str + + +def elaborate_instances(top, name_to_block: Dict[str, IpBlock]): + '''Add additional fields to the elements of top['module'] + + These elements represent instantiations of IP blocks. This function adds + extra fields to them to carry across information from the IpBlock objects + that represent the blocks being instantiated. See elaborate_instance for + more details of what gets added. + + ''' + # Initialize RNG for compile-time netlist constants. + random.seed(int(top['rnd_cnst_seed'])) + + for instance in top['module']: + block = name_to_block[instance['type']] + elaborate_instance(instance, block) + + +def elaborate_instance(instance, block: IpBlock): + """Add additional fields to a single instance of a module. + + instance is the instance to be filled in. block is the block that it's + instantiating. + + Altered fields: + - param_list (list of parameters for the instance) + - inter_signal_list (list of inter-module signals) + - base_addrs (a map from interface name to its base address) + + Removed fields: + - base_addr (this is reflected in base_addrs) + + """ + mod_name = instance["name"] + + # param_list + new_params = [] + for param in block.params.by_name.values(): + if isinstance(param, LocalParam): + # Remove local parameters. + continue + + new_param = param.as_dict() + + param_expose = param.expose if isinstance(param, Parameter) else False + + # Check for security-relevant parameters that are not exposed, + # adding a top-level name. + if param.name.lower().startswith("sec") and not param_expose: + log.warning("{} has security-critical parameter {} " + "not exposed to top".format( + mod_name, param.name)) + + # Move special prefixes to the beginnining of the parameter name. + param_prefixes = ["Sec", "RndCnst"] + cc_mod_name = c.Name.from_snake_case(mod_name).as_camel_case() + name_top = cc_mod_name + param.name + for prefix in param_prefixes: + if param.name.lower().startswith(prefix.lower()): + name_top = (prefix + cc_mod_name + + param.name[len(prefix):]) + break + + new_param['name_top'] = name_top + + # Generate random bits or permutation, if needed + if isinstance(param, RandParameter): + if param.randtype == 'data': + new_default = _get_random_data_hex_literal(param.randcount) + # Effective width of the random vector + randwidth = param.randcount + else: + assert param.randtype == 'perm' + new_default = _get_random_perm_hex_literal(param.randcount) + # Effective width of the random vector + randwidth = param.randcount * ceil(log2(param.randcount)) + + new_param['default'] = new_default + new_param['randwidth'] = randwidth + + new_params.append(new_param) + + instance["param_list"] = new_params + + # These objects get added-to in place by code in intermodule.py, so we have + # to convert and copy them here. + instance["inter_signal_list"] = [s.as_dict() for s in block.inter_signals] + + # An instance must either have a 'base_addr' address or a 'base_addrs' + # address, but can't have both. + base_addrs = instance.get('base_addrs') + if base_addrs is None: + if 'base_addr' not in instance: + log.error('Instance {!r} has neither a base_addr ' + 'nor a base_addrs field.' + .format(instance['name'])) + else: + # If the instance has a base_addr field, make sure that the block + # has just one device interface. + if len(block.reg_blocks) != 1: + log.error('Instance {!r} has a base_addr field but it ' + 'instantiates the block {!r}, which has {} ' + 'device interfaces.' + .format(instance['name'], + block.name, len(block.reg_blocks))) + else: + if_name = next(iter(block.reg_blocks)) + base_addrs = {if_name: instance['base_addr']} + + # Fill in a bogus base address (we don't have proper error handling, so + # have to do *something*) + if base_addrs is None: + base_addrs = {None: 0} + + instance['base_addrs'] = base_addrs + else: + if 'base_addr' in instance: + log.error('Instance {!r} has both a base_addr ' + 'and a base_addrs field.' + .format(instance['name'])) + + # Since the instance already has a base_addrs field, make sure that + # it's got the same set of keys as the name of the interfaces in the + # block. + inst_if_names = set(base_addrs.keys()) + block_if_names = set(block.reg_blocks.keys()) + if block_if_names != inst_if_names: + log.error('Instance {!r} has a base_addrs field with keys {} ' + 'but the block it instantiates ({!r}) has device ' + 'interfaces {}.' + .format(instance['name'], inst_if_names, + block.name, block_if_names)) + + if 'base_addr' in instance: + del instance['base_addr'] + + +# TODO: Replace this part to be configurable from Hjson or template +predefined_modules = { + "corei": "rv_core_ibex", + "cored": "rv_core_ibex", + "dm_sba": "rv_dm", + "debug_mem": "rv_dm" +} + + +def is_xbar(top, name): + """Check if the given name is crossbar + """ + xbars = list(filter(lambda node: node["name"] == name, top["xbar"])) + if len(xbars) == 0: + return False, None + + if len(xbars) > 1: + log.error("Matching crossbar {} is more than one.".format(name)) + raise SystemExit() + + return True, xbars[0] + + +def xbar_addhost(top, xbar, host): + """Add host nodes information + + - xbar: bool, true if the host port is from another Xbar + """ + # Check and fetch host if exists in nodes + obj = list(filter(lambda node: node["name"] == host, xbar["nodes"])) + if len(obj) == 0: + log.warning( + "host %s doesn't exist in the node list. Using default values" % + host) + obj = OrderedDict([ + ("name", host), + ("clock", xbar['clock']), + ("reset", xbar['reset']), + ("type", "host"), + ("inst_type", ""), + ("stub", False), + # The default matches RTL default + # pipeline_byp is don't care if pipeline is false + ("pipeline", "true"), + ("pipeline_byp", "true") + ]) + xbar["nodes"].append(obj) + return + + xbar_bool, xbar_h = is_xbar(top, host) + if xbar_bool: + log.info("host {} is a crossbar. Nothing to deal with.".format(host)) + + obj[0]["xbar"] = xbar_bool + + if 'clock' not in obj[0]: + obj[0]["clock"] = xbar['clock'] + + if 'reset' not in obj[0]: + obj[0]["reset"] = xbar["reset"] + + obj[0]["stub"] = False + obj[0]["inst_type"] = predefined_modules[ + host] if host in predefined_modules else "" + obj[0]["pipeline"] = obj[0]["pipeline"] if "pipeline" in obj[0] else "true" + obj[0]["pipeline_byp"] = obj[0]["pipeline_byp"] if obj[0][ + "pipeline"] == "true" and "pipeline_byp" in obj[0] else "true" + + +def process_pipeline_var(node): + """Add device nodes pipeline / pipeline_byp information + + - Supply a default of true / true if not defined by xbar + """ + node["pipeline"] = node["pipeline"] if "pipeline" in node else "true" + node["pipeline_byp"] = node[ + "pipeline_byp"] if "pipeline_byp" in node else "true" + + +def xbar_adddevice(top: Dict[str, object], + name_to_block: Dict[str, IpBlock], + xbar: Dict[str, object], + other_xbars: List[str], + device: str) -> None: + """Add or amend an entry in xbar['nodes'] to represent the device interface + + - clock: comes from module if exist, use xbar default otherwise + - reset: comes from module if exist, use xbar default otherwise + - inst_type: comes from module or memory if exist. + - base_addr: comes from module or memory, or assume rv_plic? + - size_byte: comes from module or memory + - xbar: bool, true if the device port is another xbar + - stub: There is no backing module / memory, instead a tlul port + is created and forwarded above the current hierarchy + """ + device_parts = device.split('.', 1) + device_base = device_parts[0] + device_ifname = device_parts[1] if len(device_parts) > 1 else None + + # Try to find a block or memory instance with name device_base. Object + # names should be unique, so there should never be more than one hit. + instances = [ + node for node in top["module"] + top["memory"] + if node['name'] == device_base + ] + assert len(instances) <= 1 + inst = instances[0] if instances else None + + # Try to find a node in the crossbar called device. Node names should be + # unique, so there should never be more than one hit. + nodes = [ + node for node in xbar['nodes'] + if node['name'] == device + ] + assert len(nodes) <= 1 + node = nodes[0] if nodes else None + + log.info("Handling xbar device {} (matches instance? {}; matches node? {})" + .format(device, inst is not None, node is not None)) + + # case 1: another xbar --> check in xbar list + if node is None and device in other_xbars: + log.error( + "Another crossbar %s needs to be specified in the 'nodes' list" % + device) + return + + # If there is no module or memory with the right name, this might still be + # ok: we might be connecting to another crossbar or to a predefined module. + if inst is None: + # case 1: Crossbar handling + if device in other_xbars: + log.info( + "device {} in Xbar {} is connected to another Xbar".format( + device, xbar["name"])) + assert node is not None + node["xbar"] = True + node["stub"] = False + process_pipeline_var(node) + return + + # case 2: predefined_modules (debug_mem, rv_plic) + # TODO: Find configurable solution not from predefined but from object? + if device in predefined_modules: + if device == "debug_mem": + if node is None: + # Add new debug_mem + xbar["nodes"].append({ + "name": "debug_mem", + "type": "device", + "clock": xbar['clock'], + "reset": xbar['reset'], + "inst_type": predefined_modules["debug_mem"], + "addr_range": [OrderedDict([ + ("base_addr", top["debug_mem_base_addr"]), + ("size_byte", "0x1000"), + ])], + "xbar": False, + "stub": False, + "pipeline": "true", + "pipeline_byp": "true" + }) # yapf: disable + else: + # Update if exists + node["inst_type"] = predefined_modules["debug_mem"] + node["addr_range"] = [ + OrderedDict([("base_addr", top["debug_mem_base_addr"]), + ("size_byte", "0x1000")]) + ] + node["xbar"] = False + node["stub"] = False + process_pipeline_var(node) + else: + log.error("device %s shouldn't be host type" % device) + + return + + # case 3: not defined + # Crossbar check + log.error("Device %s doesn't exist in 'module', 'memory', predefined, " + "or as a node object" % device) + return + + # If we get here, inst points an instance of some block or memory. It + # shouldn't point at a crossbar (because that would imply a naming clash) + assert device_base not in other_xbars + base_addr, size_byte = lib.get_base_and_size(name_to_block, + inst, device_ifname) + addr_range = {"base_addr": hex(base_addr), "size_byte": hex(size_byte)} + + stub = not lib.is_inst(inst) + + if node is None: + log.error('Cannot connect to {!r} because ' + 'the crossbar defines no node for {!r}.' + .format(device, device_base)) + return + + node["inst_type"] = inst["type"] + node["addr_range"] = [addr_range] + node["xbar"] = False + node["stub"] = stub + process_pipeline_var(node) + + +def amend_xbar(top: Dict[str, object], + name_to_block: Dict[str, IpBlock], + xbar: Dict[str, object]): + """Amend crossbar informations to the top list + + Amended fields + - clock: Adopt from module clock if exists + - inst_type: Module instance some module will be hard-coded + the tool searches module list and memory list then put here + - base_addr: from top["module"] + - size: from top["module"] + """ + xbar_list = [x["name"] for x in top["xbar"]] + if not xbar["name"] in xbar_list: + log.info( + "Xbar %s doesn't belong to the top %s. Check if the xbar doesn't need" + % (xbar["name"], top["name"])) + return + + topxbar = list( + filter(lambda node: node["name"] == xbar["name"], top["xbar"]))[0] + + topxbar["connections"] = deepcopy(xbar["connections"]) + if "nodes" in xbar: + topxbar["nodes"] = deepcopy(xbar["nodes"]) + else: + topxbar["nodes"] = [] + + # xbar primary clock and reset + topxbar["clock"] = xbar["clock_primary"] + topxbar["reset"] = xbar["reset_primary"] + + # Build nodes from 'connections' + device_nodes = set() + for host, devices in xbar["connections"].items(): + # add host first + xbar_addhost(top, topxbar, host) + + # add device if doesn't exist + device_nodes.update(devices) + + other_xbars = [x["name"] + for x in top["xbar"] + if x["name"] != xbar["name"]] + + log.info(device_nodes) + for device in device_nodes: + xbar_adddevice(top, name_to_block, topxbar, other_xbars, device) + + +def xbar_cross(xbar, xbars): + """Check if cyclic dependency among xbars + + And gather the address range for device port (to another Xbar) + + @param node_name if not "", the function only search downstream + devices starting from the node_name + @param visited The nodes it visited to reach this port. If any + downstream port from node_name in visited, it means + circular path exists. It should be fatal error. + """ + # Step 1: Visit devices (gather the address range) + log.info("Processing circular path check for {}".format(xbar["name"])) + addr = [] + for node in [ + x for x in xbar["nodes"] + if x["type"] == "device" and "xbar" in x and x["xbar"] is False + ]: + addr.extend(node["addr_range"]) + + # Step 2: visit xbar device ports + xbar_nodes = [ + x for x in xbar["nodes"] + if x["type"] == "device" and "xbar" in x and x["xbar"] is True + ] + + # Now call function to get the device range + # the node["name"] is used to find the host_xbar and its connection. The + # assumption here is that there's only one connection from crossbar A to + # crossbar B. + # + # device_xbar is the crossbar has a device port with name as node["name"]. + # host_xbar is the crossbar has a host port with name as node["name"]. + for node in xbar_nodes: + xbar_addr = xbar_cross_node(node["name"], xbar, xbars, visited=[]) + node["addr_range"] = xbar_addr + + +def xbar_cross_node(node_name, device_xbar, xbars, visited=[]): + # 1. Get the connected xbar + host_xbars = [x for x in xbars if x["name"] == node_name] + assert len(host_xbars) == 1 + host_xbar = host_xbars[0] + + log.info("Processing node {} in Xbar {}.".format(node_name, + device_xbar["name"])) + result = [] # [(base_addr, size), .. ] + # Sweep the devices using connections and gather the address. + # If the device is another xbar, call recursive + visited.append(host_xbar["name"]) + devices = host_xbar["connections"][device_xbar["name"]] + + for node in host_xbar["nodes"]: + if not node["name"] in devices: + continue + if "xbar" in node and node["xbar"] is True: + if "addr_range" not in node: + # Deeper dive into another crossbar + xbar_addr = xbar_cross_node(node["name"], host_xbar, xbars, + visited) + node["addr_range"] = xbar_addr + + result.extend(deepcopy(node["addr_range"])) + + visited.pop() + + return result + + +# find the first instance name of a given type +def _find_module_name(modules, module_type): + for m in modules: + if m['type'] == module_type: + return m['name'] + + return None + + +def amend_clocks(top: OrderedDict): + """Add a list of clocks to each clock group + Amend the clock connections of each entry to reflect the actual gated clock + """ + clks_attr = top['clocks'] + clk_paths = clks_attr['hier_paths'] + clkmgr_name = _find_module_name(top['module'], 'clkmgr') + groups_in_top = [x["name"].lower() for x in clks_attr['groups']] + exported_clks = OrderedDict() + trans_eps = [] + + # Assign default parameters to source clocks + for src in clks_attr['srcs']: + if 'derived' not in src: + src['derived'] = "no" + src['params'] = OrderedDict() + + # Default assignments + for group in clks_attr['groups']: + + # if unique not defined, it defaults to 'no' + if 'unique' not in group: + group['unique'] = "no" + + # if no hardwired clocks, define an empty set + group['clocks'] = OrderedDict( + ) if 'clocks' not in group else group['clocks'] + + for ep in top['module'] + top['memory'] + top['xbar']: + + clock_connections = OrderedDict() + + # Ensure each module has a default case + export_if = ep.get('clock_reset_export', []) + + # if no clock group assigned, default is unique + ep['clock_group'] = 'secure' if 'clock_group' not in ep else ep[ + 'clock_group'] + ep_grp = ep['clock_group'] + + # if ep is in the transactional group, collect into list below + if ep['clock_group'] == 'trans': + trans_eps.append(ep['name']) + + # end point names and clocks + ep_name = ep['name'] + ep_clks = [] + + # clock group index + cg_idx = groups_in_top.index(ep_grp) + + # unique property of each group + unique = clks_attr['groups'][cg_idx]['unique'] + + # src property of each group + src = clks_attr['groups'][cg_idx]['src'] + + for port, clk in ep['clock_srcs'].items(): + ep_clks.append(clk) + + name = '' + hier_name = clk_paths[src] + + if src == 'ext': + # clock comes from top ports + if clk == 'main': + name = "i" + else: + name = "{}_i".format(clk) + + elif unique == "yes": + # new unqiue clock name + name = "{}_{}".format(clk, ep_name) + + else: + # new group clock name + name = "{}_{}".format(clk, ep_grp) + + clk_name = "clk_" + name + + # add clock to a particular group + clks_attr['groups'][cg_idx]['clocks'][clk_name] = clk + + # add clock connections + clock_connections[port] = hier_name + clk_name + + # clocks for this module are exported + for intf in export_if: + log.info("{} export clock name is {}".format(ep_name, name)) + + # create dict entry if it does not exit + if intf not in exported_clks: + exported_clks[intf] = OrderedDict() + + # if first time encounter end point, declare + if ep_name not in exported_clks[intf]: + exported_clks[intf][ep_name] = [] + + # append clocks + exported_clks[intf][ep_name].append(name) + + # Add to endpoint structure + ep['clock_connections'] = clock_connections + + # add entry to top level json + top['exported_clks'] = exported_clks + + # add entry to inter_module automatically + for intf in top['exported_clks']: + top['inter_module']['external']['{}.clocks_{}'.format( + clkmgr_name, intf)] = "clks_{}".format(intf) + + # add to intermodule connections + for ep in trans_eps: + entry = ep + ".idle" + top['inter_module']['connect']['{}.idle'.format(clkmgr_name)].append(entry) + + +def amend_resets(top): + """Generate exported reset structure and automatically connect to + intermodule. + """ + + rstmgr_name = _find_module_name(top['module'], 'rstmgr') + + # Generate exported reset list + exported_rsts = OrderedDict() + for module in top["module"]: + + # This code is here to ensure if amend_clocks/resets switched order + # everything would still work + export_if = module.get('clock_reset_export', []) + + # There may be multiple export interfaces + for intf in export_if: + # create dict entry if it does not exit + if intf not in exported_rsts: + exported_rsts[intf] = OrderedDict() + + # grab directly from reset_connections definition + rsts = [rst for rst in module['reset_connections'].values()] + exported_rsts[intf][module['name']] = rsts + + # add entry to top level json + top['exported_rsts'] = exported_rsts + + # add entry to inter_module automatically + for intf in top['exported_rsts']: + top['inter_module']['external']['{}.resets_{}'.format( + rstmgr_name, intf)] = "rsts_{}".format(intf) + """Discover the full path and selection to each reset connection. + This is done by modifying the reset connection of each end point. + """ + for end_point in top['module'] + top['memory'] + top['xbar']: + for port, net in end_point['reset_connections'].items(): + reset_path = lib.get_reset_path(net, end_point['domain'], + top['resets']) + end_point['reset_connections'][port] = reset_path + + # reset paths are still needed temporarily until host only modules are properly automated + reset_paths = OrderedDict() + reset_hiers = top["resets"]['hier_paths'] + + for reset in top["resets"]["nodes"]: + if "type" not in reset: + log.error("{} missing type field".format(reset["name"])) + return + + if reset["type"] == "top": + reset_paths[reset["name"]] = "{}rst_{}_n".format( + reset_hiers["top"], reset["name"]) + + elif reset["type"] == "ext": + reset_paths[reset["name"]] = reset_hiers["ext"] + reset['name'] + elif reset["type"] == "int": + log.info("{} used as internal reset".format(reset["name"])) + else: + log.error("{} type is invalid".format(reset["type"])) + + top["reset_paths"] = reset_paths + + return + + +def ensure_interrupt_modules(top: OrderedDict, name_to_block: Dict[str, IpBlock]): + '''Populate top['interrupt_module'] if necessary + + Do this by adding each module in top['modules'] that defines at least one + interrupt. + + ''' + if 'interrupt_module' in top: + return + + modules = [] + for module in top['module']: + block = name_to_block[module['type']] + if block.interrupts: + modules.append(module['name']) + + top['interrupt_module'] = modules + + +def amend_interrupt(top: OrderedDict, name_to_block: Dict[str, IpBlock]): + """Check interrupt_module if exists, or just use all modules + """ + ensure_interrupt_modules(top, name_to_block) + + if "interrupt" not in top or top["interrupt"] == "": + top["interrupt"] = [] + + for m in top["interrupt_module"]: + ips = list(filter(lambda module: module["name"] == m, top["module"])) + if len(ips) == 0: + log.warning( + "Cannot find IP %s which is used in the interrupt_module" % m) + continue + + ip = ips[0] + block = name_to_block[ip['type']] + + log.info("Adding interrupts from module %s" % ip["name"]) + for signal in block.interrupts: + sig_dict = signal.as_nwt_dict('interrupt') + qual = lib.add_module_prefix_to_signal(sig_dict, + module=m.lower()) + top["interrupt"].append(qual) + + +def ensure_alert_modules(top: OrderedDict, name_to_block: Dict[str, IpBlock]): + '''Populate top['alert_module'] if necessary + + Do this by adding each module in top['modules'] that defines at least one + alert. + + ''' + if 'alert_module' in top: + return + + modules = [] + for module in top['module']: + block = name_to_block[module['type']] + if block.alerts: + modules.append(module['name']) + + top['alert_module'] = modules + + +def amend_alert(top: OrderedDict, name_to_block: Dict[str, IpBlock]): + """Check interrupt_module if exists, or just use all modules + """ + ensure_alert_modules(top, name_to_block) + + if "alert" not in top or top["alert"] == "": + top["alert"] = [] + + # Find the alert handler and extract the name of its clock + alert_clock = None + for instance in top['module']: + if instance['type'].lower() == 'alert_handler': + alert_clock = instance['clock_srcs']['clk_i'] + break + assert alert_clock is not None + + for m in top["alert_module"]: + ips = list(filter(lambda module: module["name"] == m, top["module"])) + if len(ips) == 0: + log.warning("Cannot find IP %s which is used in the alert_module" % + m) + continue + + ip = ips[0] + block = name_to_block[ip['type']] + + log.info("Adding alert from module %s" % ip["name"]) + has_async_alerts = ip['clock_srcs']['clk_i'] != alert_clock + for alert in block.alerts: + alert_dict = alert.as_nwt_dict('alert') + alert_dict['async'] = '1' if has_async_alerts else '0' + qual_sig = lib.add_module_prefix_to_signal(alert_dict, + module=m.lower()) + top["alert"].append(qual_sig) + + +def amend_wkup(topcfg: OrderedDict, name_to_block: Dict[str, IpBlock]): + + pwrmgr_name = _find_module_name(topcfg['module'], 'pwrmgr') + + if "wakeups" not in topcfg or topcfg["wakeups"] == "": + topcfg["wakeups"] = [] + + # create list of wakeup signals + for m in topcfg["module"]: + log.info("Adding wakeup from module %s" % m["name"]) + block = name_to_block[m['type']] + for signal in block.wakeups: + log.info("Adding signal %s" % signal.name) + topcfg["wakeups"].append({ + 'name': signal.name, + 'width': str(signal.bits.width()), + 'module': m["name"] + }) + + # add wakeup signals to pwrmgr connections + signal_names = [ + "{}.{}".format(s["module"].lower(), s["name"].lower()) + for s in topcfg["wakeups"] + ] + + topcfg["inter_module"]["connect"]["{}.wakeups".format(pwrmgr_name)] = signal_names + log.info("Intermodule signals: {}".format( + topcfg["inter_module"]["connect"])) + + +# Handle reset requests from modules +def amend_reset_request(topcfg: OrderedDict, + name_to_block: Dict[str, IpBlock]): + + pwrmgr_name = _find_module_name(topcfg['module'], 'pwrmgr') + + if "reset_requests" not in topcfg or topcfg["reset_requests"] == "": + topcfg["reset_requests"] = [] + + # create list of reset signals + for m in topcfg["module"]: + log.info("Adding reset requests from module %s" % m["name"]) + block = name_to_block[m['type']] + for signal in block.reset_requests: + log.info("Adding signal %s" % signal.name) + topcfg["reset_requests"].append({ + 'name': signal.name, + 'width': str(signal.bits.width()), + 'module': m["name"] + }) + + # add reset requests to pwrmgr connections + signal_names = [ + "{}.{}".format(s["module"].lower(), s["name"].lower()) + for s in topcfg["reset_requests"] + ] + + topcfg["inter_module"]["connect"]["{}.rstreqs".format(pwrmgr_name)] = signal_names + log.info("Intermodule signals: {}".format( + topcfg["inter_module"]["connect"])) + + +def append_io_signal(temp: Dict, sig_inst: Dict) -> None: + '''Appends the signal to the correct list''' + if sig_inst['type'] == 'inout': + temp['inouts'].append(sig_inst) + if sig_inst['type'] == 'input': + temp['inputs'].append(sig_inst) + if sig_inst['type'] == 'output': + temp['outputs'].append(sig_inst) + + +def get_index_and_incr(ctrs: Dict, connection: str, io_dir: str) -> Dict: + '''Get correct index counter and increment''' + + if connection != 'muxed': + connection = 'dedicated' + + if io_dir in 'inout': + result = ctrs[connection]['inouts'] + ctrs[connection]['inouts'] += 1 + elif connection == 'muxed': + # For MIOs, the input/output arrays differ in RTL + # I.e., the input array contains {inputs, inouts}, whereas + # the output array contains {outputs, inouts}. + if io_dir == 'input': + result = ctrs[connection]['inputs'] + ctrs[connection]['inouts'] + ctrs[connection]['inputs'] += 1 + elif io_dir == 'output': + result = ctrs[connection]['outputs'] + ctrs[connection]['inouts'] + ctrs[connection]['outputs'] += 1 + else: + assert(0) # should not happen + else: + # For DIOs, the input/output arrays are identical in terms of index layout. + # Unused inputs are left unconnected and unused outputs are tied off. + if io_dir == 'input': + result = ctrs[connection]['inputs'] + ctrs[connection]['inouts'] + ctrs[connection]['inputs'] += 1 + elif io_dir == 'output': + result = (ctrs[connection]['outputs'] + + ctrs[connection]['inouts'] + + ctrs[connection]['inputs']) + ctrs[connection]['outputs'] += 1 + else: + assert(0) # should not happen + + return result + + +def amend_pinmux_io(top: Dict, name_to_block: Dict[str, IpBlock]): + """ Process pinmux/pinout configuration and assign available IOs + """ + pinmux = top['pinmux'] + pinout = top['pinout'] + targets = top['targets'] + + temp = {} + temp['inouts'] = [] + temp['inputs'] = [] + temp['outputs'] = [] + + for sig in pinmux['signals']: + # Get the signal information from the IP block type of this instance/ + mod_name = sig['instance'] + m = lib.get_module_by_name(top, mod_name) + + if m is None: + raise SystemExit("Module {} is not searchable.".format(mod_name)) + + block = name_to_block[m['type']] + + # If the signal is explicitly named. + if sig['port'] != '': + + # If this is a bus signal with explicit indexes. + if '[' in sig['port']: + name_split = sig['port'].split('[') + sig_name = name_split[0] + idx = int(name_split[1][:-1]) + else: + idx = -1 + sig_name = sig['port'] + + sig_inst = deepcopy(block.get_signal_by_name_as_dict(sig_name)) + + if idx >= 0 and idx >= sig_inst['width']: + raise SystemExit("Index {} is out of bounds for signal {}" + " with width {}.".format(idx, sig_name, sig_inst['width'])) + if idx == -1 and sig_inst['width'] != 1: + raise SystemExit("Bus signal {} requires an index.".format(sig_name)) + + # If we got this far we know that the signal is valid and exists. + # Augment this signal instance with additional information. + sig_inst.update({'idx': idx, + 'pad': sig['pad'], + 'attr': sig['attr'], + 'connection': sig['connection']}) + sig_inst['name'] = mod_name + '_' + sig_inst['name'] + append_io_signal(temp, sig_inst) + + # Otherwise the name is a wildcard for selecting all available IO signals + # of this block and we need to extract them here one by one signals here. + else: + sig_list = deepcopy(block.get_signals_as_list_of_dicts()) + + for sig_inst in sig_list: + # If this is a multibit signal, unroll the bus and + # generate a single bit IO signal entry for each one. + if sig_inst['width'] > 1: + for idx in range(sig_inst['width']): + sig_inst_copy = deepcopy(sig_inst) + sig_inst_copy.update({'idx': idx, + 'pad': sig['pad'], + 'attr': sig['attr'], + 'connection': sig['connection']}) + sig_inst_copy['name'] = sig['instance'] + '_' + sig_inst_copy['name'] + append_io_signal(temp, sig_inst_copy) + else: + sig_inst.update({'idx': -1, + 'pad': sig['pad'], + 'attr': sig['attr'], + 'connection': sig['connection']}) + sig_inst['name'] = sig['instance'] + '_' + sig_inst['name'] + append_io_signal(temp, sig_inst) + + # Now that we've collected all input and output signals, + # we can go through once again and stack them into one unified + # list, and calculate MIO/DIO global indices. + pinmux['ios'] = (temp['inouts'] + + temp['inputs'] + + temp['outputs']) + + # Remember these counts to facilitate the RTL generation + pinmux['io_counts'] = {'dedicated': {'inouts': 0, 'inputs': 0, 'outputs': 0, 'pads': 0}, + 'muxed': {'inouts': 0, 'inputs': 0, 'outputs': 0, 'pads': 0}} + + for sig in pinmux['ios']: + glob_idx = get_index_and_incr(pinmux['io_counts'], sig['connection'], sig['type']) + sig['glob_idx'] = glob_idx + + # Calculate global indices for pads. + j = k = 0 + for pad in pinout['pads']: + if pad['connection'] == 'muxed': + pad['idx'] = j + j += 1 + else: + pad['idx'] = k + k += 1 + pinmux['io_counts']['muxed']['pads'] = j + pinmux['io_counts']['dedicated']['pads'] = k + + # For each target configuration, calculate the special signal indices. + known_muxed_pads = {} + for pad in pinout['pads']: + if pad['connection'] == 'muxed': + known_muxed_pads[pad['name']] = pad + + known_mapped_dio_pads = {} + for sig in pinmux['ios']: + if sig['connection'] in ['muxed', 'manual']: + continue + if sig['pad'] in known_mapped_dio_pads: + raise SystemExit('Cannot have multiple IOs mapped to the same DIO pad {}' + .format(sig['pad'])) + known_mapped_dio_pads[sig['pad']] = sig + + for target in targets: + for entry in target['pinmux']['special_signals']: + # If this is a muxed pad, the resolution is + # straightforward. I.e., we just assign the MIO index. + if entry['pad'] in known_muxed_pads: + entry['idx'] = known_muxed_pads[entry['pad']]['idx'] + # Otherwise we need to find out which DIO this pad is mapped to. + # Note that we can't have special_signals that are manual, since + # there needs to exist a DIO connection. + elif entry['pad'] in known_mapped_dio_pads: + # This index refers to the stacked {dio, mio} array + # on the chip-level, hence we have to add the amount of MIO pads. + idx = (known_mapped_dio_pads[entry['pad']]['glob_idx'] + + pinmux['io_counts']['muxed']['pads']) + entry['idx'] = idx + else: + assert(0) # Entry should be guaranteed to exist at this point + + +def merge_top(topcfg: OrderedDict, + name_to_block: Dict[str, IpBlock], + xbarobjs: OrderedDict) -> OrderedDict: + + # Combine ip cfg into topcfg + elaborate_instances(topcfg, name_to_block) + + # Create clock connections for each block + # Assign clocks into appropriate groups + # Note, elaborate_instances references clock information to establish async handling + # as part of alerts. + # amend_clocks(topcfg) + + # Combine the wakeups + amend_wkup(topcfg, name_to_block) + amend_reset_request(topcfg, name_to_block) + + # Combine the interrupt (should be processed prior to xbar) + amend_interrupt(topcfg, name_to_block) + + # Combine the alert (should be processed prior to xbar) + amend_alert(topcfg, name_to_block) + + # Creates input/output list in the pinmux + log.info("Processing PINMUX") + amend_pinmux_io(topcfg, name_to_block) + + # Combine xbar into topcfg + for xbar in xbarobjs: + amend_xbar(topcfg, name_to_block, xbar) + + # 2nd phase of xbar (gathering the devices address range) + for xbar in topcfg["xbar"]: + xbar_cross(xbar, topcfg["xbar"]) + + # Add path names to declared resets. + # Declare structure for exported resets. + amend_resets(topcfg) + + # remove unwanted fields 'debug_mem_base_addr' + topcfg.pop('debug_mem_base_addr', None) + + return topcfg diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/README.md b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/README.md new file mode 100644 index 00000000..afd488ac --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/README.md @@ -0,0 +1,4 @@ +# OpenTitan topgen templates + +This directory contains templates used by topgen to assembly a chip toplevel. + diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chip_env_pkg__params.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chip_env_pkg__params.sv.tpl new file mode 100644 index 00000000..34079006 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chip_env_pkg__params.sv.tpl @@ -0,0 +1,17 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by topgen.py + +parameter string LIST_OF_ALERTS[] = { +% for alert in top["alert"]: + % if loop.last: + "${alert["name"]}" + % else: + "${alert["name"]}", + % endif +% endfor +}; + +parameter uint NUM_ALERTS = ${len(top["alert"])}; diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chiplevel.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chiplevel.sv.tpl new file mode 100644 index 00000000..aafec5bf --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/chiplevel.sv.tpl @@ -0,0 +1,1218 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +${gencmd} +<% +import re +import topgen.lib as lib +from copy import deepcopy + +# Provide shortcuts for some commonly used variables +pinmux = top['pinmux'] +pinout = top['pinout'] + +num_mio_inputs = pinmux['io_counts']['muxed']['inouts'] + \ + pinmux['io_counts']['muxed']['inputs'] +num_mio_outputs = pinmux['io_counts']['muxed']['inouts'] + \ + pinmux['io_counts']['muxed']['outputs'] +num_mio_pads = pinmux['io_counts']['muxed']['pads'] + +num_dio_inputs = pinmux['io_counts']['dedicated']['inouts'] + \ + pinmux['io_counts']['dedicated']['inputs'] +num_dio_outputs = pinmux['io_counts']['dedicated']['inouts'] + \ + pinmux['io_counts']['dedicated']['outputs'] +num_dio_total = pinmux['io_counts']['dedicated']['inouts'] + \ + pinmux['io_counts']['dedicated']['inputs'] + \ + pinmux['io_counts']['dedicated']['outputs'] + +def get_dio_sig(pinmux: {}, pad: {}): + '''Get DIO signal associated with this pad or return None''' + for sig in pinmux["ios"]: + if sig["connection"] == "direct" and pad["name"] == sig["pad"]: + return sig + else: + return None + +# Modify the pad lists on the fly, based on target config +maxwidth = 0 +muxed_pads = [] +dedicated_pads = [] +k = 0 +for pad in pinout["pads"]: + if pad["connection"] == "muxed": + if pad["name"] not in target["pinout"]["remove_pads"]: + maxwidth = max(maxwidth, len(pad["name"])) + muxed_pads.append(pad) + else: + k = pad["idx"] + if pad["name"] not in target["pinout"]["remove_pads"]: + maxwidth = max(maxwidth, len(pad["name"])) + dedicated_pads.append(pad) + +for pad in target["pinout"]["add_pads"]: + # Since these additional pads have not been elaborated in the merge phase, + # we need to add their global index here. + amended_pad = deepcopy(pad) + amended_pad.update({"idx" : k}) + dedicated_pads.append(pad) + k += 1 + +num_im = sum([x["width"] if "width" in x else 1 for x in top["inter_signal"]["external"]]) + +max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) +max_sigwidth = len("{}".format(max_sigwidth)) + +clks_attr = top['clocks'] +cpu_clk = top['clocks']['hier_paths']['top'] + "clk_proc_main" +cpu_rst = top["reset_paths"]["sys"] +dm_rst = top["reset_paths"]["lc"] +esc_clk = top['clocks']['hier_paths']['top'] + "clk_io_div4_timers" +esc_rst = top["reset_paths"]["sys_io_div4"] + +unused_resets = lib.get_unused_resets(top) +unused_im_defs, undriven_im_defs = lib.get_dangling_im_def(top["inter_signal"]["definitions"]) + +%>\ +% if target["name"] != "asic": +module chip_${top["name"]}_${target["name"]} #( + // Path to a VMEM file containing the contents of the boot ROM, which will be + // baked into the FPGA bitstream. + parameter BootRomInitFile = "boot_rom_fpga_${target["name"]}.32.vmem", + // Path to a VMEM file containing the contents of the emulated OTP, which will be + // baked into the FPGA bitstream. + parameter OtpCtrlMemInitFile = "otp_img_fpga_${target["name"]}.vmem", + // TODO: Remove this 0 once infra is ready + parameter bit RomCtrlSkipCheck = 1 +) ( +% else: +module chip_${top["name"]}_${target["name"]} #( + // TODO: Remove this 0 once infra is ready + parameter bit RomCtrlSkipCheck = 1 +) ( +% endif +<% + +%>\ + // Dedicated Pads +% for pad in dedicated_pads: +<% + sig = get_dio_sig(pinmux, pad) + if sig is not None: + comment = "// Dedicated Pad for {}".format(sig["name"]) + else: + comment = "// Manual Pad" +%>\ + inout ${pad["name"]}, ${comment} +% endfor + + // Muxed Pads +% for pad in muxed_pads: + inout ${pad["name"]}${" " if loop.last else ","} // MIO Pad ${pad["idx"]} +% endfor +); + + import top_${top["name"]}_pkg::*; + import prim_pad_wrapper_pkg::*; + +% if target["pinmux"]["special_signals"]: + //////////////////////////// + // Special Signal Indices // + //////////////////////////// + + % for entry in target["pinmux"]["special_signals"]: +<% param_name = (lib.Name.from_snake_case(entry["name"]) + + lib.Name(["pad", "idx"])).as_camel_case() +%>\ + parameter int ${param_name} = ${entry["idx"]}; + % endfor +% endif + + // DFT and Debug signal positions in the pinout. + localparam pinmux_pkg::target_cfg_t PinmuxTargetCfg = '{ + tck_idx: TckPadIdx, + tms_idx: TmsPadIdx, + trst_idx: TrstNPadIdx, + tdi_idx: TdiPadIdx, + tdo_idx: TdoPadIdx, + tap_strap0_idx: Tap0PadIdx, + tap_strap1_idx: Tap1PadIdx, + dft_strap0_idx: Dft0PadIdx, + dft_strap1_idx: Dft1PadIdx, + // TODO: check whether there is a better way to pass these USB-specific params + usb_dp_idx: DioUsbdevDp, + usb_dn_idx: DioUsbdevDn, + usb_dp_pullup_idx: DioUsbdevDpPullup, + usb_dn_pullup_idx: DioUsbdevDnPullup, + // Pad types for attribute WARL behavior + dio_pad_type: { +<% + pad_attr = [] + for sig in list(reversed(top["pinmux"]["ios"])): + if sig["connection"] != "muxed": + pad_attr.append((sig['name'], sig["attr"])) +%>\ +% for name, attr in pad_attr: + ${attr}${" " if loop.last else ","} // DIO ${name} +% endfor + }, + mio_pad_type: { +<% + pad_attr = [] + for pad in list(reversed(pinout["pads"])): + if pad["connection"] == "muxed": + pad_attr.append(pad["type"]) +%>\ +% for attr in pad_attr: + ${attr}${" " if loop.last else ","} // MIO Pad ${len(pad_attr) - loop.index - 1} +% endfor + } + }; + + //////////////////////// + // Signal definitions // + //////////////////////// + + pad_attr_t [pinmux_reg_pkg::NMioPads-1:0] mio_attr; + pad_attr_t [pinmux_reg_pkg::NDioPads-1:0] dio_attr; + logic [pinmux_reg_pkg::NMioPads-1:0] mio_out; + logic [pinmux_reg_pkg::NMioPads-1:0] mio_oe; + logic [pinmux_reg_pkg::NMioPads-1:0] mio_in; + logic [pinmux_reg_pkg::NMioPads-1:0] mio_in_raw; + logic [pinmux_reg_pkg::NDioPads-1:0] dio_out; + logic [pinmux_reg_pkg::NDioPads-1:0] dio_oe; + logic [pinmux_reg_pkg::NDioPads-1:0] dio_in; + + logic unused_mio_in_raw; + assign unused_mio_in_raw = ^mio_in_raw; + + // Manual pads +% for pad in dedicated_pads: +<% + pad_prefix = pad["name"].lower() +%>\ +% if not get_dio_sig(pinmux, pad): + logic manual_in_${pad_prefix}, manual_out_${pad_prefix}, manual_oe_${pad_prefix}; +% endif +% endfor + +% for pad in dedicated_pads: +<% + pad_prefix = pad["name"].lower() +%>\ +% if not get_dio_sig(pinmux, pad): + pad_attr_t manual_attr_${pad_prefix}; +% endif +% endfor + +% if target["pinout"]["remove_pads"]: + ///////////////////////// + // Stubbed pad tie-off // + ///////////////////////// + + // Only signals going to non-custom pads need to be tied off. + logic [${len(pinout["pads"])-1}:0] unused_sig; +% for pad in pinout["pads"]: + % if pad["connection"] == 'muxed': + % if pad["name"] in target["pinout"]["remove_pads"]: + assign mio_in[${pad["idx"]}] = 1'b0; + assign unused_sig[${loop.index}] = mio_out[${pad["idx"]}] ^ mio_oe[${pad["idx"]}]; + % endif + % else: + % if pad["name"] in target["pinout"]["remove_pads"]: +<% + ## Only need to tie off if this is not a custom pad. + sig = get_dio_sig(pinmux, pad) + if sig is not None: + sig_index = lib.get_io_enum_literal(sig, 'dio') +%>\ + % if sig is not None: + assign dio_in[${lib.get_io_enum_literal(sig, 'dio')}] = 1'b0; + assign unused_sig[${loop.index}] = dio_out[${sig_index}] ^ dio_oe[${sig_index}]; + % endif + % endif + % endif +% endfor +%endif + + ////////////////////// + // Padring Instance // + ////////////////////// + +% if target["name"] == "asic": + // AST signals needed in padring + ast_pkg::ast_clks_t ast_base_clks; + logic scan_rst_n; + lc_ctrl_pkg::lc_tx_t scanmode; +% endif + + padring #( + // Padring specific counts may differ from pinmux config due + // to custom, stubbed or added pads. + .NDioPads(${len(dedicated_pads)}), + .NMioPads(${len(muxed_pads)}), +% if target["name"] == "asic": + .PhysicalPads(1), + .NIoBanks(int'(IoBankCount)), + .DioScanRole ({ +% for pad in list(reversed(dedicated_pads)): + scan_role_pkg::${lib.Name.from_snake_case('dio_pad_' + pad["name"] + '_scan_role').as_camel_case()}${"" if loop.last else ","} +% endfor + }), + .MioScanRole ({ +% for pad in list(reversed(muxed_pads)): + scan_role_pkg::${lib.Name.from_snake_case('mio_pad_' + pad["name"] + '_scan_role').as_camel_case()}${"" if loop.last else ","} +% endfor + }), + .DioPadBank ({ +% for pad in list(reversed(dedicated_pads)): + ${lib.Name.from_snake_case('io_bank_' + pad["bank"]).as_camel_case()}${" " if loop.last else ","} // ${pad['name']} +% endfor + }), + .MioPadBank ({ +% for pad in list(reversed(muxed_pads)): + ${lib.Name.from_snake_case('io_bank_' + pad["bank"]).as_camel_case()}${" " if loop.last else ","} // ${pad['name']} +% endfor + }), +% endif +\ +\ + .DioPadType ({ +% for pad in list(reversed(dedicated_pads)): + ${pad["type"]}${" " if loop.last else ","} // ${pad['name']} +% endfor + }), + .MioPadType ({ +% for pad in list(reversed(muxed_pads)): + ${pad["type"]}${" " if loop.last else ","} // ${pad['name']} +% endfor + }) + ) u_padring ( + // This is only used for scan and DFT purposes +% if target["name"] == "asic": + .clk_scan_i ( ast_base_clks.clk_sys ), + .scanmode_i ( scanmode ), +% else: + .clk_scan_i ( 1'b0 ), + .scanmode_i ( lc_ctrl_pkg::Off ), + % endif + .dio_in_raw_o ( ), + .mio_in_raw_o ( mio_in_raw ), + // Chip IOs + .dio_pad_io ({ +% for pad in list(reversed(dedicated_pads)): + ${pad["name"]}${"" if loop.last else ","} +% endfor + }), + + .mio_pad_io ({ +% for pad in list(reversed(muxed_pads)): + ${pad["name"]}${"" if loop.last else ","} +% endfor + }), + + // Core-facing +% for port in ["in_o", "out_i", "oe_i", "attr_i"]: + .dio_${port} ({ + % for pad in list(reversed(dedicated_pads)): + <% + sig = get_dio_sig(pinmux, pad) + %>\ + % if sig is None: + manual_${port[:-2]}_${pad["name"].lower()}${"" if loop.last else ","} + % else: + dio_${port[:-2]}[${lib.get_io_enum_literal(sig, 'dio')}]${"" if loop.last else ","} + % endif + % endfor + }), +% endfor + +% for port in ["in_o", "out_i", "oe_i", "attr_i"]: +<% + sig_name = 'mio_' + port[:-2] + indices = list(reversed(list(pad['idx'] for pad in muxed_pads))) +%>\ + .mio_${port} (${lib.make_bit_concatenation(sig_name, indices, 6)})${"" if loop.last else ","} +% endfor + ); + + +################################################################### +## USB for CW305 ## +################################################################### +% if target["name"] == "cw305": + // Connect the DP pad + assign dio_in[DioUsbdevDp] = manual_in_usb_p; + assign manual_out_usb_p = dio_out[DioUsbdevDp]; + assign manual_oe_usb_p = dio_oe[DioUsbdevDp]; + assign manual_attr_usb_p = dio_attr[DioUsbdevDp]; + + // Connect the DN pad + assign dio_in[DioUsbdevDn] = manual_in_usb_n; + assign manual_out_usb_n = dio_out[DioUsbdevDn]; + assign manual_oe_usb_n = dio_oe[DioUsbdevDn]; + assign manual_attr_usb_n = dio_attr[DioUsbdevDn]; + + // Connect sense pad + assign dio_in[DioUsbdevSense] = manual_in_io_usb_sense0; + assign manual_out_io_usb_sense0 = dio_out[DioUsbdevSense]; + assign manual_oe_io_usb_sense0 = dio_oe[DioUsbdevSense]; + assign manual_attr_io_sense0 = dio_attr[DioUsbdevSense]; + + // Connect DN pullup + assign dio_in[DioUsbdevDnPullup] = manual_in_io_usb_dnpullup0; + assign manual_out_io_usb_dnpullup0 = dio_out[DioUsbdevDnPullup]; + assign manual_oe_io_usb_dnpullup0 = dio_oe[DioUsbdevDnPullup]; + assign manual_attr_io_dnpullup0 = dio_attr[DioUsbdevDnPullup]; + + // Connect DP pullup + assign dio_in[DioUsbdevDpPullup] = manual_in_io_usb_dppullup0; + assign manual_out_io_usb_dppullup0 = dio_out[DioUsbdevDpPullup]; + assign manual_oe_io_usb_dppullup0 = dio_oe[DioUsbdevDpPullup]; + assign manual_attr_io_dppullup0 = dio_attr[DioUsbdevDpPullup]; + + // Tie-off unused signals + assign dio_in[DioUsbdevSe0] = 1'b0; + assign dio_in[DioUsbdevTxModeSe] = 1'b0; + assign dio_in[DioUsbdevSuspend] = 1'b0; + + logic unused_usb_sigs; + assign unused_usb_sigs = ^{ + // SE0 + dio_out[DioUsbdevSe0], + dio_oe[DioUsbdevSe0], + dio_attr[DioUsbdevSe0], + // TX Mode + dio_out[DioUsbdevTxModeSe], + dio_oe[DioUsbdevTxModeSe], + dio_attr[DioUsbdevTxModeSe], + // Suspend + dio_out[DioUsbdevSuspend], + dio_oe[DioUsbdevSuspend], + dio_attr[DioUsbdevSuspend], + // D is used as an input only + dio_out[DioUsbdevD], + dio_oe[DioUsbdevD], + dio_attr[DioUsbdevD] + }; + +% endif + +################################################################### +## USB for Nexysvideo ## +################################################################### +% if target["name"] == "nexysvideo": + + ///////////////////// + // USB Overlay Mux // + ///////////////////// + + // TODO: generalize this USB mux code and align with other tops. + + // Software can enable the pinflip feature inside usbdev. + // The example hello_usbdev does this based on GPIO0 (a switch on the board) + // + // Here, we use the state of the DN pullup to effectively undo the + // swapping such that the PCB always sees the unflipped D+/D-. We + // could do the same inside the .xdc file but then two FPGA + // bitstreams would be needed for testing. + // + // dio_in/out/oe map is: PADS <- _padring <- JTAG mux -> _umux -> USB mux -> _core + + // Split out for differential PHY testing + + // Outputs always drive and just copy the value + // Let them go to the normal place too because it won't do any harm + // and it simplifies the changes needed + + // The output enable for IO_USB_DNPULLUP0 is used to decide whether we need to undo the swapping. + logic undo_swap; + assign undo_swap = dio_oe[DioUsbdevDnPullup]; + + // GPIO[2] = Switch 2 on board is used to select using the UPHY + // Keep GPIO[1] for selecting differential in sw + logic use_uphy; + assign use_uphy = mio_in[MioPadIoa2]; + + // DioUsbdevDn + assign manual_attr_usb_n = '0; + assign manual_attr_io_uphy_dn_tx = '0; + + assign manual_out_io_uphy_dn_tx = manual_out_usb_n; + assign manual_out_usb_n = undo_swap ? dio_out[DioUsbdevDp] : + dio_out[DioUsbdevDn]; + + assign manual_oe_io_uphy_dn_tx = manual_oe_usb_n; + assign manual_oe_usb_n = undo_swap ? dio_oe[DioUsbdevDp] : + dio_oe[DioUsbdevDn]; + + assign dio_in[DioUsbdevDn] = use_uphy ? + (undo_swap ? manual_in_io_uphy_dp_rx : + manual_in_io_uphy_dn_rx) : + (undo_swap ? manual_in_usb_p : + manual_in_usb_n); + // DioUsbdevDp + assign manual_attr_usb_p = '0; + assign manual_attr_io_uphy_dp_tx = '0; + + assign manual_out_io_uphy_dp_tx = manual_out_usb_p; + assign manual_out_usb_p = undo_swap ? dio_out[DioUsbdevDn] : + dio_out[DioUsbdevDp]; + + assign manual_oe_io_uphy_dp_tx = manual_oe_usb_p; + assign manual_oe_usb_p = undo_swap ? dio_oe[DioUsbdevDn] : + dio_oe[DioUsbdevDp]; + assign dio_in[DioUsbdevDp] = use_uphy ? + (undo_swap ? manual_in_io_uphy_dn_rx : + manual_in_io_uphy_dp_rx) : + (undo_swap ? manual_in_usb_n : + manual_in_usb_p); + // DioUsbdevD + // This is not connected at the moment + logic unused_out_usb_d; + assign unused_out_usb_d = dio_out[DioUsbdevD] ^ + dio_oe[DioUsbdevD]; + assign dio_in[DioUsbdevD] = use_uphy ? + (undo_swap ? ~manual_in_io_uphy_d_rx : + manual_in_io_uphy_d_rx) : + // This is not connected at the moment + (undo_swap ? 1'b1 : 1'b0); + assign manual_out_io_uphy_d_rx = 1'b0; + assign manual_oe_io_uphy_d_rx = 1'b0; + + // DioUsbdevDnPullup + assign manual_attr_io_usb_dnpullup0 = '0; + assign manual_out_io_usb_dnpullup0 = undo_swap ? dio_out[DioUsbdevDpPullup] : + dio_out[DioUsbdevDnPullup]; + assign manual_oe_io_usb_dnpullup0 = undo_swap ? dio_oe[DioUsbdevDpPullup] : + dio_oe[DioUsbdevDnPullup]; + assign dio_in[DioUsbdevDnPullup] = manual_in_io_usb_dnpullup0; + + // DioUsbdevDpPullup + assign manual_attr_io_usb_dppullup0 = '0; + assign manual_out_io_usb_dppullup0 = undo_swap ? dio_out[DioUsbdevDnPullup] : + dio_out[DioUsbdevDpPullup]; + assign manual_oe_io_usb_dppullup0 = undo_swap ? dio_oe[DioUsbdevDnPullup] : + dio_oe[DioUsbdevDpPullup]; + assign dio_in[DioUsbdevDpPullup] = manual_in_io_usb_dppullup0; + + // DioUsbdevSense + assign manual_out_io_usb_sense0 = dio_out[DioUsbdevSense]; + assign manual_oe_io_usb_sense0 = dio_oe[DioUsbdevSense]; + assign dio_in[DioUsbdevSense] = use_uphy ? manual_in_io_uphy_sense : + manual_in_io_usb_sense0; + assign manual_out_io_uphy_sense = 1'b0; + assign manual_oe_io_uphy_sense = 1'b0; + + // DioUsbdevRxEnable + assign dio_in[DioUsbdevRxEnable] = 1'b0; + + // Additional outputs for uphy + assign manual_oe_io_uphy_dppullup = 1'b1; + assign manual_out_io_uphy_dppullup = manual_out_io_usb_dppullup0 & + manual_oe_io_usb_dppullup0; + + logic unused_in_io_uphy_dppullup; + assign unused_in_io_uphy_dppullup = manual_in_io_uphy_dppullup; + + assign manual_oe_io_uphy_oe_n = 1'b1; + assign manual_out_io_uphy_oe_n = ~manual_oe_usb_p; + + logic unused_in_io_uphy_oe_n; + assign unused_in_io_uphy_oe_n = manual_in_io_uphy_oe_n; + +% endif + +################################################################### +## ASIC ## +################################################################### +% if target["name"] == "asic": + + ////////////////////////////////// + // Manual Pad / Signal Tie-offs // + ////////////////////////////////// + + assign manual_out_por_n = 1'b0; + assign manual_oe_por_n = 1'b0; + + assign manual_out_cc1 = 1'b0; + assign manual_oe_cc1 = 1'b0; + assign manual_out_cc2 = 1'b0; + assign manual_oe_cc2 = 1'b0; + + assign manual_out_flash_test_mode0 = 1'b0; + assign manual_oe_flash_test_mode0 = 1'b0; + assign manual_out_flash_test_mode1 = 1'b0; + assign manual_oe_flash_test_mode1 = 1'b0; + assign manual_out_flash_test_volt = 1'b0; + assign manual_oe_flash_test_volt = 1'b0; + assign manual_out_otp_ext_volt = 1'b0; + assign manual_oe_otp_ext_volt = 1'b0; + + // These pad attributes currently tied off permanently (these are all input-only pads). + assign manual_attr_por_n = '0; + assign manual_attr_cc1 = '0; + assign manual_attr_cc2 = '0; + assign manual_attr_flash_test_mode0 = '0; + assign manual_attr_flash_test_mode1 = '0; + assign manual_attr_flash_test_volt = '0; + assign manual_attr_otp_ext_volt = '0; + + logic unused_manual_sigs; + assign unused_manual_sigs = ^{ + manual_in_cc2, + manual_in_cc1, + manual_in_flash_test_volt, + manual_in_flash_test_mode0, + manual_in_flash_test_mode1, + manual_in_otp_ext_volt + }; + + /////////////////////////////// + // Differential USB Receiver // + /////////////////////////////// + + // TODO: generalize this USB mux code and align with other tops. + + // Connect the DP pad + assign dio_in[DioUsbdevDp] = manual_in_usb_p; + assign manual_out_usb_p = dio_out[DioUsbdevDp]; + assign manual_oe_usb_p = dio_oe[DioUsbdevDp]; + assign manual_attr_usb_p = dio_attr[DioUsbdevDp]; + + // Connect the DN pad + assign dio_in[DioUsbdevDn] = manual_in_usb_n; + assign manual_out_usb_n = dio_out[DioUsbdevDn]; + assign manual_oe_usb_n = dio_oe[DioUsbdevDn]; + assign manual_attr_usb_n = dio_attr[DioUsbdevDn]; + + // Pullups + logic usb_pullup_p_en, usb_pullup_n_en; + assign usb_pullup_p_en = dio_out[DioUsbdevDpPullup] & dio_oe[DioUsbdevDpPullup]; + assign usb_pullup_n_en = dio_out[DioUsbdevDnPullup] & dio_oe[DioUsbdevDnPullup]; + + logic usb_rx_enable; + assign usb_rx_enable = dio_out[DioUsbdevRxEnable] & dio_oe[DioUsbdevRxEnable]; + + logic [ast_pkg::UsbCalibWidth-1:0] usb_io_pu_cal; + + // pwrmgr interface + pwrmgr_pkg::pwr_ast_req_t base_ast_pwr; + pwrmgr_pkg::pwr_ast_rsp_t ast_base_pwr; + + prim_usb_diff_rx #( + .CalibW(ast_pkg::UsbCalibWidth) + ) u_prim_usb_diff_rx ( + .input_pi ( USB_P ), + .input_ni ( USB_N ), + .input_en_i ( usb_rx_enable ), + .core_pok_i ( ast_base_pwr.main_pok ), + .pullup_p_en_i ( usb_pullup_p_en ), + .pullup_n_en_i ( usb_pullup_n_en ), + .calibration_i ( usb_io_pu_cal ), + .input_o ( dio_in[DioUsbdevD] ) + ); + + // Tie-off unused signals + assign dio_in[DioUsbdevSense] = 1'b0; + assign dio_in[DioUsbdevSe0] = 1'b0; + assign dio_in[DioUsbdevDpPullup] = 1'b0; + assign dio_in[DioUsbdevDnPullup] = 1'b0; + assign dio_in[DioUsbdevTxModeSe] = 1'b0; + assign dio_in[DioUsbdevSuspend] = 1'b0; + assign dio_in[DioUsbdevRxEnable] = 1'b0; + + logic unused_usb_sigs; + assign unused_usb_sigs = ^{ + // Sense + dio_out[DioUsbdevSense], + dio_oe[DioUsbdevSense], + dio_attr[DioUsbdevSense], + // SE0 + dio_out[DioUsbdevSe0], + dio_oe[DioUsbdevSe0], + dio_attr[DioUsbdevSe0], + // TX Mode + dio_out[DioUsbdevTxModeSe], + dio_oe[DioUsbdevTxModeSe], + dio_attr[DioUsbdevTxModeSe], + // Suspend + dio_out[DioUsbdevSuspend], + dio_oe[DioUsbdevSuspend], + dio_attr[DioUsbdevSuspend], + // Rx enable + dio_attr[DioUsbdevRxEnable], + // D is used as an input only + dio_out[DioUsbdevD], + dio_oe[DioUsbdevD], + dio_attr[DioUsbdevD], + // Pullup/down + dio_attr[DioUsbdevDpPullup], + dio_attr[DioUsbdevDnPullup] + }; + + ////////////////////// + // AST // + ////////////////////// + // TLUL interface + tlul_pkg::tl_h2d_t base_ast_bus; + tlul_pkg::tl_d2h_t ast_base_bus; + + // assorted ast status + ast_pkg::ast_status_t ast_status; + + // ast clocks and resets + logic aon_pok; + + // synchronization clocks / rests + clkmgr_pkg::clkmgr_ast_out_t clks_ast; + rstmgr_pkg::rstmgr_ast_out_t rsts_ast; + + // otp power sequence + otp_ctrl_pkg::otp_ast_req_t otp_ctrl_otp_ast_pwr_seq; + otp_ctrl_pkg::otp_ast_rsp_t otp_ctrl_otp_ast_pwr_seq_h; + + logic usb_ref_pulse; + logic usb_ref_val; + + // adc + ast_pkg::adc_ast_req_t adc_req; + ast_pkg::adc_ast_rsp_t adc_rsp; + + // entropy source interface + // The entropy source pacakge definition should eventually be moved to es + entropy_src_pkg::entropy_src_rng_req_t es_rng_req; + entropy_src_pkg::entropy_src_rng_rsp_t es_rng_rsp; + logic es_rng_fips; + + // entropy distribution network + edn_pkg::edn_req_t ast_edn_edn_req; + edn_pkg::edn_rsp_t ast_edn_edn_rsp; + + // alerts interface + ast_pkg::ast_alert_rsp_t ast_alert_rsp; + ast_pkg::ast_alert_req_t ast_alert_req; + + // Flash connections + lc_ctrl_pkg::lc_tx_t flash_bist_enable; + logic flash_power_down_h; + logic flash_power_ready_h; + + // Life cycle clock bypass req/ack + lc_ctrl_pkg::lc_tx_t ast_clk_byp_req; + lc_ctrl_pkg::lc_tx_t ast_clk_byp_ack; + + // DFT connections + logic scan_en; + lc_ctrl_pkg::lc_tx_t dft_en; + pinmux_pkg::dft_strap_test_req_t dft_strap_test; + + // Debug connections + logic [ast_pkg::Ast2PadOutWidth-1:0] ast2pinmux; + logic [ast_pkg::Pad2AstInWidth-1:0] pad2ast; + + assign pad2ast = { + mio_in_raw[MioPadIoc3], + mio_in_raw[MioPadIob8], + mio_in_raw[MioPadIob7], + mio_in_raw[MioPadIob2], + mio_in_raw[MioPadIob1], + mio_in_raw[MioPadIob0] + }; + + + // Jitter enable + logic jen; + + // reset domain connections + import rstmgr_pkg::PowerDomains; + import rstmgr_pkg::DomainAonSel; + import rstmgr_pkg::Domain0Sel; + + // external clock comes in at a fixed position + logic ext_clk; + assign ext_clk = mio_in_raw[MioPadIoc6]; + + // Memory configuration connections + ast_pkg::spm_rm_t ast_ram_1p_cfg; + ast_pkg::spm_rm_t ast_rf_cfg; + ast_pkg::spm_rm_t ast_rom_cfg; + ast_pkg::dpm_rm_t ast_ram_2p_fcfg; + ast_pkg::dpm_rm_t ast_ram_2p_lcfg; + + prim_ram_1p_pkg::ram_1p_cfg_t ram_1p_cfg; + prim_ram_2p_pkg::ram_2p_cfg_t ram_2p_cfg; + prim_rom_pkg::rom_cfg_t rom_cfg; + + // conversion from ast structure to memory centric structures + assign ram_1p_cfg = '{ + ram_cfg: '{ + cfg_en: ast_ram_1p_cfg.marg_en, + cfg: ast_ram_1p_cfg.marg + }, + rf_cfg: '{ + cfg_en: ast_rf_cfg.marg_en, + cfg: ast_rf_cfg.marg + } + }; + + assign ram_2p_cfg = '{ + a_ram_fcfg: '{ + cfg_en: ast_ram_2p_fcfg.marg_en_a, + cfg: ast_ram_2p_fcfg.marg_a + }, + a_ram_lcfg: '{ + cfg_en: ast_ram_2p_lcfg.marg_en_a, + cfg: ast_ram_2p_lcfg.marg_a + }, + b_ram_fcfg: '{ + cfg_en: ast_ram_2p_fcfg.marg_en_b, + cfg: ast_ram_2p_fcfg.marg_b + }, + b_ram_lcfg: '{ + cfg_en: ast_ram_2p_lcfg.marg_en_b, + cfg: ast_ram_2p_lcfg.marg_b + } + }; + + assign rom_cfg = '{ + cfg_en: ast_rom_cfg.marg_en, + cfg: ast_rom_cfg.marg + }; + + + // AST does not use all clocks / resets forwarded to it + logic unused_slow_clk_en; + logic unused_usb_clk_aon; + logic unused_usb_clk_io_div4; + assign unused_slow_clk_en = base_ast_pwr.slow_clk_en; + assign unused_usb_clk_aon = clks_ast.clk_ast_usbdev_aon_peri; + assign unused_usb_clk_io_div4 = clks_ast.clk_ast_usbdev_io_div4_peri; + + logic unused_usb_usb_rst; + logic [PowerDomains-1:0] unused_usb_sys_io_div4_rst; + logic [PowerDomains-1:0] unused_usb_sys_aon_rst; + logic unused_ast_sys_io_div4_rst; + logic unused_sensor_ctrl_sys_io_div4_rst; + logic unused_adc_ctrl_sys_io_div4_rst; + logic unused_entropy_sys_rst; + logic unused_edn_sys_rst; + assign unused_usb_usb_rst = rsts_ast.rst_ast_usbdev_usb_n[DomainAonSel]; + assign unused_usb_sys_io_div4_rst = rsts_ast.rst_ast_usbdev_sys_io_div4_n; + assign unused_usb_sys_aon_rst = rsts_ast.rst_ast_usbdev_sys_aon_n; + assign unused_ast_sys_io_div4_rst = + rsts_ast.rst_ast_ast_sys_io_div4_n[Domain0Sel]; + assign unused_sensor_ctrl_sys_io_div4_rst = + rsts_ast.rst_ast_sensor_ctrl_aon_sys_io_div4_n[Domain0Sel]; + assign unused_adc_ctrl_sys_io_div4_rst = + rsts_ast.rst_ast_adc_ctrl_aon_sys_io_div4_n[Domain0Sel]; + assign unused_entropy_sys_rst = rsts_ast.rst_ast_entropy_src_sys_n[DomainAonSel]; + assign unused_edn_sys_rst = rsts_ast.rst_ast_edn0_sys_n[DomainAonSel]; + + ast_pkg::ast_dif_t flash_alert; + ast_pkg::ast_dif_t otp_alert; + logic ast_init_done; + + ast #( + .EntropyStreams(ast_pkg::EntropyStreams), + .AdcChannels(ast_pkg::AdcChannels), + .AdcDataWidth(ast_pkg::AdcDataWidth), + .UsbCalibWidth(ast_pkg::UsbCalibWidth), + .Ast2PadOutWidth(ast_pkg::Ast2PadOutWidth), + .Pad2AstInWidth(ast_pkg::Pad2AstInWidth) + ) u_ast ( + // tlul + .tl_i ( base_ast_bus ), + .tl_o ( ast_base_bus ), + // init done indication + .ast_init_done_o ( ast_init_done ), + // buffered clocks & resets + // Reset domain connection is manual at the moment + .clk_ast_adc_i ( clks_ast.clk_ast_adc_ctrl_aon_io_div4_peri ), + .rst_ast_adc_ni ( rsts_ast.rst_ast_adc_ctrl_aon_sys_io_div4_n[DomainAonSel] ), + .clk_ast_alert_i ( clks_ast.clk_ast_sensor_ctrl_aon_io_div4_secure ), + .rst_ast_alert_ni ( rsts_ast.rst_ast_sensor_ctrl_aon_sys_io_div4_n[DomainAonSel] ), + .clk_ast_es_i ( clks_ast.clk_ast_edn0_main_secure ), + .rst_ast_es_ni ( rsts_ast.rst_ast_edn0_sys_n[Domain0Sel] ), + .clk_ast_rng_i ( clks_ast.clk_ast_entropy_src_main_secure ), + .rst_ast_rng_ni ( rsts_ast.rst_ast_entropy_src_sys_n[Domain0Sel] ), + .clk_ast_tlul_i ( clks_ast.clk_ast_ast_io_div4_secure ), + .rst_ast_tlul_ni ( rsts_ast.rst_ast_ast_sys_io_div4_n[DomainAonSel] ), + .clk_ast_usb_i ( clks_ast.clk_ast_usbdev_usb_peri ), + .rst_ast_usb_ni ( rsts_ast.rst_ast_usbdev_usb_n[Domain0Sel] ), + .clk_ast_ext_i ( ext_clk ), + .por_ni ( manual_in_por_n ), + // pok test for FPGA + .vcc_supp_i ( 1'b1 ), + .vcaon_supp_i ( 1'b1 ), + .vcmain_supp_i ( 1'b1 ), + .vioa_supp_i ( 1'b1 ), + .viob_supp_i ( 1'b1 ), + // pok + .vcaon_pok_o ( aon_pok ), + .vcmain_pok_o ( ast_base_pwr.main_pok ), + .vioa_pok_o ( ast_status.io_pok[0] ), + .viob_pok_o ( ast_status.io_pok[1] ), + // main regulator + .main_env_iso_en_i ( base_ast_pwr.pwr_clamp_env ), + .main_pd_ni ( base_ast_pwr.main_pd_n ), + // pdm control (flash)/otp + .flash_power_down_h_o ( flash_power_down_h ), + .flash_power_ready_h_o ( flash_power_ready_h ), + .otp_power_seq_i ( otp_ctrl_otp_ast_pwr_seq ), + .otp_power_seq_h_o ( otp_ctrl_otp_ast_pwr_seq_h ), + // system source clock + .clk_src_sys_en_i ( base_ast_pwr.core_clk_en ), + // need to add function in clkmgr + .clk_src_sys_jen_i ( jen ), + .clk_src_sys_o ( ast_base_clks.clk_sys ), + .clk_src_sys_val_o ( ast_base_pwr.core_clk_val ), + // aon source clock + .clk_src_aon_o ( ast_base_clks.clk_aon ), + .clk_src_aon_val_o ( ast_base_pwr.slow_clk_val ), + // io source clock + .clk_src_io_en_i ( base_ast_pwr.io_clk_en ), + .clk_src_io_o ( ast_base_clks.clk_io ), + .clk_src_io_val_o ( ast_base_pwr.io_clk_val ), + // usb source clock + .usb_ref_pulse_i ( usb_ref_pulse ), + .usb_ref_val_i ( usb_ref_val ), + .clk_src_usb_en_i ( base_ast_pwr.usb_clk_en ), + .clk_src_usb_o ( ast_base_clks.clk_usb ), + .clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ), + // USB IO Pull-up Calibration Setting + .usb_io_pu_cal_o ( usb_io_pu_cal ), + // adc + .adc_a0_ai ( CC1 ), + .adc_a1_ai ( CC2 ), + .adc_pd_i ( adc_req.pd ), + .adc_chnsel_i ( adc_req.channel_sel ), + .adc_d_o ( adc_rsp.data ), + .adc_d_val_o ( adc_rsp.data_valid ), + // rng + .rng_en_i ( es_rng_req.rng_enable ), + .rng_fips_i ( es_rng_fips ), + .rng_val_o ( es_rng_rsp.rng_valid ), + .rng_b_o ( es_rng_rsp.rng_b ), + // entropy + .entropy_rsp_i ( ast_edn_edn_rsp ), + .entropy_req_o ( ast_edn_edn_req ), + // alerts + .fla_alert_in_i ( flash_alert ), + .otp_alert_in_i ( otp_alert ), + .alert_rsp_i ( ast_alert_rsp ), + .alert_req_o ( ast_alert_req ), + // dft + .dft_strap_test_i ( dft_strap_test ), + .lc_dft_en_i ( dft_en ), + // pinmux related + .padmux2ast_i ( pad2ast ), + .ast2padmux_o ( ast2pinmux ), + // Direct short to PAD + .pad2ast_t0_ai ( IOA4 ), + .pad2ast_t1_ai ( IOA5 ), + .ast2pad_t0_ao ( IOA2 ), + .ast2pad_t1_ao ( IOA3 ), + .lc_clk_byp_req_i ( ast_clk_byp_req ), + .lc_clk_byp_ack_o ( ast_clk_byp_ack ), + .flash_bist_en_o ( flash_bist_enable ), + // Memory configuration connections + .dpram_rmf_o ( ast_ram_2p_fcfg ), + .dpram_rml_o ( ast_ram_2p_lcfg ), + .spram_rm_o ( ast_ram_1p_cfg ), + .sprgf_rm_o ( ast_rf_cfg ), + .sprom_rm_o ( ast_rom_cfg ), + // scan + .dft_scan_md_o ( scanmode ), + .scan_shift_en_o ( scan_en ), + .scan_reset_no ( scan_rst_n ) + ); + + ////////////////////// + // Top-level design // + ////////////////////// + + top_${top["name"]} #( + .AesMasking(1'b1), + .AesSBoxImpl(aes_pkg::SBoxImplDom), + .SecAesStartTriggerDelay(0), + .SecAesAllowForcingMasks(1'b0), + .KmacEnMasking(1), // DOM AND + Masking scheme + .KmacReuseShare(0), + .SramCtrlRetAonInstrExec(0), + .SramCtrlMainInstrExec(1), + .PinmuxAonTargetCfg(PinmuxTargetCfg), + .RomCtrlSkipCheck(RomCtrlSkipCheck) + ) top_${top["name"]} ( + .rst_ni ( aon_pok ), + // ast connections + .clk_main_i ( ast_base_clks.clk_sys ), + .clk_io_i ( ast_base_clks.clk_io ), + .clk_usb_i ( ast_base_clks.clk_usb ), + .clk_aon_i ( ast_base_clks.clk_aon ), + .clks_ast_o ( clks_ast ), + .clk_main_jitter_en_o ( jen ), + .rsts_ast_o ( rsts_ast ), + .pwrmgr_ast_req_o ( base_ast_pwr ), + .pwrmgr_ast_rsp_i ( ast_base_pwr ), + .sensor_ctrl_ast_alert_req_i ( ast_alert_req ), + .sensor_ctrl_ast_alert_rsp_o ( ast_alert_rsp ), + .sensor_ctrl_ast_status_i ( ast_status ), + .usbdev_usb_ref_val_o ( usb_ref_pulse ), + .usbdev_usb_ref_pulse_o ( usb_ref_val ), + .ast_tl_req_o ( base_ast_bus ), + .ast_tl_rsp_i ( ast_base_bus ), + .adc_req_o ( adc_req ), + .adc_rsp_i ( adc_rsp ), + .ast_edn_req_i ( ast_edn_edn_req ), + .ast_edn_rsp_o ( ast_edn_edn_rsp ), + .otp_ctrl_otp_ast_pwr_seq_o ( otp_ctrl_otp_ast_pwr_seq ), + .otp_ctrl_otp_ast_pwr_seq_h_i ( otp_ctrl_otp_ast_pwr_seq_h ), + .otp_alert_o ( otp_alert ), + .flash_bist_enable_i ( flash_bist_enable ), + .flash_power_down_h_i ( flash_power_down_h ), + .flash_power_ready_h_i ( flash_power_ready_h ), + .flash_alert_o ( flash_alert ), + .es_rng_req_o ( es_rng_req ), + .es_rng_rsp_i ( es_rng_rsp ), + .es_rng_fips_o ( es_rng_fips ), + .ast_clk_byp_req_o ( ast_clk_byp_req ), + .ast_clk_byp_ack_i ( ast_clk_byp_ack ), + .ast2pinmux_i ( ast2pinmux ), + .ast_init_done_i ( ast_init_done ), + + // Flash test mode voltages + .flash_test_mode_a_io ( {FLASH_TEST_MODE1, + FLASH_TEST_MODE0} ), + .flash_test_voltage_h_io ( FLASH_TEST_VOLT ), + + // OTP external voltage + .otp_ext_voltage_h_io ( OTP_EXT_VOLT ), + + // Multiplexed I/O + .mio_in_i ( mio_in ), + .mio_out_o ( mio_out ), + .mio_oe_o ( mio_oe ), + + // Dedicated I/O + .dio_in_i ( dio_in ), + .dio_out_o ( dio_out ), + .dio_oe_o ( dio_oe ), + + // Pad attributes + .mio_attr_o ( mio_attr ), + .dio_attr_o ( dio_attr ), + + // Memory attributes + .ram_1p_cfg_i ( ram_1p_cfg ), + .ram_2p_cfg_i ( ram_2p_cfg ), + .rom_cfg_i ( rom_cfg ), + + // DFT signals + .ast_lc_dft_en_o ( dft_en ), + .dft_strap_test_o ( dft_strap_test ), + .dft_hold_tap_sel_i ( '0 ), + .scan_rst_ni ( scan_rst_n ), + .scan_en_i ( scan_en ), + .scanmode_i ( scanmode ) + ); +% endif + +################################################################### +## FPGA shared ## +################################################################### +% if target["name"] in ["cw305", "nexysvideo"]: + ////////////////// + // PLL for FPGA // + ////////////////// + + assign manual_out_io_clk = 1'b0; + assign manual_oe_io_clk = 1'b0; + assign manual_out_por_n = 1'b0; + assign manual_oe_por_n = 1'b0; + assign manual_out_io_jsrst_n = 1'b0; + assign manual_oe_io_jsrst_n = 1'b0; + + logic clk_main, clk_usb_48mhz, clk_aon, rst_n; + clkgen_xil7series # ( + .AddClkBuf(0) + ) clkgen ( + .clk_i(manual_in_io_clk), + .rst_ni(manual_in_por_n), + .jtag_srst_ni(manual_in_io_jsrst_n), + .clk_main_o(clk_main), + .clk_48MHz_o(clk_usb_48mhz), + .clk_aon_o(clk_aon), + .rst_no(rst_n) + ); + + ////////////////////// + // Top-level design // + ////////////////////// + pwrmgr_pkg::pwr_ast_rsp_t ast_base_pwr; + ast_pkg::ast_alert_req_t ast_base_alerts; + ast_pkg::ast_status_t ast_base_status; + + assign ast_base_pwr.slow_clk_val = 1'b1; + assign ast_base_pwr.core_clk_val = 1'b1; + assign ast_base_pwr.io_clk_val = 1'b1; + assign ast_base_pwr.usb_clk_val = 1'b1; + assign ast_base_pwr.main_pok = 1'b1; + + ast_pkg::ast_dif_t silent_alert = '{ + p: 1'b0, + n: 1'b1 + }; + + assign ast_base_alerts.alerts = {ast_pkg::NumAlerts{silent_alert}}; + assign ast_base_status.io_pok = {ast_pkg::NumIoRails{1'b1}}; + + // the rst_ni pin only goes to AST + // the rest of the logic generates reset based on the 'pok' signal. + // for verilator purposes, make these two the same. + lc_ctrl_pkg::lc_tx_t lc_clk_bypass; + +% if target["name"] == "cw305": + // This is used for outputting the capture trigger + logic [pinmux_reg_pkg::NMioPads-1:0] mio_out_pre; +% endif + +// TODO: align this with ASIC version to minimize the duplication. +// Also need to add AST simulation and FPGA emulation models for things like entropy source - +// otherwise Verilator / FPGA will hang. + top_${top["name"]} #( +% if target["name"] == "cw305": + .AesMasking(1'b1), + .AesSBoxImpl(aes_pkg::SBoxImplDom), + .SecAesStartTriggerDelay(40), + .SecAesAllowForcingMasks(1'b1), + .SecAesSkipPRNGReseeding(1'b1), + .IbexICache(0), + .BootRomInitFile(BootRomInitFile), +% else: + .AesMasking(1'b0), + .AesSBoxImpl(aes_pkg::SBoxImplLut), + .SecAesStartTriggerDelay(0), + .SecAesAllowForcingMasks(1'b0), + .SecAesSkipPRNGReseeding(1'b0), + .EntropySrcStub(1'b1), + .CsrngSBoxImpl(aes_pkg::SBoxImplLut), + .OtbnRegFile(otbn_pkg::RegFileFPGA), + .OtbnStub(1'b1), + .OtpCtrlMemInitFile(OtpCtrlMemInitFile), + .RomCtrlBootRomInitFile(BootRomInitFile), +% endif + .IbexRegFile(ibex_pkg::RegFileFPGA), + .IbexPipeLine(1), + .SecureIbex(0), + .SramCtrlRetAonInstrExec(0), + .SramCtrlMainInstrExec(1), + .PinmuxAonTargetCfg(PinmuxTargetCfg) + ) top_${top["name"]} ( + .rst_ni ( rst_n ), + .clk_main_i ( clk_main ), + .clk_io_i ( clk_main ), + .clk_usb_i ( clk_usb_48mhz ), + .clk_aon_i ( clk_aon ), + .clks_ast_o ( ), + .clk_main_jitter_en_o ( ), + .rsts_ast_o ( ), + .pwrmgr_ast_req_o ( ), + .pwrmgr_ast_rsp_i ( ast_base_pwr ), + .sensor_ctrl_ast_alert_req_i ( ast_base_alerts ), + .sensor_ctrl_ast_alert_rsp_o ( ), + .sensor_ctrl_ast_status_i ( ast_base_status ), + .usbdev_usb_ref_val_o ( ), + .usbdev_usb_ref_pulse_o ( ), + .ast_edn_req_i ( '0 ), + .ast_edn_rsp_o ( ), + .flash_bist_enable_i ( lc_ctrl_pkg::Off ), + .flash_power_down_h_i ( 1'b0 ), + .flash_power_ready_h_i ( 1'b1 ), + .ast_clk_byp_req_o ( lc_clk_bypass ), + .ast_clk_byp_ack_i ( lc_clk_bypass ), + +% if target["name"] != "cw305": + .ast_tl_req_o ( ), + .ast_tl_rsp_i ( '0 ), + .otp_ctrl_otp_ast_pwr_seq_o ( ), + .otp_ctrl_otp_ast_pwr_seq_h_i ( '0 ), + .otp_alert_o ( ), + .es_rng_req_o ( ), + .es_rng_rsp_i ( '0 ), + .es_rng_fips_o ( ), + .ast2pinmux_i ( '0 ), +% endif + + // Multiplexed I/O + .mio_in_i ( mio_in ), +% if target["name"] == "cw305": + .mio_out_o ( mio_out_pre ), +% else: + .mio_out_o ( mio_out ), +% endif + .mio_oe_o ( mio_oe ), + + // Dedicated I/O + .dio_in_i ( dio_in ), + .dio_out_o ( dio_out ), + .dio_oe_o ( dio_oe ), + + // Pad attributes + .mio_attr_o ( mio_attr ), + .dio_attr_o ( dio_attr ), + + // Memory attributes + .ram_1p_cfg_i ( '0 ), + .ram_2p_cfg_i ( '0 ), + .rom_cfg_i ( '0 ), + + // DFT signals + .dft_hold_tap_sel_i ( '0 ), + .scan_rst_ni ( 1'b1 ), + .scan_en_i ( 1'b0 ), + .scanmode_i ( lc_ctrl_pkg::Off ) + ); +% endif + + +################################################################### +## CW305 capture trigger ## +################################################################### +% if target["name"] == "cw305": + + ////////////////////////////////////// + // Generate precise capture trigger // + ////////////////////////////////////// + + // TODO: make this a "manual" IO specific to the CW305 target + // such that we can decouple this from the MIO signals. + localparam int MioIdxTrigger = 15; + + // To obtain a more precise capture trigger for side-channel analysis, we only forward the + // software-controlled capture trigger when the AES module is actually busy (performing + // either encryption/decryption or clearing internal registers). + // GPIO15 is used as capture trigger (mapped to IOB9 at the moment in pinmux.c). + always_comb begin : p_trigger + mio_out = mio_out_pre; + mio_out[MioIdxTrigger] = mio_out_pre[MioIdxTrigger] & + ~top_englishbreakfast.clkmgr_aon_idle[clkmgr_pkg::Aes]; + end + + ////////////////////// + // ChipWhisperer IO // + ////////////////////// + + logic unused_inputs; + assign unused_inputs = manual_in_tio_clkout ^ manual_in_io_utx_debug; + + // Clock ouput to capture board. + assign manual_out_tio_clkout = manual_in_io_clk; + assign manual_oe_tio_clkout = 1'b1; + + // UART Tx for debugging. The UART itself is connected to the capture board. + assign manual_out_io_utx_debug = top_${top["name"]}.cio_uart0_tx_d2p; + assign manual_oe_io_utx_debug = 1'b1; + +% endif + +endmodule : chip_${top["name"]}_${target["name"]} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/clang-format b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/clang-format new file mode 100644 index 00000000..7cb47a7a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/clang-format @@ -0,0 +1,4 @@ +# This disables clang-format on all files in the sw/autogen directory. +# This is needed so that git-clang-format and similar scripts work. +DisableFormat: true +SortIncludes: false diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__alert_handler_connect.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__alert_handler_connect.sv.tpl new file mode 100644 index 00000000..559926a7 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__alert_handler_connect.sv.tpl @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// tb__alert_handler_connect.sv is auto-generated by `topgen.py` tool + +<% + index = 0 + module_name = "" +%>\ +% for alert in top["alert"]: + % if alert["module_name"] == module_name: +<% index = index + 1 %>\ + % else: +<% + module_name = alert["module_name"] + index = 0 +%>\ + % endif +assign alert_if[${loop.index}].alert_tx = `CHIP_HIER.u_${module_name}.alert_tx_o[${index}]; +% endfor diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__xbar_connect.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__xbar_connect.sv.tpl new file mode 100644 index 00000000..d4910958 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/tb__xbar_connect.sv.tpl @@ -0,0 +1,124 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// tb__xbar_connect generated by `topgen.py` tool +<% +from collections import OrderedDict +import topgen.lib as lib + +top_hier = 'tb.dut.top_' + top["name"] + '.' +clk_hier = top_hier + top["clocks"]["hier_paths"]["top"] + +clk_src = OrderedDict() +for xbar in top["xbar"]: + for clk, src in xbar["clock_srcs"].items(): + clk_src[clk] = src + +clk_freq = OrderedDict() +for clock in top["clocks"]["srcs"] + top["clocks"]["derived_srcs"]: + if clock["name"] in clk_src.values(): + clk_freq[clock["name"]] = clock["freq"] + +hosts = OrderedDict() +devices = OrderedDict() +for xbar in top["xbar"]: + for node in xbar["nodes"]: + if node["type"] == "host" and not node["xbar"]: + hosts[node["name"]] = "clk_" + clk_src[node["clock"]] + elif node["type"] == "device" and not node["xbar"]: + devices[node["name"]] = "clk_" + clk_src[node["clock"]] + +def escape_if_name(qual_if_name): + return qual_if_name.replace('.', '__') + +%>\ +<%text> +`define DRIVE_CHIP_TL_HOST_IF(tl_name, inst_name, sig_name) \ + force ``tl_name``_tl_if.d2h = dut.top_earlgrey.u_``inst_name``.``sig_name``_i; \ + force dut.top_earlgrey.u_``inst_name``.``sig_name``_o = ``tl_name``_tl_if.h2d; \ + force dut.top_earlgrey.u_``inst_name``.clk_i = 0; \ + uvm_config_db#(virtual tl_if)::set(null, $sformatf("*%0s*", `"tl_name`"), "vif", \ + ``tl_name``_tl_if); + +`define DRIVE_CHIP_TL_DEVICE_IF(tl_name, inst_name, sig_name) \ + force ``tl_name``_tl_if.h2d = dut.top_earlgrey.u_``inst_name``.``sig_name``_i; \ + force dut.top_earlgrey.u_``inst_name``.``sig_name``_o = ``tl_name``_tl_if.d2h; \ + force dut.top_earlgrey.u_``inst_name``.clk_i = 0; \ + uvm_config_db#(virtual tl_if)::set(null, $sformatf("*%0s*", `"tl_name`"), "vif", \ + ``tl_name``_tl_if); + +`define DRIVE_CHIP_TL_EXT_DEVICE_IF(tl_name, port_name) \ + force ``tl_name``_tl_if.h2d = dut.top_earlgrey.``port_name``_req_o; \ + force dut.top_earlgrey.``port_name``_rsp_i = ``tl_name``_tl_if.d2h; \ + uvm_config_db#(virtual tl_if)::set(null, $sformatf("*%0s*", `"tl_name`"), "vif", \ + ``tl_name``_tl_if); +\ + +% for c in clk_freq.keys(): +wire clk_${c}; +clk_rst_if clk_rst_if_${c}(.clk(clk_${c}), .rst_n(rst_n)); +% endfor + +% for i, clk in hosts.items(): +tl_if ${escape_if_name(i)}_tl_if(${clk}, rst_n); +% endfor + +% for i, clk in devices.items(): +tl_if ${escape_if_name(i)}_tl_if(${clk}, rst_n); +% endfor + +initial begin + bit xbar_mode; + void'($value$plusargs("xbar_mode=%0b", xbar_mode)); + if (xbar_mode) begin + // only enable assertions in xbar as many pins are unconnected + $assertoff(0, tb); +% for xbar in top["xbar"]: + $asserton(0, tb.dut.top_${top["name"]}.u_xbar_${xbar["name"]}); +% endfor + +% for c in clk_freq.keys(): + clk_rst_if_${c}.set_active(.drive_rst_n_val(0)); + clk_rst_if_${c}.set_freq_khz(${clk_freq[c]} / 1000); +% endfor + + // bypass clkmgr, force clocks directly +% for xbar in top["xbar"]: + % for clk, src in xbar["clock_srcs"].items(): + force ${top_hier}u_xbar_${xbar["name"]}.${clk} = clk_${src}; + % endfor +% endfor + + // bypass rstmgr, force resets directly +% for xbar in top["xbar"]: + % for rst in xbar["reset_connections"]: + force ${top_hier}u_xbar_${xbar["name"]}.${rst} = rst_n; + % endfor +% endfor + +% for xbar in top["xbar"]: + % for node in xbar["nodes"]: +<% +clk = 'clk_' + clk_src[node["clock"]] +esc_name = node['name'].replace('.', '__') +inst_sig_list = lib.find_otherside_modules(top, xbar["name"], 'tl_' + esc_name) +inst_name = inst_sig_list[0][1] +sig_name = inst_sig_list[0][2] + +%>\ + % if node["type"] == "host" and not node["xbar"]: + `DRIVE_CHIP_TL_HOST_IF(${esc_name}, ${inst_name}, ${sig_name}) + % elif node["type"] == "device" and not node["xbar"] and node["stub"]: + `DRIVE_CHIP_TL_EXT_DEVICE_IF(${esc_name}, ${inst_name}_${sig_name}) + % elif node["type"] == "device" and not node["xbar"]: + `DRIVE_CHIP_TL_DEVICE_IF(${esc_name}, ${inst_name}, ${sig_name}) + % endif + % endfor +% endfor + end +end + +`undef DRIVE_CHIP_TL_HOST_IF +`undef DRIVE_CHIP_TL_DEVICE_IF +`undef DRIVE_CHIP_TL_EXT_DEVICE_IF diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.c.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.c.tpl new file mode 100644 index 00000000..4cfbabe2 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.c.tpl @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "${helper.header_path}" + +/** + * PLIC Interrupt Source to Peripheral Map + * + * This array is a mapping from `${helper.plic_interrupts.name.as_c_type()}` to + * `${helper.plic_sources.name.as_c_type()}`. + */ +${helper.plic_mapping.render_definition()} + +/** + * Alert Handler Alert Source to Peripheral Map + * + * This array is a mapping from `${helper.alert_alerts.name.as_c_type()}` to + * `${helper.alert_sources.name.as_c_type()}`. + */ +${helper.alert_mapping.render_definition()} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.h.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.h.tpl new file mode 100644 index 00000000..24ba4100 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.h.tpl @@ -0,0 +1,201 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _TOP_${top["name"].upper()}_H_ +#define _TOP_${top["name"].upper()}_H_ + +/** + * @file + * @brief Top-specific Definitions + * + * This file contains preprocessor and type definitions for use within the + * device C/C++ codebase. + * + * These definitions are for information that depends on the top-specific chip + * configuration, which includes: + * - Device Memory Information (for Peripherals and Memory) + * - PLIC Interrupt ID Names and Source Mappings + * - Alert ID Names and Source Mappings + * - Pinmux Pin/Select Names + * - Power Manager Wakeups + */ + +#ifdef __cplusplus +extern "C" { +#endif + +% for (inst_name, if_name), region in helper.devices(): +<% + if_desc = inst_name if if_name is None else '{} device on {}'.format(if_name, inst_name) + hex_base_addr = "0x{:X}u".format(region.base_addr) + hex_size_bytes = "0x{:X}u".format(region.size_bytes) + + base_addr_name = region.base_addr_name().as_c_define() + size_bytes_name = region.size_bytes_name().as_c_define() + +%>\ +/** + * Peripheral base address for ${if_desc} in top ${top["name"]}. + * + * This should be used with #mmio_region_from_addr to access the memory-mapped + * registers associated with the peripheral (usually via a DIF). + */ +#define ${base_addr_name} ${hex_base_addr} + +/** + * Peripheral size for ${if_desc} in top ${top["name"]}. + * + * This is the size (in bytes) of the peripheral's reserved memory area. All + * memory-mapped registers associated with this peripheral should have an + * address between #${base_addr_name} and + * `${base_addr_name} + ${size_bytes_name}`. + */ +#define ${size_bytes_name} ${hex_size_bytes} + +% endfor + +% for name, region in helper.memories(): +<% + hex_base_addr = "0x{:X}u".format(region.base_addr) + hex_size_bytes = "0x{:X}u".format(region.size_bytes) + + base_addr_name = region.base_addr_name().as_c_define() + size_bytes_name = region.size_bytes_name().as_c_define() + +%>\ +/** + * Memory base address for ${name} in top ${top["name"]}. + */ +#define ${base_addr_name} ${hex_base_addr} + +/** + * Memory size for ${name} in top ${top["name"]}. + */ +#define ${size_bytes_name} ${hex_size_bytes} + +% endfor + +/** + * PLIC Interrupt Source Peripheral. + * + * Enumeration used to determine which peripheral asserted the corresponding + * interrupt. + */ +${helper.plic_sources.render()} + +/** + * PLIC Interrupt Source. + * + * Enumeration of all PLIC interrupt sources. The interrupt sources belonging to + * the same peripheral are guaranteed to be consecutive. + */ +${helper.plic_interrupts.render()} + +/** + * PLIC Interrupt Source to Peripheral Map + * + * This array is a mapping from `${helper.plic_interrupts.name.as_c_type()}` to + * `${helper.plic_sources.name.as_c_type()}`. + */ +${helper.plic_mapping.render_declaration()} + +/** + * PLIC Interrupt Target. + * + * Enumeration used to determine which set of IE, CC, threshold registers to + * access for a given interrupt target. + */ +${helper.plic_targets.render()} + +/** + * Alert Handler Source Peripheral. + * + * Enumeration used to determine which peripheral asserted the corresponding + * alert. + */ +${helper.alert_sources.render()} + +/** + * Alert Handler Alert Source. + * + * Enumeration of all Alert Handler Alert Sources. The alert sources belonging to + * the same peripheral are guaranteed to be consecutive. + */ +${helper.alert_alerts.render()} + +/** + * Alert Handler Alert Source to Peripheral Map + * + * This array is a mapping from `${helper.alert_alerts.name.as_c_type()}` to + * `${helper.alert_sources.name.as_c_type()}`. + */ +${helper.alert_mapping.render_declaration()} + +#define PINMUX_MIO_PERIPH_INSEL_IDX_OFFSET 2 + +// PERIPH_INSEL ranges from 0 to NUM_MIO_PADS + 2 -1} +// 0 and 1 are tied to value 0 and 1 +#define NUM_MIO_PADS ${top["pinmux"]["io_counts"]["muxed"]["pads"]} +#define NUM_DIO_PADS ${top["pinmux"]["io_counts"]["dedicated"]["inouts"] + \ + top["pinmux"]["io_counts"]["dedicated"]["inputs"] + \ + top["pinmux"]["io_counts"]["dedicated"]["outputs"] } + +#define PINMUX_PERIPH_OUTSEL_IDX_OFFSET 3 + +/** + * Pinmux Peripheral Input. + */ +${helper.pinmux_peripheral_in.render()} + +/** + * Pinmux MIO Input Selector. + */ +${helper.pinmux_insel.render()} + +/** + * Pinmux MIO Output. + */ +${helper.pinmux_mio_out.render()} + +/** + * Pinmux Peripheral Output Selector. + */ +${helper.pinmux_outsel.render()} + +/** + * Power Manager Wakeup Signals + */ +${helper.pwrmgr_wakeups.render()} + +/** + * Reset Manager Software Controlled Resets + */ +${helper.rstmgr_sw_rsts.render()} + +/** + * Power Manager Reset Request Signals + */ +${helper.pwrmgr_reset_requests.render()} + +/** + * Clock Manager Software-Controlled ("Gated") Clocks. + * + * The Software has full control over these clocks. + */ +${helper.clkmgr_gateable_clocks.render()} + +/** + * Clock Manager Software-Hinted Clocks. + * + * The Software has partial control over these clocks. It can ask them to stop, + * but the clock manager is in control of whether the clock actually is stopped. + */ +${helper.clkmgr_hintable_clocks.render()} + +// Header Extern Guard +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _TOP_${top["name"].upper()}_H_ diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.sv.tpl new file mode 100644 index 00000000..f0248b3c --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel.sv.tpl @@ -0,0 +1,832 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +${gencmd} +<% +import re +import topgen.lib as lib + +num_mio_inputs = top['pinmux']['io_counts']['muxed']['inouts'] + \ + top['pinmux']['io_counts']['muxed']['inputs'] +num_mio_outputs = top['pinmux']['io_counts']['muxed']['inouts'] + \ + top['pinmux']['io_counts']['muxed']['outputs'] +num_mio_pads = top['pinmux']['io_counts']['muxed']['pads'] + +num_dio_inputs = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['inputs'] +num_dio_outputs = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['outputs'] +num_dio_total = top['pinmux']['io_counts']['dedicated']['inouts'] + \ + top['pinmux']['io_counts']['dedicated']['inputs'] + \ + top['pinmux']['io_counts']['dedicated']['outputs'] + +num_im = sum([x["width"] if "width" in x else 1 for x in top["inter_signal"]["external"]]) + +max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) +max_sigwidth = len("{}".format(max_sigwidth)) + +clks_attr = top['clocks'] +cpu_clk = top['clocks']['hier_paths']['top'] + "clk_proc_main" +cpu_rst = top["reset_paths"]["sys"] +dm_rst = top["reset_paths"]["lc"] +esc_clk = top['clocks']['hier_paths']['top'] + "clk_io_div4_timers" +esc_rst = top["reset_paths"]["sys_io_div4"] + +unused_resets = lib.get_unused_resets(top) +unused_im_defs, undriven_im_defs = lib.get_dangling_im_def(top["inter_signal"]["definitions"]) + +has_toplevel_rom = False +for m in top['memory']: + if m['type'] == 'rom': + has_toplevel_rom = True + +%>\ +module top_${top["name"]} #( + // Auto-inferred parameters +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif + % for p_exp in filter(lambda p: p.get("expose") == "true", m["param_list"]): + parameter ${p_exp["type"]} ${p_exp["name_top"]} = ${p_exp["default"]}, + % endfor +% endfor + + // Manually defined parameters +% if has_toplevel_rom: + parameter BootRomInitFile = "", +% endif + parameter ibex_pkg::regfile_e IbexRegFile = ibex_pkg::RegFileFF, + parameter bit IbexICache = 1, + parameter bit IbexPipeLine = 0, + parameter bit SecureIbex = 1 +) ( + // Reset, clocks defined as part of intermodule + input rst_ni, + +% if num_mio_pads != 0: + // Multiplexed I/O + input ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_in_i, + output logic ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_out_o, + output logic ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_oe_o, +% endif +% if num_dio_total != 0: + // Dedicated I/O + input ${lib.bitarray(num_dio_total, max_sigwidth)} dio_in_i, + output logic ${lib.bitarray(num_dio_total, max_sigwidth)} dio_out_o, + output logic ${lib.bitarray(num_dio_total, max_sigwidth)} dio_oe_o, +% endif + +% if "pinmux" in top: + // pad attributes to padring + output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NMioPads-1:0] mio_attr_o, + output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NDioPads-1:0] dio_attr_o, +% endif + +% if num_im != 0: + + // Inter-module Signal External type + % for sig in top["inter_signal"]["external"]: + ${"input " if sig["direction"] == "in" else "output"} ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}, + % endfor + + // Flash specific voltages + inout [1:0] flash_test_mode_a_io, + inout flash_test_voltage_h_io, + + // OTP specific voltages + inout otp_ext_voltage_h_io, + +% endif + input scan_rst_ni, // reset used for test mode + input scan_en_i, + input lc_ctrl_pkg::lc_tx_t scanmode_i // lc_ctrl_pkg::On for Scan +); + + // JTAG IDCODE for development versions of this code. + // Manufacturers of OpenTitan chips must replace this code with one of their + // own IDs. + // Field structure as defined in the IEEE 1149.1 (JTAG) specification, + // section 12.1.1. + localparam logic [31:0] JTAG_IDCODE = { + 4'h0, // Version + 16'h4F54, // Part Number: "OT" + 11'h426, // Manufacturer Identity: Google + 1'b1 // (fixed) + }; + + import tlul_pkg::*; + import top_pkg::*; + import tl_main_pkg::*; + import top_${top["name"]}_pkg::*; + // Compile-time random constants + import top_${top["name"]}_rnd_cnst_pkg::*; + + // Signals + logic [${num_mio_inputs - 1}:0] mio_p2d; + logic [${num_mio_outputs - 1}:0] mio_d2p; + logic [${num_mio_outputs - 1}:0] mio_en_d2p; + logic [${num_dio_total - 1}:0] dio_p2d; + logic [${num_dio_total - 1}:0] dio_d2p; + logic [${num_dio_total - 1}:0] dio_en_d2p; +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif +<% + block = name_to_block[m['type']] + inouts, inputs, outputs = block.xputs +%>\ + // ${m["name"]} + % for p_in in inputs + inouts: + logic ${lib.bitarray(p_in.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_in.name}_p2d; + % endfor + % for p_out in outputs + inouts: + logic ${lib.bitarray(p_out.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_out.name}_d2p; + logic ${lib.bitarray(p_out.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_out.name}_en_d2p; + % endfor +% endfor + + +<% + # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec. + # So, total number of interrupts are the number of entries in the list + 1 + interrupt_num = sum([x["width"] if "width" in x else 1 for x in top["interrupt"]]) + 1 +%>\ + logic [${interrupt_num-1}:0] intr_vector; + // Interrupt source list +% for m in top["module"]: +<% + block = name_to_block[m['type']] +%>\ + % if not lib.is_inst(m): +<% continue %> + % endif + % for intr in block.interrupts: + % if intr.bits.width() != 1: + logic [${intr.bits.width()-1}:0] intr_${m["name"]}_${intr.name}; + % else: + logic intr_${m["name"]}_${intr.name}; + % endif + % endfor +% endfor + + +<% add_spaces = " " * len(str((interrupt_num-1).bit_length()-1)) %> + logic [0:0]${add_spaces}irq_plic; + logic [0:0]${add_spaces}msip; + logic [${(interrupt_num-1).bit_length()-1}:0] irq_id[1]; + logic [${(interrupt_num-1).bit_length()-1}:0] unused_irq_id[1]; + + // this avoids lint errors + assign unused_irq_id = irq_id; + + // Alert list + prim_alert_pkg::alert_tx_t [alert_pkg::NAlerts-1:0] alert_tx; + prim_alert_pkg::alert_rx_t [alert_pkg::NAlerts-1:0] alert_rx; + +% if not top["alert"]: + for (genvar k = 0; k < alert_pkg::NAlerts; k++) begin : gen_alert_tie_off + // tie off if no alerts present in the system + assign alert_tx[k].alert_p = 1'b0; + assign alert_tx[k].alert_n = 1'b1; + end +% endif + +## Inter-module Definitions +% if len(top["inter_signal"]["definitions"]) >= 1: + // define inter-module signals +% endif +% for sig in top["inter_signal"]["definitions"]: + ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}; +% endfor + +## Mixed connection to port +## Index greater than 0 means a port is assigned to an inter-module array +## whereas an index of 0 means a port is directly driven by a module + // define mixed connection to port +% for port in top['inter_signal']['external']: + % if port['conn_type'] and port['index'] > 0: + % if port['direction'] == 'in': + assign ${port['netname']}[${port['index']}] = ${port['signame']}; + % else: + assign ${port['signame']} = ${port['netname']}[${port['index']}]; + % endif + % elif port['conn_type']: + % if port['direction'] == 'in': + assign ${port['netname']} = ${port['signame']}; + % else: + assign ${port['signame']} = ${port['netname']}; + % endif + % endif +% endfor + +## Partial inter-module definition tie-off + // define partial inter-module tie-off +% for sig in unused_im_defs: + % for idx in range(sig['end_idx'], sig['width']): + ${lib.im_defname(sig)} unused_${sig["signame"]}${idx}; + % endfor +% endfor + + // assign partial inter-module tie-off +% for sig in unused_im_defs: + % for idx in range(sig['end_idx'], sig['width']): + assign unused_${sig["signame"]}${idx} = ${sig["signame"]}[${idx}]; + % endfor +% endfor +% for sig in undriven_im_defs: + % for idx in range(sig['end_idx'], sig['width']): + assign ${sig["signame"]}[${idx}] = ${sig["default"]}; + % endfor +% endfor + +## Inter-module signal collection + + // Unused reset signals +% for k, v in unused_resets.items(): + logic unused_d${v.lower()}_rst_${k}; +% endfor +% for k, v in unused_resets.items(): + assign unused_d${v.lower()}_rst_${k} = ${lib.get_reset_path(k, v, top['resets'])}; +% endfor + + // Non-debug module reset == reset for everything except for the debug module + logic ndmreset_req; + + // debug request from rv_dm to core + logic debug_req; + + // processor core + rv_core_ibex #( + .PMPEnable (1), + .PMPGranularity (0), // 2^(PMPGranularity+2) == 4 byte granularity + .PMPNumRegions (16), + .MHPMCounterNum (10), + .MHPMCounterWidth (32), + .RV32E (0), + .RV32M (ibex_pkg::RV32MSingleCycle), + .RV32B (ibex_pkg::RV32BNone), + .RegFile (IbexRegFile), + .BranchTargetALU (1), + .WritebackStage (1), + .ICache (IbexICache), + .ICacheECC (1), + .BranchPredictor (0), + .DbgTriggerEn (1), + .SecureIbex (SecureIbex), + .DmHaltAddr (ADDR_SPACE_DEBUG_MEM + dm::HaltAddress[31:0]), + .DmExceptionAddr (ADDR_SPACE_DEBUG_MEM + dm::ExceptionAddress[31:0]), + .PipeLine (IbexPipeLine) + ) u_rv_core_ibex ( + // clock and reset + .clk_i (${cpu_clk}), + .rst_ni (${cpu_rst}[rstmgr_pkg::Domain0Sel]), + .clk_esc_i (${esc_clk}), + .rst_esc_ni (${esc_rst}[rstmgr_pkg::Domain0Sel]), + .ram_cfg_i (ast_ram_1p_cfg), + // static pinning + .hart_id_i (32'b0), + .boot_addr_i (ADDR_SPACE_ROM_CTRL__ROM), + // TL-UL buses + .tl_i_o (main_tl_corei_req), + .tl_i_i (main_tl_corei_rsp), + .tl_d_o (main_tl_cored_req), + .tl_d_i (main_tl_cored_rsp), + // interrupts + .irq_software_i (msip), + .irq_timer_i (intr_rv_timer_timer_expired_0_0), + .irq_external_i (irq_plic), + // escalation input from alert handler (NMI) + .esc_tx_i (alert_handler_esc_tx[0]), + .esc_rx_o (alert_handler_esc_rx[0]), + // debug interface + .debug_req_i (debug_req), + // crash dump interface + .crash_dump_o (rv_core_ibex_crash_dump), + // CPU control signals + .lc_cpu_en_i (lc_ctrl_lc_cpu_en), + .pwrmgr_cpu_en_i (pwrmgr_aon_fetch_en), + .core_sleep_o (pwrmgr_aon_pwr_cpu.core_sleeping), + + // dft bypass + .scan_rst_ni, + .scanmode_i + ); + + // Debug Module (RISC-V Debug Spec 0.13) + // + + rv_dm #( + .NrHarts (1), + .IdcodeValue (JTAG_IDCODE) + ) u_dm_top ( + .clk_i (${cpu_clk}), + .rst_ni (${dm_rst}[rstmgr_pkg::Domain0Sel]), + .hw_debug_en_i (lc_ctrl_lc_hw_debug_en), + .scanmode_i, + .scan_rst_ni, + .ndmreset_o (ndmreset_req), + .dmactive_o (), + .debug_req_o (debug_req), + .unavailable_i (1'b0), + + // bus device with debug memory (for execution-based debug) + .tl_d_i (main_tl_debug_mem_req), + .tl_d_o (main_tl_debug_mem_rsp), + + // bus host (for system bus accesses, SBA) + .tl_h_o (main_tl_dm_sba_req), + .tl_h_i (main_tl_dm_sba_rsp), + + //JTAG + .jtag_req_i (pinmux_aon_rv_jtag_req), + .jtag_rsp_o (pinmux_aon_rv_jtag_rsp) + ); + + assign rstmgr_aon_cpu.ndmreset_req = ndmreset_req; + assign rstmgr_aon_cpu.rst_cpu_n = ${top["reset_paths"]["sys"]}[rstmgr_pkg::Domain0Sel]; + +## Memory Instantiation +% for m in top["memory"]: +<% + resets = m['reset_connections'] + clocks = m['clock_connections'] +%>\ + % if m["type"] == "ram_1p_scr": +<% + data_width = int(top["datawidth"]) + full_data_width = data_width + int(m["integ_width"]) + dw_byte = data_width // 8 + addr_width = ((int(m["size"], 0) // dw_byte) -1).bit_length() + sram_depth = (int(m["size"], 0) // dw_byte) + max_char = len(str(max(data_width, addr_width))) +%>\ + // sram device + logic ${lib.bitarray(1, max_char)} ${m["name"]}_req; + logic ${lib.bitarray(1, max_char)} ${m["name"]}_gnt; + logic ${lib.bitarray(1, max_char)} ${m["name"]}_we; + logic ${lib.bitarray(1, max_char)} ${m["name"]}_intg_err; + logic ${lib.bitarray(addr_width, max_char)} ${m["name"]}_addr; + logic ${lib.bitarray(full_data_width, max_char)} ${m["name"]}_wdata; + logic ${lib.bitarray(full_data_width, max_char)} ${m["name"]}_wmask; + logic ${lib.bitarray(full_data_width, max_char)} ${m["name"]}_rdata; + logic ${lib.bitarray(1, max_char)} ${m["name"]}_rvalid; + logic ${lib.bitarray(2, max_char)} ${m["name"]}_rerror; + + tlul_adapter_sram #( + .SramAw(${addr_width}), + .SramDw(${data_width}), + .Outstanding(2), + .CmdIntgCheck(1), + .EnableRspIntgGen(1), + .EnableDataIntgGen(0), + .EnableDataIntgPt(1) + ) u_tl_adapter_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + .tl_i (${m["name"]}_tl_req), + .tl_o (${m["name"]}_tl_rsp), + .en_ifetch_i (${m["inter_signal_list"][3]["top_signame"]}), + .req_o (${m["name"]}_req), + .req_type_o (), + .gnt_i (${m["name"]}_gnt), + .we_o (${m["name"]}_we), + .addr_o (${m["name"]}_addr), + .wdata_o (${m["name"]}_wdata), + .wmask_o (${m["name"]}_wmask), + .intg_error_o(${m["name"]}_intg_err), + .rdata_i (${m["name"]}_rdata), + .rvalid_i (${m["name"]}_rvalid), + .rerror_i (${m["name"]}_rerror) + ); + +<% +mem_name = m["name"].split("_") +mem_name = lib.Name(mem_name[1:]) +%>\ + prim_ram_1p_scr #( + .Width(${full_data_width}), + .Depth(${sram_depth}), + .EnableParity(0), + .LfsrWidth(${data_width}), + .StatePerm(RndCnstSramCtrl${mem_name.as_camel_case()}SramLfsrPerm), + .DataBitsPerMask(1), // TODO: Temporary change to ensure byte updates can still be done + .DiffWidth(8) + ) u_ram1p_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + + .key_valid_i (${m["inter_signal_list"][1]["top_signame"]}_req.valid), + .key_i (${m["inter_signal_list"][1]["top_signame"]}_req.key), + .nonce_i (${m["inter_signal_list"][1]["top_signame"]}_req.nonce), + .init_req_i (${m["inter_signal_list"][2]["top_signame"]}_req.req), + .init_seed_i (${m["inter_signal_list"][2]["top_signame"]}_req.seed), + .init_ack_o (${m["inter_signal_list"][2]["top_signame"]}_rsp.ack), + + .req_i (${m["name"]}_req), + .intg_error_i(${m["name"]}_intg_err), + .gnt_o (${m["name"]}_gnt), + .write_i (${m["name"]}_we), + .addr_i (${m["name"]}_addr), + .wdata_i (${m["name"]}_wdata), + .wmask_i (${m["name"]}_wmask), + .rdata_o (${m["name"]}_rdata), + .rvalid_o (${m["name"]}_rvalid), + .rerror_o (${m["name"]}_rerror), + .raddr_o (${m["inter_signal_list"][1]["top_signame"]}_rsp.raddr), + .intg_error_o(${m["inter_signal_list"][4]["top_signame"]}), + .cfg_i (ram_1p_cfg_i) + ); + + assign ${m["inter_signal_list"][1]["top_signame"]}_rsp.rerror = ${m["name"]}_rerror; + + % elif m["type"] == "rom": +<% + data_width = int(top["datawidth"]) + full_data_width = data_width + int(m['integ_width']) + dw_byte = data_width // 8 + addr_width = ((int(m["size"], 0) // dw_byte) -1).bit_length() + rom_depth = (int(m["size"], 0) // dw_byte) + max_char = len(str(max(data_width, addr_width))) +%>\ + // ROM device + logic ${lib.bitarray(1, max_char)} ${m["name"]}_req; + logic ${lib.bitarray(addr_width, max_char)} ${m["name"]}_addr; + logic ${lib.bitarray(full_data_width, max_char)} ${m["name"]}_rdata; + logic ${lib.bitarray(1, max_char)} ${m["name"]}_rvalid; + + tlul_adapter_sram #( + .SramAw(${addr_width}), + .SramDw(${data_width}), + .Outstanding(2), + .ErrOnWrite(1), + .CmdIntgCheck(1), + .EnableRspIntgGen(1), + .EnableDataIntgGen(1) // TODO: Needs to be updated for intgerity passthrough + ) u_tl_adapter_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + + .tl_i (${m["name"]}_tl_req), + .tl_o (${m["name"]}_tl_rsp), + .en_ifetch_i (tlul_pkg::InstrEn), + .req_o (${m["name"]}_req), + .req_type_o (), + .gnt_i (1'b1), // Always grant as only one requester exists + .we_o (), + .addr_o (${m["name"]}_addr), + .wdata_o (), + .wmask_o (), + .intg_error_o(), // Connect to ROM checker and ROM scramble later + .rdata_i (${m["name"]}_rdata[${data_width-1}:0]), + .rvalid_i (${m["name"]}_rvalid), + .rerror_i (2'b00) + ); + + prim_rom_adv #( + .Width(${full_data_width}), + .Depth(${rom_depth}), + .MemInitFile(BootRomInitFile) + ) u_rom_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + .req_i (${m["name"]}_req), + .addr_i (${m["name"]}_addr), + .rdata_o (${m["name"]}_rdata), + .rvalid_o (${m["name"]}_rvalid), + .cfg_i (rom_cfg_i) + ); + + % elif m["type"] == "eflash": + + // host to flash communication + logic flash_host_req; + tlul_pkg::tl_type_e flash_host_req_type; + logic flash_host_req_rdy; + logic flash_host_req_done; + logic flash_host_rderr; + logic [flash_ctrl_pkg::BusWidth-1:0] flash_host_rdata; + logic [flash_ctrl_pkg::BusAddrW-1:0] flash_host_addr; + logic flash_host_intg_err; + + tlul_adapter_sram #( + .SramAw(flash_ctrl_pkg::BusAddrW), + .SramDw(flash_ctrl_pkg::BusWidth), + .Outstanding(2), + .ByteAccess(0), + .ErrOnWrite(1), + .CmdIntgCheck(1), + .EnableRspIntgGen(1), + .EnableDataIntgGen(1) + ) u_tl_adapter_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + + .tl_i (${m["name"]}_tl_req), + .tl_o (${m["name"]}_tl_rsp), + .en_ifetch_i (tlul_pkg::InstrEn), // tie this to secure boot somehow + .req_o (flash_host_req), + .req_type_o (flash_host_req_type), + .gnt_i (flash_host_req_rdy), + .we_o (), + .addr_o (flash_host_addr), + .wdata_o (), + .wmask_o (), + .intg_error_o(flash_host_intg_err), + .rdata_i (flash_host_rdata), + .rvalid_i (flash_host_req_done), + .rerror_i ({flash_host_rderr,1'b0}) + ); + + flash_phy u_flash_${m["name"]} ( + % for key in clocks: + .${key} (${clocks[key]}), + % endfor + % for key, value in resets.items(): + .${key} (${value}), + % endfor + .host_req_i (flash_host_req), + .host_intg_err_i (flash_host_intg_err), + .host_req_type_i (flash_host_req_type), + .host_addr_i (flash_host_addr), + .host_req_rdy_o (flash_host_req_rdy), + .host_req_done_o (flash_host_req_done), + .host_rderr_o (flash_host_rderr), + .host_rdata_o (flash_host_rdata), + .flash_ctrl_i (${m["inter_signal_list"][0]["top_signame"]}_req), + .flash_ctrl_o (${m["inter_signal_list"][0]["top_signame"]}_rsp), + .lc_nvm_debug_en_i (${m["inter_signal_list"][2]["top_signame"]}), + .flash_bist_enable_i, + .flash_power_down_h_i, + .flash_power_ready_h_i, + .flash_test_mode_a_io, + .flash_test_voltage_h_io, + .flash_alert_o, + .scanmode_i, + .scan_en_i, + .scan_rst_ni + ); + + % else: + // flash memory is embedded within controller + % endif +% endfor +## Peripheral Instantiation + +<% alert_idx = 0 %> +% for m in top["module"]: +<% +if not lib.is_inst(m): + continue + +block = name_to_block[m['type']] +inouts, inputs, outputs = block.xputs + +port_list = inputs + outputs + inouts +max_sigwidth = max(len(x.name) for x in port_list) if port_list else 0 +max_intrwidth = (max(len(x.name) for x in block.interrupts) + if block.interrupts else 0) +%>\ + % if m["param_list"] or block.alerts: + ${m["type"]} #( + % if block.alerts: +<% +w = len(block.alerts) +slice = str(alert_idx+w-1) + ":" + str(alert_idx) +%>\ + .AlertAsyncOn(alert_handler_reg_pkg::AsyncOn[${slice}])${"," if m["param_list"] else ""} + % endif + % for i in m["param_list"]: + .${i["name"]}(${i["name_top" if i.get("expose") == "true" or i.get("randtype", "none") != "none" else "default"]})${"," if not loop.last else ""} + % endfor + ) u_${m["name"]} ( + % else: + ${m["type"]} u_${m["name"]} ( + % endif + % for p_in in inputs + inouts: + % if loop.first: + + // Input + % endif + .${lib.ljust("cio_"+p_in.name+"_i",max_sigwidth+9)} (cio_${m["name"]}_${p_in.name}_p2d), + % endfor + % for p_out in outputs + inouts: + % if loop.first: + + // Output + % endif + .${lib.ljust("cio_"+p_out.name+"_o", max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_d2p), + .${lib.ljust("cio_"+p_out.name+"_en_o",max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_en_d2p), + % endfor + % for intr in block.interrupts: + % if loop.first: + + // Interrupt + % endif + .${lib.ljust("intr_"+intr.name+"_o",max_intrwidth+7)} (intr_${m["name"]}_${intr.name}), + % endfor + % if block.alerts: + % for alert in block.alerts: + // [${alert_idx}]: ${alert.name}<% alert_idx += 1 %> + % endfor + .alert_tx_o ( alert_tx[${slice}] ), + .alert_rx_i ( alert_rx[${slice}] ), + % endif + ## TODO: Inter-module Connection + % if m.get('inter_signal_list'): + + // Inter-module signals + % for sig in m['inter_signal_list']: + ## TODO: handle below condition in lib.py + % if sig['type'] == "req_rsp": + .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), + .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), + % elif sig['type'] == "uni": + ## TODO: Broadcast type + ## TODO: default for logic type + .${lib.im_portname(sig)}(${lib.im_netname(sig)}), + % endif + % endfor + % endif + % if m["type"] == "rv_plic": + + .intr_src_i (intr_vector), + .irq_o (irq_plic), + .irq_id_o (irq_id), + .msip_o (msip), + % endif + % if m["type"] == "pinmux": + + .periph_to_mio_i (mio_d2p ), + .periph_to_mio_oe_i (mio_en_d2p ), + .mio_to_periph_o (mio_p2d ), + + .mio_attr_o, + .mio_out_o, + .mio_oe_o, + .mio_in_i, + + .periph_to_dio_i (dio_d2p ), + .periph_to_dio_oe_i (dio_en_d2p ), + .dio_to_periph_o (dio_p2d ), + + .dio_attr_o, + .dio_out_o, + .dio_oe_o, + .dio_in_i, + + % endif + % if m["type"] == "alert_handler": + // alert signals + .alert_rx_o ( alert_rx ), + .alert_tx_i ( alert_tx ), + % endif + % if m["type"] == "otp_ctrl": + .otp_ext_voltage_h_io, + % endif + % if block.scan: + .scanmode_i, + % endif + % if block.scan_reset: + .scan_rst_ni, + % endif + % if block.scan_en: + .scan_en_i, + % endif + + // Clock and reset connections + % for k, v in m["clock_connections"].items(): + .${k} (${v}), + % endfor + % for k, v in m["reset_connections"].items(): + .${k} (${v})${"," if not loop.last else ""} + % endfor + ); + +% endfor + // interrupt assignments +<% base = interrupt_num %>\ + assign intr_vector = { + % for intr in top["interrupt"][::-1]: +<% base -= intr["width"] %>\ + intr_${intr["name"]}, // IDs [${base} +: ${intr['width']}] + % endfor + 1'b 0 // ID [0 +: 1] is a special case and tied to zero. + }; + + // TL-UL Crossbar +% for xbar in top["xbar"]: +<% + name_len = max([len(x["name"]) for x in xbar["nodes"]]); +%>\ + xbar_${xbar["name"]} u_xbar_${xbar["name"]} ( + % for k, v in xbar["clock_connections"].items(): + .${k} (${v}), + % endfor + % for k, v in xbar["reset_connections"].items(): + .${k} (${v}), + % endfor + + ## Inter-module signal + % for sig in xbar["inter_signal_list"]: +<% assert sig['type'] == "req_rsp" %>\ + // port: ${sig['name']} + .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), + .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), + + % endfor + + .scanmode_i + ); +% endfor + +% if "pinmux" in top: + // Pinmux connections + // All muxed inputs + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "input"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_in') %>\ + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = mio_p2d[${literal}]; + % endif + % endfor + + // All muxed outputs + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ + assign mio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All muxed output enables + % for sig in top["pinmux"]["ios"]: + % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: +<% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ + assign mio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All dedicated inputs +<% idx = 0 %>\ + logic [${num_dio_total-1}:0] unused_dio_p2d; + assign unused_dio_p2d = dio_p2d; + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; + % endif + % endfor + + // All dedicated outputs + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign dio_d2p[${literal}] = 1'b0; + % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: + assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + + // All dedicated output enables + % for sig in top["pinmux"]["ios"]: +<% literal = lib.get_io_enum_literal(sig, 'dio') %>\ + % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: + assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: + assign dio_en_d2p[${literal}] = 1'b0; + % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: + assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; + % endif + % endfor + +% endif + + // make sure scanmode_i is never X (including during reset) + `ASSERT_KNOWN(scanmodeKnown, scanmode_i, clk_main_i, 0) + +endmodule diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.h.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.h.tpl new file mode 100644 index 00000000..bfb0274a --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.h.tpl @@ -0,0 +1,62 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _TOP_${top["name"].upper()}_MEMORY_H_ +#define _TOP_${top["name"].upper()}_MEMORY_H_ + +/** + * @file + * @brief Assembler-only Top-Specific Definitions. + * + * This file contains preprocessor definitions for use within assembly code. + * + * These are not shared with C/C++ code because these are only allowed to be + * preprocessor definitions, no data or type declarations are allowed. The + * assembler is also stricter about literals (not allowing suffixes for + * signed/unsigned which are sensible to use for unsigned values in C/C++). + */ + +// Include guard for assembler +#ifdef __ASSEMBLER__ + +/** + * Memory base address for rom in top earlgrey. + */ +#define TOP_EARLGREY_ROM_BASE_ADDR 0x00008000 + +/** + * Memory size for rom in top earlgrey. + */ +#define TOP_EARLGREY_ROM_SIZE_BYTES 0x4000 + +% for m in top["memory"]: +/** + * Memory base address for ${m["name"]} in top ${top["name"]}. + */ +#define TOP_${top["name"].upper()}_${m["name"].upper()}_BASE_ADDR ${m["base_addr"]} + +/** + * Memory size for ${m["name"]} in top ${top["name"]}. + */ +#define TOP_${top["name"].upper()}_${m["name"].upper()}_SIZE_BYTES ${m["size"]} + +% endfor + +% for (inst_name, if_name), region in helper.devices(): +<% + if_desc = inst_name if if_name is None else '{} device on {}'.format(if_name, inst_name) + hex_base_addr = "0x{:X}".format(region.base_addr) + base_addr_name = region.base_addr_name().as_c_define() +%>\ +/** + * Peripheral base address for ${if_desc} in top ${top["name"]}. + * + * This should be used with #mmio_region_from_addr to access the memory-mapped + * registers associated with the peripheral (usually via a DIF). + */ +#define ${base_addr_name} ${hex_base_addr} +% endfor +#endif // __ASSEMBLER__ + +#endif // _TOP_${top["name"].upper()}_MEMORY_H_ diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.ld.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.ld.tpl new file mode 100644 index 00000000..42c41989 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_memory.ld.tpl @@ -0,0 +1,30 @@ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ +<%! +def memory_to_flags(memory): + memory_type = memory["type"] + memory_access = memory.get("swaccess", "rw") + assert memory_access in ["ro", "rw"] + + flags_str = "" + if memory_access == "ro": + flags_str += "r" + else: + flags_str += "rw" + + if memory_type in ["rom", "eflash"]: + flags_str += "x" + + return flags_str +%>\ + +/** + * Partial linker script for chip memory configuration. + */ +MEMORY { + rom(rx) : ORIGIN = 0x00008000, LENGTH = 0x4000 +% for m in top["memory"]: + ${m["name"]}(${memory_to_flags(m)}) : ORIGIN = ${m["base_addr"]}, LENGTH = ${m["size"]} +% endfor +} diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_pkg.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_pkg.sv.tpl new file mode 100644 index 00000000..a25d4fd7 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_pkg.sv.tpl @@ -0,0 +1,112 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +${gencmd} +<% +import topgen.lib as lib +%>\ +package top_${top["name"]}_pkg; +% for (inst_name, if_name), region in helper.devices(): +<% + if_desc = inst_name if if_name is None else '{} device on {}'.format(if_name, inst_name) + hex_base_addr = "32'h{:X}".format(region.base_addr) + hex_size_bytes = "32'h{:X}".format(region.size_bytes) +%>\ + /** + * Peripheral base address for ${if_desc} in top ${top["name"]}. + */ + parameter int unsigned ${region.base_addr_name().as_c_define()} = ${hex_base_addr}; + + /** + * Peripheral size in bytes for ${if_desc} in top ${top["name"]}. + */ + parameter int unsigned ${region.size_bytes_name().as_c_define()} = ${hex_size_bytes}; + +% endfor +% for name, region in helper.memories(): +<% + hex_base_addr = "32'h{:x}".format(region.base_addr) + hex_size_bytes = "32'h{:x}".format(region.size_bytes) +%>\ + /** + * Memory base address for ${name} in top ${top["name"]}. + */ + parameter int unsigned ${region.base_addr_name().as_c_define()} = ${hex_base_addr}; + + /** + * Memory size for ${name} in top ${top["name"]}. + */ + parameter int unsigned ${region.size_bytes_name().as_c_define()} = ${hex_size_bytes}; + +% endfor + + // Enumeration of IO power domains. + // Only used in ASIC target. + typedef enum logic [${len(top["pinout"]["banks"]).bit_length()-1}:0] { +% for bank in top["pinout"]["banks"]: + ${lib.Name(['io', 'bank', bank]).as_camel_case()} = ${loop.index}, +% endfor + IoBankCount = ${len(top["pinout"]["banks"])} + } pwr_dom_e; + + // Enumeration for MIO signals on the top-level. + typedef enum int unsigned { +% for sig in top["pinmux"]["ios"]: + % if sig['type'] in ['inout', 'input'] and sig['connection'] == 'muxed': + ${lib.get_io_enum_literal(sig, 'mio_in')} = ${sig['glob_idx']}, + % endif +% endfor +<% total = top["pinmux"]['io_counts']['muxed']['inouts'] + \ + top["pinmux"]['io_counts']['muxed']['inputs'] %>\ + ${lib.Name.from_snake_case("mio_in_count").as_camel_case()} = ${total} + } mio_in_e; + + typedef enum { +% for sig in top["pinmux"]["ios"]: + % if sig['type'] in ['inout', 'output'] and sig['connection'] == 'muxed': + ${lib.get_io_enum_literal(sig, 'mio_out')} = ${sig['glob_idx']}, + % endif +% endfor +<% total = top["pinmux"]['io_counts']['muxed']['inouts'] + \ + top["pinmux"]['io_counts']['muxed']['outputs'] %>\ + ${lib.Name.from_snake_case("mio_out_count").as_camel_case()} = ${total} + } mio_out_e; + + // Enumeration for DIO signals, used on both the top and chip-levels. + typedef enum int unsigned { +% for sig in top["pinmux"]["ios"]: + % if sig['connection'] != 'muxed': + ${lib.get_io_enum_literal(sig, 'dio')} = ${sig['glob_idx']}, + % endif +% endfor +<% total = top["pinmux"]['io_counts']['dedicated']['inouts'] + \ + top["pinmux"]['io_counts']['dedicated']['inputs'] + \ + top["pinmux"]['io_counts']['dedicated']['outputs'] %>\ + ${lib.Name.from_snake_case("dio_count").as_camel_case()} = ${total} + } dio_e; + + // Raw MIO/DIO input array indices on chip-level. + // TODO: Does not account for target specific stubbed/added pads. + // Need to make a target-specific package for those. + typedef enum int unsigned { +% for pad in top["pinout"]["pads"]: + % if pad["connection"] == "muxed": + ${lib.Name.from_snake_case("mio_pad_" + pad["name"]).as_camel_case()} = ${pad["idx"]}, + % endif +% endfor + ${lib.Name.from_snake_case("mio_pad_count").as_camel_case()} + } mio_pad_e; + + typedef enum int unsigned { +% for pad in top["pinout"]["pads"]: + % if pad["connection"] != "muxed": + ${lib.Name.from_snake_case("dio_pad_" + pad["name"]).as_camel_case()} = ${pad["idx"]}, + % endif +% endfor + ${lib.Name.from_snake_case("dio_pad_count").as_camel_case()} + } dio_pad_e; + + // TODO: Enumeration for PLIC Interrupt source peripheral. + // TODO: Enumeration for PLIC Interrupt Ids. + +endpackage diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_rnd_cnst_pkg.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_rnd_cnst_pkg.sv.tpl new file mode 100644 index 00000000..9700c3d5 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/toplevel_rnd_cnst_pkg.sv.tpl @@ -0,0 +1,44 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +${gencmd} +<% + def make_blocked_sv_literal(hexstr, randwidth): + """This chops the random hexstring into manageable blocks of 64 chars such that the + lines do not get too long. + """ + # Make all-caps and drop '0x' preamble + hexstr = str(hexstr[2:]).upper() + # Block width in hex chars + blockwidth = 64 + remainder = randwidth % (4*blockwidth) + numbits = remainder if remainder else 4*blockwidth + idx = 0 + hexblocks = [] + while randwidth > 0: + hexstr = hexstr[idx:] + randwidth -= numbits + idx = (numbits + 3) // 4 + hexblocks.append(str(numbits) + "'h" + hexstr[0:idx]) + numbits = 4*blockwidth + return hexblocks +%> +package top_${top["name"]}_rnd_cnst_pkg; + +% for m in top["module"]: + % for p in filter(lambda p: p.get("randtype") in ["data", "perm"], m["param_list"]): + % if loop.first: + //////////////////////////////////////////// + // ${m['name']} + //////////////////////////////////////////// + % endif + // ${p['desc']} + parameter ${p["type"]} ${p["name_top"]} = { + % for block in make_blocked_sv_literal(p["default"], p["randwidth"]): + ${block}${"" if loop.last else ","} + % endfor + }; + + % endfor +% endfor +endpackage : top_${top["name"]}_rnd_cnst_pkg diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/xbar_env_pkg__params.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/xbar_env_pkg__params.sv.tpl new file mode 100644 index 00000000..63c59fe1 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/templates/xbar_env_pkg__params.sv.tpl @@ -0,0 +1,88 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// xbar_env_pkg__params generated by `topgen.py` tool + +<% + from collections import OrderedDict + + def is_device_a_xbar(dev_name): + for xbar in top["xbar"]: + if xbar["name"] == dev_name: + return 1 + return 0 + + # recursively find all non-xbar devices under this xbar + def get_xbar_edge_nodes(xbar_name): + edge_devices = [] + for xbar in top["xbar"]: + if xbar["name"] == xbar_name: + for host, devices in xbar["connections"].items(): + for dev_name in devices: + if is_device_a_xbar(dev_name): + edge_devices.extend(get_xbar_edge_nodes()) + else: + edge_devices.append(dev_name) + + return edge_devices + + # find device xbar and assign all its device nodes to it: "peri" -> "uart, gpio, ..." + xbar_device_dict = OrderedDict() + + for xbar in top["xbar"]: + for n in xbar["nodes"]: + if n["type"] == "device" and n["xbar"]: + xbar_device_dict[n["name"]] = get_xbar_edge_nodes(n["name"]) + + # create the mapping: host with the corresponding devices map + host_dev_map = OrderedDict() + for host, devices in top["xbar"][0]["connections"].items(): + dev_list = [] + for dev in devices: + if dev not in xbar_device_dict.keys(): + dev_list.append(dev) + else: + dev_list.extend(xbar_device_dict[dev]) + host_dev_map[host] = dev_list + +%>\ + +// List of Xbar device memory map +tl_device_t xbar_devices[$] = '{ +% for xbar in top["xbar"]: + % for device in xbar["nodes"]: + % if device["type"] == "device" and not device["xbar"]: + '{"${device["name"].replace('.', '__')}", '{ + % for addr in device["addr_range"]: +<% + start_addr = int(addr["base_addr"], 0) + end_addr = start_addr + int(addr["size_byte"], 0) - 1 +%>\ + '{32'h${"%08x" % start_addr}, 32'h${"%08x" % end_addr}}${"," if not loop.last else ""} + % endfor + }}${"," if not loop.last or xbar != top["xbar"][-1] else "};"} + % endif + % endfor +% endfor + + // List of Xbar hosts +tl_host_t xbar_hosts[$] = '{ +% for host in host_dev_map.keys(): + '{"${host}", ${loop.index}, '{ +<% + host_devices = host_dev_map[host]; +%>\ + % for device in host_devices: + % if loop.last: + "${device}"}} + % else: + "${device}", + % endif + % endfor + % if loop.last: +}; + % else: + , + % endif +% endfor diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top.py new file mode 100644 index 00000000..dcdf1cae --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top.py @@ -0,0 +1,122 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +'''Code representing the entire chip for reggen''' + +from typing import Dict, List, Optional, Tuple, Union + +from reggen.ip_block import IpBlock +from reggen.params import ReggenParams +from reggen.reg_block import RegBlock +from reggen.window import Window + +_IFName = Tuple[str, Optional[str]] +_Triple = Tuple[int, str, IpBlock] + + +class Top: + '''An object representing the entire chip, as seen by reggen. + + This contains instances of some blocks (possibly multiple instances of each + block), starting at well-defined base addresses. It may also contain some + windows. These are memories that don't have their own comportable IP (so + aren't defined in a block), but still take up address space. + + ''' + + def __init__(self, + regwidth: int, + blocks: Dict[str, IpBlock], + instances: Dict[str, str], + if_addrs: Dict[Tuple[str, Optional[str]], int], + windows: List[Window], + attrs: Dict[str, str]): + '''Class initializer. + + regwidth is the width of the registers (which must match for all the + blocks) in bits. + + blocks is a map from block name to IpBlock object. + + instances is a map from instance name to the name of the block it + instantiates. Every block name that appears in instances must be a key + of blocks. + + if_addrs is a dictionary that maps the name of a device interface on + some instance of some block to its base address. A key of the form (n, + i) means "the device interface called i on an instance called n". If i + is None, this is an unnamed device interface. Every instance name (n) + that appears in connections must be a key of instances. + + windows is a list of windows (these contain base addresses already). + + attrs is a map from instance name to attr field of the block + + ''' + + self.regwidth = regwidth + self.blocks = blocks + self.instances = instances + self.if_addrs = if_addrs + self.attrs = attrs + + self.window_block = RegBlock(regwidth, ReggenParams()) + + # Generate one list of base addresses and objects (with each object + # either a block name and interface name or a window). While we're at + # it, construct inst_to_block_name and if_addrs. + merged = [] # type: List[Tuple[int, Union[_IFName, Window]]] + for full_if_name, addr in if_addrs.items(): + merged.append((addr, full_if_name)) + + inst_name, if_name = full_if_name + + # The instance name must match some key in instances, whose value + # should in turn match some key in blocks. + assert inst_name in instances + block_name = instances[inst_name] + assert block_name in blocks + + # Check that if_name is indeed the name of a device interface for + # that block. + block = blocks[block_name] + assert block.bus_interfaces.has_interface(False, if_name) + + for window in sorted(windows, key=lambda w: w.offset): + merged.append((window.offset, window)) + self.window_block.add_window(window) + + # A map from block name to the list of its instances. These instances + # are listed in increasing order of the lowest base address of one of + # their interfaces. The entries are added into the dict in the same + # order, so an iteration over items() will give blocks ordered by their + # first occurrence in the address map. + self.block_instances = {} # type: Dict[str, List[str]] + + # Walk the merged list in order of increasing base address. Check for + # overlaps and construct block_instances. + offset = 0 + for base_addr, item in sorted(merged, key=lambda pr: pr[0]): + # Make sure that this item doesn't overlap with the previous one + assert offset <= base_addr, item + + if isinstance(item, Window): + addrsep = (regwidth + 7) // 8 + offset = item.next_offset(addrsep) + continue + + inst_name, if_name = item + block_name = instances[inst_name] + block = blocks[block_name] + + lst = self.block_instances.setdefault(block_name, []) + if inst_name not in lst: + lst.append(inst_name) + + # This should be guaranteed by the fact that we've already checked + # the existence of a device interface. + assert if_name in block.reg_blocks + reg_block = block.reg_blocks[if_name] + + offset = base_addr + reg_block.offset diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top_uvm_reg.sv.tpl b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top_uvm_reg.sv.tpl new file mode 100644 index 00000000..1486a926 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/top_uvm_reg.sv.tpl @@ -0,0 +1,151 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// UVM registers auto-generated by `reggen` containing UVM definitions for the entire top-level +<%! + from topgen.gen_dv import sv_base_addr + from reggen.gen_dv import bcname, mcname, miname +%> +## +## This template is used for chip-wide tests. It expects to be run with the +## following arguments +## +## top a Top object +## +## dv_base_prefix a string for the base register type. If it is FOO, then +## we will inherit from FOO_reg (assumed to be a subclass +## of uvm_reg). +## +## Like uvm_reg.sv.tpl, we use functions from uvm_reg_base.sv.tpl to define +## per-device-interface code. +## +<%namespace file="uvm_reg_base.sv.tpl" import="*"/>\ +## +## +## Waive the package-filename check: we're going to be defining all sorts of +## packages in a single file. + +// verilog_lint: waive-start package-filename +## +## Iterate over the device interfaces of blocks in Top, constructing a package +## for each. Sorting items like this guarantees we'll work alphabetically in +## block name. +% for block_name, block in sorted(top.blocks.items()): +% for if_name, rb in block.reg_blocks.items(): +<% + if_suffix = '' if if_name is None else '_' + if_name + esc_if_name = block_name.lower() + if_suffix + if_desc = '' if if_name is None else '; interface {}'.format(if_name) + reg_block_path = 'u_reg' + if_suffix + reg_block_path = reg_block_path if block.hier_path is None else block.hier_path + "." + reg_block_path +%>\ +// Block: ${block_name.lower()}${if_desc} +${make_ral_pkg(dv_base_prefix, top.regwidth, reg_block_path, rb, esc_if_name)} +% endfor +% endfor +## +## +## Now that we've made the block-level packages, re-instate the +## package-filename check. The only package left is chip_ral_pkg, which should +## match the generated filename. + +// verilog_lint: waive-start package-filename + +// Block: chip +package chip_ral_pkg; +<% + if_packages = [] + for block_name, block in sorted(top.blocks.items()): + for if_name in block.reg_blocks: + if_suffix = '' if if_name is None else '_' + if_name + if_packages.append('{}{}_ral_pkg'.format(block_name.lower(), if_suffix)) + + windows = top.window_block.windows +%>\ +${make_ral_pkg_hdr(dv_base_prefix, if_packages)} +${make_ral_pkg_fwd_decls('chip', [], windows)} +% for window in windows: + +${make_ral_pkg_window_class(dv_base_prefix, 'chip', window)} +% endfor + + class chip_reg_block extends ${dv_base_prefix}_reg_block; + // sub blocks +% for block_name, block in sorted(top.blocks.items()): +% for inst_name in top.block_instances[block_name.lower()]: +% for if_name, rb in block.reg_blocks.items(): +<% + if_suffix = '' if if_name is None else '_' + if_name + esc_if_name = block_name.lower() + if_suffix + if_inst = inst_name + if_suffix +%>\ + rand ${bcname(esc_if_name)} ${if_inst}; +% endfor +% endfor +% endfor +% if windows: + // memories +% for window in windows: + rand ${mcname('chip', window)} ${miname(window)}; +% endfor +% endif + + `uvm_object_utils(chip_reg_block) + + function new(string name = "chip_reg_block", + int has_coverage = UVM_NO_COVERAGE); + super.new(name, has_coverage); + endfunction : new + + virtual function void build(uvm_reg_addr_t base_addr, + csr_excl_item csr_excl = null); + // create default map + this.default_map = create_map(.name("default_map"), + .base_addr(base_addr), + .n_bytes(${top.regwidth//8}), + .endian(UVM_LITTLE_ENDIAN)); + if (csr_excl == null) begin + csr_excl = csr_excl_item::type_id::create("csr_excl"); + this.csr_excl = csr_excl; + end + + // create sub blocks and add their maps +% for block_name, block in sorted(top.blocks.items()): +% for inst_name in top.block_instances[block_name.lower()]: +% for if_name, rb in block.reg_blocks.items(): +<% + if_suffix = '' if if_name is None else '_' + if_name + esc_if_name = block_name.lower() + if_suffix + if_inst = inst_name + if_suffix + + if top.attrs.get(inst_name) == 'reggen_only': + hdl_path = 'tb.dut.u_' + inst_name + else: + hdl_path = 'tb.dut.top_earlgrey.u_' + inst_name + qual_if_name = (inst_name, if_name) + base_addr = top.if_addrs[qual_if_name] + base_addr_txt = sv_base_addr(top, qual_if_name) + + hpr_indent = (len(if_inst) + len('.set_hdl_path_root(')) * ' ' +%>\ + ${if_inst} = ${bcname(esc_if_name)}::type_id::create("${if_inst}"); + ${if_inst}.configure(.parent(this)); + ${if_inst}.build(.base_addr(base_addr + ${base_addr_txt}), .csr_excl(csr_excl)); + ${if_inst}.set_hdl_path_root("${hdl_path}", + ${hpr_indent}"BkdrRegPathRtl"); + ${if_inst}.set_hdl_path_root("${hdl_path}", + ${hpr_indent}"BkdrRegPathRtlCommitted"); + ${if_inst}.set_hdl_path_root("${hdl_path}", + ${hpr_indent}"BkdrRegPathRtlShadow"); + default_map.add_submap(.child_map(${if_inst}.default_map), + .offset(base_addr + ${base_addr_txt})); +% endfor +% endfor +% endfor +${make_ral_pkg_window_instances(top.regwidth, 'chip', top.window_block)} + + endfunction : build + endclass : chip_reg_block + +endpackage diff --git a/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/validate.py b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/validate.py new file mode 100644 index 00000000..bfb42987 --- /dev/null +++ b/hw/vendor/esl_epfl_cgra/util/lowrisc_opentitan/topgen/validate.py @@ -0,0 +1,878 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +import re +import logging as log +from collections import OrderedDict +from enum import Enum +from typing import Dict, List + +from reggen.validate import check_keys +from reggen.ip_block import IpBlock + +# For the reference +# val_types = { +# 'd': ["int", "integer (binary 0b, octal 0o, decimal, hex 0x)"], +# 'x': ["xint", "x for undefined otherwise int"], +# 'b': [ +# "bitrange", "bit number as decimal integer, \ +# or bit-range as decimal integers msb:lsb" +# ], +# 'l': ["list", "comma separated list enclosed in `[]`"], +# 'ln': ["name list", 'comma separated list enclosed in `[]` of '\ +# 'one or more groups that have just name and dscr keys.'\ +# ' e.g. `{ name: "name", desc: "description"}`'], +# 'lnw': ["name list+", 'name list that optionally contains a width'], +# 'lp': ["parameter list", 'parameter list having default value optionally'], +# 'g': ["group", "comma separated group of key:value enclosed in `{}`"], +# 's': ["string", "string, typically short"], +# 't': ["text", "string, may be multi-line enclosed in `'''` "\ +# "may use `**bold**`, `*italic*` or `!!Reg` markup"], +# 'T': ["tuple", "tuple enclosed in ()"], +# 'pi': ["python int", "Native Python type int (generated)"], +# 'pb': ["python Bool", "Native Python type Bool (generated)"], +# 'pl': ["python list", "Native Python type list (generated)"], +# 'pe': ["python enum", "Native Python type enum (generated)"] +# } + +# Required/optional field in top hjson +top_required = { + 'name': ['s', 'Top name'], + 'type': ['s', 'type of hjson. Shall be "top" always'], + 'clocks': ['g', 'group of clock properties'], + 'resets': ['l', 'list of resets'], + 'module': ['l', 'list of modules to instantiate'], + 'memory': ['l', 'list of memories. At least one memory ' + 'is needed to run the software'], + 'debug_mem_base_addr': ['d', 'Base address of RV_DM. ' + 'Planned to move to module'], + 'xbar': ['l', 'List of the xbar used in the top'], + 'rnd_cnst_seed': ['int', "Seed for random netlist constant computation"], + 'pinout': ['g', 'Pinout configuration'], + 'targets': ['l', ' Target configurations'], + 'pinmux': ['g', 'pinmux configuration'], +} + +top_optional = { + 'alert_async': ['l', 'async alerts (generated)'], + 'alert': ['lnw', 'alerts (generated)'], + 'alert_module': [ + 'l', + 'list of the modules that connects to alert_handler' + ], + 'datawidth': ['pn', "default data width"], + 'exported_clks': ['g', 'clock signal routing rules'], + 'host': ['g', 'list of host-only components in the system'], + 'inter_module': ['g', 'define the signal connections between the modules'], + 'interrupt': ['lnw', 'interrupts (generated)'], + 'interrupt_module': ['l', 'list of the modules that connects to rv_plic'], + 'num_cores': ['pn', "number of computing units"], + 'power': ['g', 'power domains supported by the design'], + 'port': ['g', 'assign special attributes to specific ports'] +} + +top_added = {} + +pinmux_required = {} +pinmux_optional = { + 'num_wkup_detect': [ + 'd', 'Number of wakeup detectors' + ], + 'wkup_cnt_width': [ + 'd', 'Number of bits in wakeup detector counters' + ], + 'signals': ['l', 'List of Dedicated IOs.'], +} +pinmux_added = { + 'ios': ['l', 'Full list of IO'], +} + +pinmux_sig_required = { + 'instance': ['s', 'Module instance name'], + 'connection': ['s', 'Specification of connection type, ' + 'can be direct, manual or muxed'], +} +pinmux_sig_optional = { + 'port': ['s', 'Port name of module'], + 'pad': ['s', 'Pad name for direct connections'], + 'desc': ['s', 'Signal description'], + 'attr': ['s', 'Pad type for generating the correct attribute CSR'] +} +pinmux_sig_added = {} + +pinout_required = { + 'banks': ['l', 'List of IO power banks'], + 'pads': ['l', 'List of pads'] +} +pinout_optional = { +} +pinout_added = {} + +pad_required = { + 'name': ['l', 'Pad name'], + 'type': ['s', 'Pad type'], + 'bank': ['s', 'IO power bank for the pad'], + 'connection': ['s', 'Specification of connection type, ' + 'can be direct, manual or muxed'], +} +pad_optional = { + 'desc': ['s', 'Pad description'], +} +pad_added = {} + +target_required = { + 'name': ['s', 'Name of target'], + 'pinout': ['g', 'Target-specific pinout configuration'], + 'pinmux': ['g', 'Target-specific pinmux configuration'] +} +target_optional = { +} +target_added = {} + +target_pinmux_required = { + 'special_signals': ['l', 'List of special signals and the pad they are mapped to.'], +} +target_pinmux_optional = {} +target_pinmux_added = {} + +target_pinout_required = { + 'remove_pads': ['l', 'List of pad names to remove and stub out'], + 'add_pads': ['l', 'List of manual pads to add'], +} +target_pinout_optional = {} +target_pinout_added = {} + +straps_required = { + 'tap0': ['s', 'Name of tap0 pad'], + 'tap1': ['s', 'Name of tap1 pad'], + 'dft0': ['s', 'Name of dft0 pad'], + 'dft1': ['s', 'Name of dft1 pad'], +} +straps_optional = {} +straps_added = {} + +straps_required = { + 'tap0': ['s', 'Name of tap0 pad'], + 'tap1': ['s', 'Name of tap1 pad'], + 'dft0': ['s', 'Name of dft0 pad'], + 'dft1': ['s', 'Name of dft1 pad'], +} +straps_optional = {} +straps_added = {} + +special_sig_required = { + 'name': ['s', 'DIO name'], + 'pad': ['s', 'Pad name'], +} +special_sig_optional = { + 'desc': ['s', 'Description of signal connection'], +} +special_sig_added = {} + +clock_srcs_required = { + 'name': ['s', 'name of clock group'], + 'aon': ['s', 'yes, no. aon attribute of a clock'], + 'freq': ['s', 'frequency of clock in Hz'], +} + +clock_srcs_optional = { + 'derived': ['s', 'whether clock is derived'], + 'params': ['s', 'extra clock parameters'] +} + +derived_clock_srcs_required = { + 'name': ['s', 'name of clock group'], + 'aon': ['s', 'yes, no. aon attribute of a clock'], + 'freq': ['s', 'frequency of clock in Hz'], + 'src': ['s', 'source clock'], + 'div': ['d', 'ratio between source clock and derived clock'], +} + +clock_groups_required = { + 'name': ['s', 'name of clock group'], + 'src': ['s', 'yes, no. This clock group is directly from source'], + 'sw_cg': ['s', 'yes, no, hint. Software clock gate attributes'], +} +clock_groups_optional = { + 'unique': ['s', 'whether clocks in the group are unique'], + 'clocks': ['g', 'groups of clock name to source'], +} +clock_groups_added = {} + +eflash_required = { + 'banks': ['d', 'number of flash banks'], + 'base_addr': ['s', 'strarting hex address of memory'], + 'clock_connections': ['g', 'generated, elaborated version of clock_srcs'], + 'clock_group': ['s', 'associated clock attribute group'], + 'clock_srcs': ['g', 'clock connections'], + 'inter_signal_list': ['lg', 'intersignal list'], + 'name': ['s', 'name of flash memory'], + 'pages_per_bank': ['d', 'number of data pages per flash bank'], + 'program_resolution': ['d', 'maximum number of flash words allowed to program'], + 'reset_connections': ['g', 'reset connections'], + 'swaccess': ['s', 'software accessibility'], + 'type': ['s', 'type of memory'] +} + +eflash_optional = {} + +eflash_added = {} + + +# Supported PAD types. +# Needs to coincide with enum definition in prim_pad_wrapper_pkg.sv +class PadType(Enum): + INPUT_STD = 'InputStd' + BIDIR_STD = 'BidirStd' + BIDIR_TOL = 'BidirTol' + BIDIR_OD = 'BidirOd' + ANALOG_IN0 = 'AnalogIn0' + + +def is_valid_pad_type(obj): + try: + PadType(obj) + except ValueError: + return False + return True + + +class TargetType(Enum): + MODULE = "module" + XBAR = "xbar" + + +class Target: + """Target class informs the checkers if we are validating a module or xbar + """ + def __init__(self, target_type): + # The type of this target + self.target_type = target_type + # The key to search against + if target_type == TargetType.MODULE: + self.key = "type" + else: + self.key = "name" + + +class Flash: + """Flash class contains information regarding parameter defaults. + For now, only expose banks / pages_per_bank for user configuration. + For now, also enforce power of 2 requiremnt. + """ + max_banks = 4 + max_pages_per_bank = 1024 + + def __init__(self, mem): + self.banks = mem['banks'] + self.pages_per_bank = mem['pages_per_bank'] + self.program_resolution = mem['program_resolution'] + self.words_per_page = 256 + self.data_width = 64 + self.metadata_width = 12 + self.info_types = 3 + self.infos_per_bank = [10, 1, 2] + + def is_pow2(self, n): + return (n != 0) and (n & (n - 1) == 0) + + def check_values(self): + pow2_check = (self.is_pow2(self.banks) and + self.is_pow2(self.pages_per_bank) and + self.is_pow2(self.program_resolution)) + limit_check = ((self.banks <= Flash.max_banks) and + (self.pages_per_bank <= Flash.max_pages_per_bank)) + + return pow2_check and limit_check + + def calc_size(self): + word_bytes = self.data_width / 8 + bytes_per_page = word_bytes * self.words_per_page + bytes_per_bank = bytes_per_page * self.pages_per_bank + return bytes_per_bank * self.banks + + def populate(self, mem): + mem['words_per_page'] = self.words_per_page + mem['data_width'] = self.data_width + mem['metadata_width'] = self.metadata_width + mem['info_types'] = self.info_types + mem['infos_per_bank'] = self.infos_per_bank + mem['size'] = hex(int(self.calc_size())) + + word_bytes = self.data_width / 8 + mem['pgm_resolution_bytes'] = int(self.program_resolution * word_bytes) + + +# Check to see if each module/xbar defined in top.hjson exists as ip/xbar.hjson +# Also check to make sure there are not multiple definitions of ip/xbar.hjson for each +# top level definition +# If it does, return a dictionary of instance names to index in ip/xbarobjs +def check_target(top, objs, tgtobj): + error = 0 + idxs = OrderedDict() + + # Collect up counts of object names. We support entries of objs that are + # either dicts (for top-levels) or IpBlock objects. + name_indices = {} + for idx, obj in enumerate(objs): + if isinstance(obj, IpBlock): + name = obj.name.lower() + else: + name = obj['name'].lower() + + log.info("%d Order is %s" % (idx, name)) + name_indices.setdefault(name, []).append(idx) + + tgt_type = tgtobj.target_type.value + inst_key = tgtobj.key + + for cfg in top[tgt_type]: + cfg_name = cfg['name'].lower() + log.info("Checking target %s %s" % (tgt_type, cfg_name)) + + indices = name_indices.get(cfg[inst_key], []) + if not indices: + log.error("Could not find %s.hjson" % cfg_name) + error += 1 + elif len(indices) > 1: + log.error("Duplicate %s.hjson" % cfg_name) + error += 1 + else: + idxs[cfg_name] = indices[0] + + log.info("Current state %s" % idxs) + return error, idxs + + +def check_pad(top: Dict, + pad: Dict, + known_pad_names: Dict, + valid_connections: List[str], + prefix: str) -> int: + error = 0 + error += check_keys(pad, pad_required, pad_optional, + pad_added, prefix) + + # check name uniqueness + if pad['name'] in known_pad_names: + log.warning('Pad name {} is not unique'.format(pad['name'])) + error += 1 + known_pad_names[pad['name']] = 1 + + if not is_valid_pad_type(pad['type']): + log.warning('Unkown pad type {}'.format(pad['type'])) + error += 1 + + if pad['bank'] not in top['pinout']['banks']: + log.warning('Unkown io power bank {}'.format(pad['bank'])) + error += 1 + + if pad['connection'] not in valid_connections: + log.warning('Connection type {} of pad {} is invalid' + .format(pad['connection'], pad['name'])) + error += 1 + + return error + + +def check_pinout(top: Dict, prefix: str) -> int: + error = check_keys(top['pinout'], pinout_required, pinout_optional, + pinout_added, prefix + ' Pinout') + + known_names = {} + for pad in top['pinout']['pads']: + error += check_keys(pad, pad_required, pad_optional, + pad_added, prefix + ' Pinout') + + error += check_pad(top, pad, known_names, + ['direct', 'manual', 'muxed'], + prefix + ' Pad') + + return error + + +def check_pinmux(top: Dict, prefix: str) -> int: + error = check_keys(top['pinmux'], pinmux_required, pinmux_optional, + pinmux_added, prefix + ' Pinmux') + + # This is used for the direct connection accounting below, + # where we tick off already connected direct pads. + known_direct_pads = {} + direct_pad_attr = {} + for pad in top['pinout']['pads']: + if pad['connection'] == 'direct': + known_direct_pads[pad['name']] = 1 + direct_pad_attr[pad['name']] = pad['type'] + + # Note: the actual signal crosscheck is deferred until the merge stage, + # since we have no idea at this point which IOs comportable IPs expose. + for sig in top['pinmux']['signals']: + error += check_keys(sig, pinmux_sig_required, pinmux_sig_optional, + pinmux_sig_added, prefix + ' Pinmux signal') + + if sig['connection'] not in ['direct', 'manual', 'muxed']: + log.warning('Invalid connection type {}'.format(sig['connection'])) + error += 1 + + # The pad needs to refer to a valid pad name in the pinout that is of + # connection type "direct". We tick off all direct pads that have been + # referenced in order to make sure there are no double connections + # and unconnected direct pads. + padname = sig.setdefault('pad', '') + if padname != '': + if padname in known_direct_pads: + if known_direct_pads[padname] == 1: + known_direct_pads[padname] = 0 + padattr = direct_pad_attr[padname] + else: + log.warning('Warning, direct pad {} is already connected' + .format(padname)) + error += 1 + else: + log.warning('Unknown direct pad {}'.format(padname)) + error += 1 + + # Check port naming scheme. + port = sig.setdefault('port', '') + pattern = r'^[a-zA-Z0-9_]*(\[[0-9]*\]){0,1}' + matches = re.match(pattern, port) + if matches is None: + log.warning('Port name {} has wrong format' + .format(port)) + error += 1 + + # Check that only direct connections have pad keys + if sig['connection'] == 'direct': + if sig.setdefault('attr', '') != '': + log.warning('Direct connection of instance {} port {} ' + 'must not have an associated pad attribute field' + .format(sig['instance'], + sig['port'])) + error += 1 + # Since the signal is directly connected, we can automatically infer + # the pad type needed to instantiate the correct attribute CSR WARL + # module inside the pinmux. + sig['attr'] = padattr + + if padname == '': + log.warning('Instance {} port {} connection is of direct type ' + 'and therefore must have an associated pad name.' + .format(sig['instance'], + sig['port'])) + error += 1 + if port == '': + log.warning('Instance {} port {} connection is of direct type ' + 'and therefore must have an associated port name.' + .format(sig['instance'], + sig['port'])) + error += 1 + elif sig['connection'] == 'muxed': + # Muxed signals do not have a corresponding pad and attribute CSR, + # since they first go through the pinmux matrix. + if sig.setdefault('attr', '') != '': + log.warning('Muxed connection of instance {} port {} ' + 'must not have an associated pad attribute field' + .format(sig['instance'], + sig['port'])) + error += 1 + if padname != '': + log.warning('Muxed connection of instance {} port {} ' + 'must not have an associated pad' + .format(sig['instance'], + sig['port'])) + error += 1 + elif sig['connection'] == 'manual': + # This pad attr key is only allowed in the manual case, + # as there is no way to infer the pad type automatically. + sig.setdefault('attr', 'BidirStd') + if padname != '': + log.warning('Manual connection of instance {} port {} ' + 'must not have an associated pad' + .format(sig['instance'], + sig['port'])) + error += 1 + + # At this point, all direct pads should have been ticked off. + for key, val in known_direct_pads.items(): + if val == 1: + log.warning('Direct pad {} has not been connected' + .format(key)) + error += 1 + + return error + + +def check_implementation_targets(top: Dict, prefix: str) -> int: + error = 0 + known_names = {} + for target in top['targets']: + error += check_keys(target, target_required, target_optional, + target_added, prefix + ' Targets') + + # check name uniqueness + if target['name'] in known_names: + log.warning('Target name {} is not unique'.format(target['name'])) + error += 1 + known_names[target['name']] = 1 + + error += check_keys(target['pinmux'], target_pinmux_required, target_pinmux_optional, + target_pinmux_added, prefix + ' Target pinmux') + + error += check_keys(target['pinout'], target_pinout_required, target_pinout_optional, + target_pinout_added, prefix + ' Target pinout') + + # Check special pad signals + known_entry_names = {} + for entry in target['pinmux']['special_signals']: + error += check_keys(entry, special_sig_required, special_sig_optional, + special_sig_added, prefix + ' Special signal') + + # check name uniqueness + if entry['name'] in known_entry_names: + log.warning('Special pad name {} is not unique'.format(entry['name'])) + error += 1 + known_entry_names[entry['name']] = 1 + + # The pad key needs to refer to a valid pad name. + is_muxed = False + for pad in top['pinout']['pads']: + if entry['pad'] == pad['name']: + is_muxed = pad['connection'] == 'muxed' + break + else: + log.warning('Unknown pad {}'.format(entry['pad'])) + error += 1 + + if not is_muxed: + # If this is not a muxed pad, we need to make sure this refers to + # DIO that is NOT a manual pad. + for sig in top['pinmux']['signals']: + if entry['pad'] == sig['pad']: + break + else: + log.warning('Special pad {} cannot refer to a manual pad'.format(entry['pad'])) + error += 1 + + # Check pads to remove and stub out + for entry in target['pinout']['remove_pads']: + # The pad key needs to refer to a valid pad name. + for pad in top['pinout']['pads']: + if entry == pad['name']: + break + else: + log.warning('Unknown pad {}'.format(entry)) + error += 1 + + # Check pads to add + known_pad_names = {} + for pad in top['pinout']['pads']: + known_pad_names.update({pad['name']: 1}) + + for pad in target['pinout']['add_pads']: + error += check_pad(top, pad, known_pad_names, ['manual'], + prefix + ' Additional Pad') + + return error + + +# check for inconsistent clock group definitions +def check_clock_groups(top): + + # default empty assignment + if "groups" not in top['clocks']: + top['clocks']['groups'] = [] + + error = 0 + for group in top['clocks']['groups']: + error = check_keys(group, clock_groups_required, clock_groups_optional, + clock_groups_added, "Clock Groups") + + # Check sw_cg values are valid + if group['sw_cg'] not in ['yes', 'no', 'hint']: + log.error("Incorrect attribute for sw_cg: {}".format( + group['sw_cg'])) + error += 1 + + # Check combination of src and sw are valid + if group['src'] == 'yes' and group['sw_cg'] != 'no': + log.error("Invalid combination of src and sw_cg: {} and {}".format( + group['src'], group['sw_cg'])) + error += 1 + + # Check combination of sw_cg and unique are valid + unique = group['unique'] if 'unique' in group else 'no' + if group['sw_cg'] == 'no' and unique != 'no': + log.error( + "Incorrect attribute combination. When sw_cg is no, unique must be no" + ) + error += 1 + + if error: + break + + return error + + +def check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs): + + error = 0 + + # there should only be one each of pwrmgr/clkmgr/rstmgr + pwrmgrs = [m for m in top['module'] if m['type'] == 'pwrmgr'] + clkmgrs = [m for m in top['module'] if m['type'] == 'clkmgr'] + rstmgrs = [m for m in top['module'] if m['type'] == 'rstmgr'] + + if len(pwrmgrs) == 1 * len(clkmgrs) == 1 * len(rstmgrs) != 1: + log.error("Incorrect number of pwrmgr/clkmgr/rstmgr") + error += 1 + + # check clock fields are all there + ext_srcs = [] + for src in top['clocks']['srcs']: + check_keys(src, clock_srcs_required, clock_srcs_optional, {}, + "Clock source") + ext_srcs.append(src['name']) + + # check derived clock sources + log.info("Collected clocks are {}".format(ext_srcs)) + for src in top['clocks']['derived_srcs']: + check_keys(src, derived_clock_srcs_required, {}, {}, "Derived clocks") + try: + ext_srcs.index(src['src']) + except Exception: + error += 1 + log.error("{} is not a valid src for {}".format( + src['src'], src['name'])) + + # all defined clock/reset nets + reset_nets = [reset['name'] for reset in top['resets']['nodes']] + clock_srcs = [ + clock['name'] + for clock in top['clocks']['srcs'] + top['clocks']['derived_srcs'] + ] + + # Check clock/reset port connection for all IPs + for ipcfg in top['module']: + ipcfg_name = ipcfg['name'].lower() + log.info("Checking clock/resets for %s" % ipcfg_name) + error += validate_reset(ipcfg, ipobjs[ip_idxs[ipcfg_name]], reset_nets) + error += validate_clock(ipcfg, ipobjs[ip_idxs[ipcfg_name]], clock_srcs) + + if error: + log.error("module clock/reset checking failed") + break + + # Check clock/reset port connection for all xbars + for xbarcfg in top['xbar']: + xbarcfg_name = xbarcfg['name'].lower() + log.info("Checking clock/resets for xbar %s" % xbarcfg_name) + error += validate_reset(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]], + reset_nets, "xbar") + error += validate_clock(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]], + clock_srcs, "xbar") + + if error: + log.error("xbar clock/reset checking failed") + break + + return error + + +# Checks the following +# For each defined reset connection in top*.hjson, there exists a defined port at the destination +# and defined reset net +# There are the same number of defined connections as there are ports +def validate_reset(top, inst, reset_nets, prefix=""): + # Gather inst port list + error = 0 + + # Handle either an IpBlock (generated by reggen) or an OrderedDict + # (generated by topgen for a crossbar) + if isinstance(inst, IpBlock): + name = inst.name + reset_signals = inst.reset_signals + else: + name = inst['name'] + reset_signals = ([inst.get('reset_primary', 'rst_ni')] + + inst.get('other_reset_list', [])) + + log.info("%s %s resets are %s" % + (prefix, name, reset_signals)) + + if len(top['reset_connections']) != len(reset_signals): + error += 1 + log.error("%s %s mismatched number of reset ports and nets" % + (prefix, name)) + + missing_port = [ + port for port in top['reset_connections'].keys() + if port not in reset_signals + ] + + if missing_port: + error += 1 + log.error("%s %s Following reset ports do not exist:" % + (prefix, name)) + [log.error("%s" % port) for port in missing_port] + + missing_net = [ + net for port, net in top['reset_connections'].items() + if net not in reset_nets + ] + + if missing_net: + error += 1 + log.error("%s %s Following reset nets do not exist:" % + (prefix, name)) + [log.error("%s" % net) for net in missing_net] + + return error + + +# Checks the following +# For each defined clock_src in top*.hjson, there exists a defined port at the destination +# and defined clock source +# There are the same number of defined connections as there are ports +def validate_clock(top, inst, clock_srcs, prefix=""): + # Gather inst port list + error = 0 + + # Handle either an IpBlock (generated by reggen) or an OrderedDict + # (generated by topgen for a crossbar) + if isinstance(inst, IpBlock): + name = inst.name + clock_signals = inst.clock_signals + else: + name = inst['name'] + clock_signals = ([inst.get('clock_primary', 'rst_ni')] + + inst.get('other_clock_list', [])) + + if len(top['clock_srcs']) != len(clock_signals): + error += 1 + log.error("%s %s mismatched number of clock ports and nets" % + (prefix, name)) + + missing_port = [ + port for port in top['clock_srcs'].keys() + if port not in clock_signals + ] + + if missing_port: + error += 1 + log.error("%s %s Following clock ports do not exist:" % + (prefix, name)) + [log.error("%s" % port) for port in missing_port] + + missing_net = [ + net for port, net in top['clock_srcs'].items() if net not in clock_srcs + ] + + if missing_net: + error += 1 + log.error("%s %s Following clock nets do not exist:" % + (prefix, name)) + [log.error("%s" % net) for net in missing_net] + + return error + + +def check_flash(top): + error = 0 + + for mem in top['memory']: + if mem['type'] == "eflash": + error = check_keys(mem, eflash_required, eflash_optional, + eflash_added, "Eflash") + + flash = Flash(mem) + error += 1 if not flash.check_values() else 0 + + if error: + log.error("Flash check failed") + else: + flash.populate(mem) + + return error + + +def check_power_domains(top): + error = 0 + + # check that the default domain is valid + if top['power']['default'] not in top['power']['domains']: + error += 1 + return error + + # check that power domain definition is consistent with reset and module definition + for reset in top['resets']['nodes']: + if reset['gen']: + if 'domains' not in reset: + log.error("{} missing domain definition".format(reset['name'])) + error += 1 + return error + else: + for domain in reset['domains']: + if domain not in top['power']['domains']: + log.error("{} defined invalid domain {}".format( + reset['name'], domain)) + error += 1 + return error + + # Check that each module, xbar, memory has a power domain defined. + # If not, give it a default. + # If there is one defined, check that it is a valid definition + for end_point in top['module'] + top['memory'] + top['xbar']: + if 'domain' not in end_point: + end_point['domain'] = top['power']['default'] + + if end_point['domain'] not in top['power']['domains']: + log.error("{} defined invalid domain {}" + .format(end_point['name'], + end_point['domain'])) + error += 1 + return error + + # arrived without incident, return + return error + + +def validate_top(top, ipobjs, xbarobjs): + # return as it is for now + error = check_keys(top, top_required, top_optional, top_added, "top") + + if error != 0: + log.error("Top HJSON has top level errors. Aborting") + return top, error + + component = top['name'] + + # MODULE check + err, ip_idxs = check_target(top, ipobjs, Target(TargetType.MODULE)) + error += err + + # XBAR check + err, xbar_idxs = check_target(top, xbarobjs, Target(TargetType.XBAR)) + error += err + + # MEMORY check + error += check_flash(top) + + # Power domain check + error += check_power_domains(top) + + # Clock / Reset check + error += check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs) + + # Clock group check + error += check_clock_groups(top) + + # RV_PLIC check + + # Pinout, pinmux and target checks + # Note that these checks must happen in this order, as + # the pinmux and target configs depend on the pinout. + error += check_pinout(top, component) + error += check_pinmux(top, component) + error += check_implementation_targets(top, component) + + return top, error diff --git a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_bitrev.py b/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_bitrev.py deleted file mode 100644 index b40736a3..00000000 --- a/hw/vendor/esl_epfl_cgra/utilities/instructions_fft_bitrev.py +++ /dev/null @@ -1,209 +0,0 @@ -# -# FFT input bit reversal reordering instructions (manual mapping) -# - -ker_col_needed = 1 -ker_num_instr = 11 - -ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ - get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ - get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) - -# Save current start address -start_add = ker_start_add -# Update start address and ID for next kernel -ker_start_add = ker_start_add + ker_num_instr*ker_col_needed -ker_next_id = ker_next_id+1 - -# Used for multi-column kernels -k = ker_num_instr - -################################################################################################# -############################################## RC0 ############################################## -################################################################################################# - -# COLUMN-0 -# PROLOGUE -rcs_instructions[0][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] -rcs_instructions[0][start_add+ 2] = rcs_nop_instr -rcs_instructions[0][start_add+ 3] = [ "R0", "RCB", "SADD", "R0", "-", "-"] - -# ITERATION LOOP -rcs_instructions[0][start_add+ 4] = [ "-", "R0", "LWI", "R2", "-", "-"] -rcs_instructions[0][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "8"] -rcs_instructions[0][start_add+ 6] = rcs_nop_instr -rcs_instructions[0][start_add+ 7] = rcs_nop_instr - -rcs_instructions[0][start_add+ 8] = [ "RCB", "IMM", "SLT", "-", "-", "2"] -rcs_instructions[0][start_add+ 9] = [ "R1", "SELF", "SADD", "-", "-", "-"] -rcs_instructions[0][start_add+10] = [ "R2", "SELF", "SWI", "-", "-", "-"] - -################################################################################################# -############################################## RC1 ############################################## -################################################################################################# - -# COLUMN-0 -# PROLOGUE -rcs_instructions[1][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+ 1] = [ "-", "-", "LWD", "R1", "-", "-"] -rcs_instructions[1][start_add+ 2] = [ "RCB", "IMM", "SLT", "-", "-", "2"] -rcs_instructions[1][start_add+ 3] = [ "R0", "SELF", "SADD", "R0", "-", "-"] - -# ITERATION LOOP -rcs_instructions[1][start_add+ 4] = [ "-", "R0", "LWI", "R2", "-", "-"] -rcs_instructions[1][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "8"] -rcs_instructions[1][start_add+ 6] = [ "R3", "IMM", "SLT", "-", "-", "1"] -rcs_instructions[1][start_add+ 7] = ["SELF", "RCB", "LOR", "R3", "-", "-"] - -rcs_instructions[1][start_add+ 8] = ["ZERO", "ZERO", "SADD", "R3", "-", "-"] # R3=0 -rcs_instructions[1][start_add+ 9] = [ "RCT", "R1", "SADD", "-", "-", "-"] -rcs_instructions[1][start_add+10] = [ "R2", "SELF", "SWI", "-", "-", "-"] - -################################################################################################# -############################################## RC2 ############################################## -################################################################################################# - -# COLUMN-0 -# PROLOGUE -rcs_instructions[2][start_add+ 0] = [ "-", "-", "LWD", "R1", "-", "-"] -rcs_instructions[2][start_add+ 1] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[2][start_add+ 2] = rcs_nop_instr -rcs_instructions[2][start_add+ 3] = rcs_nop_instr - -# ITERATION LOOP -rcs_instructions[2][start_add+ 4] = ["ZERO", "R0", "SADD", "R2", "-", "-"] # R2=R0 -rcs_instructions[2][start_add+ 5] = rcs_nop_instr -rcs_instructions[2][start_add+ 6] = [ "R2", "IMM", "LAND", "-", "-", "1"] -rcs_instructions[2][start_add+ 7] = [ "R2", "IMM", "SRT", "R2", "-", "1"] - -rcs_instructions[2][start_add+ 8] = [ "R0", "IMM", "SADD", "R0", "-", "1"] -rcs_instructions[2][start_add+ 9] = rcs_nop_instr -rcs_instructions[2][start_add+10] = [ "R0", "R1", "BLT", "-", "-", "4"] - -################################################################################################# -############################################## RC3 ############################################## -################################################################################################# - -# COLUMN-0 -# PROLOGUE -rcs_instructions[3][start_add+ 0] = [ "-", "-", "LWD", "R0", "-", "-"] -rcs_instructions[3][start_add+ 1] = rcs_nop_instr -rcs_instructions[3][start_add+ 2] = rcs_nop_instr -rcs_instructions[3][start_add+ 3] = rcs_nop_instr - -# ITERATION LOOP -rcs_instructions[3][start_add+ 4] = ["ZERO", "ZERO", "SADD", "R1", "-", "-"] # R1=0 -rcs_instructions[3][start_add+ 5] = rcs_nop_instr -rcs_instructions[3][start_add+ 6] = [ "R1", "IMM", "SADD", "R1", "-", "1"] -rcs_instructions[3][start_add+ 7] = [ "R1", "R0", "BLT", "-", "-", "6"] - -rcs_instructions[3][start_add+ 8] = rcs_nop_instr -rcs_instructions[3][start_add+ 9] = rcs_nop_instr -rcs_instructions[3][start_add+10] = [ "-", "-", "EXIT", "-", "-", "-"] - -####################################################################################### - -# instructions.append(["NEXT RC"]) - -# # RC1_0 -# # PROLOGUE -# instructions.append(["DATA", "OUT_D", "IN1", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["DATA", "OUT_D", "IN1", "RF2", "ON", "OUT_F", "0"]) -# instructions.append(["RF1", "CONST", "SLT", "RF1", "OFF", "OUT_F", "2"]) -# instructions.append(["RF2", "OUT_D", "SADD", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["RF1", "CONST", "SSUB", "RF1", "ON", "OUT_F", "4"]) -# instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) - -# # ITERATION LOOP -# instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "8"]) -# instructions.append(["DATA", "RF1", "LWI", "RF3", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF2", "RCB", "SADD", "RF4", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF3", "RF4", "SWI", "RF1", "OFF", "OUT_F", "0"]) - -# ################################################################################################# -# ################################################################################################# -# ################################################################################################# - -# instructions.append(["NEXT RC"]) - -# # RC2_0 -# # PROLOGUE -# instructions.append(["DATA", "OUT_D", "IN1", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -# instructions.append(["RF1", "CONST", "SLT", "RF1", "OFF", "OUT_F", "2"]) -# instructions.append(["RF2", "OUT_D", "SADD", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# # ITERATION LOOP -# instructions.append(["DATA", "RF1", "LWI", "RF3", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "IN1", "RF4", "ON", "OUT_F", "0"]) -# instructions.append(["RF4", "CONST", "SLT", "RF1", "OFF", "OUT_F", "1"]) -# instructions.append(["RCB", "OUT_D", "LOR", "RF4", "ON", "OUT_F", "0"]) -# instructions.append(["RF4", "CONST", "SLT", "RF1", "OFF", "OUT_F", "2"]) -# instructions.append(["RF2", "OUT_D", "SADD", "RF4", "ON", "OUT_F", "0"]) -# instructions.append(["RF3", "RF4", "SWI", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "8"]) - -# ################################################################################################# -# ################################################################################################# -# ################################################################################################# - -# instructions.append(["NEXT RC"]) - -# # RC3_0 -# # PROLOGUE -# instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# # ITERATION LOOP -# instructions.append(["RF1", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF3", "CONST", "LAND", "RF1", "OFF", "OUT_F", "1"]) -# instructions.append(["RF3", "CONST", "SRT", "RF3", "ON", "OUT_F", "1"]) -# instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "1"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF1", "RF2", "BLT", "RF1", "OFF", "OUT_F", "6"]) - -# ################################################################################################# -# ################################################################################################# -# ################################################################################################# - -# instructions.append(["NEXT RC"]) - -# # RC4_0 -# # PROLOGUE -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# # ITERATION LOOP -# instructions.append(["ZEROS", "OUT_D", "IN1", "RF2", "ON", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["RF2", "CONST", "SADD", "RF2", "ON", "OUT_F", "1"]) -# instructions.append(["RF2", "RF1", "BLT", "RF1", "OFF", "OUT_F", "8"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -# instructions.append(["ZEROS", "OUT_D", "EXIT", "RF1", "OFF", "OUT_F", "0"]) - -# ################################################################################################# -# ################################################################################################# -# ################################################################################################# - -# kernel_col_needed = "0001" -# row_st_add = 44 -# n_instructions = 14 diff --git a/hw/vendor/eslepfl_cgra.lock.hjson b/hw/vendor/eslepfl_cgra.lock.hjson index 3b7520c1..b4a34e3f 100644 --- a/hw/vendor/eslepfl_cgra.lock.hjson +++ b/hw/vendor/eslepfl_cgra.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/OpenEdgeCGRA.git - rev: d53dd7a98ec59754ed21a5411dc985ebbdc39d3e + rev: 618b45d2c5deb0ae3741b8dfdd472354ed073126 } } diff --git a/hw/vendor/eslepfl_cgra.vendor.hjson b/hw/vendor/eslepfl_cgra.vendor.hjson index 61b8090c..0b95a6dd 100644 --- a/hw/vendor/eslepfl_cgra.vendor.hjson +++ b/hw/vendor/eslepfl_cgra.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/esl-epfl/OpenEdgeCGRA.git", - rev: "d53dd7a98ec59754ed21a5411dc985ebbdc39d3e", + rev: "618b45d2c5deb0ae3741b8dfdd472354ed073126", }, patch_dir: "patches/esl_epfl_cgra", From a20abefbc076e7db5c47ce661f821aa78f7238cc Mon Sep 17 00:00:00 2001 From: jmiranda Date: Wed, 25 Sep 2024 20:37:45 +0200 Subject: [PATCH 16/27] revendorizing x-heep --- hw/vendor/esl_epfl_x_heep/.gitignore | 14 +- hw/vendor/esl_epfl_x_heep/Makefile | 97 +- hw/vendor/esl_epfl_x_heep/README.md | 651 +-- .../block_diagrams/core_v_mini_mcu.svg | 3553 ----------------- .../esl_epfl_x_heep/block_diagrams/x-heep.svg | 2461 ------------ hw/vendor/esl_epfl_x_heep/configs/ci.hjson | 23 + hw/vendor/esl_epfl_x_heep/configs/example.py | 18 + .../configs/example_interleaved.hjson | 40 + .../esl_epfl_x_heep/configs/general.hjson | 24 + .../esl_epfl_x_heep/configs/testall.hjson | 23 + .../esl_epfl_x_heep/core-v-mini-mcu-fpga.core | 72 + .../esl_epfl_x_heep/core-v-mini-mcu.core | 78 +- .../core-v-mini-mcu.dc.upf.tpl | 159 + .../esl_epfl_x_heep/core-v-mini-mcu.upf.tpl | 38 +- .../esl_epfl_x_heep/docs/requirements.txt | 3 +- .../source/Configuration/Configuration.rst | 172 + .../docs/source/How_to/AnalogMixedSignal.md | 4 +- .../docs/source/How_to/CompileMakefile | 350 -- .../docs/source/How_to/CompileMakefile.md | 145 + .../docs/source/How_to/Debug.md | 6 +- .../docs/source/How_to/ExecuteFromFlash.md | 2 +- .../docs/source/How_to/ExternalDevices.md | 151 - .../docs/source/How_to/GettingStarted.md | 50 +- .../{ => docs/source/How_to}/IDEs.md | 18 +- .../docs/source/How_to/ImplementASIC.md | 2 +- .../docs/source/How_to/IntegratePeripheral.md | 2 +- .../docs/source/How_to/ProgramFlash.md | 2 +- .../docs/source/How_to/RunOnFPGA.md | 81 + .../docs/source/How_to/Simulate.md | 160 + .../docs/source/How_to/UpdateDocumentation.md | 27 + .../docs/source/How_to/eXtendingHEEP.md | 69 +- .../docs/source/Peripherals/DMA.md | 645 +-- .../docs/source/Peripherals/SPI.md | 1246 ++++++ .../docs/source/Peripherals/Timer.md | 107 + .../source/_static/ides}/build_screenshot.png | Bin .../source/_static/ides}/debug_screenshot.png | Bin hw/vendor/esl_epfl_x_heep/docs/source/conf.py | 11 + .../source/images}/example_adc.svg | 0 .../docs/source/images/x-heep-outline.png | Bin 0 -> 42485 bytes .../docs/source/images/xheep_diagram.png | Bin 0 -> 483438 bytes .../esl_epfl_x_heep/docs/source/index.rst | 17 +- .../hw/asic/sky130/sram_wrapper.sv | 4 + .../ao_peripheral_subsystem.sv | 153 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv | 357 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl | 155 +- .../hw/core-v-mini-mcu/debug_subsystem.sv | 31 +- .../include/addr_map_rule_pkg.sv | 6 + .../include/core_v_mini_mcu_pkg.sv.tpl | 75 +- .../include/power_manager_pkg.sv | 17 + .../include/x-heep_packages.core | 1 + .../core-v-mini-mcu/memory_subsystem.sv.tpl | 73 +- .../core-v-mini-mcu/peripheral_subsystem.sv | 173 +- .../peripheral_subsystem.sv.tpl | 59 +- .../hw/core-v-mini-mcu/system_bus.sv.tpl | 8 +- .../hw/core-v-mini-mcu/system_xbar.sv.tpl | 24 +- .../hw/fpga/constraints/nexys/pin_assign.xdc | 24 +- .../fpga/constraints/pynq-z2/constraints.xdc | 2 +- .../hw/fpga/constraints/zcu104/pin_assign.xdc | 99 + .../hw/fpga/pad_cell_inout_xilinx.sv | 3 +- .../hw/fpga/pad_cell_input_xilinx.sv | 3 +- .../hw/fpga/pad_cell_output_xilinx.sv | 3 +- .../hw/fpga/prim_xilinx_clk.sv | 15 +- .../hw/fpga/scripts/generate_sram.tcl | 27 - .../hw/fpga/scripts/generate_sram.tcl.tpl | 50 + .../hw/fpga/scripts/nexys/set_board.tcl | 3 - .../hw/fpga/scripts/pynq-z2/set_board.tcl | 3 - .../hw/fpga/scripts/zcu104/set_board.tcl | 3 - .../{sram_wrapper.sv => sram_wrapper.sv.tpl} | 33 +- .../esl_epfl_x_heep/hw/ip/dma/data/dma.hjson | 191 +- hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core | 2 +- .../esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv | 798 +++- .../hw/ip/dma/rtl/dma_reg_pkg.sv | 216 +- .../hw/ip/dma/rtl/dma_reg_top.sv | 670 +++- .../hw/ip/dma_subsystem/dma_subsystem.core | 21 + .../hw/ip/dma_subsystem/dma_subsystem.vlt | 10 + .../hw/ip/dma_subsystem/rtl/dma_subsystem.sv | 198 + .../hw/ip/i2s/rtl/i2s_rx_channel.sv | 2 +- .../esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/fir.sv | 4 +- .../hw/ip/pdm2pcm/rtl/halfband.sv | 6 +- .../data/power_manager.hjson.tpl | 60 +- .../power_manager/data/power_manager.sv.tpl | 152 +- .../hw/ip/power_manager/power_manager.vlt | 2 +- .../hw/simulation/pad_cell_inout.sv | 1 + .../hw/simulation/pad_cell_input.sv | 1 + .../hw/simulation/pad_cell_output.sv | 1 + .../hw/simulation/simulation.vlt | 2 + .../hw/simulation/sram_wrapper.sv | 3 + .../pad_control/data/pad_control.hjson.tpl | 2 +- .../hw/system/x_heep_system.sv.tpl | 32 +- .../hw/vendor/esl_epfl_cv32e40px.lock.hjson | 2 +- .../hw/vendor/esl_epfl_cv32e40px.vendor.hjson | 2 +- .../hw/vendor/esl_epfl_cv32e40px/.gitignore | 8 + .../bhv/cv32e40px_instr_trace.svh | 466 ++- .../esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv | 397 +- .../bhv/cv32e40px_rvfi_trace.sv | 123 +- .../bhv/cv32e40px_tb_wrapper.sv | 83 +- .../bhv/cv32e40px_tracer.sv | 47 +- .../bhv/include/cv32e40px_rvfi_pkg.sv | 28 +- .../bhv/include/cv32e40px_tracer_pkg.sv | 30 +- .../esl_epfl_cv32e40px/bhv/insn_trace.sv | 111 +- .../bhv/pipe_freeze_trace.sv | 41 +- .../rtl/cv32e40px_controller.sv | 42 +- .../esl_epfl_cv32e40px/rtl/cv32e40px_core.sv | 18 +- .../rtl/cv32e40px_cs_registers.sv | 2 +- .../rtl/cv32e40px_decoder.sv | 86 +- .../rtl/cv32e40px_ex_stage.sv | 2 +- .../rtl/cv32e40px_fp_wrapper.sv | 2 +- .../rtl/cv32e40px_id_stage.sv | 10 +- .../rtl/cv32e40px_load_store_unit.sv | 32 +- .../rtl/cv32e40px_register_file_latch.sv | 8 +- .../esl_epfl_cv32e40px/rtl/cv32e40px_top.sv | 50 +- .../rtl/cv32e40px_x_disp.sv | 26 +- .../openhwgroup_cv32e20/rtl/cve2_core.sv | 15 +- .../rtl/cve2_cs_registers.sv | 81 +- .../rtl/cve2_fetch_fifo.sv | 2 - .../openhwgroup_cv32e20/rtl/cve2_id_stage.sv | 1 + .../openhwgroup_cv32e20/rtl/cve2_pkg.sv | 80 + .../rtl/cve2_top_tracing.sv | 2 - .../hw/vendor/openhwgroup_cv32e40p.lock.hjson | 2 +- .../vendor/openhwgroup_cv32e40p.vendor.hjson | 2 +- .../hw/vendor/openhwgroup_cv32e40p/.gitignore | 2 + .../bhv/cv32e40p_instr_trace.svh | 466 ++- .../openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv | 319 +- .../bhv/cv32e40p_rvfi_trace.sv | 123 +- .../bhv/cv32e40p_tb_wrapper.sv | 40 +- .../bhv/cv32e40p_tracer.sv | 47 +- .../bhv/include/cv32e40p_rvfi_pkg.sv | 28 +- .../bhv/include/cv32e40p_tracer_pkg.sv | 30 +- .../openhwgroup_cv32e40p/bhv/insn_trace.sv | 107 +- .../bhv/pipe_freeze_trace.sv | 41 +- .../rtl/cv32e40p_controller.sv | 40 +- .../openhwgroup_cv32e40p/rtl/cv32e40p_core.sv | 12 +- .../rtl/cv32e40p_decoder.sv | 86 +- .../rtl/cv32e40p_fp_wrapper.sv | 2 +- .../rtl/cv32e40p_id_stage.sv | 10 +- .../rtl/cv32e40p_load_store_unit.sv | 32 +- .../rtl/cv32e40p_register_file_latch.sv | 8 +- .../openhwgroup_cv32e40p/rtl/cv32e40p_top.sv | 50 +- .../hw/vendor/openhwgroup_cve2.lock.hjson | 2 +- .../hw/vendor/openhwgroup_cve2.vendor.hjson | 2 +- .../pulp_platform_riscv_dbg/fix_nrharts.patch | 28 + .../pulp_platform_riscv_dbg.vendor.hjson | 2 + .../pulp_platform_riscv_dbg/src/dm_csrs.sv | 2 +- .../pulp_platform_riscv_dbg/src/dm_mem.sv | 4 +- .../hw/vendor/waiver/lint/cv32e40px.vlt | 3 + .../hw/vendor/waiver/lint/riscv_dbg.vlt | 1 + hw/vendor/esl_epfl_x_heep/logo/x-heep.png | Bin 30569 -> 0 bytes hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson | 47 +- .../esl_epfl_x_heep/mcu_cfg_minimal.hjson | 50 +- hw/vendor/esl_epfl_x_heep/pad_cfg.hjson | 18 +- .../scripts/synthesis/dc_shell/dc_script.tcl | 4 + hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt | 105 +- hw/vendor/esl_epfl_x_heep/sw/Makefile | 2 +- .../sw/applications/coremark/coremark.h | 2 +- .../example_ams_peripheral/main.c | 2 +- .../sw/applications/example_asm/add.s | 6 + .../sw/applications/example_asm/constants.h | 1 + .../sw/applications/example_asm/main.c | 31 + .../sw/applications/example_asm/multiply.S | 9 + .../applications/example_clock_gating/main.c | 63 - .../sw/applications/example_cpp/MyClass.cpp | 21 + .../sw/applications/example_cpp/MyClass.hpp | 15 + .../sw/applications/example_cpp/main.c | 27 - .../sw/applications/example_cpp/main.cpp | 50 + .../sw/applications/example_cpp/test_cpp.cpp | 43 - .../sw/applications/example_cpp/test_cpp.h | 4 - .../gen_stimuly.py | 65 + .../example_data_processing_from_flash/main.c | 87 + .../example_data_processing_from_flash/main.h | 42 + .../matrices.h | 206 + .../sw/applications/example_dma/main.c | 519 ++- .../sw/applications/example_dma_2d/main.c | 890 +++++ .../applications/example_dma_2d/test_data.h | 40 + .../applications/example_dma_external/main.c | 8 +- .../example_dma_multichannel/main.c | 1261 ++++++ .../example_dma_multichannel/test_data.h | 34 + .../sw/applications/example_dma_sdk/main.c | 112 + .../example_freertos_blinky/main.c | 4 +- .../sw/applications/example_gpio_intr/main.c | 5 +- .../applications/example_gpio_toggle/main.c | 2 +- .../sw/applications/example_i2s/main.c | 61 +- .../sw/applications/example_iffifo/main.c | 8 +- .../example_im2col/im2colGolden.c | 72 + .../example_im2col/im2colGolden.h | 31 + .../applications/example_im2col/im2col_lib.c | 211 + .../applications/example_im2col/im2col_lib.h | 74 + .../sw/applications/example_im2col/main.c | 81 + .../sw/applications/example_matadd/main.c | 2 +- .../example_matadd_interleaved/main.c | 2 +- .../sw/applications/example_matfadd/main.c | 110 +- .../sw/applications/example_matmul/main.c | 2 +- .../sw/applications/example_pdm2pcm/main.c | 2 +- .../example_power_gating_core/main.c | 189 - .../example_power_gating_external/main.c | 68 - .../example_power_gating_periph/main.c | 66 - .../example_power_gating_ram_blocks/main.c | 74 - .../applications/example_power_manager/main.c | 471 +++ .../applications/example_sdk_spi_flash/main.c | 353 ++ .../example_set_retentive_ram_blocks/main.c | 70 - .../main.c | 63 - .../example_simple_accelerator/main.c | 2 +- .../example_spi_host_dma_power_gate/main.c | 341 -- .../sw/applications/example_spi_read/main.c | 12 +- .../sw/applications/example_spi_write/main.c | 15 +- .../example_spidma_powergate/main.c | 192 + .../sw/applications/example_timer_sdk/main.c | 126 + .../sw/applications/hello_world/main.c | 1 - .../sw/applications/minver/chipsupport.c | 2 +- .../esl_epfl_x_heep/sw/cmake/riscv.cmake | 2 +- .../esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c | 541 ++- .../sw/device/bsp/w25q/w25q128jw.h | 14 +- .../sw/device/lib/base/freestanding/assert.h | 17 +- .../device/lib/base/freestanding/stdalign.h | 6 + .../sw/device/lib/base/freestanding/stdbool.h | 4 + .../sw/device/lib/base/memory.c | 12 +- .../sw/device/lib/base/memory.h | 2 +- .../esl_epfl_x_heep/sw/device/lib/base/mmio.c | 10 + .../sw/device/lib/crt/{crt0.S => crt0.S.tpl} | 317 +- .../sw/device/lib/crt/vectors.S | 30 +- .../sw/device/lib/crt/vectors_freertos.S | 27 - .../sw/device/lib/drivers/dma/dma.c | 681 +++- .../sw/device/lib/drivers/dma/dma.h | 145 +- .../sw/device/lib/drivers/dma/dma_regs.h | 153 +- .../drivers/fast_intr_ctrl/fast_intr_ctrl.c | 6 + .../drivers/fast_intr_ctrl/fast_intr_ctrl.h | 8 +- .../sw/device/lib/drivers/gpio/gpio.c | 11 +- .../power_manager/data/power_manager.h.tpl | 18 +- .../lib/drivers/power_manager/power_manager.c | 208 +- .../power_manager/power_manager_cpu_restore.S | 88 + .../power_manager/power_manager_cpu_store.S | 88 + .../sw/device/lib/drivers/rv_plic/rv_plic.c | 13 +- .../sw/device/lib/drivers/rv_timer/rv_timer.h | 6 + .../sw/device/lib/drivers/soc_ctrl/soc_ctrl.h | 2 +- .../sw/device/lib/drivers/spi_host/spi_host.c | 526 ++- .../sw/device/lib/drivers/spi_host/spi_host.h | 916 ++++- .../sw/device/lib/drivers/uart/uart.c | 20 +- .../device/lib/runtime/core_v_mini_mcu.h.tpl | 15 +- .../lib/runtime/core_v_mini_mcu_memory.h.tpl | 29 + .../sw/device/lib/runtime/handler.c | 8 + .../sw/device/lib/runtime/handler.h | 9 + .../sw/device/lib/runtime/hart.h | 10 + .../sw/device/lib/runtime/heap.cpp | 60 + .../sw/device/lib/runtime/init.c | 11 +- .../sw/device/lib/runtime/syscalls.c | 42 +- .../sw/device/lib/runtime/syscalls_cpp.cpp | 39 + .../sw/device/lib/sdk/dma/dma_sdk.c | 100 + .../sw/device/lib/sdk/dma/dma_sdk.h | 108 + .../sw/device/lib/sdk/spi/spi_sdk.c | 1127 ++++++ .../sw/device/lib/sdk/spi/spi_sdk.h | 576 +++ .../sw/device/lib/sdk/timer/timer_sdk.c | 142 + .../sw/device/lib/sdk/timer/timer_sdk.h | 121 + .../sw/device/target/nexys-a7-100t/x-heep.h | 1 + .../sw/device/target/pynq-z2/x-heep.h | 1 + .../sw/device/target/zcu104/x-heep.h | 1 + .../esl_epfl_x_heep/sw/linker/link.ld.tpl | 18 +- .../sw/linker/link_flash_exec.ld.tpl | 2 +- .../sw/linker/link_flash_load.ld.tpl | 36 +- hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl | 43 +- hw/vendor/esl_epfl_x_heep/tb/testharness.sv | 24 +- hw/vendor/esl_epfl_x_heep/util/MakefileHelp | 12 +- .../util/generate-makefile-help | 2 - hw/vendor/esl_epfl_x_heep/util/mcu_gen.py | 162 +- .../util/structs_periph_gen.py | 28 +- hw/vendor/esl_epfl_x_heep/util/test_all.sh | 10 +- .../util/x_heep_gen/__init__.py | 4 + .../util/x_heep_gen/linker_section.py | 80 + .../util/x_heep_gen/load_config.py | 293 ++ .../util/x_heep_gen/ram_bank.py | 133 + .../esl_epfl_x_heep/util/x_heep_gen/system.py | 430 ++ hw/vendor/eslepfl_x_heep.lock.hjson | 2 +- hw/vendor/eslepfl_x_heep.vendor.hjson | 2 +- 271 files changed, 19587 insertions(+), 12028 deletions(-) delete mode 100644 hw/vendor/esl_epfl_x_heep/block_diagrams/core_v_mini_mcu.svg delete mode 100644 hw/vendor/esl_epfl_x_heep/block_diagrams/x-heep.svg create mode 100644 hw/vendor/esl_epfl_x_heep/configs/ci.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/configs/example.py create mode 100644 hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/configs/general.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/configs/testall.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/core-v-mini-mcu-fpga.core create mode 100644 hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.dc.upf.tpl create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/Configuration/Configuration.rst delete mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile.md delete mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md rename hw/vendor/esl_epfl_x_heep/{ => docs/source/How_to}/IDEs.md (92%) create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/RunOnFPGA.md create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/Simulate.md create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/How_to/UpdateDocumentation.md create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/SPI.md create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/Timer.md rename hw/vendor/esl_epfl_x_heep/{ides/img => docs/source/_static/ides}/build_screenshot.png (100%) rename hw/vendor/esl_epfl_x_heep/{ides/img => docs/source/_static/ides}/debug_screenshot.png (100%) rename hw/vendor/esl_epfl_x_heep/{block_diagrams => docs/source/images}/example_adc.svg (100%) create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/images/x-heep-outline.png create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/images/xheep_diagram.png create mode 100644 hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/power_manager_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl create mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl.tpl delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl delete mode 100644 hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl rename hw/vendor/esl_epfl_x_heep/hw/fpga/{sram_wrapper.sv => sram_wrapper.sv.tpl} (66%) create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.vlt create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_riscv_dbg/fix_nrharts.patch delete mode 100644 hw/vendor/esl_epfl_x_heep/logo/x-heep.png create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/add.s create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/constants.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/multiply.S delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_clock_gating/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.cpp create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.hpp delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.cpp delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.cpp delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/test_data.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_sdk/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_core/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_external/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_periph/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_ram_blocks/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_sdk_spi_flash/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks_external/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma_power_gate/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_spidma_powergate/main.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_timer_sdk/main.c rename hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/{crt0.S => crt0.S.tpl} (83%) create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_restore.S create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_store.S create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu_memory.h.tpl create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/heap.cpp create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls_cpp.cpp create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.h delete mode 100755 hw/vendor/esl_epfl_x_heep/util/generate-makefile-help create mode 100644 hw/vendor/esl_epfl_x_heep/util/x_heep_gen/__init__.py create mode 100644 hw/vendor/esl_epfl_x_heep/util/x_heep_gen/linker_section.py create mode 100644 hw/vendor/esl_epfl_x_heep/util/x_heep_gen/load_config.py create mode 100644 hw/vendor/esl_epfl_x_heep/util/x_heep_gen/ram_bank.py create mode 100644 hw/vendor/esl_epfl_x_heep/util/x_heep_gen/system.py diff --git a/hw/vendor/esl_epfl_x_heep/.gitignore b/hw/vendor/esl_epfl_x_heep/.gitignore index f2b85af8..d369ddf8 100644 --- a/hw/vendor/esl_epfl_x_heep/.gitignore +++ b/hw/vendor/esl_epfl_x_heep/.gitignore @@ -7,8 +7,10 @@ build/ *.dis *.map *.do +*.jou +*.str .venv/ -util/__pycache__/* +__pycache__/ # ignore apps output file run_verif_rtl_log.txt @@ -16,6 +18,7 @@ run_verif_rtl_log.txt # ignore the following hw automatically generated files environment.yml core-v-mini-mcu.upf +core-v-mini-mcu.dc.upf tb/tb_util.svh hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv hw/core-v-mini-mcu/system_bus.sv @@ -32,9 +35,13 @@ hw/system/pad_control/data/pad_control.hjson hw/system/pad_control/rtl/pad_control.sv hw/system/pad_control/rtl/pad_control_reg_pkg.sv hw/system/pad_control/rtl/pad_control_reg_top.sv +hw/fpga/sram_wrapper.sv +hw/fpga/scripts/generate_sram.tcl -# same for the C header file and linker scripts +# same for the C header file and linker scripts and assembly files +sw/device/lib/crt/crt0.S sw/device/lib/runtime/core_v_mini_mcu.h +sw/device/lib/runtime/core_v_mini_mcu_memory.h sw/linker/link.ld sw/linker/link_flash_exec.ld sw/linker/link_flash_load.ld @@ -46,6 +53,9 @@ sw/device/lib/drivers/**/*_structs.h # openroad flow/OpenROAD-flow-scripts +# automatically generated docs +/docs/source/Configuration/generated + # User-dependent configuration files .vscode private/ diff --git a/hw/vendor/esl_epfl_x_heep/Makefile b/hw/vendor/esl_epfl_x_heep/Makefile index 2d67386a..ca1a02b0 100644 --- a/hw/vendor/esl_epfl_x_heep/Makefile +++ b/hw/vendor/esl_epfl_x_heep/Makefile @@ -9,8 +9,10 @@ mkfile_path := $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") $(info $$You are executing from: $(mkfile_path)) # Include the self-documenting tool -FILE=$(mkfile_path)/Makefile -include $(mkfile_path)/util/generate-makefile-help +export FILE_FOR_HELP=$(mkfile_path)/Makefile + +help: + ${mkfile_path}/util/MakefileHelp # Setup to autogenerate python virtual environment VENVDIR?=$(WORKDIR)/.venv @@ -31,12 +33,15 @@ endif # Project options are based on the app to be build (default - hello_world) PROJECT ?= hello_world +LINK_FOLDER ?= $(mkfile_path)/sw/linker + # Linker options are 'on_chip' (default),'flash_load','flash_exec','freertos' LINKER ?= on_chip # Target options are 'sim' (default) and 'pynq-z2' and 'nexys-a7-100t' TARGET ?= sim -MCU_CFG ?= mcu_cfg.hjson +MCU_CFG_PERIPHERALS ?= mcu_cfg.hjson +X_HEEP_CFG ?= configs/general.hjson PAD_CFG ?= pad_cfg.hjson EXT_PAD_CFG ?= @@ -63,23 +68,23 @@ FLASHREAD_ADDR ?= 0x0 FLASHREAD_FILE ?= $(mkfile_path)/flashcontent.hex FLASHREAD_BYTES ?= 256 + +#binary to store in flash memory +FLASHWRITE_FILE ?= $(mkfile_path)/sw/build/main.hex + #max address in the hex file, used to program the flash -ifeq ($(wildcard sw/build/main.hex),) - MAX_HEX_ADDRESS = 0 - MAX_HEX_ADDRESS_DEC = 0 - BYTES_AFTER_MAX_HEX_ADDRESS = 0 - FLASHRWITE_BYTES = 0 +ifeq ($(wildcard $(FLASHWRITE_FILE)),) + MAX_HEX_ADDRESS := 0 + MAX_HEX_ADDRESS_DEC := 0 + BYTES_AFTER_MAX_HEX_ADDRESS := 0 + FLASHWRITE_BYTES := 0 else - MAX_HEX_ADDRESS = $(shell cat sw/build/main.hex | grep "@" | tail -1 | cut -c2-) - MAX_HEX_ADDRESS_DEC = $(shell printf "%d" 0x$(MAX_HEX_ADDRESS)) - BYTES_AFTER_MAX_HEX_ADDRESS = $(shell tac sw/build/main.hex | awk 'BEGIN {count=0} /@/ {print count; exit} {count++}') - FLASHRWITE_BYTES = $(shell echo $(MAX_HEX_ADDRESS_DEC) + $(BYTES_AFTER_MAX_HEX_ADDRESS)*16 | bc) + MAX_HEX_ADDRESS := $(shell cat $(FLASHWRITE_FILE) | grep "@" | tail -1 | cut -c2-) + MAX_HEX_ADDRESS_DEC := $(shell printf "%d" 0x$(MAX_HEX_ADDRESS)) + BYTES_AFTER_MAX_HEX_ADDRESS := $(shell tac $(FLASHWRITE_FILE) | awk 'BEGIN {count=0} /@/ {print count; exit} {count++}') + FLASHWRITE_BYTES := $(shell echo $(MAX_HEX_ADDRESS_DEC) + $(BYTES_AFTER_MAX_HEX_ADDRESS)*16 | bc) endif - -#binary to store in flash memory -FLASHWRITE_FILE = $(mkfile_path)/sw/build/main.hex - # Export variables to sub-makefiles export @@ -98,28 +103,33 @@ environment.yml: python-requirements.txt ## @param MEMORY_BANKS=[2(default) to (16 - MEMORY_BANKS_IL)] ## @param MEMORY_BANKS_IL=[0(default),2,4,8] mcu-gen: - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/include --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_bus.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_xbar.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/memory_subsystem.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir tb/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv tb/tb_util.svh.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/pad_ring.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/x_heep_system.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/runtime --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --header-c sw/device/lib/runtime/core_v_mini_mcu.h.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link.ld.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir . --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --pkg-sv ./core-v-mini-mcu.upf.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.sv.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.hjson.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/include --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_bus.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/system_xbar.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/memory_subsystem.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir tb/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv tb/tb_util.svh.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/pad_ring.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/core-v-mini-mcu/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/system/x_heep_system.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/runtime --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --header-c sw/device/lib/runtime/core_v_mini_mcu.h.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/runtime --cpu $(CPU) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --header-c sw/device/lib/runtime/core_v_mini_mcu_memory.h.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir $(LINK_FOLDER) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script $(LINK_FOLDER)/link.ld.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir . --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --pkg-sv ./core-v-mini-mcu.upf.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir . --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --pkg-sv ./core-v-mini-mcu.dc.upf.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/ip/power_manager/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv hw/ip/power_manager/data/power_manager.hjson.tpl bash -c "cd hw/ip/power_manager; source power_manager_gen.sh; cd ../../../" - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/drivers/power_manager --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv sw/device/lib/drivers/power_manager/data/power_manager.h.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/data/pad_control.hjson.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/rtl/pad_control.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/drivers/power_manager --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_domains $(EXTERNAL_DOMAINS) --pkg-sv sw/device/lib/drivers/power_manager/data/power_manager.h.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/data --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/data/pad_control.hjson.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/system/pad_control/rtl --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --external_pads $(EXT_PAD_CFG) --pkg-sv hw/system/pad_control/rtl/pad_control.sv.tpl bash -c "cd hw/system/pad_control; source pad_control_gen.sh; cd ../../../" - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link_flash_exec.ld.tpl - $(PYTHON) util/mcu_gen.py --cfg $(MCU_CFG) --pads_cfg $(PAD_CFG) --outdir sw/linker --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script sw/linker/link_flash_load.ld.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir $(LINK_FOLDER) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script $(LINK_FOLDER)/link_flash_exec.ld.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir $(LINK_FOLDER) --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --linker_script $(LINK_FOLDER)/link_flash_load.ld.tpl $(PYTHON) ./util/structs_periph_gen.py + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/fpga/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/fpga/sram_wrapper.sv.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir hw/fpga/scripts/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv hw/fpga/scripts/generate_sram.tcl.tpl + $(PYTHON) util/mcu_gen.py --config $(X_HEEP_CFG) --cfg_peripherals $(MCU_CFG_PERIPHERALS) --pads_cfg $(PAD_CFG) --outdir sw/device/lib/crt/ --bus $(BUS) --memorybanks $(MEMORY_BANKS) --memorybanks_il $(MEMORY_BANKS_IL) --tpl-sv sw/device/lib/crt/crt0.S.tpl $(MAKE) verible ## Display mcu_gen.py help @@ -140,7 +150,15 @@ verible: ## @param COMPILER_PREFIX=riscv32-unknown-(default) ## @param ARCH=rv32imc(default), app: clean-app - $(MAKE) -C sw PROJECT=$(PROJECT) TARGET=$(TARGET) LINKER=$(LINKER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH) SOURCE=$(SOURCE) + $(MAKE) -C sw PROJECT=$(PROJECT) TARGET=$(TARGET) LINKER=$(LINKER) LINK_FOLDER=$(LINK_FOLDER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH) SOURCE=$(SOURCE) \ + || { \ + echo "\033[0;31mHmmm... seems like the compilation failed...\033[0m"; \ + echo "\033[0;31mIf you do not understand why, it is likely that you either:\033[0m"; \ + echo "\033[0;31m a) offended the Leprechaun of Electronics\033[0m"; \ + echo "\033[0;31m b) forgot to run make mcu-gen\033[0m"; \ + echo "\033[0;31mI would start by checking b) if I were you!\033[0m"; \ + exit 1; \ + } ## Just list the different application names available app-list: @@ -256,13 +274,18 @@ flash-readid: ## Loads the obtained binary to the EPFL_Programmer flash flash-prog: cd sw/vendor/yosyshq_icestorm/iceprog; make; \ - ./iceprog -a $(FLASHRWITE_BYTES) -d i:0x0403:0x6011 -I B $(FLASHWRITE_FILE); + ./iceprog -a $(FLASHWRITE_BYTES) -d i:0x0403:0x6011 -I B $(FLASHWRITE_FILE); ## Read the EPFL_Programmer flash flash-read: cd sw/vendor/yosyshq_icestorm/iceprog; make; \ ./iceprog -d i:0x0403:0x6011 -I B -o $(shell printf "%d" $(FLASHREAD_ADDR)) -R $(FLASHREAD_BYTES) $(FLASHREAD_FILE); +## Erase the EPFL_Programmer flash +flash-erase: + cd sw/vendor/yosyshq_icestorm/iceprog; make; \ + ./iceprog -d i:0x0403:0x6011 -I B -b; + ## Run openOCD w/ EPFL_Programmer openOCD_epflp: xterm -e openocd -f ./tb/core-v-mini-mcu-pynq-z2-esl-programmer.cfg; diff --git a/hw/vendor/esl_epfl_x_heep/README.md b/hw/vendor/esl_epfl_x_heep/README.md index c9705474..1a539464 100644 --- a/hw/vendor/esl_epfl_x_heep/README.md +++ b/hw/vendor/esl_epfl_x_heep/README.md @@ -1,3 +1,22 @@ +
+

+ +`X-HEEP` (eXtendable Heterogeneous Energy-Efficient Platform) is a `RISC-V` microcontroller described in `SystemVerilog` +that can be configured to target small and tiny platforms as well as extended to support accelerators. +The cool thing about `X-HEEP` is that we provide a simple customizable MCU, so CPUs, common peripherals, memories, etc. +so that you can extend it with your own accelerator without modifying the MCU, but just instantiating it in your design. +By doing so, you inherit an IP capable of booting RTOS (such as `freeRTOS`) with the whole FW stack, including `HAL` drivers and `SDK`, +and you can focus on building your special HW supported by the microcontroller. + +`X-HEEP` supports simulation with Verilator, Questasim, etc. Morever, FW can be built and linked by using `CMake` either with gcc or with clang. It can be implemented on FPGA, and it supports implementation in Silicon, which is its main (but not only) target. See below for more details. + +The block diagram below shows the `X-HEEP` MCU + +

+ + +> :bookmark_tabs: Please refer to the documentation in [Read the Docs](https://x-heep.readthedocs.io/en/latest/index.html) + # Repository folder structure . @@ -23,22 +42,6 @@ ├── util └── README.md -
-

- -`X-HEEP` (eXtendable Heterogeneous Energy-Efficient Platform) is a `RISC-V` microcontroller described in `SystemVerilog` -that can be configured to target small and tiny platforms as well as extended to support accelerators. -The cool thing about `X-HEEP` is that we provide a simple customizable MCU, so CPUs, common peripherals, memories, etc. -so that you can extend it with your own accelerator without modifying the MCU, but just instantiating it in your design. -By doing so, you inherit an IP capable of booting RTOS (such as `freeRTOS`) with the whole FW stack, including `HAL` drivers and `SDK`, -and you can focus on building your special HW supported by the microcontroller. - -`X-HEEP` supports simulation with Verilator, Questasim, etc. Morever, FW can be built and linked by using `CMake` either with gcc or with clang. It can be implemented on FPGA, and it supports implementation in Silicon, which is its main (but not only) target. See below for more details. - -The block diagram below shows the `X-HEEP` MCU - -

- # Reference If you use X-HEEP in your academic work you can cite us: [X-HEEP Paper](https://arxiv.org/abs/2401.05548) @@ -52,618 +55,4 @@ If you use X-HEEP in your academic work you can cite us: [X-HEEP Paper](https:// archivePrefix={arXiv}, primaryClass={cs.AR} } -``` - -# Self-documented Makefile - -Note that under `util` folder, the file `generate-makefile-help` is employed to generate a self-documented helping output. In case of including any other target or command under the main `Makefile`, follow the same general and parameter descriptions as already provided for every target. Check the `help` output by doing `make` or `make help`. Moreover, **note that some of the parameters required for some of the targets are initiated with _default values_** - -# Prerequisite - -## 1. OS requirements - -To use `X-HEEP`, first make sure you have the following apt packages, or install them as: - -```bash -sudo apt install lcov libelf1 libelf-dev libftdi1-2 libftdi1-dev libncurses5 libssl-dev libudev-dev libusb-1.0-0 lsb-release texinfo autoconf cmake flex bison libexpat-dev gawk tree xterm python3-venv python3-dev -``` - -In general, have a look at the [Install required software](https://opentitan.org/guides/getting_started/index.html) section of the OpenTitan documentation. - -It has been tested only on `Ubuntu 20`, and we know it does NOT WORK on `Ubuntu 22`. - -## 2. Python - -We rely on either (a) `miniconda`, or (b) `virtual environment` enviroment. - -Choose between `2.a` or `2.b` to setup your enviroment. - -### 2.a Miniconda - -Install [Miniconda](https://docs.conda.io/en/latest/miniconda.html#linux-installers) python 3.8 version as described in the link, -and create the Conda enviroment: - -```bash -make conda -``` - -You need to do it only the first time, then just activate the environment everytime you work with `X-HEEP` as - -```bash -conda activate core-v-mini-mcu -``` - -### 2.b Virtual Environment - -Install the python virtual environment just as: - -```bash -make venv -``` - -You need to do it only the first time, then just activate the environment everytime you work with `X-HEEP` as - -```bash -source .venv/bin/activate -``` - -## 3. Install the RISC-V Compiler: - -``` -git clone --branch 2022.01.17 --recursive https://github.com/riscv/riscv-gnu-toolchain -cd riscv-gnu-toolchain -./configure --prefix=/home/$USER/tools/riscv --with-abi=ilp32 --with-arch=rv32imc --with-cmodel=medlow -make -``` - -Then, set the `RISCV` env variable as: - -``` -export RISCV=/home/$USER/tools/riscv -``` - -Optionally you can also compile with clang/LLVM instead of gcc. For that you must install the clang compiler into the same `RISCV` path. The binaries of gcc and clang do not collide so you can have both residing in the same `RISCV` directory. For this you can set the `-DCMAKE_INSTALL_PREFIX` cmake variable to `$RISCV` when building LLVM. This can be accomplished by doing the following: - -``` -git clone https://github.com/llvm/llvm-project.git -cd llvm-project -git checkout llvmorg-14.0.0 -mkdir build && cd build -cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$RISCV -DLLVM_TARGETS_TO_BUILD="RISCV" ../llvm -cmake --build . --target install -``` - -## 4. Install Verilator: - -``` -export VERILATOR_VERSION=4.210 - -git clone https://github.com/verilator/verilator.git -cd verilator -git checkout v$VERILATOR_VERSION - -autoconf -./configure --prefix=/home/$USER/tools/verilator/$VERILATOR_VERSION -make -make install -``` -Then, set the `PATH` env variable to as: - -``` -export PATH=/home/$USER/tools/verilator/$VERILATOR_VERSION/bin:$PATH -``` - -In general, have a look at the [Install Verilator](https://opentitan.org/guides/getting_started/setup_verilator.html) section of the OpenTitan documentation. - -If you want to see the vcd waveforms generated by the Verilator simulation, install GTKWAVE: - -``` -sudo apt install libcanberra-gtk-module libcanberra-gtk3-module -sudo apt-get install -y gtkwave -``` - -## Files are formatted with Verible - -We use version v0.0-1824-ga3b5bedf - -See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-7a-install-verible-optional) - -To format your RTL code type: - -``` -make verible -``` - -## Docker alternative - -A docker image containing all the required software dependancies is available on [github-packages](https://github.com/orgs/esl-epfl/packages/container/package/x-heep-toolchain). - -It is only required to install [`docker`](https://docs.docker.com/get-docker/) and pull the image. - -```bash -docker pull ghcr.io/esl-epfl/x-heep-toolchain:latest -``` - -Assuming that X-HEEP has been cloned to `X-HEEP-DIR=\absolute\path\to\x-HEEP\folder`, it is possible to directly run the docker mounting `X-HEEP-DIR` to the path `\workspace\x-heep` in the docker. - -```bash -docker run -it -v ${X-HEEP-DIR}:/workspace/x-heep ghcr.io/esl-epfl/x-heep-toolchain -``` - -Take care to indicate the absolute path to the local clone of X-HEEP, otherwise `docker` will not be able to properly nount the local folder in the container. - -All the command listed in the README can be execute in the docker container, except for: -- Simulation with Questasim and VCS, synthesis with Design Compiler (licenses are required to use these tools, so they are not installed in the container) -- OpenRoad flow is not installed in the container, so it is not possible to run the related make commands - -## Compilation Flow and Package Manager - -We use [FuseSoC](https://github.com/olofk/fusesoc) for all the tools we use. - -The `fusesoc` commands are inside the Makefile. - -# Adding external IPs - -This repository relies on [Vendor](https://opentitan.org/book/util/doc/vendor.html) to add new IPs. The `vendor.py` script in the [`./util`](./util/) folder implements what is described above, while [this](./docs/source/How_to/ExternalDevices.md) file contains additional information on how to connect external devices to the system. - -# Compiling with Makefile - -You can compile the example applications and the platform using the Makefile. Type 'make help' or 'make' for more information. Moreover, please, check the different 'clean' commands to verify that you are using the corret one. - -## Generate core-v-mini-mcu package - -First, you have to generate the SystemVerilog package and C header file of the core-v-mini-mcu: - -``` -make mcu-gen -``` - -By default, `X-HEEP` deploys the [cv32e20](https://github.com/openhwgroup/cve2) RISC-V CPU. -Other supported CPUs are: the [cv32e40p](https://github.com/openhwgroup/cv32e40p), [cv32e40x](https://github.com/openhwgroup/cv32e40x), and the [cv32e40px](https://github.com/esl-epfl/cv32e40px). -The default bus type of `X-HEEP` is a single-master-at-a-time architecture, (called `onetoM`), but the cross-bar architecture is also supported by setting -the bus to `NtoM`. Also, the user can select the number of 32kB banks addressed in continuous mode and/or the interleaved mode. -By default, `X-HEEP` is generated with 2 continuous banks and 0 interleaved banks. - -Below an example that changes the default configuration: - -``` -make mcu-gen CPU=cv32e40p BUS=NtoM MEMORY_BANKS=12 MEMORY_BANKS_IL=4 -``` - -The last command generates x-heep with the cv32e40p core, with a parallel bus, and 16 memory banks (12 continuous and 4 interleaved), -each 32KB, for a total memory of 512KB. - -If you are using `X-HEEP` just as a controller for your own system and you do not need any peripheral, you can use the `minimal` configuration file -when generating the MCU as: - -``` -make mcu-gen MCU_CFG=mcu_cfg_minimal.hjson -``` - -The `minimal` configuration is a work-in-progress, thus not all the APPs have been tested. - -## Compiling Software - -Don't forget to set the `RISCV` env variable to the compiler folder (without the `/bin` included). -To run 'hello world' application, just type 'make app'. - -``` -make app -``` - -To run any other application, please use the following command with appropiate parameters: - -``` -app PROJECT= TARGET=sim(default),systemc,pynq-z2,nexys-a7-100t,zcu104 LINKER=on_chip(default),flash_load,flash_exec COMPILER=gcc(default),clang COMPILER_PREFIX=riscv32-unknown-(default) ARCH=rv32imc(default), - -Params: -- PROJECT (ex: , hello_world(default)) -- TARGET (ex: sim(default),systemc,pynq-z2,nexys-a7-100t,zcu104) -- LINKER (ex: on_chip(default),flash_load,flash_exec) -- COMPILER (ex: gcc(default),clang) -- COMPILER_PREFIX (ex: riscv32-unknown-(default)) -- ARCH (ex: rv32imc(default),) -``` - -For instance, to run 'hello world' app for the pynq-z2 FPGA targets, just run: - -``` -make app TARGET=pynq-z2 -``` - -Or, if you use the OpenHW Group [GCC](https://www.embecosm.com/resources/tool-chain-downloads/#corev) compiler with CORE_PULP extensions, make sure to point the `RISCV` env variable to the OpenHW Group compiler, then just run: - -``` -make app COMPILER_PREFIX=riscv32-corev- ARCH=rv32imc_zicsr_zifencei_xcvhwlp_xcvmem_xcvmac_xcvbi_xcvalu_xcvsimd_xcvbitmanip -``` - -This will create the executable file to be loaded into your target system (ASIC, FPGA, Simulation). -Remember that, `X-HEEP` is using CMake to compile and link. Thus, the generated files after having -compiled and linked are under `sw\build` - -Alternatively, in case you are doing pure FW development and you are used to developing using Integrated Development Evironments (IDEs), please check [the IDE readme](./IDEs.md). - -## FreeROTS based applications - -'X-HEEP' supports 'FreeRTOS' based applications. Please see `sw\applications\blinky_freertos`. - -After that, you can run the command to compile and link the FreeRTOS based application. Please also set 'LINKER' and 'TARGET' parameters if needed. - -``` -make app PROJECT=blinky_freertos -``` - -The main FreeRTOS configuration is allocated under `sw\freertos`, in `FreeRTOSConfig.h`. Please, change this file based on your application requirements. -Moreover, FreeRTOS is being fetch from 'https://github.com/FreeRTOS/FreeRTOS-Kernel.git' by CMake. Specifically, 'V10.5.1' is used. Finally, the fetch repository is located under `sw\build\_deps` after building. - -## Simulating - -This project supports simulation with Verilator, Synopsys VCS, Siemens Questasim and Cadence Xcelium. -It relies on `fusesoc` to handle multiple EDA tools and parameters. -For example, if you want to set the `FPU` and `COREV_PULP` parameters of the `cv32e40p` CPU, -you need to add next to your compilation command `FUSESOC_PARAM="--COREV_PULP=1 --FPU=1"` -Below the different EDA examples commands. - -### Compiling for Verilator (C++ testbench) - -To simulate your application with Verilator, first compile the HDL: - -``` -make verilator-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator -``` - -and type to run your compiled software: - -``` -./Vtestharness +firmware=../../../sw/build/main.hex -``` - -or to execute all these three steps type: - -``` -make run-helloworld -``` - -### Compiling for Verilator (SystemC testbench) - -To simulate your application with Verilator using `SystemC`, - -make sure you have `SystemC 2.3.3` installed, if not, find it [here](https://www.accellera.org/downloads/standards/systemc). - -Make sure to have the following env variables set: - -``` -export SYSTEMC_INCLUDE=/your_path_to_systemc/systemc/include/ -export SYSTEMC_LIBDIR=/your_path_to_systemc/systemc/lib-linux64/ -``` - -Compile the HDL: - -``` -make verilator-sim-sc -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim_sc-verilator -``` - -and type to run your compiled software: - -``` -./Vtestharness +firmware=../../../sw/build/main.hex -``` - -If you want to know what is special about the SystemC testbench, have a look [here](./docs/source/How_to/SystemC.md) - -### Compiling for VCS - -To simulate your application with VCS, first compile the HDL: - -``` -make vcs-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs -``` - -and type to run your compiled software: - -``` -./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex -``` - -Waveforms can be viewed with Verdi. Make sure you have the env variable `VERDI_HOME` set to your Verdi install folder, then run your compiled software as above, but with the `-gui` flag: - -``` -./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex -gui -``` - -An Analog / Mixed-Signal simulation of X-HEEP, combining both the RTL system verilog files for the digital part and a SPICE file connected through a `control.init` file for the analog / mixed-signal part, can be ran by typing - -``` -make vcs-ams-sim -``` - -then going to the target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs -``` - -and running the same executable as for the digital simulation. Note that with Verdi you can view both the digital and the analog waveforms. - -Additional instructions on how to run an analog / mixed-signal simulation of X-HEEP can be found [here](./docs/source/How_to/AnalogMixedSignal.md). To try out the simulation, we provide an example SPICE netlist of an simple 1-bit ADC created by us and exported from [xschem](https://xschem.sourceforge.io/stefan/index.html) and which uses the PTM 65nm bulk CMOS model from [https://ptm.asu.edu](https://ptm.asu.edu/). - -### Compiling for Questasim - -To simulate your application with Questasim, first set the env variable `MODEL_TECH` to your Questasim bin folder, then compile the HDL: - -``` -make questasim-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-modelsim/ -``` - -and type to run your compiled software: - -``` -make run PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -You can also use vopt for HDL optimized compilation: - -``` -make questasim-sim-opt -``` - -then go to - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim_opt-modelsim/ -``` -and - -``` -make run RUN_OPT=1 PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -You can also compile with the UPF power domain description as: - -``` -make questasim-sim-opt-upf FUSESOC_PARAM="--USE_UPF" -``` - -and then execute software as: - -``` -make run RUN_OPT=1 RUN_UPF=1 PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -Questasim version must be >= Questasim 2020.4 - -### Compiling for Xcelium - -To simulate your application with Xcelium, first compile the HDL: - -``` -make xcelium-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-xcelium/ -``` - -and type to run your compiled software: - -``` -make run PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -### UART DPI - -To simulate the UART, we use the LowRISC OpenTitan [UART DPI](https://github.com/lowRISC/opentitan/tree/master/hw/dv/dpi/uartdpi). -Read how to interact with it in the Section "Running Software on a Verilator Simulation with Bazel" [here](https://opentitan.org/guides/getting_started/setup_verilator.html#running-software-on-a-verilator-simulation-with-bazel). -The output of the UART DPI module is printed in the `uart0.log` file in the simulation folder. - -For example, to see the "hello world!" output of the Verilator simulation: - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator -./Vtestharness +firmware=../../../sw/build/main.hex -cat uart0.log -``` - -## Automatic testing - -X-HEEP includes two tools to perform automatic tests over your modifications. - -### Github CIs - -Upon push, tests are run on Github runners, these include: -* The generated `.sv` files pushed are equal to those generated in the runner (the code does not depend on the modification of generated files) -* Vendor is up to date (the code does not depend on the modification of vendorized files) -* All applications can be built successfully using both gcc and clang - -All test must be successful before PRs can be merged. - -### Simulation script - -Additionally, a `test_all.sh` script is provided. Apart from compiling all apps with both gcc and clang, it will simulate them and check the result. - -The available parameters are: -* COMPILER: `gcc` (default) or `clang` (can provide more than one) -* SIMULATOR: `verilator` (default), `questasim` or disable simulation with `nosim` (only one, the last provided is used). -* LINKER: `on_chip`(default), `flash_load` or `flash_exec` (can provide more than one) -* TIMEOUT: Integer number of seconds (default 120) - -#### Usage - -##### Comands -You can use two different commands to compile or simulate all the existing APPs: -``` -make app-compile-all -``` -``` -make app-simulate-all -``` -Note that both commands allow the previous parameters to specify compiling or simulation options. E.g.: -``` -make app-simulate-all LINKER=on_chip SIMULATOR=questasim COMPILER=clang TIMEOUT=150 -``` - -##### Manually -You can also **SOURCE** the script as -```bash -. util/test_all.sh on_chip questasim clang 150 -``` - -*Pay special attention to the first period in the command!* -You will be killing simulations that take too long, if you **EXECUTE** (`./test_all.sh`) this action kills the script. - -For both usages (commands or manual), the order of the arguments is irrelevant. - -> Note: Be sure to commit all your changes before running the script! - -* Applications that fail being built with gcc will not be simulated (skipped). -* Some applications are skipped by default for not being suitable for simulation. -* If a simulation takes too long (>timeout), it is killed. - -* Upon starting, the script will modify the `mcu_cfg.hjson` file to include all peripherals (so the largest number of apps can be run), re-generates the mcu and re-builds the simulation model for the chosen tool. -These changes can be reverted at the end of the execution (default). If changes were not commited, accepting this operation will revert them! - -The success of the script is not required for merging of a PR. - -## Debug - -Follow the [Debug](./docs/source/How_to/Debug.md) guide to debug core-v-mini-mcu. - -Alternatively, in case you are used to developing using Integrated Development Environments (IDEs), please check [the IDE readme](./IDEs.md). - -## Execute From Flash - -Follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) guide to exxecute code directly from the FLASH with modelsim, FPGA, or ASIC. - -## Emulation on Xilinx FPGAs - -This project offers two different X-HEEP implementetions on Xilinx FPGAs, called Standalone and FEMU. - -### Standalone - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board. - -Three FPGA boards are supported: the Xilinx Pynq-z2, Nexys-A7-100t, Zynq Ultrascale+ ZCU104. - -Make sure you have the FPGA board files installed in your Vivado. - -For example, for the Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: - -To build and program the bitstream for your FPGA with vivado, type: - -``` -make vivado-fpga FPGA_BOARD=pynq-z2 -``` - -or - -``` -make vivado-fpga FPGA_BOARD=nexys-a7-100t -``` - -or - -``` -make vivado-fpga FPGA_BOARD=zcu104 -``` - -or add the flag `use_bscane_xilinx` to use the native Xilinx scanchain: - -``` -make vivado-fpga FPGA_BOARD=pynq-z2 FUSESOC_FLAGS=--flag=use_bscane_xilinx -``` - -Only Vivado 2021.2 has been tried. - -To program the bitstream, open Vivado, - -``` -open --> Hardware Manager --> Open Target --> Autoconnect --> Program Device -``` - -and choose the file `openhwgroup.org_systems_core-v-mini-mcu_0.bit`. - -Or simply type: - -``` -bash vivado-fpga-pgm FPGA_BOARD=pynq-z2 -``` - -or - -``` -make vivado-fpga-pgm FPGA_BOARD=nexys-a7-100t -``` - -To run SW, follow the [Debug](./docs/source/How_to/Debug.md) guide -to load the binaries with the HS2 cable over JTAG, -or follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) -guide if you have a FLASH attached to the FPGA. - -Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. - -For example, if you want to run your application using flash_exec, do as follow: - -compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` - -and then follow the [ExecuteFromFlash](./docs/source/How_to/ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. - -To look at the output of your printf, run in another terminal: - -`picocom -b 9600 -r -l --imap lfcrlf /dev/ttyUSB2` - -Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). - -### FPGA EMUlation Platform (FEMU) - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Xilinx Zynq-7020 chip on the Pynq-Z2 board and Linux is run on the ARM-based processing system (PS) side of the same chip. - -NOTE: This platform is not part of this repository, but you can access it with the following link: [FEMU](https://github.com/esl-epfl/x-heep-femu-sdk). - -# ASIC Implementation - -This project can be implemented using standard cells based ASIC flow. - -## Synthesis with Synopsys Design Compiler - -First, you need to provide technology-dependent implementations of some of the cells which require specific instantiation. - -Then, please provide a set_libs.tcl and set_constraints.tcl scripts to set link and target libraries, and constraints as the clock. - -To generate the `analyze` script for the synthesis scripts with DC, execute: - -``` -make asic -``` - -## OpenRoad support for SkyWater 130nm - -We are working on supporting OpenRoad and SkyWater 130nm PDK, please refer to the -[Implement on ASIC](./docs/source/How_to/ImplementASIC.md) page. This is not ready yet, it has not been tested. - -This relies on a fork of [edalize](https://github.com/davideschiavone/edalize) that contains templates for Design Compiler and OpenRoad. +``` \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/block_diagrams/core_v_mini_mcu.svg b/hw/vendor/esl_epfl_x_heep/block_diagrams/core_v_mini_mcu.svg deleted file mode 100644 index dbdc7cec..00000000 --- a/hw/vendor/esl_epfl_x_heep/block_diagrams/core_v_mini_mcu.svg +++ /dev/null @@ -1,3553 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -MMMSSSMSSSSSSMSSS_FLASHM_FLASHSSMMMSSSSSSSSSSSSSSSSPOWERMANAGERTIMER 2TIMER 3DMABOOT ROMSOC CTRLSPI HOSTTIMER 0TIMER 1SPISUBSYSTEMUARTGPIO AOFAST INTRCTRLPLICPERIPHERAL SUBSYSTEMAO PERIPHERAL SUBSYSTEMI2CGPIOBUS SUBSYSTEMCPUSUBSYSTEMMEMORY SUBSYSTEMCORE_V_MINI_MCUDEBUGSUBSYSTEMRAM 0INSTRDATASSRAM 1RAM 2RAM 3TCKTMSTDIRAM 4RAM 5RAM 6RAM 7TDOTRSTEXT PERIPHBOOTSELECTEXECUTEFROMFLASHEXTMASTERSCORE INSTRIO[7:0]TXRXSCK_FCS_FSD_FSDCSSCKIO[31:8]SDASCLEXIT VALUEEXIT VALIDMPAD PERIPHMMMMMCORE DATADEBUGDMA READDMA WRITEMDMA ADDR diff --git a/hw/vendor/esl_epfl_x_heep/block_diagrams/x-heep.svg b/hw/vendor/esl_epfl_x_heep/block_diagrams/x-heep.svg deleted file mode 100644 index 93b2ed0d..00000000 --- a/hw/vendor/esl_epfl_x_heep/block_diagrams/x-heep.svg +++ /dev/null @@ -1,2461 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CORE_V_MINI_MCUPAD CONTROLX-HEEPPADRINGTXRXSCKCSSDSCK_FEXIT VALIDEXIT VALIDCS_FSD_FIO[29:0]IO[30]IO[31]MSSCLSDATXRXSCK_FCS_FSD_FSCKCSSDIO[29:0]SDASCLBOOTSELECTEXECUTEFROMFLASHEXIT VALUE diff --git a/hw/vendor/esl_epfl_x_heep/configs/ci.hjson b/hw/vendor/esl_epfl_x_heep/configs/ci.hjson new file mode 100644 index 00000000..51a278b7 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/configs/ci.hjson @@ -0,0 +1,23 @@ +{ + bus_type: "onetoM", + ram_banks: { + code_and_data: { + num: 6 + sizes: 32 + } + } + + linker_sections: + [ + { + name: code + start: 0 + #minimum size for freeRTOS and clang + size: 0x00000D800 + }, + { + name: data + start: 0x00000D800 + } + ] +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/example.py b/hw/vendor/esl_epfl_x_heep/configs/example.py new file mode 100644 index 00000000..b9e3faf2 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/configs/example.py @@ -0,0 +1,18 @@ +from x_heep_gen.linker_section import LinkerSection +from x_heep_gen.system import XHeep, BusType + +def config(): + system = XHeep(BusType.NtoM) + system.add_ram_banks([32] * 2) + system.add_ram_banks_il(2, 64, "data_interleaved") + + system.add_linker_section(LinkerSection.by_size("code", 0, 0x00000C800)) + system.add_linker_section(LinkerSection("data", 0x00000C800, None)) + + # Here the system is build, + # The missing gaps are filled, like the missing end address of the data section. + system.build() + if not system.validate(): + raise RuntimeError("there are errors") + + return system diff --git a/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson b/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson new file mode 100644 index 00000000..aac0801e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson @@ -0,0 +1,40 @@ +{ + bus_type: "NtoM", + ram_banks: { + code_and_data: { + sizes: 64 + } + more_data: { + type: continuous + num: 2 + sizes: 32 + } + data_interleaved: { + auto_section: auto + // the name is used by example_matadd_interleaved as .xheep_data_interleaved + type: interleaved + num: 4 + size: 16 + } + data_interleaved_2: { + auto_section: auto + type: interleaved + num: 2 + size: 16 + } + } + + linker_sections: + [ + { + name: code + start: 0 + // minimum size for freeRTOS and clang + size: 0x00000D800 + }, + { + name: data + start: 0x00000D800 + } + ] +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/general.hjson b/hw/vendor/esl_epfl_x_heep/configs/general.hjson new file mode 100644 index 00000000..f7040640 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/configs/general.hjson @@ -0,0 +1,24 @@ +{ + ram_address: 0 + bus_type: "onetoM", + ram_banks: { + code_and_data: { + num: 2 + sizes: [32] + } + } + + linker_sections: + [ + { + name: code + start: 0 + #minimum size for freeRTOS and clang + size: 0x00000D800 + }, + { + name: data + start: 0x00000D800 + } + ] +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/testall.hjson b/hw/vendor/esl_epfl_x_heep/configs/testall.hjson new file mode 100644 index 00000000..36828dc8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/configs/testall.hjson @@ -0,0 +1,23 @@ +{ + bus_type: "onetoM", + ram_banks: { + code_and_data: { + num: 3 + sizes: 32 + } + } + + linker_sections: + [ + { + name: code + start: 0 + #minimum size for freeRTOS and clang + size: 0x00000D800 + }, + { + name: data + start: 0x00000D800 + } + ] +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu-fpga.core b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu-fpga.core new file mode 100644 index 00000000..38663aea --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu-fpga.core @@ -0,0 +1,72 @@ +CAPI=2: + +# Copyright 2024 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +name: openhwgroup.org:systems:core-v-mini-mcu-fpga +description: CORE-V MINI-MCU FPGA related files. + +filesets: + rtl-fpga: + depend: + - x-heep::packages + files: + - hw/fpga/sram_wrapper.sv + file_type: systemVerilogSource + + ip-fpga: + files: + - hw/fpga/scripts/generate_sram.tcl: { file_type: tclSource } + - hw/fpga/prim_xilinx_clk.sv: { file_type: systemVerilogSource } + - hw/fpga/cv32e40p_xilinx_clock_gate.sv: { file_type: systemVerilogSource } + - hw/fpga/cv32e40x_xilinx_clock_gate.sv: { file_type: systemVerilogSource } + - hw/fpga/cve2_xilinx_clock_gate.sv: { file_type: systemVerilogSource } + - hw/fpga/cv32e40px_xilinx_clock_gate.sv: { file_type: systemVerilogSource } + - hw/fpga/pad_cell_input_xilinx.sv: { file_type: systemVerilogSource } + - hw/fpga/pad_cell_output_xilinx.sv: { file_type: systemVerilogSource } + - hw/fpga/pad_cell_inout_xilinx.sv: { file_type: systemVerilogSource } + - hw/fpga/pad_cell_bypass_input_xilinx.sv: { file_type: systemVerilogSource } + - hw/fpga/pad_cell_bypass_output_xilinx.sv: { file_type: systemVerilogSource } + + ip-fpga-pynq-z2: + files: + - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + ip-fpga-nexys: + files: + - hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + ip-fpga-zcu104: + files: + - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + + xdc-fpga-nexys: + files: + - hw/fpga/constraints/nexys/pin_assign.xdc + - hw/fpga/constraints/nexys/constraints.xdc + file_type: xdc + + xdc-fpga-pynq-z2: + files: + - hw/fpga/constraints/pynq-z2/pin_assign.xdc + - hw/fpga/constraints/pynq-z2/constraints.xdc + file_type: xdc + + xdc-fpga-zcu104: + files: + - hw/fpga/constraints/zcu104/pin_assign.xdc + file_type: xdc + + +targets: + default: &default_target + filesets: + - rtl-fpga + - ip-fpga + - target_pynq-z2 ? (ip-fpga-pynq-z2) + - target_pynq-z2 ? (xdc-fpga-pynq-z2) + - target_nexys-a7-100t ? (ip-fpga-nexys) + - target_nexys-a7-100t ? (xdc-fpga-nexys) + - target_zcu104 ? (ip-fpga-zcu104) + - target_zcu104 ? (xdc-fpga-zcu104) diff --git a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core index dd439888..aef1f20e 100644 --- a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core +++ b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.core @@ -30,6 +30,7 @@ filesets: - x-heep:obi_spimemio:0.1.0 - x-heep:ip:boot_rom - x-heep:ip:dma + - x-heep:ip:dma_subsystem - x-heep:ip:i2s - x-heep:ip:power_manager - x-heep:ip:fast_intr_ctrl @@ -84,6 +85,7 @@ filesets: - hw/ip/boot_rom/boot_rom.vlt - hw/ip/obi_spimemio/obi_spimemio.vlt - hw/ip/dma/dma.vlt + - hw/ip/dma_subsystem/dma_subsystem.vlt - hw/ip/pdm2pcm/pdm2pcm.vlt - hw/ip_examples/pdm2pcm_dummy/pdm2pcm_dummy.vlt - hw/ip/power_manager/power_manager.vlt @@ -95,40 +97,12 @@ filesets: file_type: vlt rtl-fpga: + depend: + - openhwgroup.org:systems:core-v-mini-mcu-fpga files: - hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv - - hw/fpga/sram_wrapper.sv file_type: systemVerilogSource - ip-fpga: - files: - - hw/fpga/scripts/generate_sram.tcl: { file_type: tclSource } - - hw/fpga/prim_xilinx_clk.sv: { file_type: systemVerilogSource } - - hw/fpga/cv32e40p_xilinx_clock_gate.sv: { file_type: systemVerilogSource } - - hw/fpga/cv32e40x_xilinx_clock_gate.sv: { file_type: systemVerilogSource } - - hw/fpga/cve2_xilinx_clock_gate.sv: { file_type: systemVerilogSource } - - hw/fpga/cv32e40px_xilinx_clock_gate.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_input_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_output_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_inout_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_bypass_input_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_bypass_output_xilinx.sv: { file_type: systemVerilogSource } - - ip-fpga-pynq-z2: - files: - - hw/fpga/scripts/pynq-z2/set_board.tcl: { file_type: tclSource } - - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } - - ip-fpga-nexys: - files: - - hw/fpga/scripts/nexys/set_board.tcl: { file_type: tclSource } - - hw/fpga/scripts/nexys/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } - - ip-fpga-zcu104: - files: - - hw/fpga/scripts/zcu104/set_board.tcl: { file_type: tclSource } - - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } - ip-asic: depend: - technology::prim_mytech @@ -147,28 +121,6 @@ filesets: files: - hw/asic/sky130/sky130_sram_4kbyte_1rw_32x1024_8_TT_1p8V_25C.lib : { copyto: lib/sky130_sram_4kbyte_1rw_32x1024_8_TT_1p8V_25C.lib } - xdc-fpga-nexys: - files: - - hw/fpga/constraints/nexys/pin_assign.xdc - - hw/fpga/constraints/nexys/constraints.xdc - file_type: xdc - - xdc-fpga-pynq-z2: - files: - - hw/fpga/constraints/pynq-z2/pin_assign.xdc - - hw/fpga/constraints/pynq-z2/constraints.xdc - file_type: xdc - - xdc-fpga-zcu104: - files: - - hw/fpga/constraints/zcu104/pin_assign.xdc - file_type: xdc - - netlist-fpga: - files: - - build/openhwgroup.org_systems_core-v-mini-mcu_0/nexys-a7-100t-vivado/core_v_mini_mcu_xiling_postsynth.v - file_type: verilogSource - # Scripts for hooks post_build_modelsim_scripts: files: @@ -285,6 +237,10 @@ parameters: datatype: bool paramtype: vlogdefine default: false + FPGA_SYNTHESIS: + datatype: bool + paramtype: vlogdefine + default: false FPGA_NEXYS: datatype: bool paramtype: vlogdefine @@ -463,19 +419,19 @@ targets: filesets_append: - x_heep_system - rtl-fpga - - ip-fpga-nexys - - ip-fpga - - xdc-fpga-nexys parameters: - COREV_PULP - FPU - X_EXT - SYNTHESIS=true - REMOVE_OBI_FIFO + - FPGA_SYNTHESIS=true - FPGA_NEXYS=true tools: vivado: part: xc7a100tcsg324-1 + board_part: digilentinc.com:nexys-a7-100t:part0:1.3 + board_repo_paths: [../../../hw/fpga/board_files/vendor/esl_epfl_nexys_a7_100t_board_files] toplevel: [xilinx_core_v_mini_mcu_wrapper] pynq-z2: @@ -485,18 +441,18 @@ targets: filesets_append: - x_heep_system - rtl-fpga - - ip-fpga-pynq-z2 - - ip-fpga - - xdc-fpga-pynq-z2 parameters: - COREV_PULP - FPU - X_EXT - SYNTHESIS=true - REMOVE_OBI_FIFO + - FPGA_SYNTHESIS=true tools: vivado: part: xc7z020clg400-1 + board_part: tul.com.tw:pynq-z2:part0:1.0 + board_repo_paths: [../../../hw/fpga/board_files/vendor/esl_epfl_pynq_z2_board_files] toplevel: [xilinx_core_v_mini_mcu_wrapper] zcu104: @@ -506,19 +462,19 @@ targets: filesets_append: - x_heep_system - rtl-fpga - - ip-fpga-zcu104 - - ip-fpga - - xdc-fpga-zcu104 parameters: - COREV_PULP - FPU - X_EXT - SYNTHESIS=true - REMOVE_OBI_FIFO + - FPGA_SYNTHESIS=true - FPGA_ZCU104=true tools: vivado: part: xczu7ev-ffvc1156-2-e + board_part: xilinx.com:zcu104:part0:1.0 + board_repo_paths: [../../../hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files] toplevel: [xilinx_core_v_mini_mcu_wrapper] asic_synthesis: diff --git a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.dc.upf.tpl b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.dc.upf.tpl new file mode 100644 index 00000000..b08abad8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.dc.upf.tpl @@ -0,0 +1,159 @@ +upf_version 2.1 + +set_design_top core_v_mini_mcu +set_scope . + + +<%text> +##################### +## POWER DOMAINS ## +##################### +\ + +create_power_domain PD_TOP -include_scope +create_power_domain PD_CPU -elements {cpu_subsystem_i} +create_power_domain PD_PERIP_SUBS -elements {peripheral_subsystem_i} +% for bank in xheep.iter_ram_banks(): +create_power_domain PD_MEM_BANK_${bank.name()} -elements {memory_subsystem_i/ram${bank.name()}_i} +% endfor + + +<%text> +#################### +## POWER STATES ## +#################### +\ + +add_power_state PD_TOP.primary -state TOP_ON <%text>\ + {-supply_expr {power == `{FULL_ON, 1.2} && ground == `{FULL_ON, 0.0}}} + +add_power_state PD_CPU.primary -state CPU_ON <%text>\ + {-supply_expr {power == `{FULL_ON, 1.2} && ground == `{FULL_ON, 0.0}}} + +add_power_state PD_CPU.primary -state CPU_OFF <%text>\ + {-supply_expr {power == `{OFF} && ground == `{FULL_ON, 0.0}}} -simstate CORRUPT + +add_power_state PD_PERIP_SUBS.primary -state PERIP_SUBS_ON <%text>\ + {-supply_expr {power == `{FULL_ON, 1.2} && ground == `{FULL_ON, 0.0}}} + +add_power_state PD_PERIP_SUBS.primary -state PERIP_SUBS_OFF <%text>\ + {-supply_expr {power == `{OFF} && ground == `{FULL_ON, 0.0}}} -simstate CORRUPT + +% for bank in xheep.iter_ram_banks(): +add_power_state PD_MEM_BANK_${bank.name()}.primary -state MEM_BANK_${bank.name()}_ON <%text>\ + {-supply_expr {power == `{FULL_ON, 1.2} && ground == `{FULL_ON, 0.0}}} + +add_power_state PD_MEM_BANK_${bank.name()}.primary -state MEM_BANK_${bank.name()}_OFF <%text>\ + {-supply_expr {power == `{OFF} && ground == `{FULL_ON, 0.0}}} -simstate CORRUPT + +% endfor + +<%text> +################### +## SUPPLY NETS ## +################### +\ + +create_supply_port VDD -direction in +create_supply_port VSS -direction in + +create_supply_net VDD +create_supply_net VSS + +connect_supply_net VDD -ports VDD +connect_supply_net VSS -ports VSS + +create_supply_set PD_TOP.primary -function {power VDD} -function {ground VSS} -update + +create_supply_net VDD_CPU +create_supply_set PD_CPU.primary -function {power VDD_CPU} -function {ground VSS} -update + +create_supply_net VDD_PERIP_SUBS +create_supply_set PD_PERIP_SUBS.primary -function {power VDD_PERIP_SUBS} -function {ground VSS} -update + +% for bank in xheep.iter_ram_banks(): +create_supply_net VDD_MEM_BANK_${bank.name()} +create_supply_set PD_MEM_BANK_${bank.name()}.primary -function {power VDD_MEM_BANK_${bank.name()}} -function {ground VSS} -update + +% endfor + +<%text> +################ +## SWITCHES ## +################ +\ + +create_power_switch switch_PD_CPU <%text>\ + -supply_set PD_TOP.primary <%text>\ + -domain PD_CPU <%text>\ + -input_supply_port {sw_in VDD} <%text>\ + -output_supply_port {sw_out VDD_CPU} <%text>\ + -control_port {sw_ctrl ao_peripheral_subsystem_i/cpu_subsystem_pwr_ctrl_o<%text>\[pwrgate_en_n<%text>\]} <%text>\ + -ack_port {sw_ack ao_peripheral_subsystem_i/cpu_subsystem_pwr_ctrl_i<%text>\[pwrgate_ack_n<%text>\]} <%text>\ + -on_state {on_state sw_in {sw_ctrl}} <%text>\ + -off_state {off_state {!sw_ctrl}} + +create_power_switch switch_PD_PERIP_SUBS <%text>\ + -supply_set PD_TOP.primary <%text>\ + -domain PD_PERIP_SUBS <%text>\ + -input_supply_port {sw_in VDD} <%text>\ + -output_supply_port {sw_out VDD_PERIP_SUBS} <%text>\ + -control_port {sw_ctrl ao_peripheral_subsystem_i/peripheral_subsystem_pwr_ctrl_o<%text>\[pwrgate_en_n<%text>\]} <%text>\ + -ack_port {sw_ack ao_peripheral_subsystem_i/peripheral_subsystem_pwr_ctrl_i<%text>\[pwrgate_ack_n<%text>\]} <%text>\ + -on_state {on_state sw_in {sw_ctrl}} <%text>\ + -off_state {off_state {!sw_ctrl}} + +% for bank in xheep.iter_ram_banks(): +create_power_switch switch_PD_MEM_BANK_${bank.name()} <%text>\ + -supply_set PD_TOP.primary <%text>\ + -domain PD_MEM_BANK_${bank.name()} <%text>\ + -input_supply_port {sw_in VDD} <%text>\ + -output_supply_port {sw_out VDD_MEM_BANK_${bank.name()}} <%text>\ + -control_port {sw_ctrl ao_peripheral_subsystem_i/memory_subsystem_pwr_ctrl_o[${bank.name()}]<%text>\[pwrgate_en_n<%text>\]} <%text>\ + -ack_port {sw_ack ao_peripheral_subsystem_i/memory_subsystem_pwr_ctrl_i[${bank.name()}]<%text>\[pwrgate_ack_n<%text>\]} <%text>\ + -on_state {on_state sw_in {sw_ctrl}} <%text>\ + -off_state {off_state {!sw_ctrl}} + +% endfor + +<%text> +################# +## ISOLATION ## +################# +\ + +set_isolation cpu_iso <%text>\ + -domain PD_CPU <%text>\ + -isolation_power_net VDD <%text>\ + -isolation_ground_net VSS <%text>\ + -isolation_signal ao_peripheral_subsystem_i/cpu_subsystem_pwr_ctrl_o<%text>\[isogate_en_n<%text>\] <%text>\ + -isolation_sense low <%text>\ + -clamp_value 0 <%text>\ + -applies_to outputs <%text>\ + -name_prefix cpu_iso_cell <%text>\ + -location parent + +set_isolation perip_subs_iso <%text>\ + -domain PD_PERIP_SUBS <%text>\ + -isolation_power_net VDD <%text>\ + -isolation_ground_net VSS <%text>\ + -isolation_signal ao_peripheral_subsystem_i/peripheral_subsystem_pwr_ctrl_o<%text>\[isogate_en_n<%text>\] <%text>\ + -isolation_sense low <%text>\ + -clamp_value 0 <%text>\ + -applies_to outputs <%text>\ + -name_prefix cpu_iso_cell <%text>\ + -location parent + +% for bank in xheep.iter_ram_banks(): +set_isolation mem_bank_${bank.name()}_iso <%text>\ + -domain PD_MEM_BANK_${bank.name()} <%text>\ + -isolation_power_net VDD <%text>\ + -isolation_ground_net VSS <%text>\ + -isolation_signal ao_peripheral_subsystem_i/memory_subsystem_pwr_ctrl_o[${bank.name()}]<%text>\[isogate_en_n<%text>\] <%text>\ + -isolation_sense low <%text>\ + -clamp_value 0 <%text>\ + -elements {memory_subsystem_i/ram${bank.name()}_i/rdata_o} <%text>\ + -name_prefix cpu_iso_cell <%text>\ + -location parent + +% endfor diff --git a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.upf.tpl b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.upf.tpl index 5d687f9a..d7e0f6f1 100644 --- a/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.upf.tpl +++ b/hw/vendor/esl_epfl_x_heep/core-v-mini-mcu.upf.tpl @@ -13,8 +13,8 @@ set_scope . create_power_domain PD_TOP -include_scope create_power_domain PD_CPU -elements {cpu_subsystem_i} create_power_domain PD_PERIP_SUBS -elements {peripheral_subsystem_i} -% for bank in range(ram_numbanks): -create_power_domain PD_MEM_BANK_${bank} -elements {memory_subsystem_i/gen_sram[${bank}].ram_i} +% for bank in xheep.iter_ram_banks(): +create_power_domain PD_MEM_BANK_${bank.name()} -elements {memory_subsystem_i/ram${bank.name()}_i} % endfor @@ -39,11 +39,11 @@ add_power_state PD_PERIP_SUBS.primary -state PERIP_SUBS_ON <%text>\ add_power_state PD_PERIP_SUBS.primary -state PERIP_SUBS_OFF <%text>\ {-supply_expr {power == `{OFF} && ground == `{FULL_ON, 0.0}}} -simstate CORRUPT -% for bank in range(ram_numbanks): -add_power_state PD_MEM_BANK_${bank}.primary -state MEM_BANK_${bank}_ON <%text>\ +% for bank in xheep.iter_ram_banks(): +add_power_state PD_MEM_BANK_${bank.name()}.primary -state MEM_BANK_${bank.name()}_ON <%text>\ {-supply_expr {power == `{FULL_ON, 1.2} && ground == `{FULL_ON, 0.0}}} -add_power_state PD_MEM_BANK_${bank}.primary -state MEM_BANK_${bank}_OFF <%text>\ +add_power_state PD_MEM_BANK_${bank.name()}.primary -state MEM_BANK_${bank.name()}_OFF <%text>\ {-supply_expr {power == `{OFF} && ground == `{FULL_ON, 0.0}}} -simstate CORRUPT % endfor @@ -71,9 +71,9 @@ create_supply_set PD_CPU.primary -function {power VDD_CPU} -function {ground VSS create_supply_net VDD_PERIP_SUBS create_supply_set PD_PERIP_SUBS.primary -function {power VDD_PERIP_SUBS} -function {ground VSS} -update -% for bank in range(ram_numbanks): -create_supply_net VDD_MEM_BANK_${bank} -create_supply_set PD_MEM_BANK_${bank}.primary -function {power VDD_MEM_BANK_${bank}} -function {ground VSS} -update +% for bank in xheep.iter_ram_banks(): +create_supply_net VDD_MEM_BANK_${bank.name()} +create_supply_set PD_MEM_BANK_${bank.name()}.primary -function {power VDD_MEM_BANK_${bank.name()}} -function {ground VSS} -update % endfor @@ -103,14 +103,14 @@ create_power_switch switch_PD_PERIP_SUBS <%text>\ -on_state {on_state sw_in {sw_ctrl}} <%text>\ -off_state {off_state {!sw_ctrl}} -% for bank in range(ram_numbanks): -create_power_switch switch_PD_MEM_BANK_${bank} <%text>\ +% for bank in xheep.iter_ram_banks(): +create_power_switch switch_PD_MEM_BANK_${bank.name()} <%text>\ -supply_set PD_TOP.primary <%text>\ - -domain PD_MEM_BANK_${bank} <%text>\ + -domain PD_MEM_BANK_${bank.name()} <%text>\ -input_supply_port {sw_in VDD} <%text>\ - -output_supply_port {sw_out VDD_MEM_BANK_${bank}} <%text>\ - -control_port {sw_ctrl memory_subsystem_banks_powergate_switch_no[${bank}]} <%text>\ - -ack_port {sw_ack memory_subsystem_banks_powergate_switch_ack_ni[${bank}]} <%text>\ + -output_supply_port {sw_out VDD_MEM_BANK_${bank.name()}} <%text>\ + -control_port {sw_ctrl memory_subsystem_banks_powergate_switch_n[${bank.name()}]} <%text>\ + -ack_port {sw_ack memory_subsystem_i.ram${bank.name()}_i.pwrgate_ack_no} <%text>\ -on_state {on_state sw_in {sw_ctrl}} <%text>\ -off_state {off_state {!sw_ctrl}} @@ -144,15 +144,15 @@ set_isolation perip_subs_iso <%text>\ -name_prefix cpu_iso_cell <%text>\ -location parent -% for bank in range(ram_numbanks): -set_isolation mem_bank_${bank}_iso <%text>\ - -domain PD_MEM_BANK_${bank} <%text>\ +% for bank in xheep.iter_ram_banks(): +set_isolation mem_bank_${bank.name()}_iso <%text>\ + -domain PD_MEM_BANK_${bank.name()} <%text>\ -isolation_power_net VDD <%text>\ -isolation_ground_net VSS <%text>\ - -isolation_signal memory_subsystem_banks_powergate_iso_n[${bank}] <%text>\ + -isolation_signal memory_subsystem_banks_powergate_iso_n[${bank.name()}] <%text>\ -isolation_sense low <%text>\ -clamp_value 0 <%text>\ - -applies_to outputs <%text>\ + -elements {memory_subsystem_i/ram${bank.name()}_i/rdata_o} <%text>\ -name_prefix cpu_iso_cell <%text>\ -location parent diff --git a/hw/vendor/esl_epfl_x_heep/docs/requirements.txt b/hw/vendor/esl_epfl_x_heep/docs/requirements.txt index cf9a675b..a4cd7e7b 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/requirements.txt +++ b/hw/vendor/esl_epfl_x_heep/docs/requirements.txt @@ -1,2 +1,3 @@ sphinx-rtd-theme -myst-parser \ No newline at end of file +myst-parser +sphinxcontrib-apidoc diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/Configuration/Configuration.rst b/hw/vendor/esl_epfl_x_heep/docs/source/Configuration/Configuration.rst new file mode 100644 index 00000000..c18a4e26 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/Configuration/Configuration.rst @@ -0,0 +1,172 @@ +Configuration +============= + +Project Configuration +--------------------- +The project can be configured either by a hjson file or a python script. +The default configurations and examples are located in the `config` directory. + +Hjson Configuration File +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../../../configs/example_interleaved.hjson + :language: js + +Bus Type Configuration +^^^^^^^^^^^^^^^^^^^^^^ +The bus type can either be configured to `NtoM` or `onetoM`. + +Ram Bank Configuration +^^^^^^^^^^^^^^^^^^^^^^ + +The system can be configured with banks of different sizes. The sizes should be a power of two in kiB. +All banks are configured in one continuous address region. + + +To configure interleaved banks the number and the size of the banks have to be provided. +The following restrictions apply: All banks must have the same size and a power of two banks must be configured. + + +For continuous banks the default mode, only the `sizes` filed is required. +It can be either the size in kiB of a single bank, +a dictionary of the same format containing more banks, or a list of multiple entries. +If the `num` field is also provided the configuration in the `sizes` field is repeated `num` times. + +.. code:: js + + ram_banks: { + code: {sizes: 64} // configure just one bank + + data: { + type: continuous // the default, can be omitted + num: 2 + sizes: 32 + } + + alt_data: {sizes: [32, 32]} // the same as data but with a list + + more_complex: { + // This also works recursively so we can easily have different sizes of banks + // and in bigger numbers without listing them all one by one. + sizes: [ + { + num: 4 + sizes: 8 + }, + { + num: 16 + sizes: 4 + }, + ] + } + + } + + +Linker Section Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The linker script sections can be configured in two ways. +Either a section can be matched with a group of ram banks +or it can be manually defined. + +To automatically add a section the entry `auto_section: auto` should be added to the banks. +It will add a section that matches the banks exactly, it can only be used in the non recursive part. +The name of the section is set with the name of the group of banks. + +When manually setting the the linker section the name and the start address have to be provided. +Additionally the end is either provided by it's address or by the size of the section. +If no end is provided the end is inferred by the start of the next linker section. +Or if no section follows, the end address of the last ram bank. + +Both configuration types can be freely combined as long as no section overlap. +All sections will e sorted by the configuration system. + +The first two sections should always be code and data. +The other name can be used in code with a `.xheep_` prefix, like in `example_matadd_interleaved` + +.. code:: c + + int32_t __attribute__((section(".xheep_data_interleaved"))) m_c[16*16]; + +.. code:: js + + { + ram_address: 0 + bus_type: "onetoM", + ram_banks: { + code_and_data: { + num: 2 + sizes: [32] + } + i_am_a_section_name: { + auto_section: auto + sizes: 16 + } + } + + linker_sections: + [ + { + name: code + start: 0 + + // Alternatively the end tag can be used to provide the end. + size: 0x00000C800 + }, + { + name: data + start: 0x00000C800 + // The end of this section will be at the beginning of the next. + // In this example the next section is i_am_a_section_name + } + ] + } + + + + +Python Configuration +~~~~~~~~~~~~~~~~~~~~ + +The same can be done by using a python script + +.. literalinclude:: ../../../configs/example.py + :language: python + + +The script should include a config function that return an :py:class:`x_heep_gen.system.XHeep` instance. +The configuration is simmilar to the hjson one. The order in which sections are added is also the one used in hardware. +The script writer is responsible to call :py:meth:`x_heep_gen.system.XHeep.build` and :py:meth:`x_heep_gen.system.XHeep.validate` and to raise an error in case of failure. +The first does make the system ready to be used and the second does check for errors in the configuration. + + + +Select Configuration File +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To configure the system call + +.. code:: bash + + make mcu-gen X_HEEP_CFG=configs/name_of_file.hjson + + + +Other configurations +~~~~~~~~~~~~~~~~~~~~ + +The pads are configured in `pad_cfg.hjson`. + +One part of the configuration is in `mcu_cfg.hjson`. + +Additionally if a `hjson` file is ussed for configuration the following parameters can be set to the make command to override the configuration: + +- `BUS=NtoM,onetoM` +- `MEMORY_BANKS=integer` +- `MEMORY_BANKS_IL=integer` + +They will replace the configuration used in the configuration file. +When one parameter is not provided the configuration files value is used. +The memory banks configured this way will only be of size 32kiB. +For compatibility reasons `MEMORY_BANKS` does not create linker sections while `MEMORY_BANKS_IL` does create a linker section. + diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/AnalogMixedSignal.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/AnalogMixedSignal.md index 8ba4ed5c..5e2d0bb4 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/AnalogMixedSignal.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/AnalogMixedSignal.md @@ -1,4 +1,4 @@ -# integrate Analog / Mixed-Signal simulations +# Integrate Analog / Mixed-Signal simulations ## About @@ -68,7 +68,7 @@ The example AMS peripheral used by simulations of X-HEEP is located in `hw/ip_ex ### The repository's example SPICE files -

+

An example `adc.sp` file can be found in `hw/ip_examples/ams/analog`. This is a 1-bit ADC with a threshold that is configured through the 2-bit wide SEL input: an input of 00, 01, 10 and 11 will provide a threshold of 20%, 40%, 60% and 80% of VDD (1.2V) respectively. The input signal of the ADC is a sine wave with a peak-to-peak amplitude of 1.2V directly placed inside the SPICE netlist. diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile deleted file mode 100644 index 2db8a17d..00000000 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile +++ /dev/null @@ -1,350 +0,0 @@ -# compile with Makefile - -You can compile the example applications and the platform using the Makefile. Type 'make help' or 'make' for more information. Moreover, please, check the different 'clean' commands to verify that you are using the corret one. - -## Generate core-v-mini-mcu package - -First, you have to generate the SystemVerilog package and C header file of the core-v-mini-mcu: - -``` -make mcu-gen -``` - -To change the default cpu type (i.e., cv32e20), the default bus type (i.e., onetoM), -the default continuous memory size (i.e., 2 continuous banks) or the default interleaved memory size (i.e., 0 interleaved banks): - -``` -make mcu-gen CPU=cv32e40p BUS=NtoM MEMORY_BANKS=12 MEMORY_BANKS_IL=4 -``` - -The last command generates x-heep with the cv32e40p core, with a parallel bus, and 16 memory banks (12 continuous and 4 interleaved), -each 32KB, for a total memory of 512KB. - -## Compiling Software - -Don't forget to set the `RISCV` env variable to the compiler folder (without the `/bin` included). -To run 'hello world' application, just type 'make app'. - -``` -make app -``` - -To run any other application, please use the following command with appropiate parameters: - -``` -app PROJECT= TARGET=sim(default),pynq-z2 LINKER=on_chip(default),flash_load,flash_exec COMPILER=gcc(default),clang COMPILER_PREFIX=riscv32-unknown-(default) ARCH=rv32imc(default), - -Params: -- PROJECT (ex: , hello_world(default)) -- TARGET (ex: sim(default),pynq-z2) -- LINKER (ex: on_chip(default),flash_load,flash_exec) -- COMPILER (ex: gcc(default),clang) -- COMPILER_PREFIX (ex: riscv32-unknown-(default)) -- ARCH (ex: rv32imc(default),) -``` - -For instance, to run 'hello world' app for the pynq-z2 FPGA targets, just run: - -``` -make app TARGET=pynq-z2 -``` - -Or, if you use the OpenHW Group [GCC](https://www.embecosm.com/resources/tool-chain-downloads/#corev) compiler with CORE_PULP extensions, make sure to point the `RISCV` env variable to the OpenHW Group compiler, then just run: - - -``` -make app COMPILER_PREFIX=riscv32-corev- ARCH=rv32imc_zicsr_zifencei_xcvhwlp1p0_xcvmem1p0_xcvmac1p0_xcvbi1p0_xcvalu1p0_xcvsimd1p0_xcvbitmanip1p0 -``` - -This will create the executable file to be loaded in your target system (ASIC, FPGA, Simulation). -Remember that, `X-HEEP` is using CMake to compile and link. Thus, the generated files after having -compiled and linked are under `sw\build` - -## FreeROTS based applications - -'X-HEEP' supports 'FreeRTOS' based applications. Please see `sw\applications\blinky_freertos`. - -After that, you can run the command to compile and link the FreeRTOS based application. Please also set 'LINKER' and 'TARGET' parameters if needed. - -``` -make app PROJECT=blinky_freertos -``` - -The main FreeRTOS configuration is allocated under `sw\freertos`, in `FreeRTOSConfig.h`. Please, change this file based on your application requirements. -Moreover, FreeRTOS is being fetch from 'https://github.com/FreeRTOS/FreeRTOS-Kernel.git' by CMake. Specifically, 'V10.5.1' is used. Finally, the fetch repository is located under `sw\build\_deps` after building. - -## Simulating - -This project supports simulation with Verilator, Synopsys VCS, and Siemens Questasim. -It relies on `fusesoc` to handle multiple EDA tools and parameters. -For example, if you want to set the `FPU` and `COREV_PULP` parameters of the `cv32e40p` CPU, -you need to add next to your compilation command `FUSESOC_PARAM="--COREV_PULP=1 --FPU=1"` -Below the different EDA examples commands. - -### Compiling for Verilator - -To simulate your application with Verilator, first compile the HDL: - -``` -make verilator-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator -``` - -and type to run your compiled software: - -``` -./Vtestharness +firmware=../../../sw/build/main.hex -``` - -or to execute all these three steps type: - -``` -make run-helloworld -``` - -### Compiling for VCS - -To simulate your application with VCS, first compile the HDL: - -``` -make vcs-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs -``` - -and type to run your compiled software: - -``` -./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex -``` - -Waveforms can be viewed with Verdi. Make sure you have the env variable `VERDI_HOME` set to your Verdi install folder, then run your compiled software as above, but with the `-gui` flag: - -``` -./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex -gui -``` - -An Analog / Mixed-Signal simulation of X-HEEP, combining both the RTL system verilog files for the digital part and a SPICE file connected through a `control.init` file for the analog / mixed-signal part, can be ran by typing - -``` -make vcs-ams-sim -``` - -then going to the target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs -``` - -and running the same executable as for the digital simulation. Note that with Verdi you can view both the digital and the analog waveforms. - -Additional instructions on how to run an analog / mixed-signal simulation of X-HEEP can be found [here](AnalogMixedSignal.md). To try out the simulation, we provide an example SPICE netlist of an simple 1-bit ADC created by us and exported from [xschem](https://xschem.sourceforge.io/stefan/index.html) and which uses the PTM 65nm bulk CMOS model from [https://ptm.asu.edu](https://ptm.asu.edu/). - -### Compiling for Questasim - -To simulate your application with Questasim, first set the env variable `MODEL_TECH` to your Questasim bin folder, then compile the HDL: - -``` -make questasim-sim -``` - -then, go to your target system built folder - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-modelsim/ -``` - -and type to run your compiled software: - -``` -make run PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -You can also use vopt for HDL optimized compilation: - -``` -make questasim-sim-opt -``` - -then go to - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim_opt-modelsim/ -``` -and - -``` -make run RUN_OPT=1 PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -You can also compile with the UPF power domain description as: - -``` -make questasim-sim-opt-upf FUSESOC_PARAM="--USE_UPF" -``` - -and then execute software as: - -``` -make run RUN_OPT=1 RUN_UPF=1 PLUSARGS="c firmware=../../../sw/build/main.hex" -``` - -Questasim version must be >= Questasim 2020.4 - -### UART DPI - -To simulate the UART, we use the LowRISC OpenTitan [UART DPI](https://github.com/lowRISC/opentitan/tree/master/hw/dv/dpi/uartdpi). -Read how to interact with it in the Section "Running Software on a Verilator Simulation with Bazel" [here](https://opentitan.org/guides/getting_started/setup_verilator.html#running-software-on-a-verilator-simulation-with-bazel). -The output of the UART DPI module is printed in the `uart0.log` file in the simulation folder. - -For example, to see the "hello world!" output of the Verilator simulation: - -``` -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator -./Vtestharness +firmware=../../../sw/build/main.hex -cat uart0.log -``` - -## Automatic testing - -X-HEEP includes two tools to perform automatic tests over your modifications. - -### Github CIs - -Upon push, tests are run on Github runners, these include: -* The generated `.sv` files pushed are equal to those generated in the runner (the code does not depend on the modification of generated files) -* Vendor is up to date (the code does not depend on the modification of vendorized files) -* All applications can be built successfully using both gcc and clang - -All test must be successful before PRs can be merged. - -### Simulation script - -Additionally, a `test_all.sh` script is provided. Apart from compiling all apps with both gcc and clang, it will simulate them and check the result. - -The available parameters are: -* COMPILER: `gcc` (default) or `clang` (can provide more than one) -* SIMULATOR: `verilator` (default), `questasim` or disable simulation with `nosim` (only one, the last provided is used). -* LINKER: `on_chip`(default), `flash_load` or `flash_exec` (can provide more than one) -* TIMEOUT: Integer number of seconds (default 120) - -#### Usage - -##### Comands -You can use two different commands to compile or simulate all the existing APPs: -``` -make app-compile-all -``` -``` -make app-simulate-all -``` -Note that both commands allow the previous parameters to specify compiling or simulation options. E.g.: -``` -make app-simulate-all LINKER=on_chip SIMULATOR=questasim COMPILER=clang TIMEOUT=150 -``` - -##### Manually -You can also **SOURCE** the script as -```bash -. util/test_all.sh on_chip questasim clang 150 -``` - -*Pay special attention to the first period in the command!* -You will be killing simulations that take too long, if you **EXECUTE** (`./test_all.sh`) this action kills the script. - -For both usages (commands or manual), the order of the arguments is irrelevant. - -> Note: Be sure to commit all your changes before running the script! - -* Applications that fail being built with gcc will not be simulated (skipped). -* Some applications are skipped by default for not being suitable for simulation. -* If a simulation takes too long (>timeout), it is killed. - -* Upon starting, the script will modify the `mcu_cfg.hjson` file to include all peripherals (so the largest number of apps can be run), re-generates the mcu and re-builds the simulation model for the chosen tool. -These changes can be reverted at the end of the execution (default). If changes were not commited, accepting this operation will revert them! - -The success of the script is not required for merging of a PR. - -## Debug - -Follow the [Debug](./Debug.md) guide to debug core-v-mini-mcu. - -## Execute From Flash - -Follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide to exxecute code directly from the FLASH with modelsim, FPGA, or ASIC. - -## Emulation on Xilinx FPGAs - -This project offers two different X-HEEP implementetions on Xilinx FPGAs, called Standalone and FEMU. - -### Standalone - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board. - -Two FPGA boards are supported: the Xilinx Pynq-z2 and Nexys-A7-100t. - -Make sure you have the FPGA board files installed in your Vivado. - -For example, for the Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them: - -To build and program the bitstream for your FPGA with vivado, type: - -``` -make vivado-fpga FPGA_BOARD=pynq-z2 -``` - -or - -``` -make vivado-fpga FPGA_BOARD=nexys-a7-100t -``` - -or add the flag `use_bscane_xilinx` to use the native Xilinx scanchain: - -``` -make vivado-fpga FPGA_BOARD=pynq-z2 FUSESOC_FLAGS=--flag=use_bscane_xilinx -``` - -Only Vivado 2021.2 has been tried. - -To program the bitstream, open Vivado, - -``` -open --> Hardware Manager --> Open Target --> Autoconnect --> Program Device -``` - -and choose the file `openhwgroup.org_systems_core-v-mini-mcu_0.bit` - -To run SW, follow the [Debug](./Debug.md) guide -to load the binaries with the HS2 cable over JTAG, -or follow the [ExecuteFromFlash](./ExecuteFromFlash.md) -guide if you have a FLASH attached to the FPGA. - -Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. - -For example, if you want to run your application using flash_exec, do as follow: - -compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` - -and then follow the [ExecuteFromFlash](./ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. - -To look at the output of your printf, run in another terminal: - -`picocom -b 9600 -r -l --imap lfcrlf /dev/ttyUSB2` - -Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). - -### FPGA EMUlation Platform (FEMU) - -In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Xilinx Zynq-7020 chip on the Pynq-Z2 board and Linux is run on the ARM-based processing system (PS) side of the same chip. - -NOTE: This platform is not part of this repository, but you can access it with the following link: [FEMU](https://github.com/esl-epfl/x-heep-femu-sdk). diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile.md new file mode 100644 index 00000000..774f8ae3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/CompileMakefile.md @@ -0,0 +1,145 @@ +# Compile with Makefile + +You can compile the example applications and the platform using the Makefile. Type 'make help' or 'make' for more information. Moreover, please, check the different 'clean' commands to verify that you are using the corret one. + +## Generate core-v-mini-mcu package + +First, you have to generate the SystemVerilog package and C header file of the core-v-mini-mcu: + +``` +make mcu-gen +``` + +To change the default cpu type (i.e., cv32e20), the default bus type (i.e., onetoM), +the default continuous memory size (i.e., 2 continuous banks) or the default interleaved memory size (i.e., 0 interleaved banks): + +``` +make mcu-gen CPU=cv32e40p BUS=NtoM MEMORY_BANKS=12 MEMORY_BANKS_IL=4 +``` + +The last command generates x-heep with the cv32e40p core, with a parallel bus, and 16 memory banks (12 continuous and 4 interleaved), +each 32KB, for a total memory of 512KB. +This method is limmited to 32KB banks. + +To configure the ram banks with more flexibility, edit `configs/general.hjson` or provided your own one. +Both method work together the first one overrides the second. + +``` +make mcu-gen X_HEEP_CFG=configs/my_config.hjson +``` + +For more information see Configuration section. + +## Compiling Software + +Don't forget to set the `RISCV` env variable to the compiler folder (without the `/bin` included). +To run 'hello world' application, just type 'make app'. + +``` +make app +``` + +To run any other application, please use the following command with appropiate parameters: + +``` +app PROJECT= TARGET=sim(default),pynq-z2 LINKER=on_chip(default),flash_load,flash_exec COMPILER=gcc(default),clang COMPILER_PREFIX=riscv32-unknown-(default) ARCH=rv32imc(default), + +Params: +- PROJECT (ex: , hello_world(default)) +- TARGET (ex: sim(default),pynq-z2) +- LINKER (ex: on_chip(default),flash_load,flash_exec) +- COMPILER (ex: gcc(default),clang) +- COMPILER_PREFIX (ex: riscv32-unknown-(default)) +- ARCH (ex: rv32imc(default),) +``` + +For instance, to run 'hello world' app for the pynq-z2 FPGA targets, just run: + +``` +make app TARGET=pynq-z2 +``` + +Or, if you use the OpenHW Group [GCC](https://www.embecosm.com/resources/tool-chain-downloads/#corev) compiler with CORE_PULP extensions, make sure to point the `RISCV` env variable to the OpenHW Group compiler, then just run: + + +``` +make app COMPILER_PREFIX=riscv32-corev- ARCH=rv32imc_zicsr_zifencei_xcvhwlp_xcvmem_xcvmac_xcvbi_xcvalu_xcvsimd_xcvbitmanip +``` + +This will create the executable file to be loaded in your target system (ASIC, FPGA, Simulation). +Remember that, `X-HEEP` is using CMake to compile and link. Thus, the generated files after having +compiled and linked are under `sw\build` + +## FreeROTS based applications + +'X-HEEP' supports 'FreeRTOS' based applications. Please see `sw\applications\blinky_freertos`. + +After that, you can run the command to compile and link the FreeRTOS based application. Please also set 'LINKER' and 'TARGET' parameters if needed. + +``` +make app PROJECT=blinky_freertos +``` + +The main FreeRTOS configuration is allocated under `sw\freertos`, in `FreeRTOSConfig.h`. Please, change this file based on your application requirements. +Moreover, FreeRTOS is being fetch from 'https://github.com/FreeRTOS/FreeRTOS-Kernel.git' by CMake. Specifically, 'V10.5.1' is used. Finally, the fetch repository is located under `sw\build\_deps` after building. + + +## Automatic testing + +X-HEEP includes two tools to perform automatic tests over your modifications. + +### Github CIs + +Upon push, tests are run on Github runners, these include: +* The generated `.sv` files pushed are equal to those generated in the runner (the code does not depend on the modification of generated files) +* Vendor is up to date (the code does not depend on the modification of vendorized files) +* All applications can be built successfully using both gcc and clang + +All test must be successful before PRs can be merged. + +### Simulation script + +Additionally, a `test_all.sh` script is provided. Apart from compiling all apps with both gcc and clang, it will simulate them and check the result. + +The available parameters are: +* COMPILER: `gcc` (default) or `clang` (can provide more than one) +* SIMULATOR: `verilator` (default), `questasim` or disable simulation with `nosim` (only one, the last provided is used). +* LINKER: `on_chip`(default), `flash_load` or `flash_exec` (can provide more than one) +* TIMEOUT: Integer number of seconds (default 120) + +#### Usage + +##### Comands +You can use two different commands to compile or simulate all the existing APPs: +``` +make app-compile-all +``` +``` +make app-simulate-all +``` +Note that both commands allow the previous parameters to specify compiling or simulation options. E.g.: +``` +make app-simulate-all LINKER=on_chip SIMULATOR=questasim COMPILER=clang TIMEOUT=150 +``` + +##### Manually +You can also **SOURCE** the script as +```bash +. util/test_all.sh on_chip questasim clang 150 +``` + +*Pay special attention to the first period in the command!* +You will be killing simulations that take too long, if you **EXECUTE** (`./test_all.sh`) this action kills the script. + +For both usages (commands or manual), the order of the arguments is irrelevant. + +> Note: Be sure to commit all your changes before running the script! + +* Applications that fail being built with gcc will not be simulated (skipped). +* Some applications are skipped by default for not being suitable for simulation. +* If a simulation takes too long (>timeout), it is killed. + +* Upon starting, the script will modify the `mcu_cfg.hjson` file to include all peripherals (so the largest number of apps can be run), re-generates the mcu and re-builds the simulation model for the chosen tool. +These changes can be reverted at the end of the execution (default). If changes were not commited, accepting this operation will revert them! + +The success of the script is not required for merging of a PR. \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md index 2a5882f6..9bcc76fb 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Debug.md @@ -1,11 +1,11 @@ -# debug +# Debug ## Prerequisite 1. Install the required linux tools: ``` -sudo apt install pkg-config libftdi1-2 libusb-1.0-4 +sudo apt install pkg-config libftdi1-2 ``` You need at least gcc>10, so in case you do not have it: @@ -42,7 +42,7 @@ The remote bitbang server is simplemented in the folder ./hw/vendor/pulp_platfor ### Verilator (C++ only) -To simulate your application with Questasim using the remote_bitbang server, you need to compile you system adding the `JTAG DPI` functions: +To simulate your application with Verilator using the remote_bitbang server, you need to compile you system adding the `JTAG DPI` functions: ``` make verilator-sim FUSESOC_PARAM="--JTAG_DPI=1" diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExecuteFromFlash.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExecuteFromFlash.md index 8413a129..ce7b9a9c 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExecuteFromFlash.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExecuteFromFlash.md @@ -1,4 +1,4 @@ -# execute Code from FLASH +# Execute Code from FLASH ## Boot Procedure diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md deleted file mode 100644 index bbc89bd3..00000000 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ExternalDevices.md +++ /dev/null @@ -1,151 +0,0 @@ -# interface with external devices - -The top module [`core_v_mini_mcu`]((./../../../hw/core-v-mini-mcu/corecore_v_mini_mcu.sv) exposes several external interfaces: - -- `ext_xbar_master`: N ports to connect external masters to the internal system bus. - -- Five external ports to connect internal masters (e.g., CPU instruction and data ports) to external slaves. Every internal master is exposed to the external subsystem: - 1. `ext_core_instr`: CPU instruction interface. - 2. `ext_core_data`: CPU data interface. - 3. `ext_debug_master`: debug interface. - 4. `ext_dma_read_ch0`: DMA read master, channel 0. - 5. `ext_dma_write_ch0`: DMA write master, channel 0. - 6. `ext_dma_addr_ch0`: DMA address (read) master, channel 0. - -- `ext_peripheral_slave`: 1 peripheral slave port connected to the system bus (through the peripheral interface). - -The number of external master ports is set by the [`EXT_XBAR_NMASTER`](./../../../tb/testharness_pkg.sv#L10) parameter from `testharness_pkg`. -Multiple OBI slaves can be connected to the exposed internal masters using an external bus, as demonstrated in [`testharness.sv`](./../../../tb/testharness.sv#L232). - -> NOTE: the internal bus has no master port connected to the external subsystem. Therefore, an external master cannot send a request to an external slave through one of the exposed master ports. All the address decoding must be done by the external bus: the request must be forwarded to one of the `ext_xbar_master` ports only if the target address falls into the space where internal slaves are mapped. This can be achieved using a 1-to-2 crossbar for each external master as done [here](./../../../tb/ext_bus.sv#L131). - -Finally, only one peripheral slave port is available to the external subsystem. - -## External device example - -One example using the external ports is provided where: - -- hw/ip_examples/slow_sram is a memory slave device -- hw/ip_examples/memcopy is a slave peripheral with a master port. It implements a simple memcopy feature (i.e., DMA). -- hw/ip_examples/ams is an example AMS peripheral which can interface with SPICE netlists to run mixed-signal simulations (in this repository, the example analog peripheral is a 1-bit ADC) - - For more information, see [here](AnalogMixedSignal.md) - -## Run the external device example - -To run the external device example, first compile the software example: - -```bash -make app PROJECT=example_external_dma -``` - -By default, the external device example RTL code is disabled. This example is available for the sim and sim_opt targets. - -For example, compile for Verilator with: - -``` -make verilator-sim -``` - -then, go to your target system built folder - -```bash -cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator -``` - -and type to run your compiled software: - -```bash -./Vtestharness +firmware=../../../sw/build/main.hex -``` - -If you don't compile the platform with the correct fusesoc flag, the simulation will hang forever because the external peripheral is disabled and never replies. - -You can display the UART output with: - -```bash -cat uart0.log -``` - -It should print: - -``` ---- MEMCOPY EXAMPLE - external peripheral --- -Init the PLIC...success -Set MEMCOPY interrupt priority to 1...success -Enable MEMCOPY interrupt...Success -Memcopy launched...finished -Complete interrupt...success -MEMCOPY SUCCESS -``` - -## Add an external master/slave or peripheral - -1. Master(s): use the obi_pkg (import obi_pkg::\*;) to create your master_req output port (obi_req_t) and master_resp input port (obi_resp_t). Adjust the EXT_XBAR_NMASTER parameter accordingly. - -2. Slave(s): similar to adding a master but you have a slave_req input port (obi_req_t) and slave_resp output port (obi_resp_t). Remember to connect external masters with external slaves through an external bus. The same bus can be used to connect multiple external slaves to the internal `core_v_mini_mcu` masters. - -3. Peripheral slave(s): use the reg_pkg (import obi_pkg::\*;) to create your slave_periph_req input port (reg_req_t) and slave_resp output port (reg_rsp_t). If multiple peripheral slaves are used, add a decoding stage for addresses dispatching. - -To create and maintain a peripheral unit efficiently, use the `reggen` tool: - -1. Define the registers of your peripheral in a `.hjson` file (read the documentation [here](https://docs.opentitan.org/doc/rm/register_tool/)). - -2. Launch the `regtool.py` script to generate SystemVerilog RTL code and a C header file. - -For example, launching the script [`memcopy_periph_gen.sh`](./../../../hw/ip_examples/memcopy_periph/memcopy_periph_gen.sh) generates 2 SystemVerilog files and one C header file: - -1. `memcopy_periph_reg_top.sv`: the register file module. It can be directly instantiated inside your peripheral RTL code (e.g., [`memcopy_periph.sv`](./../../../hw/ip_examples/memcopy_periph/rtl/memcopy_periph.sv)) and connected to the peripheral device controller(s). -2. `memcopy_periph_reg_pkg.sv`: SystemVerilog package containing the definitions used in the SystemVerilog module above. -3. `memcopy_periph_regs.h`: C/C++ header file defining the address offset of the peripheral configuration registers. Take a look at the C code [here](./../../../sw/applications/example_external_peripheral/memcopy_periph.c) for a usage example. - -## External Interrupts - -X-HEEP includes several empty external interrupts slots that can be assigned both in HW and SW. - -Firstly, connect your external device's interrupt to one of the slots of the `external_interrupt_vector` of X-HEEP: - -```systemverilog - -logic [core_v_mini_mcu_pkg::NEXT_INT-1:0] ext_intr_vector; - -always_comb begin -for (int i = 0; i < core_v_mini_mcu_pkg::NEXT_INT; i++) begin - ext_intr_vector[i] = 1'b0; // All interrupt lines set to zero by default -end -ext_intr_vector[0] = my_device_int; // Re-assign the interrupt lines used here -end - -x_heep_system #( - . . . -) x_heep_system_i ( - .intr_vector_ext_i(ext_intr_vector), - . . . -) - -``` - -Then, when initializing the PLIC system in software, do not forget to assign the corresponding interrupt ID to your custom handler. - -```C -#define MY_DEVICE_INTR EXT_INTR_0 - -void handler_irq_my_device(uint32_t id) { - my_device_intr_flag = 1; - // Do whatever you need here -} - -void main() { - plic_Init(); // Init the PLIC, this will clear all external interrupts assigned previously. - plic_irq_set_priority(MY_DEVICE_INTR, 1); // Set the priority of the external device's interrupt. - plic_irq_set_enabled(MY_DEVICE_INTR, kPlicToggleEnabled); // Enable the external device's interrupt. - plic_assign_external_irq_handler( MY_DEVICE_INTR, (void *) &handler_irq_my_device); // Assign a handler taht will be called when this interrupt is triggered. - - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - // Set mie.MEIE bit to one to enable machine-level external interrupts - const uint32_t mask = 1 << 11;//IRQ_EXT_ENABLE_OFFSET; - CSR_SET_BITS(CSR_REG_MIE, mask); - - . . . -} -``` \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/GettingStarted.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/GettingStarted.md index e5b877dd..4b7b6685 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/GettingStarted.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/GettingStarted.md @@ -1,6 +1,34 @@ -# get started +# Get started -## 1. OS requirements +## Docker setup + +A docker image containing all the required software dependancies is available on [github-packages](https://github.com/orgs/esl-epfl/packages/container/package/x-heep-toolchain). + +It is only required to install docker and pull the image. + +```bash +docker pull ghcr.io/esl-epfl/x-heep-toolchain:latest +``` + +Assuming that X-HEEP has been cloned to `X-HEEP-DIR=\absolute\path\to\x-HEEP\folder`, it is possible to directly run the docker mounting `X-HEEP-DIR` to the path `\workspace\x-heep` in the docker. + +```bash +docker run -it -v ${X-HEEP-DIR}:/workspace/x-heep ghcr.io/esl-epfl/x-heep-toolchain +``` + +:warning: Take care to indicate the absolute path to the local clone of X-HEEP, otherwise docker will not be able to properly mount the local folder in the container. + +All the command listed in the README can be execute in the docker container, except for: + +- Simulation with Questasim and VCS, synthesis with Design Compiler (licenses are required to use these tools, so they are not installed in the container) + +- OpenRoad flow is not installed in the container, so it is not possible to run the related make commands + +- Synthesis with Vivado could be possible, but currently is untested + +## Manual setup + +### 1. OS requirements To use `X-HEEP`, first make sure you have the following apt packages, or install them as: @@ -10,16 +38,14 @@ sudo apt install lcov libelf1 libelf-dev libftdi1-2 libftdi1-dev libncurses5 lib In general, have a look at the [Install required software](https://opentitan.org/guides/getting_started/index.html) section of the OpenTitan documentation. -It has been tested only on `Ubuntu 20`, and we know it does NOT WORK on `Ubuntu 22`. - -## 2. Python +### 2. Python We rely on either (a) `miniconda`, or (b) `virtual environment` enviroment. Choose between `2.a` or `2.b` to setup your enviroment. -### 2.a Miniconda +#### 2.a Miniconda Install [Miniconda](https://docs.conda.io/en/latest/miniconda.html#linux-installers) python 3.8 version as described in the link, and create the Conda enviroment: @@ -35,7 +61,7 @@ conda activate core-v-mini-mcu ``` -### 2.b Virtual Environment +#### 2.b Virtual Environment Install the python virtual environment just as: @@ -49,7 +75,7 @@ You need to do it only the first time, then just activate the environment everyt source .venv/bin/activate ``` -## 3. Install the RISC-V Compiler: +### 3. Install the RISC-V Compiler: ``` git clone --branch 2022.01.17 --recursive https://github.com/riscv/riscv-gnu-toolchain @@ -75,7 +101,7 @@ cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Releas cmake --build . --target install ``` -## 4. Install Verilator: +### 4. Install Verilator: ``` export VERILATOR_VERSION=4.210 @@ -104,18 +130,18 @@ sudo apt install libcanberra-gtk-module libcanberra-gtk3-module sudo apt-get install -y gtkwave ``` -## Files are formatted with Verible +### Files are formatted with Verible We use version v0.0-1824-ga3b5bedf -See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-6a-install-verible-optional) +See: [Install Verible](https://opentitan.org/guides/getting_started/index.html#step-7a-install-verible-optional) To format your RTL code type: ``` make verible ``` -## Compilation Flow and Package Manager +### Compilation Flow and Package Manager We use [FuseSoC](https://github.com/olofk/fusesoc) for all the tools we use. diff --git a/hw/vendor/esl_epfl_x_heep/IDEs.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IDEs.md similarity index 92% rename from hw/vendor/esl_epfl_x_heep/IDEs.md rename to hw/vendor/esl_epfl_x_heep/docs/source/How_to/IDEs.md index e1fce194..ee932dc3 100644 --- a/hw/vendor/esl_epfl_x_heep/IDEs.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IDEs.md @@ -1,14 +1,14 @@ +# Set up an IDE For FW development, `X-HEEP` can be used together with different Integrated Development Environments (IDEs) flavours. Up to now, full support is just provided by [Segger Embedded Studio (SES)](https://www.segger.com/products/development-tools/embedded-studio/editions/risc-v/). This readme guides you through all the needed steps to get SES working and debugging when prototyping `X-HEEP` into the pynq-z2 board. -# Prerequisite -## 1. SES installation. +## SES installation. The platform was only tested under Linux and version 7.32 of the Embedded Studio for RISC-V. Please, go to the Segger [download center](https://www.segger.com/downloads/embedded-studio/) to get that version. It is assumed that you have already installed the RISC-V compiler and openOCD. If the latter is not true, check the main [Readme](https://github.com/esl-epfl/x-heep) please. -# Configuration +## Configuration -After installing SES, you need to indicate to Segger your Toolchain directory (RISC-V Compiler) as well as your openOCD installation folder. Those need to be specified into `xheep.emProject` file. +After installing SES, you need to indicate to Segger your Toolchain directory (RISC-V Compiler) as well as your openOCD installation folder. Those need to be specified into `xheep.emProject` file. For the RISC-V Compiler path, **line 71**: ``` @@ -22,23 +22,23 @@ gdb_server_command_line="/home/< user >/tools/openocd/bin/openocd -f "$(Pro ``` Please, substitute that path to your current path where openOCD was installed. Do not forget to target the `openocd` file inside the `bin` installation folder of openocd. -# Building +## Building Once the paths are set properly, you can open `xheep.emProject` with SES. That will launch SES with one solution already configured, `xheep_ses`, and one project into that solution `helloworld`. Note that this project has already everything configured to run the `helloworld` application of the main repo, i.e. all the source files are linked to the project as well as the `c user include directories` already set up. Moreover, this project is configured to be running (compile, linking, and debug) by using the on-chip linker `sw/linker/link.ld`. If you want to change any of these options, you will need to change the options of the project or the options of the solution. Note that the project is currently set-up to be working on the `Debug_External` configuration. Please, do not move to other configuration when building and/or debugging. Finally, to build the whole project just press `F7` or `Build > Build helloworld`. The output should be like this: -

+

Note that on the right part, you have the memory usage based on the linker we have configured. If you do not see this, you can activate that view in `View > Memory Usage`. -# Debugging +## Debugging -Finally, after building (compile and linking), you can directly start debugging by pressing `F5` or also `Target > Connect GDB Server` and `Debug > Go`. You also have the possibility to activate the terminal to see directly into the SES window the printing characters. +Finally, after building (compile and linking), you can directly start debugging by pressing `F5` or also `Target > Connect GDB Server` and `Debug > Go`. You also have the possibility to activate the terminal to see directly into the SES window the printing characters. The output should be something like this: -

+

Note that when debugging and setting breakpoints, please, go one-by-one (one breakpoint at a time). Several breakpoints support will be supported in the following releases. diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ImplementASIC.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ImplementASIC.md index bacb7050..2ddf20c8 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ImplementASIC.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ImplementASIC.md @@ -1,4 +1,4 @@ -# implement on ASIC +# Implement on ASIC This project can be implemented using standard cells based ASIC flow. diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IntegratePeripheral.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IntegratePeripheral.md index ae8b3b3f..f39bdbd1 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IntegratePeripheral.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/IntegratePeripheral.md @@ -206,7 +206,7 @@ module #( b. The corresponding package must be imported: -```systemverilog +``` import _reg_pkg::*; ``` diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md index 7ed89d24..efbe78a9 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/ProgramFlash.md @@ -1,4 +1,4 @@ -# program the FLASH on the EPFL Programmer +# Program the FLASH on the EPFL Programmer Install the required linux tools: diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/RunOnFPGA.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/RunOnFPGA.md new file mode 100644 index 00000000..79790a91 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/RunOnFPGA.md @@ -0,0 +1,81 @@ +# Run on FPGA + +This project offers two different X-HEEP implementetions on Xilinx FPGAs, called Standalone and FEMU. + +## Standalone + +### Set-up +In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board. + +Two FPGA boards are supported: the Xilinx Pynq-z2 and Nexys-A7-100t. + +1. Make sure you have the FPGA board files installed in your Vivado. +> For example, for the Pynq-Z2 board, use the documentation provided at the following [link](https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html) to download and install them. + +2. Make sure you set up the Vivado environments by running + ``` + source /settings64.sh + ``` + > We recommend adding this command to your `.bashrc` + +3. Install the Xilinx cable drivers. +* Follow the [instructions for Linux](https://docs.amd.com/api/khub/documents/6EIhov6ruoilhq8zq7bXBA/content?Ft-Calling-App=ft%2Fturnkey-portal&Ft-Calling-App-Version=4.3.26#G4.262534) +* Restart your PC + +### Running + +To build and program the bitstream for your FPGA with vivado, type: + +``` +make vivado-fpga FPGA_BOARD=pynq-z2 +``` + +or + +``` +make vivado-fpga FPGA_BOARD=nexys-a7-100t +``` + +or add the flag `use_bscane_xilinx` to use the native Xilinx scanchain: + +``` +make vivado-fpga FPGA_BOARD=pynq-z2 FUSESOC_FLAGS=--flag=use_bscane_xilinx +``` + +To program the bitstream, open Vivado, + +``` +open --> Hardware Manager --> Open Target --> Autoconnect --> Program Device +``` + +and choose the file `openhwgroup.org_systems_core-v-mini-mcu_0.bit`. + +Or simply type: + +``` +bash vivado-fpga-pgm FPGA_BOARD=pynq-z2 +``` + +or + +``` +make vivado-fpga-pgm FPGA_BOARD=nexys-a7-100t +``` + +To run SW, follow the [Debug](./Debug.md) guide to load the binaries with the HS2 cable over JTAG, +or follow the [ExecuteFromFlash](./ExecuteFromFlash.md) guide if you have a FLASH attached to the FPGA. + +Do not forget that the `pynq-z2` board requires you to have the ethernet cable attached to the board while running. + +For example, if you want to run your application using flash_exec, do as follow: +compile your application, e.g. `make app PROJECT=example_matfadd TARGET=pynq-z2 ARCH=rv32imfc LINKER=flash_exec` +and then follow the [ExecuteFromFlash](./ExecuteFromFlash.md) to program the flash and set the boot buttons on the FPGA correctly. +To look at the output of your printf, run in another terminal: +`picocom -b 9600 -r -l --imap lfcrlf /dev/ttyUSB2` +Please be sure to use the right `ttyUSB` number (you can discover it with `dmesg --time-format iso | grep FTDI` for example). + +## FPGA EMUlation Platform (FEMU) + +In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the Xilinx Zynq-7020 chip on the Pynq-Z2 board and Linux is run on the ARM-based processing system (PS) side of the same chip. + +NOTE: This platform is not part of this repository, but you can access it with the following link: [FEMU](https://github.com/esl-epfl/x-heep-femu-sdk). diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Simulate.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Simulate.md new file mode 100644 index 00000000..6147648c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/Simulate.md @@ -0,0 +1,160 @@ +# Simulate + +This project supports simulation with Verilator, Synopsys VCS, Siemens Questasim and Cadence Xcelium. +It relies on `fusesoc` to handle multiple EDA tools and parameters. +For example, if you want to set the `FPU` and `COREV_PULP` parameters of the `cv32e40p` CPU, +you need to add next to your compilation command `FUSESOC_PARAM="--COREV_PULP=1 --FPU=1"` +Below the different EDA examples commands. + +## Compiling for Verilator + +To simulate your application with Verilator, first compile the HDL: + +``` +make verilator-sim +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator +``` + +and type to run your compiled software: + +``` +./Vtestharness +firmware=../../../sw/build/main.hex +``` + +or to execute all these three steps type: + +``` +make run-helloworld +``` + +## Compiling for VCS + +To simulate your application with VCS, first compile the HDL: + +``` +make vcs-sim +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs +``` + +and type to run your compiled software: + +``` +./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex +``` + +Waveforms can be viewed with Verdi. Make sure you have the env variable `VERDI_HOME` set to your Verdi install folder, then run your compiled software as above, but with the `-gui` flag: + +``` +./openhwgroup.org_systems_core-v-mini-mcu_0 +firmware=../../../sw/build/main.hex -gui +``` + +An Analog / Mixed-Signal simulation of X-HEEP, combining both the RTL system verilog files for the digital part and a SPICE file connected through a `control.init` file for the analog / mixed-signal part, can be ran by typing + +``` +make vcs-ams-sim +``` + +then going to the target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-vcs +``` + +and running the same executable as for the digital simulation. Note that with Verdi you can view both the digital and the analog waveforms. + +Additional instructions on how to run an analog / mixed-signal simulation of X-HEEP can be found [here](./AnalogMixedSignal.md). To try out the simulation, we provide an example SPICE netlist of an simple 1-bit ADC created by us and exported from [xschem](https://xschem.sourceforge.io/stefan/index.html) and which uses the PTM 65nm bulk CMOS model from [https://ptm.asu.edu](https://ptm.asu.edu/). + +## Compiling for Questasim + +To simulate your application with Questasim, first set the env variable `MODEL_TECH` to your Questasim bin folder, then compile the HDL: + +``` +make questasim-sim +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-modelsim/ +``` + +and type to run your compiled software: + +``` +make run PLUSARGS="c firmware=../../../sw/build/main.hex" +``` + +You can also use vopt for HDL optimized compilation: + +``` +make questasim-sim-opt +``` + +then go to + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim_opt-modelsim/ +``` +and + +``` +make run RUN_OPT=1 PLUSARGS="c firmware=../../../sw/build/main.hex" +``` + +You can also compile with the UPF power domain description as: + +``` +make questasim-sim-opt-upf FUSESOC_PARAM="--USE_UPF" +``` + +and then execute software as: + +``` +make run RUN_OPT=1 RUN_UPF=1 PLUSARGS="c firmware=../../../sw/build/main.hex" +``` + +Questasim version must be >= Questasim 2020.4 + +## Compiling for Xcelium + +To simulate your application with Xcelium, first compile the HDL: + +``` +make xcelium-sim +``` + +then, go to your target system built folder + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-xcelium/ +``` + +and type to run your compiled software: + +``` +make run PLUSARGS="c firmware=../../../sw/build/main.hex" +``` + +## UART DPI + +To simulate the UART, we use the LowRISC OpenTitan [UART DPI](https://github.com/lowRISC/opentitan/tree/master/hw/dv/dpi/uartdpi). +Read how to interact with it in the Section "Running Software on a Verilator Simulation with Bazel" [here](https://opentitan.org/guides/getting_started/setup_verilator.html#running-software-on-a-verilator-simulation-with-bazel). +The output of the UART DPI module is printed in the `uart0.log` file in the simulation folder. + +For example, to see the "hello world!" output of the Verilator simulation: + +``` +cd ./build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator +./Vtestharness +firmware=../../../sw/build/main.hex +cat uart0.log +``` \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/UpdateDocumentation.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/UpdateDocumentation.md new file mode 100644 index 00000000..c27a8776 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/UpdateDocumentation.md @@ -0,0 +1,27 @@ +# Update the documentation + +All documentation is found in the `/docs` directory. + +1. If you need to create a new entry, add the new document in markdown (`.md` extension) to the corresponding folder. Otherwise, just edit the corresponding file. + +> Make sure the document has one single `# header`, otherwise they will be considered different documents. + +2. If a new folder is added, add it to the `toctree` inside `docs/source/index.rst` (as the `peripherals` folder is) +3. Commit and push + +## Refresh the web documentation + +After each change to the documentation, once the branch is merged into the main branch of X-HEEP, anyone must do the following: + +1. Open a terminal in the `docs` folder and make sure the conda environment is activated. +2. If it is your first time updating the web docs, run: +```bash +pip install -r requirements.txt +``` +3. Run +```bash +make clean html +``` +4. Wait a few minutes and enjoy your brand new documentation in [Read the Docs](https://x-heep.readthedocs.io/en/latest/). + +Thank you for helping keep X-HEEP accurately and extensively documented! diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md index ad8805b1..59c1b1e9 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md @@ -10,6 +10,7 @@ Here you can find a list of `X-HEEP` based open-source examples. If you want to * [CGRA-X-HEEP](https://github.com/esl-epfl/cgra_x_heep): A CGRA loosely coupled with X-HEEP. * [F-HEEP](https://github.com/davidmallasen/F-HEEP): System integrating [fpu_ss](https://github.com/pulp-platform/fpu_ss) into X-HEEP via the eXtension interface and cv32e40x. +* [KALIPSO](https://github.com/vlsi-lab/ntt_intt_kyber) and [KRONOS](https://github.com/vlsi-lab/keccak_integration/tree/keccak_xheep): Loosely-coupled, post-quantum cryptography accelerators for NTT/INTT and Keccak hash function integrated into X-HEEP. In addition, the `X-HEEP` testbench has been extended with a `DMA`, dummy `PERIPHERALs` (including the `FLASH`), and a CORE-V-XIF compatible co-processor @@ -304,7 +305,7 @@ To do so, it MUST include the `external.mk` AFTER all your custom rules.
Example of BASE/Makefile -``` +```Makefile MAKE = make .PHONY: test test: @@ -326,12 +327,69 @@ include $(XHEEP_MAKE) * The `app` rule will perform actions before calling `X-HEEP` Makefile's `app` rule. In this case, the project and where the source files are to be extracted from is being specified. The `SOURCE=.` argument will set `X-HEEP`'s own `sw/` folder as the directory from which to fetch source files. This is an example of building inner sources from an external directory. * The `verilator-sim` rule will override the `X-HEEP` Makefile's one. * Any other target will be passed straight to `X-HEEP`'s Makefile. For example -``` +```sh make mcu-gen CPU=cv32e40x ```
+### Excluding files from compilation +If you have files that need to be excluded from the gcc compilation flow, you can add them to a directory containing the keyword `exclude`, and/or rename the file to include the keyword `exclude`. +In the following example, the files marked with ✅ will be compiled, and the ones marked with ❌ will not. + + BASE + ├── sw + │ ├── applications + │ │ └── your_app + │ │ ├── ✅ main.c + │ │ ├── ✅ your_app.c + │ │ ├── your_app.h + │ │ ├── ❌ my_kernel_exclude.c + │ │ ├── my_kernel.h + │ │ └── exclude_files + │ │ └── ❌ kernel_asm.S + + + +### Makefile help +If you want that the commands `make` or `make help` show the help for your external Makefile, add the following lines before the first `include` directive or target. + +
+ Addition to print the target's help + +```Makefile +# HEEP_DIR might already be defined, you may want to move it to the top +export HEEP_DIR = hw/vendor/esl_epfl_x_heep/ + +# Get the path of this Makefile to pass to the Makefile help generator +MKFILE_PATH = $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") +export FILE_FOR_HELP = $(MKFILE_PATH)/Makefile + + +## Call the help generator. Calling simply +## $ make +## or +## $ make help +## Will print the help of this project. +## With the parameter WHICH you can select to print +## either the help of X-HEEP (WHICH=xheep) +## or both this project's and X-HEEP's (WHICH=all) +help: +ifndef WHICH + ${HEEP_DIR}/util/MakefileHelp +else ifeq ($(filter $(WHICH),xheep x-heep),) + ${HEEP_DIR}/util/MakefileHelp + $(MAKE) -C $(HEEP_DIR) help +else + $(MAKE) -C $(HEEP_DIR) help +endif +``` + +
+ +> Remeber to add double hashes `##` on any comment you want printed on the help. +> Use `## @section SectionName` to divide the documentation in sections + ### Different use cases If you plan to vendorize `X-HEEP` in a different directory than the one proposed, just update in your `BASE/Makefile`: ``` @@ -343,3 +401,10 @@ If you plan to store source files in a different location that the one proposed, make app PROJECT=your_app SOURCE= ``` Consider that inside this `sw` folder the same structure than the one proposed is required. + + +## Inter-process communication using Verilator's DPI + +The following [repository](https://github.com/specs-feup/x-heep) uses X-HEEP and the Verilator simulator to model a CPU-CGRA hybrid system. This architecture simulates the CPU integrated into the X-HEEP system, and an external Java process simulates the accelerator. Both components require a communication channel to exchange instructions and data. Using the existing infrastructure to to interact with an external OS process is not feasible at first sight, given that the X-HEEP ecosystem's pipeline encapsulates most of the simulation build and execution, with all modules supplied directly to Verilator. + +To circumvent this issue, this project uses [Direct Programming Interface (DPI)](https://verilator.org/guide/latest/connecting.html) calls (defined in `hw/ip_examples/cgraitf/cgraitfdpi.c`) to establish a connection and communicate with an external process through a Unix Domain Socket. This behavior mirrors the UART module (used as the skeleton code) that connects and outputs _printf_ information to the pseudo-terminal. These calls are embedded in a mock CGRA peripheral/interface, located in `hw/ip_examples/cgraitf/cgraitf.sv`. The module overrides reads and writes to the specified peripheral address, with the proper socket-based mechanism (_send_ or _recv_). The _simple_accelerator_ module could also be similarly customized to perform the same operations, using X-HEEP's interfaces and memory access protocols. A given user program executed in the CPU (such as `sw/applications/cgra_itf/main.c`) must then select assignments to or from the address to trigger the appropriate action. \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md index e955df91..6b57642f 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md @@ -1,327 +1,376 @@ + # DMA The **Direct Memory Access (DMA)** peripheral allows data transfers with reduced CPU interaction. It can perform *transactions* of data between peripherals and memory, or memory-to-memory (as a `memcpy` would). The CPU is required to configure the transaction, but once launched it is free to go to sleep, process the incoming data or do anything else. - + The DMA **Hardware Abstraction Layer (HAL)** facilitates the configuration of transactions from the users application. Furthermore, it adds an additional layer of safety checks to reduce the risk of faulty memory accesses, data override or infinite loops. - - + + ## Previous Definitions The implementation of this software layer introduced some concepts that need to be understood in order to make proper use of the DMA's functionalities . - + ### Transaction -A transaction is an operation to be performed by the DMA. It implies copying bytes from a source pointer into a destination pointer. The transaction configuration can be loaded into the DMA registers once it has been cross-checked and it only starts when the size of the transaction is written in its corresponding register. The transaction is finished once the DMA has sent all its bytes (which not necessarily means they have been received by the final destination). +A transaction is an operation to be performed by the DMA. It implies copying bytes from a source pointer into a destination pointer. The transaction configuration can be loaded into the DMA registers once it has been cross-checked and it only starts when the size along the *first dimension* of the transaction is written in its corresponding register. The transaction is finished once the DMA has sent all its bytes (which not necessarily means they have been received by the final destination). Transactions cannot be stopped once they were launched. While a transaction is running, new transactions can be validated, but not launched or loaded into the DMA. Transactions can be re-launched automatically in `circular mode`. Once the transaction has finished, a status bit is changed (that can be monitored through polling) and a fast interrupt is triggered. - + ### Source and destination Sources and destinations are the two pointers that will exchange data. Bytes will be copied from the source and into the destination address. - + ### Data type The DMA allows transactions in chunks of 1, 2 or 4 Bytes (`Byte`, `Half-Word` and `Word` respectively). The size in bytes of the chosen data type is called _data unit_ (usually abbreviated as `du`). For example, 16 bytes can be 16 data units if the data type is `Byte`, but 8 data units if the data type is `Half Word`. - +Source and destination can have different data types, if the destination type is wider than the source type, data can be sign extended. +### Sign extension +If specified (setting the bit in the corresponding register) and if the destination data type is wider than the source type, sign of the source data is extended to fill the size of the destination data type. + +### Dimensionality +The DMA can perform both **1D transactions** and **2D transactions**. +When set to perform 1D transactions, the DMA copies the defined number of elements from the source pointer to the destination pointer using a 1D increment. +When set to perform 2D transactions, the DMA copies data from the source pointer to the destination pointer using both a 1D increment and an additional 2D increment. +In this way, two-dimensional data manipulations (e.g. matrix manipulations) can be performed in a single DMA transaction, greatly reducing the CPU time. ### Increment -In the case that source and/or destination data are not to be consecutively read/written, a certain increment can be defined. +In the 1D configuration, if source and/or destination data are not to be consecutively read/written, a certain increment can be defined. For instance, if you have an array of 4-bytes-words, but only want to copy the first 2 bytes of each word, you could define the transaction with a data type of half word, an increment of 2 data units in the source, and 1 data unit in the destination. This way, after each read operation the DMA will increment the read pointer in 4 bytes (2 data units), but the write pointer by only 2 bytes. +In the 2D configuration, a second increment has to be set in order to enable the 2D transaction. +In the context of matrix manipulation, the 2D increment is the number of words that the DMA has to "skip" to move to the next row. +For instance, let's examine the extraction of a continuous 2x2 matrix from a 4x4 matrix, stored in a continuous 2x2 matrix. +``` +| 3 | 5 | 7 | 9 | +| 2 | 4 | 6 | 8 | -> | 3 | 5 | +| 1 | 3 | 5 | 7 | | 2 | 4 | +| 0 | 2 | 4 | 6 | +``` +The total number of elements copied from the source is 4 elements. The increments are: + - For the source: + - 1D increment set to 1 word + - 2D increment set to 3 words + - For the destination: + - 1D increment set to 1 word + - 2D increment set to 1 word +By exploiting the 2D increment, it's possible to implement a non-continuous read and/or write by computing the correct 2D increment. Detailed formulas for the computation of 2D increments are reported in the *example_dma_2d* folder. + +### Zero padding + +The DMA is capable of performing zero padding on the extracted data, both in 1D and 2D transactions. +This is done by by setting four padding parameters: +- **T**op +- **B**ottom +- **L**eft +- **R**ight + +e.g. + +``` +| T | T | T | T | T | +| L | x | x | x | R | +| L | x | x | x | R | +| B | B | B | B | B | +``` +It's important to highlight the fact that the padding is performed (conceptually) only *after* the matrix has been extracted. +Let's examine the previous 2x2 extraction example, adding a left and top padding of 1 word: + +``` +| 3 | 5 | 7 | 9 | | 0 | 0 | 0 | +| 2 | 4 | 6 | 8 | -> | 0 | 3 | 5 | +| 1 | 3 | 5 | 7 | | 0 | 2 | 4 | +| 0 | 2 | 4 | 6 | +``` ### Alignment When doing transactions with bytes, the DMA can read/write from any pointer. However, if the data type is larger, words should be aligned so the DMA can perform a read/write operation and affect only the chosen bytes. If a word or half-word's pointer is not a multiple of 4 or 2 (respectively), the pointer is _misaligned_. In some cases the DMA HAL can overcome this problem reducing the data type (which will reflect on an efficiency loss). - + ### Environment An environment is a region of memory that can optionally be defined by the user to let the HAL know that it is allowed to read/write on that region. It is useful to make sure the DMA will not affect reserved memory regions. Right now, read and write permissions are not supported by environments, meaning that if it is defined, the DMA will be able to read AND write on it. - + ### Triggers and Slots If the source or destination pointer is a peripheral, there are lines connecting the peripheral and the DMA that can be used to control the data flow (they behave as _triggers_). These lines are connected to _slots_ on the DMA and they allow/stop the DMA from reading/writing data. - + ### Target A target is either a region of memory or a peripheral to which the DMA will be able to read/write. When targets are pointing to memory, they can be assigned an environment to make sure that they will comply with memory restrictions. Targets include a pointer (a point in the memory, or the Rx/Tx buffer in case of peripherals), a size to be copied (if its going to be used as a source), a data type and an increment. - + ### Configuration flags During the creation or configuration of environments, targets or transactions, there could be inconsistencies or threatening situations (like writing outside the boundaries of a defined region). To provide the user with information about this potentially harmful situations, configuration flags are set while creating each of these entities. They can be unmasked and checked. In some cases, when the threat is too risky, a _crucial error_ might be raised and the operation of the configuration is halted. If senseless configurations are input to functions, assertions may halt the whole program. This is reserved for extreme situations that mean the program was not properly coded (e.g. a slot value is provided and is not among the available ones). - + ### Transaction modes There are three different transaction modes: **Single Mode:** The default mode, where the DMA will perform the copy from the source target to the destination, and trigger an interrupt once done. **Circular mode:** To take full advantage of the speed and transparency of the DMA, a _circular_ mode was implemented. When selected, the DMA will relaunch the exactly same transaction upon finishing. This cycle only stops if by the end of a transaction the _transaction mode_ was changed to _single_. The CPU receives a fast interrupt on every transaction finished. -**Address Mode:** Instead of using the destination pointer and increment to decide where to copy information, an _address list_ must be provided, containing addresses for each data unit being copied. It is only carried out in _single_ mode. - +**Address Mode:** Instead of using the destination pointer and increment to decide where to copy information, an _address list_ must be provided, containing addresses for each data unit being copied. It is only carried out in _single_ mode. +In this mode it's possible to perform only 1D transactions. + ### Windows In order to process information as it arrives, the application can define a _window size_ (smaller than the _transaction size_. Every time the DMA has finished sending that given amount of information will trigger an interrupt through the PLIC. > :warning: If the window size is a multiple of the transaction size, upon finishing the transaction there will be first an interrupt for the whole transaction (through the FIC), and then an interrupt for the window (through the PLIC, which is slower). - - + + ### Checks and Validations The DMA HAL's interface functions perform two types of checks: -* **Sanity checks**: Make sure that each individual value passed as an argument is reasonable and belongs to the proper domain. This errors will raise an _assertion_ and, depending on how assertions are managed in the application, may result in the program crashing. -* **Integrity checks**: Arguments are cross-checked to make sure that they abide by the rules of the DMA. If configurations are incompatible, contradictory, or a risk for the programs integrity, warnings are raised through the _configuration flags_. In some special cases, a _critical error_ can be raised, which blocks the deployment of the configuration into the DMA registers. - +* **Sanity checks**: Make sure that each individual value passed as an argument is reasonable and belongs to the proper domain. This errors will raise an _assertion_ and, depending on how assertions are managed in the application, may result in the program crashing. +* **Integrity checks**: Arguments are cross-checked to make sure that they abide by the rules of the DMA. If configurations are incompatible, contradictory, or a risk for the programs integrity, warnings are raised through the _configuration flags_. In some special cases, a _critical error_ can be raised, which blocks the deployment of the configuration into the DMA registers. + > :warning: Integrity checks can be disabled to speed up configuration time. Do this only if you have previously checked the configuration and are sure it will not cause any trouble. - + Checks and validations are performed during the transactions creation, loading and launching. - + A transaction is validated if it went through the creation-checks without raising critical errors. - + ### End events The DMA considers a certain amount of bytes to have been transferred once it has sent them. It does not wait for a confirmation from the recipient. When a transaction/window is finished the DMA performs a series of event. These may include: * Changing its status register. * Raising a _transaction done_ interrupt. * Raising a _window done_ interrupt. - + The DMA HAL can follow up on these changes or let the application be in charge. For this purpose, three different types of _end events_ are defined: -* **Polling**: The HAL will disable interrupts from the DMA. The application will need to frequently query the status of the DMA to know when a transaction has finished. -* **Interrupt**: Interrupts will be enabled. The _window done interrupt_ is enabled if a window size is provided. -* **Interrupt wait**: The DMA HAL will block the program in a `wfi()` state until the _transaction done interrupt_ is triggered. - - +* **Polling**: The HAL will disable interrupts from the DMA. The application will need to frequently query the status of the DMA to know when a transaction has finished. +* **Interrupt**: Interrupts will be enabled. The _window done interrupt_ is enabled if a window size is provided. +* **Interrupt wait**: The DMA HAL will block the program in a `wfi()` state until the _transaction done interrupt_ is triggered. + + ## Operation This section will explain the operation of the DMA through the DMA HAL. There is a DMA instance inside X-HEEP, but others can be connected outside through the bus (see the `example_external_peripheral` application in `sw/aplications/example_external_peripheral/main.c`). As long as the DMA instance is the same and the registers are memory mapped with the same structure, the DMA HAL can be used. - + The DMA HAL adds an extra computational overhead to transactions in order to check the consistency of the transaction configurations. By-passing this layer (and the steps here described) is disadvised. For the efficiency-hungry applications, doing at least one pass with the whole validation process is recommended. The HAL allows to load and launch transactions with minimum overhead afterwards. - + The following explanation makes use of Figure 1. - + ![DMA HAL-HW + addresses](https://github.com/esl-epfl/x-heep/assets/54960111/3092faa5-c72c-4cd9-a4d4-4c87de63d1c7) -

Figure 1: Example operation of the DMA and its HAL

- +

Figure 1: Example operation of the DMA and its HAL

+ --- - -The use of the DMA starts with the application creating a set of targets (**a**) . In the figure, the source target is a peripheral connected to an SPI and to the DMA. The address of the reception FIFO (_Rx FIFO_) of this SPI is `0x70` (**b**) . The destination target is a region of memory of address `0x16` (**c**). It is located inside an environment that spans from `0x12` to `0x35`. Any number of environments and targets can be created, and not used. - + +The use of the DMA starts with the application creating a set of targets (**a**) . In the figure, the source target is a peripheral connected to an SPI and to the DMA. The address of the reception FIFO (_Rx FIFO_) of this SPI is `0x70` (**b**) . The destination target is a region of memory of address `0x16` (**c**). It is located inside an environment that spans from `0x12` to `0x35`. Any number of environments and targets can be created, and not used. + Additionally, in the application the transaction is created. The _operation mode_ and _window size_ are selected. - -The application calls the validation function of the HAL. If the configurations do not raise a critical flag, it then calls the loading function. By doing so, the desired values are written into their corresponding registers (**d**). The only register that is not immediately written is the _transaction size_, as it is the one responsible for launching the transaction when changed from zero to a non-zero value. It is only written once the application calls the launching function (**e**). - + +The application calls the validation function of the HAL. If the configurations do not raise a critical flag, it then calls the loading function. By doing so, the desired values are written into their corresponding registers (**d**). The only register that is not immediately written is the _transaction size_, as it is the one responsible for launching the transaction when changed from zero to a non-zero value. It is only written once the application calls the launching function (**e**). + Note that there could be some changes between the configuration input in the application and the values written in the registers. For example, a _window size_ of 2 refers to _2 data units_ (i.e. 2 half-words, as such is the data type of the source in Figure 1); however, when writing on the register, this is translated to bytes, so 4 is written instead. - -Once launched, the transaction will execute completely (it cannot be stopped). Upon finishing, it will check the _operation mode_ and _transaction size_ registers. If any of both is non-zero, it will relaunch. Note that the selecting _circular mode_ during the configuration loading does not launch the transaction (despite what step (**f**) might suggest, which is only illustrative). - - -Once the transaction is launched, the DMA will take care of copying as many data units as were requested from the source target (**g**), and pasting them into the destination target (**h**). The data width of the transaction is determined by the _data type_ of the source target (**i**). However, this might be changed (for a smaller width) in case of misalignment. It is possible to reject changes by the DMA HAL and raise an error in case of misalignments instead. - -The selected slot will query the state of a trigger from the peripheral (**j**). In case the peripheral's FIFO is empty/full (for reception/transmission respectively), the transaction is paused until the trigger enables it again. - + +Once launched, the transaction will execute completely (it cannot be stopped). Upon finishing, it will check the _operation mode_ and _transaction size_ registers. If any of both is non-zero, it will relaunch. Note that the selecting _circular mode_ during the configuration loading does not launch the transaction (despite what step (**f**) might suggest, which is only illustrative). + + +Once the transaction is launched, the DMA will take care of copying as many data units as were requested from the source target (**g**), and pasting them into the destination target (**h**). The data width of the transaction is determined by the _data type_ of the source target (**i**). However, this might be changed (for a smaller width) in case of misalignment. It is possible to reject changes by the DMA HAL and raise an error in case of misalignments instead. + +The selected slot will query the state of a trigger from the peripheral (**j**). In case the peripheral's FIFO is empty/full (for reception/transmission respectively), the transaction is paused until the trigger enables it again. + The source and destination increments will determine the amount of steps the pointer should jump after every read and write, respectively. For peripherals it should always be zero (as it should always take the first element of the FIFO). - -The DMA will consider a data unit was transferred once it is sent (**k**). It does not wait for an acknowledge by the destination target. - -The _interrupts_ register controls whether the events triggered by the DMA upon finishing a window or a whole transaction should be propagated as interrupts (**l**). - -Every time _window size_ data units have been transferred the window count is incremented and a PLIC interrupt is triggered (if enabled) (**m**). - -Every time a transaction is finished a FIC interrupt is triggered and the restart condition is evaluated (**f**). - + +The DMA will consider a data unit was transferred once it is sent (**k**). It does not wait for an acknowledge by the destination target. + +The _interrupts_ register controls whether the events triggered by the DMA upon finishing a window or a whole transaction should be propagated as interrupts (**l**). + +Every time _window size_ data units have been transferred the window count is incremented and a PLIC interrupt is triggered (if enabled) (**m**). + +Every time a transaction is finished a FIC interrupt is triggered and the restart condition is evaluated (**f**). + If the window size is a multiple of the transaction size, upon finishing the transaction there will be first an interrupt for the whole transaction (through the FIC), and then an interrupt for the window (through the PLIC, which is slower). - - -The DMA HAL has weak implementations to handle each interrupt. It is up to the application to do something useful with this. the HAL will only forward the interrupt (**n**). - + + +The DMA HAL has weak implementations to handle each interrupt. It is up to the application to do something useful with this. the HAL will only forward the interrupt (**n**). + > :warning: If the window size is too small (i.e. the time the DMA requires to make the copy is smaller than the time required to attend the interrupt handling), data might be lost. The HAL implements a warning in case the transaction-window size ratio is to small. The warning can be re-configured to an appropriate threshold by overriding a weak implementation. The user should do its own testing and choose this threshold accordingly. The same type of issue might be found on circular mode. The user should be sure it can attend an interrupt before the next one occurs. There is no warning from the HAL in this case. - -The same result from this example could have been achieved by setting the transaction mode to _address_. It requires an array of destination addresses (**p**) that must be provided as the destination target pointer. Instead of copying information to that pointer, the DMA will read from there and copy the information into the addresses stored in each word (**o**). + +The same result from this example could have been achieved by setting the transaction mode to _address_. It requires an array of destination addresses (**p**) that must be provided as the destination target pointer. Instead of copying information to that pointer, the DMA will read from there and copy the information into the addresses stored in each word (**o**). This use case is very impractical as it doubles the memory usage. It is intended to be used along In-Memory-Computing architectures and algorithms. - + ## Usage This section will explain a basic usage of the DMA as a `memcpy`, and a slightly more complex situation involving a peripheral connected via an SPI. - + ### Basic application This example will provide a simplified code for copying data from one region of memory to another. For a real implementation please refer to the `dma_example` application in `sw/applications/dma_example/main.c`. - + The objective of this app would be to copy the content of an array into another. - + --- - + Start the application by calling ```C dma_init( NULL ); ``` - + This will reset the DMA registers. The `NULL` parameter tells the HAL that the devices internal DMA is to be used. - + The most basic implementation requires the creation of **two targets** and a **transaction** relating them both. - + A target will include the information of the source or destination pointer and the characteristics of the expected transaction. - + Theoretically, there is no required difference between a _source_ and _destination_ target. They will only be differentiated once the transaction is created. Eventually, they could be interchanged from one transaction to the next. In this example they will be given explicit names and will take different arguments for the sake of clarity. - + ```C static dma_target_t tgt_src = { - .ptr = copy_buffer, - .inc_du = 1, - .size_du = sizeof(copy_buffer), - }; + .ptr = copy_buffer, + .inc_du = 1, + .size_du = sizeof(copy_buffer), + .type = DMA_DATA_TYPE_WORD + }; ``` - + Here, `ptr = copy_buffer` is a `uint32_t` pointer from where the information will be extracted. `inc_du = 1` is telling the DMA that for each word copied, the pointer should be incremented by 1 unit, therefore words will be copied consecutively without gaps. - + This configuration is implicitly initializing the rest of the target configurations as zero (as of [C99](https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)). This means that: * No environment is set. * Data type is set to _word_ (32-bits). * The trigger is set to _memory_ (vs. a peripheral). - -The destination target can also dispense of a size, as the source size will be used. - ```C static dma_target_t tgt_dst = { .ptr = copy_buffer, .inc_du = 1, + .size_du = sizeof(copy_buffer), + .type = DMA_DATA_TYPE_WORD }; ``` - +Both destination and source targets have to contain a data type (they can be different) and size in data units (they should be the same). Finally, a transaction is created to relate both targets: - + ```C -static dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - }; +static dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + }; ``` - + This will also imply some configurations set to zero: * Mode is set to singular (only one transaction will be executed). * There will be no window interrupts. * The application will have to do polling to know when the transaction has finished. - + The transaction can now be created (some extra configurations are computed from the targets), loaded into the DMA and launched. - + ```C dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); dma_load_transaction( &trans ); dma_launch( &trans ); - + ``` - + When creating the transaction, the two last parameters are allowing the DMA to perform integrity checks and try some fixes (at the expense of efficiency) if misalignments are found. - + As there will be no interrupts set, the application has to check by itself the status of the transaction. - + ```C while( ! dma_is_ready() ){} // The transaction has finished! ``` - - + + ### Complete Application The objective of this example is to show various special cases, precautions and considerations that can be taken. For a real example refer to the `spi_flash_write` application in `sw/applications/spi_flash_write/main.c`. - + This example will copy every other byte from a buffer in RAM to a FLASH connected via an SPI to the DMA. Then, it will copy information from an SPI peripheral continuously into a small buffer. - + This explanation assumes you have read the previous example. - + --- - + Start the application by calling ```C dma_init( NULL ); ``` - + The first source target will be pointing to a `uint16_t` buffer in memory. Data will be copied in chunks of 1 byte. For every half-word (16 bits), the only the second half (second 8 bits) will be copied. - + ```C -static dma_target_t tgt1= { - .ptr = (uint8_t*)(copy_buffer + 1), - .inc_du = 2, - .size_du = sizeof(copy_buffer), - .type = DMA_DATA_TYPE_BYTE, -}; - +static dma_target_t tgt1= { + .ptr = (uint8_t*)(copy_buffer + 1), + .inc_du = 2, + .size_du = sizeof(copy_buffer), + .type = DMA_DATA_TYPE_BYTE, + }; ``` - + To start copying information from the second byte of `copy_buffer`, the source pointer is set to the address of `copy_buffer` plus one byte. In order to copy one byte and skip another, the data type is set to byte, and the increment is set to two data units (i.e. two bytes). As for every half-word of the buffer a data unit will be copied, the transaction size is the same as the size of the `copy_buffer`. - - + + The second target will point to the address of the SPI FLASH transmission FIFO. On this example, this value was already computed and stored in a constant `ADDRESS_SPI_FLASH_TX_FIFO`. - - + + ```C -static uint32_t *spi_flash_fifo_tx = ADDRESS_SPI_FLASH_TX_FIFO; - - -static dma_target_t tgt2= { - .inc_du = 0, - .trig = DMA_TRIG_SLOT_SPI_FLASH_TX, -}; - +static uint32_t *spi_flash_fifo_tx = ADDRESS_SPI_FLASH_TX_FIFO; + + +static dma_target_t tgt2= { + .inc_du = 0, + .trig = DMA_TRIG_SLOT_SPI_FLASH_TX, + }; tgt2.ptr = spi_flash_fifo_tx; - ``` - + Because structure initializers need to be constants, the pointer value (which is a non-constant variable) needs to be initialized outside the designated initializer. - - + + There is no need to assign a value of transaction size or data type. By default, the DMA will use the source's values. The data type could eventually be modified by the HAL if there is a misalignment and `DMA_ENABLE_REALIGN` is set when creating the transaction. - + The increment needs to be set to zero as the pointer should always be set to the FIFO address. - + Because the SPI FLASH transmission FIFO has a line connected to slot number 4 (codified as a `1` in the fourth bit of the `trig` element) to let the DMA know if the FIFO is full, a trigger is set in that position by passing `.trig = DMA_TRIG_SLOT_SPI_FLASH_TX`. - - + + The transaction is formed by selecting the source and destination targets - + ```C -static dma_trans_t trans = { - .src = &tgt1, - .dst = &tgt2, - .end = DMA_TRANS_END_INTR, - }; +static dma_trans_t trans = { + .src = &tgt1, + .dst = &tgt2, + .end = DMA_TRANS_END_INTR, + }; ``` - + To enable interrupts, the end event is set to `DMA_TRANS_END_INTR`. - - + + To create the transaction allowing the DMA to perform necessary realignments and integrity checks such arguments are passed to the creation function along with a pointer to the transaction. - + ```C dma_config_flags_t res; res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); ``` - + The result variable `res` contains configuration flags that can be used to check that no errors or warnings were raised. These are codified as bits in the 16-bit `res` variable. If only one flag was raised, the value of `res` will be equal to it. Otherwise, they can be checked by selecting individual bits, with inequalities, or comparing the result to a bitwise-or of flags. - + ```C if( res == DMA_CONFIG_OK ) // Everything was ok. if( res & DMA_CONFIG_CRITICAL_ERROR ) // A critical error was found. It has to be fixed or the transaction will not be loaded. if( res >= DMA_CONFIG_OVERLAP && res =< DMA_CONFIG_TRANS_OVERRIDE ) // One or more warning flags were raised between those two. if( res & ( DMA_CONFIG_SRC | DMA_CONFIG_DST) ) // Either one of the flags was raised. ``` - + The transaction can then be loaded into the DMA registers by calling the load function ```C res = dma_load_transaction( &trans ); ``` - + and launched ```C res = dma_load_transaction( &trans ); ``` - + Because the DMA will raise an interrupt as soon as it has sent all of its information, it is recommended to wait for the SPI interrupt. ```C -while( spi_intr_flag == 0 ) -{ - wait_for_interrupt(); +while( spi_intr_flag == 0 ) { + wait_for_interrupt(); } ``` - + If something is to be done as soon as the DMA finishes (like preparing a new transaction) it can be triggered by the interrupt attention routine: ```C -void dma_intr_handler_trans_done() -{ - // Raise a flag to trigger an action +void dma_intr_handler_trans_done() { +// Raise a flag to trigger an action } ``` This function is a strong implementation defined in the application of the weak one in `dma.c`. - - + + During this transaction * The DMA grabbed the first byte of from the pointer (i.e. the second of the buffer, letter `B` in the chart below). * Sent it to the SPI, where it will be treated as a 32-bit word. @@ -329,162 +378,212 @@ During this transaction * The source pointer was increased by two data units (i.e. two bytes) to point letter `D` from the chart. * The DMA grabbed that byte and sent it to the SPI. * The process went on until the the last byte (letter `L`) is sent to the SPI. - - - - +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RAMFLASH
ABCD000B
EFGH000D
IJKL000F
........
RAMFLASH
ABCD000B
EFGH000D
IJKL000F
........
- - + + --- - - + + For the second part of this example, the targets will be modified and their role switched. - + The source of the data will be a peripheral connected to the SPI, which will be continuously sending information in half-word format, in streams of 4096 bytes (2048 half-words). Every 1024 half-words there should be a `MILESTONE-CHARACTER`, if there is not, the data flow should be stopped. - + ```C -tgt2.ptr = spi_peripheral_fifo_rx; -tgt2.size_du = 2048; -tgt2.type = DMA_DATA_TYPE_HALF_WORD; -tgt2.trig = DMA_TRIG_SLOT_SPI_RX; +tgt2.ptr = spi_peripheral_fifo_rx; +tgt2.size_du = 2048; +tgt2.type = DMA_DATA_TYPE_HALF_WORD; +tgt2.trig = DMA_TRIG_SLOT_SPI_RX; ``` - + The source pointer is set to the reception FIFO of the SPI, and the appropriate slot is chosen. The increment is kept in zero. - + The destination pointer will be given by a function. - + ```C -tgt1.ptr = (uint8_t*) myApp_getDestination(); +tgt1.ptr = (uint8_t*) myApp_getDestination(); ``` - + To guarantee that the result of this function will not cause the DMA to write in undesired regions of memory, an environment can be created. It requires two pointers to the first and last byte where the DMA will be authorized to make any action. ```C -static dma_env_t safe_zone = { - .start = ADDRESS_START_OF_SAFE_ZONE, - .end = ADDRESS_END_OF_SAFE_ZONE, +static dma_env_t safe_zone = { + .start = ADDRESS_START_OF_SAFE_ZONE, + .end = ADDRESS_END_OF_SAFE_ZONE, }; ``` - + The environment can be assigned to the target. ```C -tgt1.env = &safe_zone; +tgt1.env = &safe_zone; tgt1.inc_du = 1; ``` - + Size and data type is up to the source, and the rest of the configurations are inherited from the last transaction. - + The transaction is conformed as: ```C -window_size_du = 1024; - -trans.src = &tgt2; -trans.dst = &tgt1; -trans.mode = DMA_TRANS_MODE_CIRCULAR; -trans.win_du = window_size_du; - +window_size_du = 1024; + +trans.src = &tgt2; +trans.dst = &tgt1; +trans.mode = DMA_TRANS_MODE_CIRCULAR; +trans.win_du = window_size_du; + ``` - + Meaning that the information will start to flow into the target 1 from target 2, and every 1024 half-words transferred the application will get an interrupt to check if the `MILESTONE_SYMBOL` is present. Upon finishing the transaction, it shall start again to refill the buffer as it was set in `CIRCULAR_MODE`. - + The amount of times the buffer was filled will be updated on every _transaction done_ interrupt. ```C -void dma_intr_handler_trans_done() -{ - transaction_count++; +void dma_intr_handler_trans_done() { + transaction_count++; } ``` - + The search for the `MILESTONE_SYMBOL` can be done inside the _window done_ interrupt handling. ```C -void dma_intr_handler_window_done() -{ - /* The current window is obtained. The count is zero when no windows have yet been written. When it is set to one, the window zero is ready. */ - window_count = dma_get_window_count() -1; - /* The pointer to the symbol is obtained from the destination pointer + the amount of half-words that have been written. this assumes the symbol is on the first element of each chunk.*/ - address = (uint16_t *)trans.dst->ptr + window_count*window_size_du; - symbol = *address; - if( symbol != MILESTONE_SYMBOL ) - { - /* If the symbol was not the expected one, future transactions should not be carried out.*/ - dma_stop_circular(); - /* The number of the first window with error is saved to analyze it later.*/ - error_window = error_window == 0 ? window_count : error_window; - } +void dma_intr_handler_window_done() { + /* The current window is obtained. The count is zero when no windows have yet been written. When it is set to one, the window zero is ready. */ + window_count = dma_get_window_count() -1; + /* The pointer to the symbol is obtained from the destination pointer + the amount of half-words that have been written. this assumes the symbol is on the first element of each chunk.*/ + address = (uint16_t *)trans.dst->ptr + window_count*window_size_du; + symbol = *address; + if( symbol != MILESTONE_SYMBOL ){ + /* If the symbol was not the expected one, future transactions should not be carried out.*/ + dma_stop_circular(); + /* The number of the first window with error is saved to analyze it later.*/ + error_window = error_window == 0 ? window_count : error_window; + } } ``` > :warning: Interrupt attention routines are advised to be kept as short as possible. This example is merely illustrative. - + Once the `dma_stop_circular()` function is called, the DMA will still finish the transaction it is currently executing (which could be a whole transaction if the faulty window was the last one). It is important to save valuable information that might be overridden by the ongoing transaction (like the faulty window number). - - + + ## Testing This section will describe the available example application in X-HEEP using the DMA, and will outline the testing that needs to be performed in order to validate its proper operation. - - + + ### Available Applications - + There are 6 applications using the DMA: -* `dma_example`: Tests memory-to-memory transfer, the blocking of transactions while another one is in progress, and window interrupts. -* `example_external_peripheral`: Tests the use of the DMA HAL one a DMA instance external to X-HEEP. Only available for simulation. -* `example_virtual_flash`: Tests the transfer to/from an external flash through the DMA. -* `spi_flash_write`: Tests the transfer to/from the flash. Tests circular mode. Not available on FPGA if linker is `flash-exec`. Should be used with `mcu gen BUS=NtoM CPU=cv32e40p` to test circular mode. -* `spi_host_dma_exampe`: Test the transfer of data through the SPI host. Not available on Verilator. -* `spi_host_dma_power_gate_example`: Test the transfer of data through the SPI host. Not available on Verilator. - +* `dma_example`: Tests memory-to-memory transfer, the blocking of transactions while another one is in progress, and window interrupts. +* `example_external_peripheral`: Tests the use of the DMA HAL one a DMA instance external to X-HEEP. Only available for simulation. +* `example_virtual_flash`: Tests the transfer to/from an external flash through the DMA. +* `spi_flash_write`: Tests the transfer to/from the flash. Tests circular mode. Not available on FPGA if linker is `flash-exec`. Should be used with `mcu gen BUS=NtoM CPU=cv32e40p` to test circular mode. +* `spi_host_dma_exampe`: Test the transfer of data through the SPI host. Not available on Verilator. +* `spi_host_dma_power_gate_example`: Test the transfer of data through the SPI host. Not available on Verilator. + + +## 😎 X-pert Zone: + +If you know what you are doing and want to minimize the overhead of using the DMA, you can try by-passing the HAL and writing directly on the configuration registers. + +```c +/* We will copy a set of 25 half-words of 16 bits into a buffer of 32-bit words. +Each word in the destination buffer will have its 16 MSB set to 0, and the 16 LSB with the corresponding value from the source.*/ +#define HALF_WORDS_TO_COPY 25 +static uint16_t src_buffer[HALF_WORDS_TO_COPY]; // The source buffer +static uint32_t dst_buffer[HALF_WORDS_TO_COPY]; // The destination buffer + +/* Set the DMA's control block's peripheral structure to point to the address defined in core_v_mini_mcu.h */ +dma_cb.peri = dma_peri; +/* Activate interrupts*/ +dma_cb.peri->INTERRUPT_EN |= INTR_EN_TRANS_DONE; +/* Set the source and destination pointers*/ +dma_cb.peri->SRC_PTR = (uint16_t*) source_buffer; +dma_cb.peri->DST_PTR = (uint32_t*) dst_buffer; + +/* Set the source increment as 2 bytes (because the source buffer is uint16_t). +Set the destination increment as 4 bytes (because the destination buffer is uint32_t). +We write 1026 = 0000 0100 0000 0010, +as the first 8 LSB refer to the source, and the next 8 bits for the destination. */ +dma_cb.peri->PTR_INC = (uint32_t) 1026; + +/* Make sure that the DMA will point to memory.*/ +dma_cb.peri->SLOT = DMA_TRIG_MEMORY; + +/* Set the data transfer type as half-words.*/ +dma_cb.peri->TYPE = DMA_DATA_TYPE_HALF_WORD; + +/* Set the transaction size, this will launch the transaction. +If you want to restart the same transaction again, just run from here.*/ +dma_cb.peri->SIZE = HALF_WORDS_TO_COPY; + +/* Go to sleep until the DMA finishes.*/ +while( dma_cb.peri->STATUS == 0 ) { + /* Disable the interrupts MSTATUS to avoid going to sleep AFTER the interrupt + was triggered.*/ + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + /* If the transaction has not yet finished, go to sleep*/ + if (dma_cb.peri->STATUS == 0) { + /* If a interrupt happened before, the core would still wake-up, + but will not jump to the interrupt handler MSTATUS is not re-set. */ + { asm volatile("wfi"); } + } + /* Restore the interrupts. */ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); +} + + +``` diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/SPI.md b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/SPI.md new file mode 100644 index 00000000..72315f6c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/SPI.md @@ -0,0 +1,1246 @@ +# SPI Host + +```{contents} Table of Contents +:depth: 2 +``` + +There are three instances of the _SPI Host IP_ in the X-HEEP platform. These will +be defined throughout the documentation as: + +- SPI Host 1 +- SPI Host 2 +- SPI Flash + +## Preliminary Definitions + +### Transaction + +A transaction is defined by one or multiple command segments. + +### Command Segment + +A command segment is a single instruction provided to the _SPI Host IP_ specifying +speed, direction, and additional parameters discussed later. + +### SPI Host + +SPI Host refers to the particular hardware device for which this SDK and HAL have +been developed. _SPI Host_, _SPI Host IP_, and _SPI Host device_ are used +interchangeably. + +### TX and RX + +- TX: Transmission-related data or operations. + +- RX: Reception-related data or operations. + +### Slave and Target + +_Slave_ and _target_ are used interchangeably, referring to the SPI device that +responds to the SPI Host. + +### Word + +A word, when used as a unit of digital information, always refers to 32 bits +throughout the entire documentation. + + +## SDK Usage + +The SDK facilitates communication with external SPI devices through the `spi_t` +structure, which holds necessary information, including the specific _SPI Host IP_ +and external _SPI slave_ data. + +```c +typedef struct { + spi_idx_e idx; // The identifier for the desired SPI devide + uint32_t id; // spi_t instance ID + bool init; // Indicates if initialization was successful + spi_slave_t slave; // The slave with whom to communicate configuration +} spi_t; +``` + +- `idx` can be `SPI_IDX_FLASH`, `SPI_IDX_HOST` or `SPI_IDX_HOST_2`, +each referring to a specific _SPI Host IP_. + +- `id` is the identifier of the specific `spi_t` instance. + +- `init` is a boolean used to verify if the `spi_t` variable is properly initialized. + +- `slave` is the structure containing all information about the external SPI slave. + + +### The Slave + +The `spi_slave_t` structure is defined as: + +```c +typedef struct { + // The Chip Select line where device connected + uint8_t csid : 2; + // The data sampling and transmitting mode (polarity and phase) + spi_datamode_e data_mode : 2; + // If 1 data is sampled a full cycle after shifting data out, instead of half cycle + bool full_cycle : 1; + // The minimum number of sck half-cycles to hold cs_n high between commands + uint8_t csn_idle : 4; + // The number of half sck cycles, CSNTRAIL+1, to leave between last edge of sck + // and the rising edge of cs_n + uint8_t csn_trail : 4; + // The number of half sck cycles, CSNLEAD+1, to leave between the falling edge + // of cs_n and the first edge of sck + uint8_t csn_lead : 4; + // The maximum frequency in hertz of the slave + uint32_t freq : 32; +} spi_slave_t; +``` + +These fields depend on the external SPI slave you intend to communicate with. + +- `csid` is the _Chip Select_ ID (i.e. the line to which your slave is connected). +It can only be __0__ or __1__. + +- `data_mode` specifies the phase and polarity the slave uses. Possible values are: + + - `SPI_DATA_MODE_0`: Clock polarity 0, phase 0. (__active-high__ + SCK, sampling data on the __leading__ edge, and asserting data on the __trailing__ edge) + - `SPI_DATA_MODE_1`: Clock polarity 0, phase 1. (__active-high__ + SCK, sampling data on the __trailing__ edge, and asserting data on the __leading__ edge) + - `SPI_DATA_MODE_2`: Clock polarity 1, phase 0. (__active-low__ + SCK, sampling data on the __leading__ edge, and asserting data on the __trailing__ edge) + - `SPI_DATA_MODE_3`: Clock polarity 1, phase 1. (__active-low__ + SCK, sampling data on the __trailing__ edge, and asserting data on the __leading__ edge) + +- `full_cycle` determines if data should be sampled _half SCK_ cycle or a _full SCK_ cycle +after shifting out data. + +- `csn_idle`, `csn_trail`, and `csn_lead` indicate the number of _half SCK_ cycles to keep +the _CS_ line active between command segments, after segments, and before segments, +respectively. The actual number of cycles will be the specified number + 1. For instance, if +`csn_lead` is 5, the _CS_ line will go active 6 _half SCK_ cycles before executing the +command segment. + +- `freq` is the maximum desired frequency for the communication. The true frequency +will be an integer division of half the MCU core frequency. The integer divisor will +be computed by the SDK based on the maximum desired frequency provided, and will take +a value between 1 and 65536 (16 bits). This implies that the true frequency will never +be larger than half the MCU core frequency. The SDK will also return an invalid `spi_t` +if the desired maximum frequency provided is lower than half the MCU core frequency +divided by 65536. + +````{tip} +It is possible to change the frequency of a particular slave after initialization if +you wish to decrease or increase the communication speed with: + +```c +spi_codes_e spi_set_slave_freq(spi_t* spi, uint32_t freq); +``` +```` + + +### Initialization + +To start using the SDK, you must create an `spi_slave_t` and an `spi_t`. However, +the `spi_t` __can't__ be created directly; it must be created through the `spi_init` +function of the SDK to avoid unexpected behaviour. + +The function is defined as: +```c +spi_t spi_init(spi_idx_e idx, spi_slave_t slave); +``` + +This function checks the provided parameters and validates the slave configuration. +If there is any error it will return an invalid `spi_t` structure. This can be verified +by reading the `init` field of the structure. + +Example: +```c +spi_slave_t slave = { + .csid = 0, + .csn_idle = 15, + .csn_lead = 15, + .csn_trail = 15, + .data_mode = SPI_DATA_MODE_0, + .full_cycle = false, + .freq = FLASH_MAX_FREQ +}; + +spi_t spi = spi_init(SPI_IDX_FLASH, slave); + +if (spi.init) { + // Properly initialized +} +else { + // Initialization error +} +``` + +````{tip} +A slave with predefined standard values can be created using the macro: +```c +#define SPI_SLAVE(csid, freq) (spi_slave_t) { \ + .csid = csid, \ + .data_mode = SPI_DATA_MODE_0, \ + .full_cycle = false, \ + .csn_lead = 10, \ + .csn_trail = 10, \ + .csn_idle = 10, \ + .freq = freq \ +} +``` +```` + +```{note} +After initialization, the `freq` field of the `spi_slave_t` structure of the +`slave` field of the obtained `spi_t` structure, will provide the value of the +_true_ frequency, no longer the maximum desired frequency provided! +``` + +### Transactions + +Once the `spi_t` has been successfully initialized, communication with its slave +device can be performed via transactions, which are lists of command segments executed +by the _SPI Host IP_. + +#### Command Segments + +Each command segment consists of a simple instruction dermining the direction of +data transfer (TX, RX or Bidirectional), its speed (Standard, Dual, or Quad), and +the length of the data. + +The command segment structure `spi_segment_t` is as: + +```c +typedef struct { + uint32_t len : 24; // Length of data in bytes for the particular segment + spi_mode_e mode : 4; // Communication mode (TX, BIDIR, RX_QUAD, ...) +} spi_segment_t; +``` + +- `len` specifies the length in **bytes** of the data managed by this segment. +For instance, to send 4 32-bit words, the length would be 16. + +- `mode` indicates the data transfer direction and speed. Possible values are: + + - `SPI_MODE_DUMMY` + - `SPI_MODE_RX_STD` + - `SPI_MODE_TX_STD` + - `SPI_MODE_BIDIR` + - `SPI_MODE_RX_DUAL` + - `SPI_MODE_TX_DUAL` + - `SPI_MODE_RX_QUAD` + - `SPI_MODE_TX_QUAD` + +_DUMMY_ mode refers to a period where the _SPI Host IP_ sends _SCK_ pulses without +reading or sending any data. The number of _SCK_ pulses is determined by the `len` +field. For example, to send 10 _SCK_ pulses, `len` must be set to 10 (seems evident, +but I rather put it explicitly). + +```{note} +There are no _Dual_ or _Quad_ speeds for _Bidirectional_ mode because the _SPI Host IP_ +doesn't support it. +``` + +```{tip} +There are macros for each segment _mode_ simplifying command segment creation. + +The macros are: `SPI_SEG_DUMMY`, `SPI_SEG_TX`, `SPI_SEG_RX`, `SPI_SEG_BIDIR`, +`SPI_SEG_TX_DUAL`, `SPI_SEG_RX_DUAL`, `SPI_SEG_TX_QUAD`, and `SPI_SEG_RX_QUAD` + +Each macro takes one argument which sets the `len` field. +``` + +As mentioned above, a transaction comprises various command segments, so an array +of segments is required. + +For example: +```c +spi_segment_t segments[2] = { SPI_SEG_TX(4), SPI_SEG_RX(256) }; +``` + +#### TX/RX Buffers + +Since these segments transmit/receive data, appropriate TX and RX buffers are needed. +These buffers must be large enough to contain the data being transmitted/received to +avoid memory overwrites. + +For our example with 4 bytes of TX and 256 bytes of RX, the buffers would be: + +```c +uint32_t src_buffer = 0; +uint32_t dest_buffer[64] = {0}; +``` + +```{caution} +:name: caution-seglen-bufflen + +While segments with lengths not multiple of 4 are allowed, buffers **must** be multiples +of 4 bytes because the _SPI Host IP_ only allows reads from the RX _FIFO_ one word at +a time. + +It is the _segment length_ that will ultimately determine the amount of bytes effectively +transmitted/received, not the buffer size. + +For example, an RX segment of length 3 is fine, but the _dest\_buffer_ should be at least +4 bytes to avoid unexpected behavior. + +This design choice was made to avoid having various alignment computations, thus favoring +computational speed at expense of minimal amount of superfluous bytes. +``` + +#### Execution + +With the buffers and segments ready, the transaction can be issued using: + +```c +spi_codes_e spi_execute(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer); +``` + +This function returns `SPI_CODE_OK` if the transaction is successfully issued. Otherwise, +it returns an error code. + +And, after a transaction has completed, the result can be checked using: + +```c +spi_state_e spi_get_state(spi_t* spi); +``` + +Which returns `SPI_STATE_DONE` if the transaction completed successfully +(i.e. all segments were completed), `SPI_STATE_ERROR` if a hardware error occured +during the transaction, or `SPI_STATE_TIMEOUT` if the transaction has timed-out. + +````{important} +The SDK completely relies on _SPI Host IP_ interrupts in order to execute any +transaction. Therefore, it is crucial to **enable _SPI Host_ interrupts** at machine- +level before any transaction is initiated. + +Example + +```c +// Enable global interrupt for machine-level interrupts +CSR_SET_BITS(CSR_REG_MSTATUS, CSR_INTR_EN); +// Set mie.MEIE bit to one to enable machine-level fast spi_flash interrupt +const uint32_t mask = 1 << FIC_FLASH_MEIE; +CSR_SET_BITS(CSR_REG_MIE, mask); +``` +```` + +#### Example + +A complete example of executing a transaction: + +```c +// Assuming spi variable is properly initialized and machine-level interrupts have +// been enabled. + +// Define transaction command segments +spi_segment_t segments[2] = { SPI_SEG_TX(4), SPI_SEG_RX(256) }; +// Initialize data buffers +uint32_t src_buffer = 0; +uint32_t dest_buffer[64] = {0}; +// Execute the transaction +if (spi_execute(&spi, segments, 2, &src_buffer, dest_buffer) == SPI_CODE_OK) +{ + if (spi_get_state(&spi) == SPI_STATE_DONE) + { + // Transaction successful + } + else { + // Transaction error + } +} +else { + // Configuration error +} +``` + +#### Simplified Transaction Functions + +This method is the most configurable. However, there are simpler methods for common +transactions: + +```c +spi_codes_e spi_transmit (spi_t* spi, const uint32_t* src_buffer, uint32_t len); +spi_codes_e spi_receive (spi_t* spi, uint32_t* dest_buffer, uint32_t len); +spi_codes_e spi_transceive(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len); +``` + +```{caution} +The `len` parameter specifies the number of **bytes**, not words. +``` + +These functions execute basic standard transactions: `spi_transmit` performs a _TX Standard_ +transaction, `spi_receive` performs an _RX Standard_ transaction, and `spi_transceive` +performs a _Bidirectional Standard_ transaction. They work like `spi_execute` but do not +require command segments to be provided. + +#### Timeout + +All blocking functions have a maximum allowed time from the start of a transaction +to its complete execution. This duration can be easily configured and retrieved +using the following functions: + +```c +spi_codes_e spi_set_timeout(spi_t* spi, uint32_t timeout); + +spi_codes_e spi_get_timeout(spi_t* spi, uint32_t* timeout); +``` + +This timeout is entirely independent for each _SPI Host_ device. It specifies the +maximum number of **milliseconds** permitted to elapse from the issuance of the +first command segment to the hardware until the last 32-bit word is read from the +RX FIFO. + +The maximum allowed value for the timeout is {math}`2^{32}-1` (unless the core +clock frequency exceeds 4 THz, which is unlikely to occur in the near future :) ). +And the default timeout value is set to 100ms. + + +### Non-Blocking Transactions + +To allow the main program to continue processing while a transaction executes, each +transaction function has also a _non-blocking_ variant: + +```c +spi_codes_e spi_transmit_nb(spi_t* spi, const uint32_t* src_buffer, uint32_t len, + spi_callbacks_t callbacks); + +spi_codes_e spi_receive_nb(spi_t* spi, uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks); + +spi_codes_e spi_transceive_nb(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks); + +spi_codes_e spi_execute_nb(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer, spi_callbacks_t callbacks); +``` + +These functions differ in two aspects from their _blocking_ counterpart. First, these +functions return immediately after launching the transaction, allowing other data +processing while the transaction completes. Secondly, they take an additional parameter +of type `spi_callbacks_t`. + +#### Callbacks + +```c +// Callback type +typedef void (*spi_cb_t)(const uint32_t*, uint32_t, uint32_t*, uint32_t); + +// Callbacks structure +typedef struct { + spi_cb_t done_cb; // Called once transaction is done + spi_cb_t txwm_cb; // Called each time TX watermark event is triggered + spi_cb_t rxwm_cb; // Called each time RX watermark event is triggered + spi_cb_t error_cb; // Called when there was an error during transaction +} spi_callbacks_t; +``` + +The _callback_ type (`spi_cb_t`) is invoked with four arguments whenever the corresponding +event occurs: + +1. The _TX buffer_ associated to the transaction. +1. The current number of words in the _TX buffer_. +1. The _RX buffer_ associated to the transaction. +1. The current number of words in the _RX buffer_. + +Callbacks in `spi_callbacks_t` can be `NULL` if not needed. + +```{note} +In this context, the function `spi_get_state` previously explained, can be used to +check if the transaction is still ongoing (`SPI_STATE_BUSY`) or has finished. Once +finished the state will also become `SPI_STATE_DONE` or `SPI_STATE_ERROR` depending +on the result of the transaction. +``` + +```{tip} +It is possible to get or set the watermark values with the functions `spi_set_txwm`, +`spi_set_rxwm`, `spi_get_txwm`, and `spi_get_rxwm`. +``` + +#### Example + +```c +void done_cb(const uint32_t* txbuff, uint32_t txlen, uint32_t* rxbuff, uint32_t rxlen) +{ + // Do stuff with the data once the transaction is done +} + +int main(int argc, char *argv[]) +{ + // ... + + // We assume an spi variable has been created by properly initializing it and + // that machine-level interrupts have been appropriately enabled. + + uint32_t src_buffer = 0x1234 // For example a command to send to slave + uint32_t dest_buffer[12] = {0} // Slave's response + + // Notice that the segments' length are not multiples of 4. + spi_segment_t segments[2] = { SPI_SEG_TX(2), SPI_SEG_RX(45) }; + + // Define the callbacks. Notice we can assign NULL when we do not want any + // callback to be called + spi_callbacks_t callbacks = { + .done_cb = &done_cb, + .error_cb = NULL, + .rxwm_cb = NULL, + .txwm_cb = NULL + }; + + if (!spi_execute_nb(&spi, segments, 2, &src_buffer, dest_buffer, callbacks)) + { + while(spi_get_state(spi) == SPI_STATE_BUSY) + { + // Do stuff while SPI is busy + } + } + else { + // There was an error in the transaction configuration + } + + // ... +} +``` + +```{note} +In this example, the _TX segment length_ is 2 while _src\_buffer_ is 4 bytes long, +and the _RX segment length_ is 45 while _dest\_buffer_ is 48 bytes long. +For explanation, please refer to [this directive](#caution-seglen-bufflen). +``` + + +## HAL Usage + +### Overview + +The three instances of the _SPI Host IP_ of the X-HEEP platform can be referenced +in the HAL with the macros: + +- `spi_host1` for _SPI Host 1_. +- `spi_host2` for _SPI Host 2_. +- `spi_flash` for _SPI Flash_. + +These macros expand to variables of type `spi_host_t*`. They must be passed to any +HAL function requiring to reference the specific peripheral. + + +#### Return Flags + +Most functions in the HAL return an enum value of type `spi_return_flags_e`, indicating +the outcome of the operation. Below is the complete list of return flags: + +```c +typedef enum { + // Everithing went well + SPI_FLAG_OK = 0x0000, + // The SPI variabled passed was a null pointer + SPI_FLAG_NULL_PTR = 0x0001, + // The Watermark exceeded SPI_HOST_PARAM_TX_DEPTH or SPI_HOST_PARAM_RX_DEPTH + // and was therefore not set + SPI_FLAG_WATERMARK_EXCEEDS = 0x0002, + // The CSID was out of the bounds specified inSPI_HOST_PARAM_NUM_C_S + SPI_FLAG_CSID_INVALID = 0x0004, + // The CMD FIFO is currently full so couldn't write command + SPI_FLAG_COMMAND_FULL = 0x0008, + // The specified speed is not valid so couldn't write command + SPI_FLAG_SPEED_INVALID = 0x0010, + // The TX Queue is full, thus could not write to TX register + SPI_FLAG_TX_QUEUE_FULL = 0x0020, + // The RX Queue is empty, thus could not read from RX register + SPI_FLAG_RX_QUEUE_EMPTY = 0x0040, + // The SPI is not ready + SPI_FLAG_NOT_READY = 0x0080, + // The event to enable is not a valid event + SPI_FLAG_EVENT_INVALID = 0x0100, + // The error irq to enable is not a valid error irq + SPI_FLAG_ERROR_INVALID = 0x0200 +} spi_return_flags_e; +``` + + +**Note**: All functions in the HAL returning a `spi_return_flags_e` will **always** +return `SPI_FLAG_NULL_PTR` when the argument `spi_host_t* spi` is a `NULL` pointer +and `SPI_FLAG_OK` if the operation has suceeded. To avoid repetition, `SPI_FLAG_NULL_PTR` +and `SPI_FLAG_OK` will be omitted from discussions of function return values. Only +`spi_return_flags_e` different from these two will be mentioned. If there is any +doubt please refer to the functions documentation. + + +### Target Device Configuration + +Using the HAL begins by configuring the slave device(s) you intend to communicate +with. For this purpose, a configuration options structure, `spi_configopts_t`, is +provided, along with functions to write the slave configuration options to the +_SPI Host IP_. + +#### Configuration Options Structure + +```c +typedef struct spi_configopts_s { + // The clock divider to use with a paricular slave + uint16_t clkdiv : 16; + // Indicates the minimum number of sck half-cycles to hold cs_n high between + // commands + uint8_t csnidle : 4; + // Indicates the number of half sck cycles, CSNTRAIL+1, to leave between last + // edge of sck and the rising edge of cs_n + uint8_t csntrail : 4; + // Indicates the number of half sck cycles, CSNLEAD+1, to leave between the + // falling edge of cs_n and the first edge of sck + uint8_t csnlead : 4; + // Will be ignored by hardware + bool __rsvd0 : 1; + // If 1 data is sampled a full cycle after shifting data out, instead of half cycle + bool fullcyc : 1; + // If 0 data lines change on trailing edge and sample done on leading edge, + // if 1 it is the opposite + bool cpha : 1; + // If 0 sck is low when idle, and emits high pulses. If 1 sck is high when idle, + // and emits of low pulses + bool cpol : 1; +} spi_configopts_t; +``` + +#### Configuration Functions + +```c +uint32_t spi_create_configopts(const spi_configopts_t configopts); + +spi_return_flags_e spi_set_configopts(spi_host_t* spi, uint32_t csid, + const uint32_t conf_reg); +``` + +#### Configuration Steps + +To create and write the configuration options to the hardware: + +1. **Define Configuration**: Create a `spi_configopts_t` structure with the desired +settings. +1. **Create Configuration Word**: Call `spi_create_configopts` with the structure +to generate a 32-bit configuration word. +1. **Apply Configuration**: Call `spi_set_configopts` with the SPI instance, _Chip Select_ +ID (`csid`), and the configuration word. +1. **Verify Configuration**: Ensure the function returns `SPI_FLAG_OK` to confirm +successful configuration. + +The configuration options persist until overwritten or the _SPI Host IP_ is reset. + + +### Enabling the SPI Host + +After configuring the slave, enable the _SPI Host IP_ and its output buffers: + +```c +spi_return_flags_e spi_set_enable(spi_host_t* spi, bool enable); +spi_return_flags_e spi_output_enable(spi_host_t* spi, bool enable); +``` + +Both functions must be called to start communication: + +- `spi_set_enable`: Enables the _SPI Host IP_. +- `spi_output_enable`: Enables the output buffers for _SCK_, _CSB_, and _SD_ lines. + + + +### Communication Commands + +Communication with SPI slaves involves creating and inputting commands to the +_SPI Host IP_. Each command instructs the _SPI Host IP_ to execute a transfer +(transmit/receive) for a certain amount of bytes, in a specific direction and speed. + + +#### Command Structure + +```c +typedef struct spi_command_s { + // Length-1 in bytes for the command to transmit/receive + uint32_t len : 24; + // Keep CS line active after command has finished (allows to instruct series + // of commands) + bool csaat : 1; + // Speed of communication + spi_speed_e speed : 2; + // Direction of communication + spi_dir_e direction : 2; +} spi_command_t; +``` + +- `len`: Length of bytes - 1 to transmit/receive. +In the case of `SPI_DIR_DUMMY` direction, it represents the number of _SCK_ impulses +to send without transmitting or receiving any data. +- `csaat`: Keeps CS line active after the command (see [Advanced Commands](#hal-advanced-commands)). +- `speed`: Communication speed (`SPI_SPEED_STANDARD`, `SPI_SPEED_DUAL`, `SPI_SPEED_QUAD`). +- `direction`:Communication direction (`SPI_DIR_DUMMY`, `SPI_DIR_RX_ONLY`, `SPI_DIR_TX_ONLY`, +`SPI_DIR_BIDIR`). + +```{note} +The direction `SPI_DIR_BIDIR` can only use the speed `SPI_SPEED_STANDARD`. Configuring +`SPI_DIR_BIDIR` with any other speed will return `SPI_FLAG_SPEED_INVALID` when issuing +the command. +``` + +#### Setting Chip Select ID + +Specify the target device by setting the Chip Select line: + +```c +spi_return_flags_e spi_set_csid(spi_host_t* spi, uint32_t csid); +``` + +- `csid`: _Chip Select_ line (0 or 1). + +This function returns `SPI_FLAG_CSID_INVALID` if the `csid` is out of range. + + +#### Loading TX FIFO + +If the command transmits data (`SPI_DIR_TX_ONLY` or `SPI_DIR_BIDIR`), load the +TX _FIFO_ with data: + +```c +spi_return_flags_e spi_write_word(spi_host_t* spi, uint32_t wdata); + +spi_return_flags_e spi_write_byte(spi_host_t* spi, uint8_t bdata); +``` + +You can load only one 32-bit word or one byte at a time. Therefore, iterate over +all the data you want to transmit until either the _FIFO_ is full or all the data +is loaded. + +Both write functions will return either `SPI_FLAG_TX_QUEUE_FULL` if the TX _FIFO_ is +full or `SPI_FLAG_OK` if the data has been loaded into the _FIFO_. + + +#### Verifying Readiness + +Ensure the _SPI Host IP_ is ready to receive commands: + +```c +spi_tristate_e spi_get_ready(spi_host_t* spi); +``` + +- Returns `SPI_TRISTATE_TRUE` if ready, `SPI_TRISTATE_FALSE` if not, and +`SPI_TRISTATE_ERROR` if the spi pointer is `NULL`. + +Alternatively, you may wait for readiness: + +```c +spi_return_flags_e spi_wait_for_ready(spi_host_t* spi); +``` + +#### Issuing Commands + +```c +uint32_t spi_create_command(const spi_command_t command); + +spi_return_flags_e spi_set_command(spi_host_t* spi, uint32_t cmd_reg); +``` + +Issue commands by following these steps: + +1. **Create Command Word**: Call `spi_create_command` with the command structure. +1. **Send Command**: Call `spi_set_command` with the generated command word. +1. **Check for Errors**: `spi_set_command` returns `SPI_FLAG_SPEED_INVALID` for +invalid speed or `SPI_FLAG_NOT_READY` if not ready. + + +#### Reading Received Data + +For RX or Bidirectional commands, read received data with: + +```c +spi_return_flags_e spi_read_word(spi_host_t* spi, uint32_t* dst); +``` + +This function returns `SPI_FLAG_RX_QUEUE_EMPTY` if no words are available. Otherwise, +stores the read word in `uint32_t* dst`. + +```{note} +There is no function to read single bytes from the RX _FIFO_ because the _SPI Host IP_ +only offers entire words to be read. The unused bytes (when the RX command length +parameter does not describe full words) will be zero-padded. +``` + + +(hal-advanced-commands)= +#### Advanced Commands + +For complex commands (e.g. TX followed by RX without deactivating the CS line, etc.), +use the `csaat` field to keep the _CS_ line active: + +- Set `csaat` to `true` to keep the _CS_ line active. +- Repeat the command steps until the last _segment_, where `csaat` should be `false`. + + + +### SPI Host Status + +To retrieve the current status of the _SPI Host IP_, a structure and a function +are provided: + +```c +typedef struct spi_status_s { + // TX queue depth (how many unsent words are in the FIFO) + uint8_t txqd : 8; + // RX queue depth (how many unread words are in the FIFO) + uint8_t rxqd : 8; + // CMD queue depth (how many unprocessed commands are in the FIFO) + uint8_t cmdqd : 4; + // Indicates wether rxqd is above the RX Watermark + bool rxwm : 1; + // Not used + bool __rsvd0 : 1; + // The endianness of the SPI Peripheral + bool byteorder : 1; + // Indicates if the SPI still still has more data to read but the RX FIFO is full + bool rxstall : 1; + // Indicates RX FIFO is empty + bool rxempty : 1; + // Indicates RX FIFO is full + bool rxfull : 1; + // Indicates wether txqd is below the TX Watermark + bool txwm : 1; + // Indicates if the SPI still has more data to send but the TX FIFO is empty + bool txstall : 1; + // Indicates TX FIFO is empty + bool txempty : 1; + // Indicates TX FIFO is full + bool txfull : 1; + // Indicates if the SPI peripheral is currently processing a command + bool active : 1; + // Indicates if the SPI peripheral is ready to receive more commands + bool ready : 1; +} spi_status_t; + +const volatile spi_status_t* spi_get_status(spi_host_t* spi); +``` + +Calling this function provides read access to all the fields in `spi_status_t`, +mapped to the `STATUS` register of the _SPI Host_ device. + +If `spi_host_t* spi` is `NULL`, this function returns a `NULL` pointer. +Check for `NULL` before accessing fields. + + +### Interrupts + +#### Overview of Interrupts + +The SPI Host features two types of interrupts: + +- **Error Interrupts**: Triggered by specific error conditions. +- **Event Interrupts**: Triggered by specific event conditions. + +To manage these interrupts, you can select which conditions trigger them and +then check the specific error/event in the interrupt handler. + +#### Interrupt Handling + +To use interrupts, first implement the _non-weak_ functions of the _weak_ functions +defined in the HAL. Each _SPI Host IP_ instance has its own _weak_ error handling +and event handling functions: + +For error interrupts: + +```c +void spi_intr_handler_error_host(spi_error_e errors); // For SPI Host 1 +void spi_intr_handler_error_host2(spi_error_e errors); // For SPI Host 2 +void spi_intr_handler_error_flash(spi_error_e errors); // For SPI Flash +``` + +For event interrupts: + +```c +void spi_intr_handler_event_host(spi_event_e events); // For SPI Host 1 +void spi_intr_handler_event_host2(spi_event_e events); // For SPI Host 2 +void spi_intr_handler_event_flash(spi_event_e events); // For SPI Flash +``` + +These handlers receive an `enum` value indicating the specific error or event +condition that triggered the interrupt. + +For error interrupts: + +```c +typedef enum { + SPI_ERROR_NONE = 0, + // Triggers error interrupt whenever a command is issued while busy. + SPI_ERROR_CMDBUSY = (1 << SPI_HOST_ERROR_ENABLE_CMDBUSY_BIT), + // Triggers error interrupt whenever the TX FIFO overflows. + SPI_ERROR_OVERFLOW = (1 << SPI_HOST_ERROR_ENABLE_OVERFLOW_BIT), + // Triggers error interrupt whenever there is a read from RXDATA but the RX + // FIFO is empty. + SPI_ERROR_UNDERFLOW = (1 << SPI_HOST_ERROR_ENABLE_UNDERFLOW_BIT), + // Triggers error interrupt whenever a command is sent with invalid values for + // COMMAND.SPEED or COMMAND.DIRECTION. + SPI_ERROR_CMDINVAL = (1 << SPI_HOST_ERROR_ENABLE_CMDINVAL_BIT), + // Triggers error interrupt whenever a command is submitted, but CSID exceeds + // NumCS. + SPI_ERROR_CSIDINVAL = (1 << SPI_HOST_ERROR_ENABLE_CSIDINVAL_BIT), + // INDICATES that TLUL attempted to write to TXDATA with no bytes enabled. + // This error cannot be set (enabled or disabled). + // This error should never happen since it is the hardware that controls this. + SPI_ERROR_ACCESSINVAL = (1 << SPI_HOST_ERROR_STATUS_ACCESSINVAL_BIT), + // All the above mentioned errors that can be set. + SPI_ERROR_IRQALL = (1 << SPI_HOST_ERROR_ENABLE_CSIDINVAL_BIT+1) - 1, + // All the above mentioned errors. + SPI_ERROR_ALL = (1 << SPI_HOST_ERROR_STATUS_ACCESSINVAL_BIT+1) - 1 +} spi_error_e; +``` + +For event interrupts: + +```c +typedef enum { + SPI_EVENT_NONE = 0, + // Triggers event when RX becomes full + SPI_EVENT_RXFULL = (1 << SPI_HOST_EVENT_ENABLE_RXFULL_BIT), + // Triggers event when TX becomes empty + SPI_EVENT_TXEMPTY = (1 << SPI_HOST_EVENT_ENABLE_TXEMPTY_BIT), + // Triggers event when RX goes above watermark + SPI_EVENT_RXWM = (1 << SPI_HOST_EVENT_ENABLE_RXWM_BIT), + // Triggers event when TX falls below watermark + SPI_EVENT_TXWM = (1 << SPI_HOST_EVENT_ENABLE_TXWM_BIT), + // Triggers event as soon as SPI Host IP is ready to receive more commands + SPI_EVENT_READY = (1 << SPI_HOST_EVENT_ENABLE_READY_BIT), + // Triggers event as soon as SPI Host IP is not processing any command + SPI_EVENT_IDLE = (1 << SPI_HOST_EVENT_ENABLE_IDLE_BIT), + // All the above mentioned events + SPI_EVENT_ALL = (1 << SPI_HOST_EVENT_ENABLE_IDLE_BIT+1) - 1 +} spi_event_e; +``` + +```{attention} +The `spi_event_e events` passed to the event handler does not represent the event +that _triggered_ the interrupt. Since the _SPI Host IP_ has no manner of determining +the specific event that triggered the interrupt, the implemented workaround consists +in reading the `STATUS` register to map the corresponding status to the related +event. Therefore, the `events` variable received by the handler functions is +actually the statuses mapped to `spi_event_e`. +``` + +##### Interrupt Acknowledgment + +After handling an interrupt, it must be acknowledged to the _SPI Host_. + +For event interrupts, the HAL handles acknowledgment automatically. + +For error interrupts, the user must acknowledge the error once resolved. The +_SPI Host_ will remain idle until the error is acknowledged. Use the following +function to acknowledge errors: + +```c +spi_return_flags_e spi_acknowledge_errors(spi_host_t* spi); +``` + +#### Enabling Interrupts + +To enable or disable interrupts, use the following functions: + +```c +// For Error Interrupts +spi_return_flags_e spi_enable_error_intr(spi_host_t* spi, bool enable); + +// For Event Interrupts +spi_return_flags_e spi_enable_evt_intr(spi_host_t* spi, bool enable); +``` + +These functions enable/disable the interrupts but do not specify the conditions +that trigger them. To set the conditions, use these functions: + +```c +// For Error Conditions +spi_return_flags_e spi_set_errors_enabled(spi_host_t* spi, spi_error_e errors, bool enable); + +// For Event Conditions +spi_return_flags_e spi_set_events_enabled(spi_host_t* spi, spi_event_e events, bool enable); +``` + +- `spi_set_errors_enabled` returns `SPI_FLAG_ERROR_INVALID` if the provided `errors` +are not valid (note that `SPI_ERROR_ACCESSINVAL` and `SPI_ERROR_ALL` are +**not valid**). + +- `spi_set_events_enabled` returns `SPI_FLAG_EVENT_INVALID` if the provided `events` +are not valid. + +When setting an error or event condition, the other conditions remain unaffected. +For instance, if `SPI_EVENT_RXWM` and `SPI_EVENT_TXWM` are enabled and you call +`spi_set_events_enabled` to enable `SPI_EVENT_IDLE`, both `SPI_EVENT_RXWM` and +`SPI_EVENT_TXWM` will remain enabled. + +```{tip} +It is possible to enable/disable multiple `events` or `errors` simultaneously by +OR-ing the different `spi_error_e` or `spi_event_e` values. +``` + + + +## Using HAL Together With SDK + +While it is possible to use the HAL together with the SDK, there are important +considerations to be aware of. Also, consistency is key: do not mix SDK usage with HAL +usage within the same context. If you need to use both, clearly separate the +contexts in which each is used. + +### Interrupt Handling + +#### Event and Error Interrupts + +Since the SDK already implements the weak interrupt handlers of the HAL, it is +not possible to redefine handlers. This means that it is not possible to use any +interrupt from the HAL when using the SDK. + +Because the SDK uses interrupts to operate, it is **crucial not to change any +interrupt triggering configuration**. In any case, it would be pointless to modify +it since there is no way to use the interrupts. + +### Configuration Management + +#### Watermarks + +It is possible to modify the TX and RX watermarks using the HAL, but they will +not be implicitly reset by the SDK. Hence, if you modify any watermarks, they +should be reset if you want to use different watermarks when using the SDK. + +The SDK also provides functions to modify the watermarks. If setting the watermarks +for SDK usage, it is advised to set them with the SDK's functions rather than with +the HAL's functions because the SDK will also internally keep an instance of these +watermarks. + +#### Slave Configuration Options + +It is possible to change the configuration options for a particular _CSID_ using +the HAL, but, subsequently, the SDK will not reset the configuration if the same +SDK `spi_t` instance was used in the previous SDK transaction. + +For example, if you execute a transaction with an `spi_t` instance and then use HAL +functions to change the configuration options of the same _CSID_, the SDK will not +reset these options in subsequent transactions with the same `spi_t` instance. +Therefore, it is important to maintain consistency with configuration changes. + +### Transaction Management + +#### SPI Host Activeness + +Since the tracking of busyness by the SDK is managed internally, the `spi_get_state` +function of the SDK will not return `SPI_STATE_BUSY` if the _SPI Host IP_ is +processing a transaction that was executed through HAL functions. + +It is, anyway, impossible to issue transactions through SDK functions while the _SPI +Host IP_ is processing a transaction (whether issued by HAL or SDK), but it would +be useless to check the state of the device using the `spi_get_state` function of +the SDK. + +### Summary of Key Points + +- **Consistency**: Do not mix SDK and HAL usage in the same context. Clearly +separate their usage. + +- **Interrupts**: Do not alter interrupt triggering conditions; SDK relies on +its interrupt handlers. + +- **Watermarks**: Use SDK functions to modify watermarks when using SDK to +maintain consistency. + +- **Configuration**: Be consistent with configuration changes, especially when +switching between HAL and SDK. + +- **Activeness**: The `spi_get_state` function of the SDK will not reflect +transactions initiated by HAL functions. + + +## 😎 X-pert Zone + +Another option for speeding up transaction processing is to use the registers of +the _SPI Host_ directly. However, this is not recommended unless you have a strong +understanding of the process. For detailed information on the operation of the +device, please refer to the following documentation on the _SPI Host_: +[SPI Host: Theory of Operation](https://opentitan.org/book/hw/ip/spi_host/doc/theory_of_operation.html). + +To access the registers of the _SPI Host_ directly, the `spi_host` structure is +defined in `spi_host_structs.h`, along with a pointer variable for each +_SPI Host IP_, defined as follows: + +- `spi_host1_peri ((volatile spi_host *) SPI_HOST_START_ADDRESS)` +- `spi_host2_peri ((volatile spi_host *) SPI2_START_ADDRESS)` +- `spi_flash_peri ((volatile spi_host *) SPI_FLASH_START_ADDRESS)` + +Below is an example of implementing an SPI _Standard_ speed transaction with a +_W25Q128JW_ Flash slave device using this method: + +```c +#include "bitfield.h" +#include "soc_ctrl_structs.h" +#include "spi_host_regs.h" +#include "spi_host_structs.h" + +// MCU frequency +#define SYS_FREQ (soc_ctrl_peri->SYSTEM_FREQUENCY_HZ) + +// Flash paramters +#define FLASH_MAX_FREQ (133*1000*1000) +#define FLASH_CSN_TIMES 0x0F +#define FLASH_POL 0 +#define FLASH_PHA 0 +#define FC_RD 0x03 /* Flash Read Data Command */ + +// SPI transaction parameters +#define SPI_TX 0x02 +#define SPI_RX 0x01 +#define SPI_STD 0x00 + +#define LEN_B = 4096 /* Amount of bytes of data to read from flash */ + +#define ADDRESS = 0x00800000 /* Flash address where to read */ + +int main(int argc, char *argv[]) +{ + // Initialize RX buffer + uint8_t dest_buff[LEN_B] = {0}; + + // Compute frequency of SPI communication based on slave and MCU frequency + uint16_t clk_div = 0; + if (FLASH_MAX_FREQ < SYS_FREQ / 2) { + clk_div = (SYS_FREQ / FLASH_MAX_FREQ - 2) / 2; + if (SYS_FREQ / (2 * clk_div + 2) > FLASH_MAX_FREQ) clk_div++; + } + // Set slave configuration options + spi_flash_peri->CONFIGOPTS0 = (FLASH_CSN_TIMES << SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_OFFSET) | + (FLASH_CSN_TIMES << SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_OFFSET) | + (FLASH_CSN_TIMES << SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_OFFSET) | + (FLASH_PHA << SPI_HOST_CONFIGOPTS_0_CPHA_0_BIT) | + (FLASH_POL << SPI_HOST_CONFIGOPTS_0_CPOL_0_BIT) | + (clk_div << SPI_HOST_CONFIGOPTS_0_CLKDIV_0_OFFSET); + + // Enable SPI Host device and output + bitfield_write(spi_flash_peri->CONTROL, BIT_MASK_1, SPI_HOST_CONTROL_SPIEN_BIT, true); + bitfield_write(spi_flash_peri->CONTROL, BIT_MASK_1, SPI_HOST_CONTROL_OUTPUT_EN_BIT, true); + + // Set command to send to slave + spi_flash_peri->TXDATA = ((bitfield_byteswap32(ADDRESS & 0x00ffffff)) | FC_RD); + // Set CSID line where slave is connected + spi_flash_peri->CSID = 0; + // Wait for SPI Host to be ready before setting command + while (!bitfield_read(spi_flash_peri->STATUS, BIT_MASK_1, SPI_HOST_STATUS_READY_BIT)); + // Set command + spi_flash_peri->COMMAND = (SPI_TX << SPI_HOST_COMMAND_DIRECTION_OFFSET) | + (SPI_STD << SPI_HOST_COMMAND_SPEED_OFFSET) | + (0x01 << SPI_HOST_COMMAND_CSAAT_BIT) | + (0x03 << SPI_HOST_COMMAND_LEN_OFFSET); + // Wait for SPI Host to be ready before setting command + while (!bitfield_read(spi_flash_peri->STATUS, BIT_MASK_1, SPI_HOST_STATUS_READY_BIT)); + // Set command + spi_flash_peri->COMMAND = (SPI_RX << SPI_HOST_COMMAND_DIRECTION_OFFSET) | + (SPI_STD << SPI_HOST_COMMAND_SPEED_OFFSET) | + (0x00 << SPI_HOST_COMMAND_CSAAT_BIT) | + (LEN_B-1 << SPI_HOST_COMMAND_LEN_OFFSET); + + // Setup RX word counter and set watermark + uint32_t rxcnt = 0; + const uint8_t watermark = 48; + bitfield_write(spi_flash_peri->CONTROL, SPI_HOST_CONTROL_RX_WATERMARK_MASK, + SPI_HOST_CONTROL_RX_WATERMARK_OFFSET, watermark); + + // While the SPI Host is active (i.e. still processing transaction) + while (bitfield_read(spi_flash_peri->STATUS, BIT_MASK_1, SPI_HOST_STATUS_ACTIVE_BIT)) + { + // If there are still more words to be read than watermark, then wait + // for RX watermark to go high + if ((LEN_B/4) - rxcnt > watermark) + while (!bitfield_read(spi_flash_peri->STATUS, BIT_MASK_1, + SPI_HOST_STATUS_RXWM_BIT)) + // Needed because too fast otherwise + asm volatile ("nop"); + // Just read as much as possible (but no more than watermark words) + for (int i = 0; i < watermark; i++) + { + // If there are words in the RX FIFO read them + if (bitfield_read(spi_flash_peri->STATUS, SPI_HOST_STATUS_RXQD_MASK, + SPI_HOST_STATUS_RXQD_OFFSET)) + { + dest_buff[rxcnt] = spi_flash_peri->RXDATA; + rxcnt++; + } + } + } + // Read the remaining words if there are any + while (bitfield_read(spi_flash_peri->STATUS, SPI_HOST_STATUS_RXQD_MASK, + SPI_HOST_STATUS_RXQD_OFFSET)) + { + dest_buff[rxcnt] = spi_flash_peri->RXDATA; + rxcnt++; + } +} +``` + +```{note} +There are practically no sanity checks performed in this example in order to keep it +as simple as possible. In a practical application there should of course be sanity +checks wherever needed. +``` + + +## Performance Analysis + +A performance testing was carried out utilizing the _EPFL Programmer_, which includes +a _W25Q128JW_ flash memory, and the _PYNQ-Z2_ FPGA. The +[SPI Flash Loading Boot Procedure](/How_to/ExecuteFromFlash.html#spi-flash-loading-boot-procedure) +was employed for all tests. + +The test application used the +[Clock Cycle Counter `mcycle(h)`](https://ibex-core.readthedocs.io/en/latest/03_reference/performance_counters.html) +of X-HEEP, recording time via the `CSR_REG_MCYCLE` register. The test tracked the +duration to create and execute a transaction of various command segments with the +SDK, where each transaction involved reading 4KiB from the _W25Q128JW_ flash device. +This read operation was repeated 500 times to obtain an average. + +The exact same procedure was applied to the HAL and the _direct register_ method, +which involves direct manipulation of _SPI Host_ registers without using the HAL or +SDK. The tests were conducted at both _Standard_ SPI and _Quad_ SPI speeds. For +accurate comparison, only essential steps for transaction execution were implemented, +avoiding as many sanity checks as possible to maximize performance. + +Results indicate that at _Standard_ SPI speed, _direct register_ manipulation was +slightly faster than the HAL by approximately 0.8%. At _Quad_ SPI speed, _direct register_ +manipulation showed a significant performance gain, being about 18.6% faster than +the HAL. Comparing the HAL to the SDK, the HAL was about 1% faster at _Quad_ speed +and 0.8% faster at _Standard_ speed. + +Exact numbers are provided in the following tables. + +```{table} +:widths: auto +:align: center + +| | SDK | HAL | Register | +| :------: | :--------: | :--------: | :--------: | +| **Standard** | 4472.00 μs | 4437.40 μs | 4402.07 μs | +| **Quad** | 1970.00 μs | 1951.40 μs | 1588.00 μs | +``` + +To illustrate these numbers rather in percentage of change, the following table +shows the speed gain(-) and the speed loss(+) when changing method for a Quad speed +read. For example, when switching from the _direct register_ method to the SDK, +there is a + +```{math} +\frac{SDK - Register}{Register}\ =\ 24.055\% +``` + +change, which means 24.055% slower. + +```{table} +:widths: auto +:align: center + +| | SDK | HAL | Register | +| :------: | :------: | :------: | :------: | +| **SDK** | 0% | 0.953% | 24.055% | +| **HAL** | -0.944% | 0% | 22.884% | +| **Register** | -19.391% | -18.623% | 0% | +``` \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/Timer.md b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/Timer.md new file mode 100644 index 00000000..052faf0d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/Timer.md @@ -0,0 +1,107 @@ + +# Timer SDK + +This SDK provides utilities for execution time measurements using HW timers. It includes functions to start, stop, reset, and configure timers, as well as to enable timer interrupts and measure elapsed time. + +## Usage + +The SDK provides a set of functions to interact with the HW Timer for various timing operations. + +### Initialize Timer for Counting Cycles + +This function configures the counter at the running clock frequency to count the number of clock cycles. Call this function before any of the other timer SDK functions. + +```c +void timer_cycles_init(); +``` + +### Start Timer + +Start the HW timer. + +```c +void timer_start(); +``` + +### Get Current Timer Value + +Retrieve the current value of the HW timer without stopping it. + +```c +uint32_t timer_get_cycles(); +``` + +### Complete timer reset + +Completely resets the HW counter, disabling all IRQs, counters, and comparators. +```c +void timer_reset(); +``` + +### Stop and Reset Timer + +Retrieve the current value of the HW timer and stop it. + +```c +uint32_t timer_stop(); +``` + +### Set Timer Threshold + +Set the timer to go off once the counter value reaches the specified threshold. If the timer interrupts and the timer IRQ have been enabled, when the timer reaches that value an interrupt will be called. + +```c +void timer_arm_set(uint32_t threshold); +``` + +### Set Timer Threshold and Start + +Set the timer to go off once the counter value reaches the specified threshold, and start the timer. If the timer interrupts and the timer IRQ have been enabled, when the timer reaches that value an interrupt will be called. + +```c +void timer_arm_start(uint32_t threshold); +``` + +### Enable Timer IRQ + +Enable the timer interrupt request. + +```c +void timer_irq_enable(); +``` + +### Clear Timer IRQ + +Clear the timer interrupt request. + +```c +void timer_irq_clear(); +``` + +### Enable Timer Machine-level Interrupts + +Enable the timer machine-level interrupts for the X-Heep platform. + +```c +void enable_timer_interrupt(); +``` + +### Wait for Microseconds + +Block execution for a specified number of microseconds. This function is not precise for small numbers of microseconds. Enable timer interrupts with `enable_timer_interrupt()` before using this function. + +```c +void timer_wait_us(uint32_t ms); +``` + +### Get Execution Time in Microseconds + +Get the time taken to execute a certain number of cycles, returned as a float representing the time in microseconds. + +```c +float get_time_from_cycles(uint32_t cycles); +``` + +## Example Usage + +An example of utilization of the timer SDK can be found in `sw/applications/example_timer_sdk/main.c`. diff --git a/hw/vendor/esl_epfl_x_heep/ides/img/build_screenshot.png b/hw/vendor/esl_epfl_x_heep/docs/source/_static/ides/build_screenshot.png similarity index 100% rename from hw/vendor/esl_epfl_x_heep/ides/img/build_screenshot.png rename to hw/vendor/esl_epfl_x_heep/docs/source/_static/ides/build_screenshot.png diff --git a/hw/vendor/esl_epfl_x_heep/ides/img/debug_screenshot.png b/hw/vendor/esl_epfl_x_heep/docs/source/_static/ides/debug_screenshot.png similarity index 100% rename from hw/vendor/esl_epfl_x_heep/ides/img/debug_screenshot.png rename to hw/vendor/esl_epfl_x_heep/docs/source/_static/ides/debug_screenshot.png diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/conf.py b/hw/vendor/esl_epfl_x_heep/docs/source/conf.py index c9f6eaab..44ce6b68 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/conf.py +++ b/hw/vendor/esl_epfl_x_heep/docs/source/conf.py @@ -4,6 +4,10 @@ # # Author: Embedded Systems Laboratory (EPFL) +import os +import sys +sys.path.insert(0, os.path.abspath("../../util")) + project = 'X-HEEP' copyright = '2023, EPFL' author = 'ESL' @@ -17,9 +21,12 @@ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', + 'sphinxcontrib.apidoc', 'myst_parser', ] +html_static_path = ['_static'] + source_suffix = ['.rst', '.md'] intersphinx_mapping = { @@ -33,3 +40,7 @@ html_theme = 'sphinx_rtd_theme' epub_show_urls = 'footnote' + +apidoc_module_dir = '../../util/x_heep_gen' +apidoc_output_dir = 'Configuration/generated' +apidoc_separate_modules = True \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/block_diagrams/example_adc.svg b/hw/vendor/esl_epfl_x_heep/docs/source/images/example_adc.svg similarity index 100% rename from hw/vendor/esl_epfl_x_heep/block_diagrams/example_adc.svg rename to hw/vendor/esl_epfl_x_heep/docs/source/images/example_adc.svg diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/images/x-heep-outline.png b/hw/vendor/esl_epfl_x_heep/docs/source/images/x-heep-outline.png new file mode 100644 index 0000000000000000000000000000000000000000..b2aa5446f0cd09aedda76b5bf5b2e0529642e24d GIT binary patch literal 42485 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

! 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

BqcYcU#2AJScmb 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�Z%{jEy*O?jU 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� zHaHqLXIdZaL!J7+&&T~a0vSkAt_;z{K|(VA54&dS(u;lkvMPPg&qWX!(TWi&RR({q z3F0?ic~4KugE^c8ZBVtI9OY7-Mp2ZVnK`m>{Jfl8M7EY=$5tAeI-hw^7lMASaPk~b-mE#seMAZ?6AijfE`*nic?U`^* z`peh`FBqepBb?Fi$WXvATYn#;2$KK!omWX>Upt zdw64ii_J*u>~sfGOy!7kG(6iVn#pBbH*U;y+TwsxjmJGoXFl9+#9*rlSnVIf!wTR3 zqH^3zeyR!o6?F3MfuoKZbk^5@12o7VGlRGdC*ZQnbO3-{j=l`G8FB-@J>>n1m9(ew z`uraxbTtK8SDUa|B!KfT!ZBMxIIKM*qoW@XU5+@U%kMvFGo+s2)Pe%Uq>btFiq-Ad zzTM2<8tM(xU^-u?zj>CdWGx=x5r_P>Gc(ZW1W)!u5j6DEthpBfiVdkT0PY!*UexH% z_ZvFnX{rCn>D5psH_KwSW1}Y4ei$^L5E$wZUz}9YJGMvl+&OB5($1yx zF4P10FTrMn1#*eZQ6QkepJ)2i-D00#9*4BdUzsgfe#93LtM`rhx27a+iqVsju)NCD2M6pD$ zXA33)Xr&nWHsx}%vp-EOrzv&@L&z>J9%^axW&ET?rwfJ+Q_l-^zMdDR+V^(d!_{&% zcrFtm(QSJ0W1#7kt2o7rl|1|3+m19;Wwz1KnOi6$$a2| zM1!pu;%eb3O1!+eNJFY=3)8Xyo`^dqiJg#(`9o=!vXKavwx!HI*CkvY2 z|7rndXZynXvYVcZ&USnM7#uu$@ZiB8eSK1o@_Wj!xn%7c=`MLlO84>fcF@!tP^`zQKCqLb;~L9jSjFHArc)D;@38Icd4&x%Q#_f zZa#})muI`fjL*{S<2#_zDvd^Ny|0hARYzZ7yw>pWC`K_Xu@D0?%+1XmNAb=>$gI;- zilJ(;npN`wevZ$qHQ*U}y7Z+xE{Gn)-#WW=QczGG{d5sM&X=}+Nm!F< z^}?!G_HDe>pWKsJ*)wl#DPcizRtQ@^BvNcvvhGYX13e~XEl^03nJKfa?0qmd_rj+b*J}NI}w0Q4pz>5UKeb%!S|!|L=(ytX#u$ zg7e^C2y?GX9TJMCz$?NP>`y~Ur_CCnZbbA{>6(mY`Z}kNo|ZDyQa&K;jF^;Cbo0Td1DMv&xA(u6Z`bcF0l3pWi19&uhSwW< zR=aC1Q&CdEC((et*}2UVZU2=vt0|qQ`xJnmx5L5D&rwlaZ%l0aB;@Cs6swt$2tBA4 z$fBanJ~9p)3WQSEQYw3EY$+~3V>Hs@|NZyh)+JH+n6c?;)*F8hQkr8(Pi^TqhOkdzhb zr(JF6kbm3j7jhH7f2Y5ox2_oP3!tWG=9NXqt#je=Wo4SVB5Z{Rs0%mE#8jQ@VA7}+}@1d zMw8!O;-B`mrY{KHT^oXFc(j3?k4(igaFDCC2RG90198m6w6wG|j#{MWy_FxLSln5$ zytPfYB){rf?jE^<$NP;OTk@*lVDg2^gYk2N{rxg;Zk2B?)=A>9+$kY5bUWUkCRTXkz6Z3psD$^Q z?JI3RF1%sUkilFgK(`!+fqXi5rXO2NadAtWI^zP0B5QaZD6x+f$JY+y=*72H0A*Zg zQmLo>YEh(})oGvf$vd=gciU$c zXBy7k{`)IFySd~+ncr}q+#bQ1_K@xhY~Mtsz2F3%)!4k<+?|;t&c%CO%BR0ykUZ~m z)>*}G@N|>rNsBdpwNz4bi_`CudTuQg9zQD4@x#QF1w)XstXTeE-@Q71p|flF!6VBp z|0o3!FXe9g{!G{wip${C*d!$J4qv}uh#P)ZXl zca69C9Ce@fU6Pj60no+;&r68_f()TgYhIl&{tz zaq}d@ttp#Yh8~sr2x!#S>!L51MWo`uJW)IIomNrpUsIp2DW zC+x7^tc7@^z|$*fNgcI42hGDvr}=|l44hr=bF?#fal+porjllrkl0FH?n@s%w7+K| zY&=Op+;X$=^2C~EmVx#8xtsB=E>>#=?c1$#{yJa@M&b&>R|^C^tq4xcR{HYb;}BhZ z<_qOCs;to)C$^STnl;^bP*La`e1>Nk`sC>y1m`n&8TU_bMn+D~ z8<`B;oFD338fa}fh5yY}mpCy#-VHw0%g>LszrX)Se?J=nt}k+>r^rHEAww8S9)j1Q zxV)qPvV1`@G<#}>os$QN$dUHPE57mdKKQfAhZM>j zL&2ZLk%jOh1q|g{TaTQ~*K0m-5{s*JEl-D`c>LtW3x80C7ju{9jFTqzY^L5TeEaR~ zfm)d>$p!~QLqln~PjYf9KnQmT?J{0)*G&E=bqoKogX|>=nKn|D=REU^gh@y??`R(w zHE&Lq(YEhrai||WX2gc;zB=*KBv@-xrZuNL8~M9 zSfWN)C(2b$ZFZQ@?&{sED8C$vk21C%=f;WNYEhXv?9Oc+7S367`1o-pltfw3D0P%a z@WEqgd;3gB?Cq?MRXf_>@F9#|_;%sz9;7mt@Dy3m{LalI_$99ALJ*$}lwEo;5V$yE z>%`F4`+Ltx-*JKRt(fc+9{6s!8J!f%R6?rsT<%`P8{Xhm6p?inr z(4jMlNl8(bJ;lmVvb&J%W!ApGtg@MUbzoeQ=Huq!)_EKU^5`pPEKFU-qZcUAH>c#< znwpx%8+4qDfTPJ*fCpkGb;NfUIms2>vA3^Ym*G+tEI<&*$S5b86#Tff*wHu~K_i(mA~DF|`^aP@GD3O1HkDt}w=bVy`!5*J zoFf5a=m?02?c2BOqM(;}_0y^hi>}iN6YJKlmBDbyD2#F5|$N1y<(EOUi+?erD~ zQG+^LOjNjH$3Cz#9XAM-lB^g@=B;9i&~`YQate*MbSN5^O2L5?F?M7e!bq^Gwx zDET;M==$Ns4K&B2o>Yi>pP|<@8uAMtQ4Xpp1bmkXK4B_f z4V}+nJG6|nWoG+xT)v*FlNycFUj(s@g57FL@!Ued;9prXd21|67X@$s@)$t*ZTq%& z(GX``dMSA8^;c^>eSJS8u{2i9T;Mlt=1Xy2zUvzt{BDSikFR#<1Zq0{SGJ_o*iCOx z{6MwNFwZYb#ldoRT+hv&3R=oD!Gourx=?F2Q_4W8()aELis04=o#-JptKxs?SNq%T z@4&+z9~-N(9)_9K4=l`1oaLIp)WW2Jpg(BoR=s}xx?yZdcXhWM)``aDhB||f<@r!y z&wCi_)b?(sE=zTW!U&grgB>$ZCSGFFR}6?AgOLyPf)@Eh!ZKY$XfDoSg)T4^SpFZ?(T2@5ytYTUSfy%s7Gj!-V0+@WI)!st+|<<48Up6bXM zNXw=9*5Rg{j0`3jZ_8}Zfixymk)zZf5;?V`fMe=c0O5OXmu zh*WtHoCwS5K~tL=q7Z4TOQ)^TM)7 zo-}hsmF&TmjbqK;m8l$!zKT>-))|YW7@e4FqA&QP$RUGYp5$UWEy=`oIc{OWF_6#D zt7v^aata>X5lzE(teEe}g42)E%Cf0Ov)(KQi$r1v>e=#O1POEUozjpVo~t*egWL;bOzWh7B94 zlWtxRvKa~(v4&1T9_=h_7|-m7wVBfR7Ly=b%m}VdGuQDprNfd+Ne~loK!%$sbn0nl zFCkDmPv}(u2QLzz8fLO?_cMWs!&SX$F(f4tFt3ElxNTkml?4kIS2^?W$>rG>q!9Gk zlHwyk$uI9auleq8TLmolqfh9OYMcRfn>DU*Yq5AzF-TEkfX8>y(`yc`KjZhz#Kg^0 z>S@sT7mOc}Xz15Sx4?urY+k}pSS-`rhPFPGsui}Md`ko#q`3aX`U7$iBM@aq2p}L{ zRbs=#^I4}pgojIzn|8vufB`6L*=~toTg_|m5z*Us?65X{kYNvXf%O2N;*x2A+97-R zkN3616_`9xhw(&ekiyEDILytAet=*&I$kqF8GGcaJ1QUvdffx(9t*|ETe$XEhz~Vt zL(_~K&O@>wjYD3pU$C8&WZ|&T|Y~8tUpHZFN9mDZ&UW>7B`{BIxw8N&lOF(PNr#4(Y_7>5+ zZ5Csm-$_bBQzbEx2jmj`{svr9roVar;(Cp41^Ba~Y1YGsMM@Jql#LSGdDuk39?8ey zy^)vD;k>Lx{u_TrmT1MIXy5v@YYcSxav zHD^%Njno%nbei-JZrbwqRBYZBHOs68?OBC$7PFOd$=HZ zMqAS%YPkYiI*1SlW;3I*HOoa27_G3PWq^Dz=(WU4{0^lP6H5 zN!x}#$JRQnT*u1|ndd_UU$Ol}?})LsG!wF;^l7`sIR6QNnAgH6XOZ)NWKiu;<4)lPvIPI>ToY>E)+Jeqqb!(JxcxWmu z;3<+$jb+-7#t(jTuxFUBoj^IpxZL*XrXyasZ8RmvJ|14)I^3s1ZbPQEv9Fhx@|%0w8`l{~D=5^}`KdRDRBu* z!)z@1cE57c%(h96pU_al@B3$^_C1rerg?=dQER%co!s9v|`Vct07k4 zMpfIniCN-7l&L4n?Deu*WCLvlJBx~nYzBGX_qR+wee#4&Efkg9SO|`N>_s-_O@2Qk zNa+mfyP7sPjPbiZvCA9QuUEvRkYq!bM_zBxs{0lK4L^Ha+3{_*nU00k-EOp19}oWrHhiPkZsjL z!jxXGUOu$|pH$q?Fk_Q}T;&S=8dl6rfWMAw9K7YX#^Bh@_%!ewzqLL_B=yjSe^Sz} z=Qa)Y^YFOp6^)ua`{BdUs(D{Do%Ui}Mf~o84V8*R(;7R&51u%2(dvEpjBo|&c6v(r z?ob5mqNUYO6bINRK)-FV8DbaHec=a@N?MthR8(BpfAVhY8$Epmmq%{9xrH4yR>h}j z*yk+b!3KSzF;lSDPR>hOWXldgmGsxfJ*t1^;X*Bf7mFB7<*r|U&3XYvjho(jD(w`_ zgtp{f(E$D^jp z&ct;3?74HX7@V|I#2mQ{CxcUJ_9{L;^L9;sfZDIK*i^@9J<+S+y1w$N`MRwP9F}y8 z3k#}H)67AHS%=zsErx-+ISC~ue@Y|_TDlrh;gk6CvS24tpgOVp z8Aqpd>KA%}I8)FovVEcf`ScX_711z=sy~Dg?Nm*OJU~MbSOOOcYSJJAWT8xX*V%a$ zMb!0`od;&s|FFD)ur=zda8T3-@ZP$5dNGe5uP?I)YjC5k#9>lA z^+O*v=0wXh4YlXAyy?@%<5C<5tMWz5i-tm*5d3k>;4_hR2FUCl$=v<^{d;pyT8cSF zs|X|Yhgnin?c2C+t{w2CZQK!=ZqWRObzA5^&gs2H=?sVU40NYWR}J!(m$J%Ao>6Ez z?X#3IiTM(YJV?(GU3?eodhjW`fKzx|Au@?fELcBU2Ry`p5wU9Fp|$V;8vvkXc#x zSAWyBgP4*X2iWS+0K^49KT#iUXEdvec+K!@dAx)hF5RoRy!^y`cy}Q0%~~KIv;;-S zP9+Y*^Se1I{Q`BM1n|KQif^I~R{}&Lv}?zX8#a??*$#TF|IhgFtZq>mA@_R)@OAUV zV-=L$Vb5Xv#2xQ=a_e5+o?X;VwQmI-UI>dvpNfDlJUD^b+rP3MJ}d=^`8iWeWvZF! z2m*JdmqeifI6S`hi5fk=8a}qk)phmi)pbw~lukbYB3DEE*@LDIA?GDW@@)F9vgD>K zD_cB*UU>@r46y{FhK}vQ=ru^dz(J8C;XM@#27X@ z?gS19W?HSmbvaRTznFdPP=-8GPucV5FQS?7xWkrz05sEfZ--KXFCw6$Sj1T8SolnW zlUPTho|{6sg6aP7u8Sh->5ITF3{?BxFDL-cu{KCT=$DD(uXQ&#FK>Bx3X;NqDKvWj zgunWo6H>i~jk~}3Zr1_js5U9W9Kf&0?hn6)JSs^1F!Takdf??Oauyje4|18W1d~8q z>bPZS?~dg{OwN*f$DC_VJN!tSk+bD@3JpT1l(~TE-j!LdaE&|dOrs+WQ8gXF2ILc) zDt}|ZPz*3quslQxx86}`q}=J1kdo1w-#}bOe&aPV6(V@+w08rH@Dj|kxBb|E=#p|o z$FDWy4~&if(5!Cfp0qXp(*o%03+uT&(%>$7K__rNsTB&8V5h*!YP!=8{cQ(NC7@?2 zIPwL(ke4f6$Q@@z*%%;|fc;uy0DqaqQ%L-bkVvpYlrU40YAYV#)Q5o>QGh77IU(!5 z5w!cwhDwT{9-aQox^o|3X*~CT#uXXx#RA>N;&r<*>>+GW(}Ar-N0!%kwS+9Vnz_4KwM`dGP-5MhT|KGuXB0OQ0?R3>L~I{&UkG#sbM_ano*;xg-kfvsMb>M z^1kp-t;ZWMC35JZHY%D8Ez6!D_BJ%5UuYeL$F?ms{cfY?u@vY>+~TLQChTGltuYAC zrV_NzGK9I2BaenHF6)0Dko+B4MhmmV7bq;>UvbY_#pj5QJ3afbKS&raA+3VP(A{N|a!w?WGIoWPX2Fk$7B^4yBpD z-X2b6QGB9wWb3maI_q={b|b*!;#vWona-G~LynC+5@!s%dwOC3ThyK8Zvi=^fN+6J zRPFxq#~p6v_t>k)zwAFvf_G2qfBZ}o%WC2sw!HCCE_lHx;IJjxwB>{r_cl;TZ*f^~ zLBm|$AAYLh!B?V`L;8<)HQQnXzMw@KB0F)nDFr?!1VMMy4~-h)-}z&$fsgFbwD#2L z6e~Z!T2eb`KwqOAa8Ifjy5z61*5JsfqpGaoeapv>!I&z+DB0>#LU1oloD!HLm>Yzy z@um|$VR7024qTmDC^sg_f^9m5MwU&%X%1xDhRUmR4jdaRKVl@Kw__^?Y_*kVp}$eS z-g@EBt+cI`iciO1n#g2vJ-q+8xdih&JTe`%jD8e;Oua(eb`+HUvYY9zmW`!FtTU(-36M9$&%G%$ZX;9aF*iyHzr-){ z>%rryVplz(%xCnu|i|Ne}B9qM2e4~rb^K9rHc%}ro#;KUpp-8CAc@yc2pbV z3;gs$ftoa+e_;k-vUN+Wo&RSD54RhR^Mnj)908>K5PLDsXv&5ZTQKBFWG~uQJts(c z!~4YbuaA}E(!f`YqlG%7Zb_qkHo(V+8D+>+Rwp2}YE*RIrM&_NNEBU2>Z|IuTuu)w z#PF^|SPOVU2Au(kHp5p8F&%sVg9jN&;-uII(wN?i4ztfq$Ayj`_q?BU+R`$ys1N*9 zi>Ve0HOFT~ff-TAd-KmwB#L*eVLyNTU_N}fpm&fkw`BPUGujvRd$d33UBH?n8yt#p+W!dOa8AmTsP^1$E4qTiv zXGj%4Lfu1?KO7YuU4mxHLm-QCdY$3+y#oUFWPs{I`z|*R7A)^Yccdf!k>&Kzgrm8i|#>Q;|uDA2=9-eD(C}dukh%H?CU(E&>ia`Sy8q48@<=9s6k93f3L1_-O5ON zX+8TQtlQX3^EoC~@$m56<~$72AN}bDUen-3+m~9PQJVPC3&zMg?!l3E_n(+^R~<<@ zQ%mcYG0dtMSEx`;8onTgJ#l%7EL0=+ts1NP$MV0@B_=wEIniR0y_-;1M=vc_73TLmRA6?da&(4ekC% znXB*c7)vltpaAUlzP0gO^muszZt#jX*$Ah+_GY>Ygm-#?&?nk@ z2}h0M9bZ3C9hY^>H#gO3CBg7pUAuSDgMOxwkAJv~CU&biNA4GM3*d|b9CNW#emFHA zCCAU*6JRshG4b64@2=5NtJV2W-`WN=Lbil)qe_SrFJ;yqp3ZpO4)fb=;-pw)6cl`s zF$8J$;UEQMKKMjng6eQ$U6MhUm|@$X$V~+DdGhu;uikcYaUzJ$trULE;Z! zJ7A&Kk$(=K0Yi8eafI02ETA+W5h4bnD_Ed9)l?&C^=5p{lPUuun=eN7i5YDtyce(@ zwHqN$Zz&5;>oA5zysuLMyTl?U)}|YXnP-oD>JFL$bds}+! zGazvIgRVBX&o?>TatRRb?XSP)w*^@jmKYMoSYhP|Py7?en~BEyZp4>{$lZ6lJ~AU& z;+YkNG_vf=A{7-CYuL@wfP+M_YbkWlDk8|QZnY2CWl{}Rm?Iq$(_Ng#b@5snNVLvf zTb(|P_dO22DIk&`$uVHwl>t476$XR0T?J2j0Ppoy&;mSPWwu~f@mAjeI-2^{BjzlI zmEre_`j8ImX+d|lZke?Y5}5wFcm4_u zHPC4Va~h-6P#vcspkR;o-`=^`yG;M#4sVv}vgyWzl)CI=O6^27fKZpdXonpA{QiG4 zvInfXI@kAVQzz=RDF2Bn;?DhZnnVChyZ1#mLoxEcNE9v(mSEADikFX%Zk119VE;cY ztzc-qD|WETd!P=|czgdtomI$YE@v#ZBjqmwwWo(fGpz=@1`Z>& zp<#|_%>qU35?P(#LskEigRNVUCzyOS;4`X5BQ#h1Z!VXNb-`2F^a0Q~06+7|IG}9J zKOu&CNRag+R1vCNhjmA~j5MgFj+CRP`_+c^+fh}Gts11t-;VQL6NxPW-*qPyjMYfH z7fQY|XkoF66=fHV4d)#He);aZ6sK!lu8VeE+bCDd@r?NlVF)$@9Z1ro(Ad-v2`z!= zs%2-41klAwGFC(Uo%&~~`WGIqHg29^(Y$mqbaoHQ4l?uDn0N>*aoU;QIs`vf0zy~t z1WWk#?(TXQI|YcN;0lMWWf42cb_0f^prOH#Ks^HP$&B!5a5GKj+3OwV`@1x@^Yn z;6=tUdZ-w;+=HNb;&K6!PI>VL^igQu9mFAKVP`L9K5!8yvKvu~TkWKb^XkTt^c2up zQCE72$3>46kBmmHV}=P-KtOkguqxsBYzM#}5jiC2tC?rY3JF@#or4!*0d(*O0`7R_N)Hakp~PbL`Kz|S_! zLGlr6$8Z%5m|h@DAO0;0S}3l_D$kWZUnKxINI(z}YE6uDaE5D#JL5^Su^9|y-KX?#0}xqR-S)K2CnH_Z8ZpVuwbN^uz_cRy7#C;Ca2WT zW4n(T7J0Fp-?e!FAel7`wYS0FE!kFm=P!esFVZb4^dJhGpFdRwa(|ODCWAj@izAs2 zq7Fq0#S*xO5*S}UmMeHbg|$&ja(cAmgNy^_g%$IKt8{rvZeR4J)A>hDp zqeo8K2IW95L%cZFMMM-Iyj~xprfd#lXB;9Plg4A-$-o415)v-RATDBF^HD4c)~5j^A-UR>NQ7iB`@{j7^c1Dgx~eRKU0b6+Ic=qJZ|r)Ohl;@ z8z`hvyaXjEg=#Q)Jby7FlHFkM`C=~cf(Kz91kxr7D18LpoUB9^YDheD@Yc(N*`*r07qO(UJv}8 z>Ye{E5lQPQCeS=wKnB6rPx5a9LWt-J;ldNRBYNHxsc0T6r;t$7k5M3pU`Gbn4jHea z-v>AyRn!L@X~^*X!B5^93Dqv84?|>$PA-VcvfL)9qBgE|(RztuI!Q~tPT)x@i+$7z zz!BD86Afn}Yh)Cw(p`nRMK^E)kBkGvZTs(L?bxv+%6WN-)tiNTkLr7MCBQ6GbU{cw zWLa!RUygh={p?wKip1=30iKk&bH}(YfQqfuG?tN<_W{gM{KZ7zy8`whh+TTqqL`$w zP<8?r;rIELmm`qzd&qABBcJa%{&^@Rf83@spUMt{PWbxqO6o+j<9C1BTU?Hj&Ts7! zG`hq5vk0k-%CrY5;Zx&(pIlx@(#)|>DNReT@SwZ7HCMA9eaQ;qyR8|+-#S%&`4Z6- zCsSchYW+aUK=>2e`{2jlty#Oa2#5VB(wxZ3+XPfYda+J_b#EkKGeQ;=Yh2ZDl@1YQ zhNPrqA-oem)e$$9JMCm4ZK?B3lxVS*xObXp*8w%1V(ve$?x56T)wl;*rVXkcCVyS? z?jep5=TxEE%iCKIYj;@<5gUBK8GalU`Nw$NZ=AYwBec_O$P23?x1z)gWrtkK5K1K_ zq|8+fg#=%PlThsEh73u`P^h7JMD#Cb-i~=AKe@)o2xy@<+XidbRiQB@pLPEk5kxHQ zc76MkmRo?|VQ$17cVlj`H&NCg#)k-7%TDCKKEz|2R9L;f4d9EY>%5b}oze>BLHg5b z0-}|1S7{O27mWzExG}RXNJUwhFJcWDt-!mTh0++5;lD=5aqMjHhd%HkRgo`6?W(&b zq}W(G94DU31VKiMF$r0>bACaORn$kO55()_5f8{97Hc<__@04j6-98jRiEg?isvD| z8OH0M?VGL`tHX%faG4LFW&+JzGd!yxG31hEvynesC}q`moPfYDJr&3@B7u?+#m&5y za1@KNcUUP_Z(@~N6C^iYAY%%_wz<7D$0M(XWFGrcpFp?2RnML#=eJuY?ssR1_xkng zJs^`Pgi6%)n>EAt7?WNnOeDYDy$rUw2Q|BB z33?Cy;iJgXnic_BgN*Y4MPO|a%G_C`Q54y>Q8k*gyME7l1qUC66XcblL*1(u??=8q zEGUQ_jhS@2C zqfu~9$F|Y4i1lym3LBM>%NsFRHsMU5*TCmb8z{Rnnzui+zrR;cc)gPQm;xwgre3;r zGqzO>OX#bylgT?7ptBH!Xb)058x3<=*{7^=&|~ggPstJiBhFeDROKr>jz?}>4IevP zY3J?jeTdjTLa+BE(ePo&#?R_0rUM7^nctp6%8b?Nt*=M*Z{9R!*p3l1AIWTv{aYyE zWEi>esva6faZQBwpOblItq;DTqGB=6lZR}!_tX&8YU*G1_o`?iwR|f>hh}=9JQtxQ&}tIa?f3ZppH_y#aI4Xsv-(H>Ro5(VssLCEcumg{4a4^JF3#jt8QJ zZrB&cn0oy0vI+6r4YR(27e!y2^O)9k9_k+_;xP2 z?j3)`k=@T&LS(~6@M|E)hM^ghmkq1mZ+Jr_wcZtgEo*4Ov*Yt0(D{zch8=$#wENIg z%b~{OWV8xoq|y*b=wbBM7P}i!pj(3Yitq!S^|A*a}qu_}X927}IFQ|AC5p3vIEy5iUo3ch^ z|M~N$5V4pWZBlIODB)@`$}9@bN5?N%gdw)9K)0V^K(ZN&Z?E;9 z3}!g zw7%xp%11T3BNWSGn42C-4VG9+{lwk<1fBF%xNd^pZRC$mWI&xa4zdHDQA!t^JD?p7 zyPoIm;c)iPEd47HJH-Kf-#qQ1WWs)aA}w;Vpz>gl$<8H3M9*DQi{j1Itnn9s_$v&ll=2F z2>5rv*MwD+C#1+zvFOxZ!90MBph>tN*Ye=c57s?-OjciH`h&JQ0x^<6AhaKH3!xbl zn))?91X=PMx--!KW#RL+##Ax6*QOF=f{e7Z2L_u-Hq4M`zX467==ubick6A3Ds=M- zS7fO65s0A8v2&Z-Ipvig+S>(^ZU+=qOt}RC`J{UQP3(Gw$*{2bb=CxQ;pFcY6JCg zN5L@#RjnoIKjE66$qvL4x(AIA0vp=vavW?)55WSceoOS5L+E}#QAyXB9s8*q0ohMH4Kn4LgK@gT`*i-_4BKVK_cVE8i_eGjAA6YfJTX%`6K z0a>$s-@e#DTUg=t{rgR4Of$h@7WGxv^4m@!J8xftxVPzG^8y}oAwb>{!r3jLMK)-8 zcdiYU6Tnauc6C)pNNv5GY~V>Gxvcb&~s)nSJqmJ_Mi>70#jqK}B zN6GqjV_k678by1UVK*%HBKM^X2cP5NJ7I04?`|CMyCurG9q@=y0^SUCbjHJ-8)uY_ z+@VnJd=Iv$8%hOMLs;H!xY6MFK5Sj6jf8ly@!ABD_9CDgdYwS_^KKQh`a27kN8nW6 z6@P1;pul#*$N$=;-~m!czIvFz_H5V)IheCxYju$|&^imCp+x&m*IGh|(d$b}TXBo~ z@Yy$pIWMu13`%BVW`_Hg7ASl#m|_icS?d|^Z(Rq|#%-baD29hn(3a-p08xq{bC^uR zA)Ge}W*EBTgD<%Z4fF?xm%Xd_h*+7{dAWSuq@6mW3-*xTU7SMW10y42)|vyy(n|3U z1kZ{SRR!sYBMMo3O{Us@NP|3}{zKg$^JOZyOw=HA(1t35B&!>vZT-m)LPTa}xqxn2 zfu(hTACl7^!A9#Sr8Ny&ekmf>j6lb)XTWkv^E2JM;@0gDCy$J^;|eA{WtEJ+un z&7PK1_H&;-|0N~09>;r(M1hen!48mOmALqW7hpg@|mZ> z`fUem?3dI13(DJN$^$}}J1QnZT$3!Po9ExBlrz+~52nScd1J~)2^7%XfGCzf&-Dj% zk|i;j$t1xXoXfQy^y4b~Z1sNcY`k-v*=9&(5}~?1ebNf)$6g`J$ZX62B`wp2NUA`k zoPqH35PB3AT;#&(H)Xn`v+;G4onRuP9+^u;NhORb2yi*r-TQL?C5D2JQW=>U8Nfpd zk>H=kp&*n&L7VH(AXo-^@y6wmwye}4je|^x*g-Spw{yFCds#_W_OLlP=%c7Gs)oKK zdhk&D0XE_mOxm+ABkg8}3(36EOyvCOj!RTBv(EnCzO}V!VGss8NE}BGKgg}Y0`p|= zzV_+(pY?HTK9<5`p{#fg+dS1=*W8r8aG_zcO`PN4!BZHhD8nMiW*oX9JeSHx|6D~C zUS9RcAW>*@5&m+^pvtl9G7JdsnG%usP0NIO1#myTPRR7@8dPSREEoS%z!j|Ye{H!) zoCwLGpbvnz85DE%N1fX&m5 z9LJ6+PLSyZM3lczm2Cp#zpT1?z(`lg=h6@%6@oU9TzWttsKH0)TV?Vwb+bom!SkyW zJsn7b&5qRq3A-5oocNy>VA#W24e{QVLkyU-#vclOk8Et+BqIW%Oa+8dL!p9l?OTa zxgKW>X3>LZCMe`qy}B!@oki_k>&0>5nZ8%*F^R55$5G=J%i(#frz?azE)~CkPCI`D z7Fqn}HvkHBo5#J3N|s;S&rxp4m+77`b?>g!Oa!sTA0s1XHPg3}EjBwWZ^447C;*Z~ zl+?>y9$}hKKec9~#*(9EEjdDP!p?1+K%w*}_W zR%Gxj$^+>r8lsfQrqy>fuSrgfZ_-6kN?+`@9-p`0TB?0!iW-#nV&{APmrsqqF6ZSC zYA8IZei9{Bz_5_aXCzdTVSfuf+|HihC3m-c5h+L2;SlLLK=->B;?l0!S)eS!J@o)P zb0!2bQBk5Uz+bKe9n_72a>zawVmZ4p&Wzx9(l*$?ihmDH;fZ~vmqPcH9Wa-1p_alR ziU;&!_Nt_q>*fdk!V9~-)SFXHkAetgpUM0AgIy}ZY8?7yjfB0aYur%TZGI6Dd$jXVCN1*qNtr>S0F#Fhs-JOdG5w%mE z5w`4pY|@ddg%M-#HS~eId7w?s(%BRW07Jcn9yu9Y>d2iF#`PTU>f?N_$UPT%#6Pb* zKqp~%b8;a7<-@jyp92HLh1Eu4ER&#KWh)BOg(&Uv84|@g$$JG~$ZTg|h?jY%6!EBT zHpQUo^u!WCKi}Pze1vjXlF(%6dVdmmGk1>x?^YW)p--nPqLNaXvhcz>K zLEyo-+w$V~7<}2}M6{tQws!ESU#Y^tRW&M-M{y{-T^(S_^qGa-m;q`O) zK;W`sB#x2z!k~(RuV1C%L3$v8yVYoNvz!&pIMC8_pvaVH6Q@_9zw}>YA^}>=tgPcV zR#O5<7R6)LE8mo5`{6e9cdzvbE#f>|qO%f*yM&}6jxBFelY zH;B(lpHhCZGKQJ#ATMpbKa@_ZMJ}?S{4gXeC-}Q0b!>M5F%?Fu<*scOKE0WWe)%UUZ#_o^k#xa@BHN6auOAdJJn5tbO}w_(ecddF$P+!G22<=v94TPW$& zymGK%GAM<#WeMF~NXL7Zx&j%)^f+FEH)!}4i*rA{Jb6Ae%>cH%$TTzO?-3!qWU! zy;qD)Q9C7fLiJLcEnq}9`@oUxRRdm^b!;K}i9pD5S>s@cne*4^y(#m*QJhEXs~j$e zzaJ8u#9!Gd$G{?!KQyjJN8}MmY`kGJa#>53_p9w6?ZlV<&?rd6~QwqKC-Q!TlRBOp}}&|7t*Ahl&z@ zj6@YUF(SU|2Kns;h5dlnK03y9;nGv$rN>jI^ZfFNW;qPnTd&`GxH3_=~-FE@eeUt(E1bW z%Tr7D&d#nrq1flH1QR(u*tK+%xE&d+e>pN{YHMxn>%8!jkx(}Z_TX50NNs64K=n#9 zZSfnDyW;3r_k%Utso^ZVckf=}))cNlEf9&KHq&_6r+Cz|8y3*@s0sWb_s!=t@nD~S z1vUCfP#zv1FfT4Dx)nPPaPE(rHC`F{htTycbN{(T!_-NgzO9+pCNY&|<@5iv_vL|D z=WF|qnlcq>qs`JNqEM+sSu4p_(jt3`Bx?zkEY+k%CHs=15G6~9C}E83J0V#rPh@Qf z!((}``)SU5&imi*|KI74b7m&%_xt(W%XMGZb!&jk3jj`XC0}x;E#57S+OMnaW-4R674asb$qu`UD zdTm}#HQOcDIx~*`af)xgTG@Q7E$hh)qBhv4*xV04m^UUxqHf=6Vl2|Nf#mH+-x;eu z1a&>kZ-KC@`<4Yed>!P+1Jg;vxP_XJI_SAO$cEbAP$i%=_hZiQ(S+8GvL#%Kc41WOHT&%o) z&c&Bcl#)wS))wm-Zn7!dXf^f&-Fr0e)N4?wse;v3G4EoDD@Yk<{b--w!(q_p^gI-0 z?$uG$oLSb5HGeFheUPM%L+(J9Why}_U3=Uc)a`Ot%lTF9$GvK56cI=gF4!+Qr?LB7 zY6wU&RgX9f$_@js#7*2!GYFm<#2#}jM)vA_&d2Ycn5x8a8?Q!-%`mzT<{wI=nkSdw zI46d}ttJ|bF!jwRoM1C$4v}YAB^KZ81>zz%Dq#_4&#<^w9qFN_wPMwA{w29h`*@-r zKR%b&C#0yi;oZsO_PkD3cb9co-9;E>vlYtG zacxg_z-gV|{19bLF?2Ym)>wq&RgypqG+WM=Hdy9Az97aj1J5ig4Oz+{t$$i^<3Vo& z#<81tA>ZhC>wWtWjYD_M+<9RgT7qsr4v>f0Rx5mT5Z+>NvCKkLVoW!2j={Vr=;yMiRfXC><6}PGQPf9mBgN zB%sQJBo1Sd6Yv^1s0(<`EdANhgV5sL>>HI6fs<+` zR1L-g6HVaDZnIqwSZ*rSByIFuV z&_oEmX@eK$1c>eF+jGzZ$wHuh#R@*JIvW-ExDlfxrO?NuXmh}hIv!{k;`0+!pFO8)T6cm;Q zl?pJ4JN;Q>;4swp#bakydvacKvJxd8bbN`LrAi@fCX=hiW(wW7fyrz2qqfQ#_b{k8 ztXo~rpFfqj`j+nljwNue|j;HL#jc^6m_uq#Acho%=Mcc}y^KPKQ zoq1}>sfvXSn?|Z&lhKsv7%N4l#PBFNeXviu(_<0SFJwdR-6%qV6a%!^%Y%iff5O}eVuBJb8x18> z$gR!0RNRKX%DVK2+bKJ#Fimjb5jmcT_F+8}7S)Kwzkh(i99cz5g*f(8rY(?k%XI3D>l1dH*r#tBJ`? zBcB6pjFJFE?d}>05S`~lMP^qlDcT5`%r?1P5NwVLUv|4QL$7gB}&VlmI%>5}@lp}MoKmf)42(7Cn$ z2=D}|mwuqqU+&&2rks!CTB?1a`u%0U6HC_QExg)=wG2*HxXtIEim#2D`~eao-n}g3 zfL|w}6Xg;LTcb*oGf`3!Cz9zz8o#$esE8dzxK~0U+H~8TM^5>)X)LL0M594TJdLqE!!T z;sCX6nw@U+>BOg5NmDu8by`b|6(Tp(GXM09Aq?{*g9ceC% z&F;kuJ|*Tk6aG4fgVRxcdk@K>g$5H?+ojhY58`qufR$aCz$dBCn=^+zEMnij;~eIW z?AIsELnK{LoOX@l5^o04;`E!(7XLW(fzj zuUz}@GzHLH-+z6kqoX4eT&jlhJ$0~DxByq8c}8}qki$mNhI*ymG8CS+sU-`bPj{39 zwD(+{1x^{4l415mr{(a45w%5Thq=_)*@GtXT{8o?qEvnW`*>+}^7aIVG)}3%hiZw! zQhME1CNjAQxQO-9a@~&}`2~3-D^CsBO8FPB!Qe~v;rbbjV;lDHy!gr^e<=L+6%#C@ zKX~X6hm*yRV`r_ZVI*N}03%f1zFdOC^fS-Kn0-HLSq?;N+-yINHrLG5qYWHl4vBT`W~nB zMgroKhD>@>s1{ERjb1#ah9WFb8=UQ~6VF#JgRCP3Zb;vtkV{Nz*o&d}kKU$(FoX@HH54$o4Wv(N5}P^)xD)YBuLr2om=7bBurydc6k~FQ z!}LG_?wyPH`Jbz=#0q*})|Klxpe10>ZnYxHC`mT6jBrq$SiZ;~rEpu^T_C%OG7WHM z1>>*-o`$ZyyBc5)(R>}qaFbbEdCl8UG?S-WU0q#Qj(GD1PxS25&`4Pq(c8%Qi;l zR^BHau9m3(Nk%6Uk=@@5SfYR1=SwVS%jk7j2SVdn#GhqX{l}B%r z&O%1}UX(hEu)N^HuXQ#0xB3v3$&)%JxZ`SiMKl$YX~=&?P;+MJy6$_>hJN?yDbAoM zR83%vSVQF&Z8

C+_8sRP`gavS&nvQ*FZ2{4(7y-iM2)Kko}Lx8aE7D zQ$A+9!bvAnm}8BY`0yaW=ecgN`9G zlPW1Mmvjh4*WVSSj}vvcCkJTkMM7Q1Zr*?f?-q7Yt#@cbHSsNofRvQ$5R7WS#d()X z(;AH8T{b@&DOEsuU$K1#KB0+<6>hAC!8@jX(|lClF&wr z9k<8#0s%_E1vY$=#Cn`7?yD@x$S1(;wq1n?5!GrJh^v0V;;#M#|Pu_js335HA7rTIdNW!YvwkK)=64Xh(LCWOix zatpjX319r^@q>HS)qO$U=&oUn4s1wFyt~7uv!jDRAaf91Vd3~Rl-c}%Tn z$>8mlyJCE8{JVoSJPA~W+|hhz>Hm2^20KB&)vzmlNz%h=A^s^h zc71}*cm;1?`&k?GMpTgb^T8zwDb=xCrlY@Kia;mQ0MvZ>^2H+8ljF!}<*f-zWrk$& z6g;~`P{Z>27n@g~1zv@9x=U$=9)F54Cb53Rm)dmvca$Ur-7@)}UVjkB1>r9S!*)K& zZ7ANzloC?5;_t105*CeI&6lx$A))_8!KUuw02pGgNF<}V$RFZybVJod-J~~5=HZ2} z%bQ@20z&A!&rai*Kj2DQ;I5Mm?)3ng57JB&zK4^mY@y?&8Uyj~Zar&}0e>VDAsIv4 zng`R6?`9NP05^KJLv5l^Y09ix;XH=)#O&@r54C_QQ+7F}?8D%h5Qe(Nid~~A95p0O zS5_Kne9YQPYaH8fYph$**WQeXFunQy4g$4Qd0a%I7*;rBrGYqK{rAt&ZTJELlaf=R zyU{=m)Ipx!^rGPcbGSnq3YQctI{NnEWxNgeV?*0;^=QB=*?Jf4zXtk>ekdMApy3Ll zsTWX8bBMcZ9;?o?djC8WV!RIo24EI!TT)cCk?YlQSSg<_hRB@>(k+&kkV5ES4)@jLee^sA@$Y*vNeA?? zOA)kG;iRXS{er${f@K|Zx%qASw;CXTSm5tdF!rEHv{8<`F~-yU+l!(l&b~;ICPoE~ z1dwA&(1FdJAY6xpgScLF)UePdb%qiPNKGkm+lbDDQbyCk!QoNf3J?&@!9*iA4?#tT zFAJ2oD&GZ5ie@gfPB0y*2rQ6wDg1yrh{#7n?d1v=(+)GGgli&IW`+VDz!@13Yma>nMi*GvyM7ZJkWA3pWzn7N2J*e`%h zBGp|%64jKCO9I_Wst*_tU*}?|dNdzwor|XU=Z=8Y%0C-rgjlhc0n0JSgaOy+;Ex}N zphnW6i$o4bWGMy+1HKx%2!~HW1Am4GlW(EA+ZJU*ky9H|axT->4Fh;>q?h<2TdY0u zw4>xN?z#eVPSI%$$)3V;H#I1RGXE!Zmt>p*UU1W)P9$tyY}E))v^7RMQ)B_+L!x0K zg4Q|^p`Os`(ZTTLpzvc*rA^v9-zS+S8Rp34h`2@u&bZc}|K7mS$QUJveohVww*1NW z7?GAKo>Y)nyH*Vwo%0<$f7|@3cRU9iw$t;@)JO9ktsjEiXFB)Us>Y zW@P#J21r0-!G^SHRKuzR(*SSl)iHI)G~afDqIu53LOQe#$IgLr@lxKe8HWumtps zj7jiplC4;BGvua@I-%Nd`dYSp7{@yvM>`(P`BS9UXXu&Y(4oxgw7oy_w;&z_+nxvd zXef`2yGhEA*V_$cq72h@pjCnGJOXbV^kh*WKgEMBPzR{nwly|zczZ@n86e+Cbb{lN ziuA;USFf%I`0>1Z@n$tt7+5AbaWxA$KVvQrj~+b9x-pUNm5{A?#PuU%sX5L^mOMV~ z)Za}Q?L4DxK8h7_tor&2AvWd%DwuyC(*YZ;}kuH?>M5zOzBWqF@ z$=dd9P}Tst%PM9LRwN4t_teJ+pA1Dwkvd8x1%TG)&2O$#Tn}^d#!w}E_66V&CIu^S^ot#>8JUmhdfwX6xMhjv$MyDQ!B>qD? zQtDwqih>;wBSaqR&*z`Y?ZRR@Zl45@(lWDLM-x?9d6>Sf{A$sEYzOQj_G)S#1Qq&- zxVZR{zF?B%&=~UYs%L)lt6*~SthpcAhA;CY#>W9b)$E!;dkx9%2g=?RG=QF=p5xy6 zUpW~i{aYK6qU(W-flfJUv%Md8?kOTn_gy8Vc*!6JH){Vw^Y|n-%1?u@p$kSA^XrEq zzk$#P4-!yY+b)a#)HXepakz6n@?==LP8B1RHED)#p1yt6ada^-Y)RG5ODNIEIj$ab z0?T9fL*QSzM_k~>KBLH!*XRlPe;>Az{**dFE>QdrQ z!QRlBl<$B3QT}F8QGOE>m^h@o*T1O2M_vc2+)XUeJ21b1@Z%X?Qan|!b_-hGTsSzo zpbU)QUiZ~Km>6c+nq;08+2#}eebhloIe)SN-FiK4Livg%;Rp<9k?Uz&O5;9QtsFm~ zd~L#ZXv!J|6@0`rRloZB`$z42DF2j}QkUk}Fu1|X(?frm`c2i9)28)0Z|Te^;CRv> zM`^zb-Qa8U{Ypzq4`OFjox=CEN6OO7DjD3Pl?Nz{<11Oczbb{cmI_+0wkX5`+B|g9 z9(8ojxjKC)lp-Y|cdl0ZGrz;;0=;>(1Z! z8SN{yI?<*fYyoVkM|t!-%t;^LogM3GZ!1Cj5U|?Mt+*=LB)Ios*jVi<`u&<59jkR z-ddLJ$d4ZqDJ_8o3~mwQyL&dTDe>SGA`hdMS7-8{yO)5D8jlL%+m*cS+pD|}IOr`r z0Er@(kyDBrInvMA;^{W0%RZwXyn3gxcOY6RI)Z7}vZ@vr(9o$oybaAH*MP#{%Cz2B z$MFQ|NWBtDOIIS2tXE|i%nO^IOg^aY;DCS4Nl8O~junW^(amo$?ys?`cyVX^iA1RK zNepbVn3WH9{BLww%iP26SUe_sOhwS6BN~WMQh9Ft`iOIHquBvLc!sdCpno`g4n@x6 z7`p&SWMW^CqD7$sB#+F}@reC!#5BPKqB?~%8u^#7 zDOC*2ENRzl5|p9+R0Wdffa)7aSmbp9ia%c2sKG

Dep$CMXs6DbvF6yh}o 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 literal 0 HcmV?d00001 diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/index.rst b/hw/vendor/esl_epfl_x_heep/docs/source/index.rst index e3968a3f..a0d4c746 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/index.rst +++ b/hw/vendor/esl_epfl_x_heep/docs/source/index.rst @@ -1,6 +1,11 @@ X-HEEP ====== +.. image:: images/x-heep-outline.png + :width: 600 + + + ``X-HEEP`` (eXtendable Heterogeneous Energy-Efficient Platform) is a RISC-V microcontroller described in SystemVerilog that can be configured to target small and tiny platforms as well as extended to support accelerators. The cool thing about X-HEEP is that we provide a simple customizable MCU, so CPUs, common peripherals, memories, etc. so that you can extend it with your own accelerator without modifying the MCU, but just instantiating it in your design. By doing so, you inherit an IP capable of booting RTOS (such as FreeRTOS) with the whole FW stack, including HAL drivers and SDK, and you can focus on building your special HW or APP supported by the microcontroller. @@ -23,7 +28,7 @@ The CPU subsystem is based on the `RISC-V lowRISC Ibex 1 ? $clog2(SYSTEM_XBAR_NMASTER) : 32'd1; localparam int unsigned LOG_SYSTEM_XBAR_NSLAVE = SYSTEM_XBAR_NSLAVE > 1 ? $clog2(SYSTEM_XBAR_NSLAVE) : 32'd1; - localparam int unsigned NUM_BANKS = ${ram_numbanks}; - localparam int unsigned NUM_BANKS_IL = ${ram_numbanks_il}; + localparam int unsigned NUM_BANKS = ${xheep.ram_numbanks()}; + localparam int unsigned NUM_BANKS_IL = ${xheep.ram_numbanks_il()}; localparam int unsigned EXTERNAL_DOMAINS = ${external_domains}; localparam logic[31:0] ERROR_START_ADDRESS = 32'hBADACCE5; @@ -62,49 +63,44 @@ package core_v_mini_mcu_pkg; localparam logic[31:0] ERROR_END_ADDRESS = ERROR_START_ADDRESS + ERROR_SIZE; localparam logic[31:0] ERROR_IDX = 32'd0; -% for bank in range(ram_numbanks_cont): - localparam logic [31:0] RAM${bank}_START_ADDRESS = 32'h${'{:08X}'.format(int(ram_start_address) + bank*32*1024)}; - localparam logic [31:0] RAM${bank}_SIZE = 32'h${hex(32*1024)[2:]}; - localparam logic [31:0] RAM${bank}_END_ADDRESS = RAM${bank}_START_ADDRESS + RAM${bank}_SIZE; - localparam logic [31:0] RAM${bank}_IDX = 32'd${bank + 1}; +% for bank in xheep.iter_ram_banks(): + localparam logic [31:0] RAM${bank.name()}_IDX = 32'd${bank.map_idx()}; + localparam logic [31:0] RAM${bank.name()}_SIZE = 32'h${f'{bank.size():08X}'}; + localparam logic [31:0] RAM${bank.name()}_START_ADDRESS = 32'h${f'{bank.start_address():08X}'}; + localparam logic [31:0] RAM${bank.name()}_END_ADDRESS = 32'h${f'{bank.end_address():08X}'}; % endfor -% if ram_numbanks_il != 0: - localparam logic [31:0] RAM${ram_numbanks_cont}_START_ADDRESS = 32'h${'{:08X}'.format(int(ram_start_address) + int(ram_numbanks_cont)*32*1024)}; - localparam logic [31:0] RAM${ram_numbanks_cont}_SIZE = 32'h${hex(int(ram_numbanks_il)*32*1024)[2:]}; - localparam logic [31:0] RAM${ram_numbanks_cont}_END_ADDRESS = RAM${ram_numbanks_cont}_START_ADDRESS + RAM${ram_numbanks_cont}_SIZE; - localparam logic [31:0] RAM${ram_numbanks_cont}_IDX = 32'd${ram_numbanks_cont + 1}; -% for bank in range(ram_numbanks_il - 1): - localparam logic [31:0] RAM${int(ram_numbanks_cont) + bank + 1}_IDX = 32'd${int(ram_numbanks_cont) + bank + 2}; + +% for i, group in enumerate(xheep.iter_il_groups()): + localparam logic [31:0] RAM_IL${i}_START_ADDRESS = 32'h${f'{group.start:08X}'}; + localparam logic [31:0] RAM_IL${i}_SIZE = 32'h${f'{group.size:08X}'}; + localparam logic [31:0] RAM_IL${i}_END_ADDRESS = RAM_IL${i}_START_ADDRESS + RAM_IL${i}_SIZE; + localparam logic [31:0] RAM_IL${i}_IDX = RAM${group.first_name}_IDX; % endfor -% endif localparam logic[31:0] DEBUG_START_ADDRESS = 32'h${debug_start_address}; localparam logic[31:0] DEBUG_SIZE = 32'h${debug_size_address}; localparam logic[31:0] DEBUG_END_ADDRESS = DEBUG_START_ADDRESS + DEBUG_SIZE; - localparam logic[31:0] DEBUG_IDX = 32'd${int(ram_numbanks) + 1}; + localparam logic[31:0] DEBUG_IDX = 32'd${xheep.ram_numbanks() + 1}; localparam logic[31:0] AO_PERIPHERAL_START_ADDRESS = 32'h${ao_peripheral_start_address}; localparam logic[31:0] AO_PERIPHERAL_SIZE = 32'h${ao_peripheral_size_address}; localparam logic[31:0] AO_PERIPHERAL_END_ADDRESS = AO_PERIPHERAL_START_ADDRESS + AO_PERIPHERAL_SIZE; - localparam logic[31:0] AO_PERIPHERAL_IDX = 32'd${int(ram_numbanks) + 2}; + localparam logic[31:0] AO_PERIPHERAL_IDX = 32'd${xheep.ram_numbanks() + 2}; localparam logic[31:0] PERIPHERAL_START_ADDRESS = 32'h${peripheral_start_address}; localparam logic[31:0] PERIPHERAL_SIZE = 32'h${peripheral_size_address}; localparam logic[31:0] PERIPHERAL_END_ADDRESS = PERIPHERAL_START_ADDRESS + PERIPHERAL_SIZE; - localparam logic[31:0] PERIPHERAL_IDX = 32'd${int(ram_numbanks) + 3}; + localparam logic[31:0] PERIPHERAL_IDX = 32'd${xheep.ram_numbanks() + 3}; localparam logic[31:0] FLASH_MEM_START_ADDRESS = 32'h${flash_mem_start_address}; localparam logic[31:0] FLASH_MEM_SIZE = 32'h${flash_mem_size_address}; localparam logic[31:0] FLASH_MEM_END_ADDRESS = FLASH_MEM_START_ADDRESS + FLASH_MEM_SIZE; - localparam logic[31:0] FLASH_MEM_IDX = 32'd${int(ram_numbanks) + 4}; + localparam logic[31:0] FLASH_MEM_IDX = 32'd${xheep.ram_numbanks() + 4}; localparam addr_map_rule_t [SYSTEM_XBAR_NSLAVE-1:0] XBAR_ADDR_RULES = '{ '{ idx: ERROR_IDX, start_addr: ERROR_START_ADDRESS, end_addr: ERROR_END_ADDRESS }, -% for bank in range(ram_numbanks_cont): - '{ idx: RAM${bank}_IDX, start_addr: RAM${bank}_START_ADDRESS, end_addr: RAM${bank}_END_ADDRESS }, -% endfor -% for bank in range(ram_numbanks_il): - '{ idx: RAM${int(ram_numbanks_cont) + bank}_IDX, start_addr: RAM${ram_numbanks_cont}_START_ADDRESS, end_addr: RAM${ram_numbanks_cont}_END_ADDRESS }, +% for bank in xheep.iter_ram_banks(): + '{ idx: RAM${bank.name()}_IDX, start_addr: RAM${bank.name()}_START_ADDRESS, end_addr: RAM${bank.name()}_END_ADDRESS }, % endfor '{ idx: DEBUG_IDX, start_addr: DEBUG_START_ADDRESS, end_addr: DEBUG_END_ADDRESS }, '{ idx: AO_PERIPHERAL_IDX, start_addr: AO_PERIPHERAL_START_ADDRESS, end_addr: AO_PERIPHERAL_END_ADDRESS }, @@ -142,6 +138,7 @@ package core_v_mini_mcu_pkg; // always-on peripherals // --------------------- localparam AO_PERIPHERALS = ${ao_peripherals_count}; + localparam DMA_CH_NUM = ${dma_ch_count}; % for peripheral, addr in ao_peripherals.items(): localparam logic [31:0] ${peripheral.upper()}_START_ADDRESS = AO_PERIPHERAL_START_ADDRESS + 32'h${addr["offset"]}; @@ -150,6 +147,7 @@ package core_v_mini_mcu_pkg; localparam logic [31:0] ${peripheral.upper()}_IDX = 32'd${loop.index}; % endfor + localparam addr_map_rule_t [AO_PERIPHERALS-1:0] AO_PERIPHERALS_ADDR_RULES = '{ % for peripheral, addr in ao_peripherals.items(): '{ idx: ${peripheral.upper()}_IDX, start_addr: ${peripheral.upper()}_START_ADDRESS, end_addr: ${peripheral.upper()}_END_ADDRESS }${"," if not loop.last else ""} @@ -158,6 +156,23 @@ package core_v_mini_mcu_pkg; localparam int unsigned AO_PERIPHERALS_PORT_SEL_WIDTH = AO_PERIPHERALS > 1 ? $clog2(AO_PERIPHERALS) : 32'd1; + // Relative DMA channels addresses +% for i in range(int(dma_ch_count)): + localparam logic [7:0] DMA_CH${i}_START_ADDRESS = 8'h${hex(int(ao_peripherals["dma"]["ch_length"], 16)*(i) >> 8)[2:]}; + localparam logic [7:0] DMA_CH${i}_SIZE = 8'h${hex(int(ao_peripherals["dma"]["ch_length"], 16) >> 8)[2:]}; + localparam logic [7:0] DMA_CH${i}_END_ADDRESS = DMA_CH${i}_START_ADDRESS + DMA_CH${i}_SIZE; + localparam logic [7:0] DMA_CH${i}_IDX = 8'd${i}; + +% endfor + + localparam addr_map_rule_8bit_t [DMA_CH_NUM-1:0] DMA_ADDR_RULES = '{ + % for i in range(int(dma_ch_count)): + '{ idx: DMA_CH${i}_IDX, start_addr: DMA_CH${i}_START_ADDRESS, end_addr: DMA_CH${i}_END_ADDRESS }${"," if not loop.last else ""} +% endfor + }; + + localparam int unsigned DMA_CH_PORT_SEL_WIDTH = DMA_CH_NUM > 1 ? $clog2(DMA_CH_NUM) : 32'd1; + ###################################################################### ## Automatically add all peripherals listed ###################################################################### @@ -195,5 +210,11 @@ package core_v_mini_mcu_pkg; localparam int unsigned NUM_PAD_PORT_SEL_WIDTH = NUM_PAD > 1 ? $clog2(NUM_PAD) : 32'd1; + typedef enum logic [1:0] { + TOP, + RIGHT, + BOTTOM, + LEFT + } pad_side_e; endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/power_manager_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/power_manager_pkg.sv new file mode 100644 index 00000000..613d2c7d --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/power_manager_pkg.sv @@ -0,0 +1,17 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +package power_manager_pkg; + + typedef struct packed {logic pwrgate_ack_n;} power_manager_in_t; + + typedef struct packed { + logic clkgate_en_n; + logic pwrgate_en_n; + logic isogate_en_n; + logic retentive_en_n; + logic rst_n; + } power_manager_out_t; + +endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/x-heep_packages.core b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/x-heep_packages.core index 8a1a838d..6cbf61b0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/x-heep_packages.core +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/x-heep_packages.core @@ -13,6 +13,7 @@ filesets: - addr_map_rule_pkg.sv - obi_pkg.sv - reg_pkg.sv + - power_manager_pkg.sv - core_v_mini_mcu_pkg.sv file_type: systemVerilogSource diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/memory_subsystem.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/memory_subsystem.sv.tpl index 9e89348c..660b1b6a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/memory_subsystem.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/memory_subsystem.sv.tpl @@ -19,33 +19,27 @@ module memory_subsystem input obi_req_t [NUM_BANKS-1:0] ram_req_i, output obi_resp_t [NUM_BANKS-1:0] ram_resp_o, + // power manager signals that goes to the ASIC macros + input logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] pwrgate_ni, + output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] pwrgate_ack_no, input logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] set_retentive_ni ); - localparam int NumWords = 32 * 1024 / 4; - localparam int AddrWidth = $clog2(32 * 1024); -% if ram_numbanks_il != 0: - localparam int ilAddrWidth = $clog2(${ram_numbanks_il} * 32 * 1024); -% endif - logic [NUM_BANKS-1:0] ram_valid_q; // Clock-gating logic [NUM_BANKS-1:0] clk_cg; -% if ram_numbanks_il != 0: - logic [NUM_BANKS-1:0][AddrWidth-3:0] ram_req_addr; - for (genvar i = 0; i < NUM_BANKS; i++) begin : gen_addr_napot - if (i >= NUM_BANKS - ${ram_numbanks_il}) begin - assign ram_req_addr[i] = { - ram_req_i[i].addr[ilAddrWidth-1:AddrWidth] - - core_v_mini_mcu_pkg::RAM${ram_numbanks_cont}_START_ADDRESS[ilAddrWidth-1:AddrWidth], - ram_req_i[i].addr[AddrWidth-1:${2+log_ram_numbanks_il}] - }; - end else begin - assign ram_req_addr[i] = ram_req_i[i].addr[AddrWidth-1:2]; - end - end -% endif +% for i, bank in enumerate(xheep.iter_ram_banks()): + logic [${bank.size().bit_length()-1 -2}-1:0] ram_req_addr_${i}; +% endfor + +% for i, bank in enumerate(xheep.iter_ram_banks()): +<% + p1 = bank.size().bit_length()-1 + bank.il_level() + p2 = 2 + bank.il_level() +%> + assign ram_req_addr_${i} = ram_req_i[${i}].addr[${p1}-1:${p2}]; +% endfor for (genvar i = 0; i < NUM_BANKS; i++) begin : gen_sram @@ -66,27 +60,26 @@ module memory_subsystem assign ram_resp_o[i].gnt = ram_req_i[i].req; assign ram_resp_o[i].rvalid = ram_valid_q[i]; + end - //Fixed to 8KWords per bank (32KB) - sram_wrapper #( - .NumWords (NumWords), - .DataWidth(32'd32) - ) ram_i ( - .clk_i(clk_cg[i]), - .rst_ni(rst_ni), - .req_i(ram_req_i[i].req), - .we_i(ram_req_i[i].we), -% if ram_numbanks_il == 0: - .addr_i(ram_req_i[i].addr[AddrWidth-1:2]), -% else: - .addr_i(ram_req_addr[i]), -% endif - .wdata_i(ram_req_i[i].wdata), - .be_i(ram_req_i[i].be), - .set_retentive_ni(set_retentive_ni[i]), - .rdata_o(ram_resp_o[i].rdata) - ); +%for i, bank in enumerate(xheep.iter_ram_banks()): + sram_wrapper #( + .NumWords (${bank.size() // 4}), + .DataWidth(32'd32) + ) ram${bank.name()}_i ( + .clk_i(clk_cg[${i}]), + .rst_ni(rst_ni), + .req_i(ram_req_i[${i}].req), + .we_i(ram_req_i[${i}].we), + .addr_i(ram_req_addr_${i}), + .wdata_i(ram_req_i[${i}].wdata), + .be_i(ram_req_i[${i}].be), + .pwrgate_ni(pwrgate_ni[${i}]), + .pwrgate_ack_no(pwrgate_ack_no[${i}]), + .set_retentive_ni(set_retentive_ni[${i}]), + .rdata_o(ram_resp_o[${i}].rdata) + ); - end +%endfor endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv index bb1c1d19..4fa663e6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv @@ -50,6 +50,18 @@ module peripheral_subsystem output logic cio_sda_en_o, // SPI Host + output logic spi_sck_o, + output logic spi_sck_en_o, + output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_o, + output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_en_o, + output logic [ 3:0] spi_sd_o, + output logic [ 3:0] spi_sd_en_o, + input logic [ 3:0] spi_sd_i, + output logic spi_intr_event_o, + output logic spi_rx_valid_o, + output logic spi_tx_ready_o, + + // SPI 2 Host output logic spi2_sck_o, output logic spi2_sck_en_o, output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_o, @@ -291,11 +303,48 @@ module peripheral_subsystem .msip_o(msip_o) ); + spi_host #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) spi_host_dma_i ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI_HOST_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_HOST_IDX]), + .alert_rx_i(), + .alert_tx_o(), + .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), + .passthrough_o(), + .cio_sck_o(spi_sck_o), + .cio_sck_en_o(spi_sck_en_o), + .cio_csb_o(spi_csb_o), + .cio_csb_en_o(spi_csb_en_o), + .cio_sd_o(spi_sd_o), + .cio_sd_en_o(spi_sd_en_o), + .cio_sd_i(spi_sd_i), + .rx_valid_o(spi_rx_valid_o), + .tx_ready_o(spi_tx_ready_o), + .intr_error_o(), + .intr_spi_event_o(spi_intr_event_o) + ); - assign cio_gpio_o = '0; - assign cio_gpio_en_o = '0; - assign gpio_intr = '0; - assign peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_IDX] = '0; + + + gpio #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) gpio_i ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::GPIO_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::GPIO_IDX]), + .gpio_in({cio_gpio_i, 8'b0}), + .gpio_out({cio_gpio_o, cio_gpio_unused}), + .gpio_tx_en_o({cio_gpio_en_o, cio_gpio_en_unused}), + .gpio_in_sync_o(), + .pin_level_interrupts_o({gpio_intr, gpio_int_unused}), + .global_interrupt_o() + ); reg_to_tlul #( .req_t(reg_pkg::reg_req_t), @@ -314,27 +363,34 @@ module peripheral_subsystem .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2C_IDX]) ); - assign i2c_tl_d2h = '0; - assign cio_scl_o = '0; - assign cio_scl_en_o = '0; - assign cio_sda_o = '0; - assign cio_sda_en_o = '0; - assign i2c_intr_fmt_watermark = '0; - assign i2c_intr_rx_watermark = '0; - assign i2c_intr_fmt_overflow = '0; - assign i2c_intr_rx_overflow = '0; - assign i2c_intr_nak = '0; - assign i2c_intr_scl_interference = '0; - assign i2c_intr_sda_interference = '0; - assign i2c_intr_stretch_timeout = '0; - assign i2c_intr_sda_unstable = '0; - assign i2c_intr_trans_complete = '0; - assign i2c_intr_tx_empty = '0; - assign i2c_intr_tx_nonempty = '0; - assign i2c_intr_tx_overflow = '0; - assign i2c_intr_acq_overflow = '0; - assign i2c_intr_ack_stop = '0; - assign i2c_intr_host_timeout = '0; + i2c i2c_i ( + .clk_i(clk_cg), + .rst_ni, + .tl_i(i2c_tl_h2d), + .tl_o(i2c_tl_d2h), + .cio_scl_i, + .cio_scl_o, + .cio_scl_en_o, + .cio_sda_i, + .cio_sda_o, + .cio_sda_en_o, + .intr_fmt_watermark_o(i2c_intr_fmt_watermark), + .intr_rx_watermark_o(i2c_intr_rx_watermark), + .intr_fmt_overflow_o(i2c_intr_fmt_overflow), + .intr_rx_overflow_o(i2c_intr_rx_overflow), + .intr_nak_o(i2c_intr_nak), + .intr_scl_interference_o(i2c_intr_scl_interference), + .intr_sda_interference_o(i2c_intr_sda_interference), + .intr_stretch_timeout_o(i2c_intr_stretch_timeout), + .intr_sda_unstable_o(i2c_intr_sda_unstable), + .intr_trans_complete_o(i2c_intr_trans_complete), + .intr_tx_empty_o(i2c_intr_tx_empty), + .intr_tx_nonempty_o(i2c_intr_tx_nonempty), + .intr_tx_overflow_o(i2c_intr_tx_overflow), + .intr_acq_overflow_o(i2c_intr_acq_overflow), + .intr_ack_stop_o(i2c_intr_ack_stop), + .intr_host_timeout_o(i2c_intr_host_timeout) + ); reg_to_tlul #( .req_t(reg_pkg::reg_req_t), @@ -362,29 +418,56 @@ module peripheral_subsystem .intr_timer_expired_1_0_o(rv_timer_3_intr_o) ); - assign peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI2_IDX] = '0; - assign spi2_sck_o = '0; - assign spi2_sck_en_o = '0; - assign spi2_csb_o = '0; - assign spi2_csb_en_o = '0; - assign spi2_sd_o = '0; - assign spi2_sd_en_o = '0; - assign spi2_intr_event = '0; + spi_host #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) spi2_host ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI2_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI2_IDX]), + .alert_rx_i(), + .alert_tx_o(), + .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), + .passthrough_o(), + .cio_sck_o(spi2_sck_o), + .cio_sck_en_o(spi2_sck_en_o), + .cio_csb_o(spi2_csb_o), + .cio_csb_en_o(spi2_csb_en_o), + .cio_sd_o(spi2_sd_o), + .cio_sd_en_o(spi2_sd_en_o), + .cio_sd_i(spi2_sd_i), + .rx_valid_o(), + .tx_ready_o(), + .intr_error_o(), + .intr_spi_event_o(spi2_intr_event) + ); assign peripheral_slv_rsp[core_v_mini_mcu_pkg::PDM2PCM_IDX] = '0; - assign pdm2pcm_clk_o = '0; + assign pdm2pcm_clk_o = '0; - assign pdm2pcm_clk_en_o = 1; + assign pdm2pcm_clk_en_o = 1; - assign peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX] = '0; - - assign i2s_sck_oe_o = 1'b0; - assign i2s_sck_o = 1'b0; - assign i2s_ws_oe_o = 1'b0; - assign i2s_ws_o = 1'b0; - assign i2s_sd_oe_o = 1'b0; - assign i2s_sd_o = 1'b0; - assign i2s_intr_event = 1'b0; - assign i2s_rx_valid_o = 1'b0; + i2s #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) i2s_i ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::I2S_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX]), + + .i2s_sck_o(i2s_sck_o), + .i2s_sck_oe_o(i2s_sck_oe_o), + .i2s_sck_i(i2s_sck_i), + .i2s_ws_o(i2s_ws_o), + .i2s_ws_oe_o(i2s_ws_oe_o), + .i2s_ws_i(i2s_ws_i), + .i2s_sd_o(i2s_sd_o), + .i2s_sd_oe_o(i2s_sd_oe_o), + .i2s_sd_i(i2s_sd_i), + .intr_i2s_event_o(i2s_intr_event), + .i2s_rx_valid_o(i2s_rx_valid_o) + ); endmodule : peripheral_subsystem diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl index 71215d04..4025cd88 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/peripheral_subsystem.sv.tpl @@ -50,6 +50,18 @@ module peripheral_subsystem output logic cio_sda_en_o, // SPI Host + output logic spi_sck_o, + output logic spi_sck_en_o, + output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_o, + output logic [spi_host_reg_pkg::NumCS-1:0] spi_csb_en_o, + output logic [ 3:0] spi_sd_o, + output logic [ 3:0] spi_sd_en_o, + input logic [ 3:0] spi_sd_i, + output logic spi_intr_event_o, + output logic spi_rx_valid_o, + output logic spi_tx_ready_o, + + // SPI 2 Host output logic spi2_sck_o, output logic spi2_sck_en_o, output logic [spi_host_reg_pkg::NumCS-1:0] spi2_csb_o, @@ -306,6 +318,49 @@ module peripheral_subsystem % endif % endfor +% for peripheral in peripherals.items(): +% if peripheral[0] in ("spi_host"): +% if peripheral[1]['is_included'] in ("yes"): + spi_host #( + .reg_req_t(reg_pkg::reg_req_t), + .reg_rsp_t(reg_pkg::reg_rsp_t) + ) spi_host_dma_i ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::SPI_HOST_IDX]), + .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_HOST_IDX]), + .alert_rx_i(), + .alert_tx_o(), + .passthrough_i(spi_device_pkg::PASSTHROUGH_REQ_DEFAULT), + .passthrough_o(), + .cio_sck_o(spi_sck_o), + .cio_sck_en_o(spi_sck_en_o), + .cio_csb_o(spi_csb_o), + .cio_csb_en_o(spi_csb_en_o), + .cio_sd_o(spi_sd_o), + .cio_sd_en_o(spi_sd_en_o), + .cio_sd_i(spi_sd_i), + .rx_valid_o(spi_rx_valid_o), + .tx_ready_o(spi_tx_ready_o), + .intr_error_o(), + .intr_spi_event_o(spi_intr_event_o) + ); +% else: + assign peripheral_slv_rsp[core_v_mini_mcu_pkg::SPI_HOST_IDX] = '0; + assign spi_sck_o = '0; + assign spi_sck_en_o = '0; + assign spi_csb_o = '0; + assign spi_csb_en_o = '0; + assign spi_sd_o = '0; + assign spi_sd_en_o = '0; + assign spi_intr_event_o = '0; + assign spi_rx_valid_o = '0; + assign spi_tx_ready_o = '0; +% endif +% endif +% endfor + + % for peripheral in peripherals.items(): % if peripheral[0] in ("gpio"): @@ -491,7 +546,7 @@ module peripheral_subsystem .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t) ) pdm2pcm_i ( - .clk_i, + .clk_i(clk_cg), .rst_ni, .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::PDM2PCM_IDX]), .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::PDM2PCM_IDX]), @@ -514,7 +569,7 @@ module peripheral_subsystem .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t) ) i2s_i ( - .clk_i, + .clk_i(clk_cg), .rst_ni, .reg_req_i(peripheral_slv_req[core_v_mini_mcu_pkg::I2S_IDX]), .reg_rsp_o(peripheral_slv_rsp[core_v_mini_mcu_pkg::I2S_IDX]), diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl index b7dbbfdc..19bb8622 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl @@ -157,8 +157,8 @@ module system_bus // Internal slave requests assign error_slave_req = int_slave_req[core_v_mini_mcu_pkg::ERROR_IDX]; -% for bank in range(ram_numbanks): - assign ram_req_o[${bank}] = int_slave_req[core_v_mini_mcu_pkg::RAM${bank}_IDX]; +% for bank in xheep.iter_ram_banks(): + assign ram_req_o[${bank.name()}] = int_slave_req[core_v_mini_mcu_pkg::RAM${bank.name()}_IDX]; % endfor assign debug_slave_req_o = int_slave_req[core_v_mini_mcu_pkg::DEBUG_IDX]; assign ao_peripheral_slave_req_o = int_slave_req[core_v_mini_mcu_pkg::AO_PERIPHERAL_IDX]; @@ -175,8 +175,8 @@ module system_bus // Internal slave responses assign int_slave_resp[core_v_mini_mcu_pkg::ERROR_IDX] = error_slave_resp; -% for bank in range(ram_numbanks): - assign int_slave_resp[core_v_mini_mcu_pkg::RAM${bank}_IDX] = ram_resp_i[${bank}]; +% for bank in xheep.iter_ram_banks(): + assign int_slave_resp[core_v_mini_mcu_pkg::RAM${bank.name()}_IDX] = ram_resp_i[${bank.name()}]; % endfor assign int_slave_resp[core_v_mini_mcu_pkg::DEBUG_IDX] = debug_slave_resp_i; assign int_slave_resp[core_v_mini_mcu_pkg::AO_PERIPHERAL_IDX] = ao_peripheral_slave_resp_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_xbar.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_xbar.sv.tpl index 2731cb4e..18cbbe4d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_xbar.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_xbar.sv.tpl @@ -38,7 +38,7 @@ module system_xbar localparam int unsigned RESP_AGG_DATA_WIDTH = 32; //Address Decoder -% if ram_numbanks_il == 0: +% if not xheep.has_il_ram(): logic [XBAR_NMASTER-1:0][LOG_XBAR_NSLAVE-1:0] port_sel; % else: logic [XBAR_NMASTER-1:0][LOG_XBAR_NSLAVE-1:0] port_sel, pre_port_sel; @@ -75,7 +75,7 @@ module system_xbar ) addr_decode_i ( .addr_i(master_req_i[i].addr), .addr_map_i, -% if ram_numbanks_il == 0: +% if not xheep.has_il_ram(): .idx_o(port_sel[i]), % else: .idx_o(pre_port_sel[i]), @@ -86,21 +86,21 @@ module system_xbar .default_idx_i ); end -% if ram_numbanks_il != 0: +% if xheep.has_il_ram(): localparam ZERO = 32'h0; for (genvar j = 0; j < XBAR_NMASTER; j++) begin : gen_addr_napot always_comb begin - port_sel[j] = 1; - post_master_req_addr[j] = '0; - if (pre_port_sel[j] == NUM_BANKS[LOG_XBAR_NSLAVE-1:0] - (NUM_BANKS_IL[LOG_XBAR_NSLAVE-1:0]-1)) begin - port_sel[j] = NUM_BANKS[LOG_XBAR_NSLAVE-1:0] - (NUM_BANKS_IL[LOG_XBAR_NSLAVE-1:0]-1) + {ZERO[LOG_XBAR_NSLAVE-${1+log_ram_numbanks_il}:0],master_req_i[j].addr[${1+log_ram_numbanks_il}:2]}; - post_master_req_addr[j] = {master_req_i[j].addr[31:${2+log_ram_numbanks_il}], ${2+log_ram_numbanks_il}'h0}; - end else begin - port_sel[j] = pre_port_sel[j]; - post_master_req_addr[j] = master_req_i[j].addr; + port_sel[j] = pre_port_sel[j]; + post_master_req_addr[j] = master_req_i[j].addr; +% for i, group in enumerate(xheep.iter_il_groups()): + + if (pre_port_sel[j] == RAM_IL${i}_IDX[LOG_XBAR_NSLAVE-1:0]) begin + port_sel[j] = RAM_IL${i}_IDX[LOG_XBAR_NSLAVE-1:0] + {ZERO[LOG_XBAR_NSLAVE-${1+group.n.bit_length()}:0],master_req_i[j].addr[${group.n.bit_length()-1 +1}:2]}; + post_master_req_addr[j] = {master_req_i[j].addr[31:${2+group.n.bit_length()-1}], ${2+group.n.bit_length()-1}'h0}; end +% endfor end end % endif @@ -113,7 +113,7 @@ module system_xbar req: master_req_i[i].req, we: master_req_i[i].we, be: master_req_i[i].be, - % if ram_numbanks_il == 0: + % if not xheep.has_il_ram(): addr: master_req_i[i].addr, % else: addr: post_master_req_addr[i], diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc index be620356..d3723fef 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/nexys/pin_assign.xdc @@ -13,9 +13,8 @@ set_property -dict {PACKAGE_PIN V11 IOSTANDARD LVCMOS33} [get_ports {rst_led_o}] set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS33} [get_ports {clk_led_o}]; set_property -dict {PACKAGE_PIN N14 IOSTANDARD LVCMOS33} [get_ports {exit_valid_o}]; set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {exit_value_o}]; -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_led_OBUF] -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_out_OBUF] -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_led_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_led_o_OBUF] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_led_o_OBUF] ##Switches set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports {execute_from_flash_i}]; #Sch=sw[1] @@ -79,5 +78,24 @@ set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[2]} set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {gpio_io[3]}]; #IO_L10N_T1_D15_14 Sch=btnr set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {gpio_io[4]}]; #IO_L9N_T1_DQS_D13_14 Sch=btnd +##7 segment display +set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports { gpio_io[11] }]; +set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33} [get_ports { gpio_io[12] }]; +set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports { gpio_io[13] }]; +set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports { gpio_io[14] }]; +set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports { pdm2pcm_clk_io }]; +set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports { pdm2pcm_pdm_io }]; +set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports { i2s_sck_io }]; +set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports { i2s_ws_io }]; +set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports { i2s_sd_io }]; +set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[15] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] +set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[16] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] +set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { gpio_io[17] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] +set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { spi2_csb_o[0] }]; #IO_L19P_T3_A22_15 Sch=an[3] +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { spi2_csb_o[1] }]; #IO_L8N_T1_D12_14 Sch=an[4] +set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { spi2_sck_o }]; #IO_L14P_T2_SRCC_14 Sch=an[5] +set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { spi2_sd_io[0] }]; #IO_L23P_T3_35 Sch=an[6] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i_IBUF] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc index ed3a6e89..38e2f6b3 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/pynq-z2/constraints.xdc @@ -1 +1 @@ -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_i}]; +create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 5} [get_ports {clk_i}]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc new file mode 100644 index 00000000..4b523cdf --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/constraints/zcu104/pin_assign.xdc @@ -0,0 +1,99 @@ +# Copyright 2022 EPFL +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +# CLOCK +set_property -dict {PACKAGE_PIN AH18 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p] +set_property -dict {PACKAGE_PIN AH17 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_tck_i] + +# RESET +set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS33} [get_ports rst_i] +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_i] + +# LEDS +set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports rst_led_o] +set_property -dict {PACKAGE_PIN D6 IOSTANDARD LVCMOS33} [get_ports clk_led_o] +set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports exit_valid_o] +set_property -dict {PACKAGE_PIN B5 IOSTANDARD LVCMOS33} [get_ports exit_value_o] + +# SWITCHES +set_property -dict {PACKAGE_PIN E4 IOSTANDARD LVCMOS33} [get_ports execute_from_flash_i] +set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports boot_select_i] + +# FLASH +# QSPI +# Q0 / MOSI +# Q1 / MISO +# Q2 / nWP +# Q3 / nHLD +set_property -dict {PACKAGE_PIN L10 IOSTANDARD LVCMOS33} [get_ports spi_flash_csb_o] +set_property -dict {PACKAGE_PIN J9 IOSTANDARD LVCMOS33} [get_ports spi_flash_sck_o] +set_property -dict {PACKAGE_PIN M10 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[0]}] +set_property -dict {PACKAGE_PIN K9 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[1]}] +set_property -dict {PACKAGE_PIN M8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[2]}] +set_property -dict {PACKAGE_PIN K8 IOSTANDARD LVCMOS33} [get_ports {spi_flash_sd_io[3]}] + +# UART +set_property -dict {PACKAGE_PIN G8 IOSTANDARD LVCMOS33} [get_ports uart_tx_o] +set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports uart_rx_i] + +# JTAG +set_property -dict {PACKAGE_PIN H8 IOSTANDARD LVCMOS33} [get_ports jtag_tdi_i] +set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports jtag_tdo_o] +set_property -dict {PACKAGE_PIN G7 IOSTANDARD LVCMOS33} [get_ports jtag_tms_i] +set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports jtag_tck_i] +set_property -dict {PACKAGE_PIN M9 IOSTANDARD LVCMOS33} [get_ports jtag_trst_ni] + +# I2C +set_property -dict {PACKAGE_PIN J7 IOSTANDARD LVCMOS33} [get_ports i2c_scl_io] +set_property -dict {PACKAGE_PIN H7 IOSTANDARD LVCMOS33} [get_ports i2c_sda_io] + +## The following pins are sent to the FMC connector, using the LA pins as single-ended. +## The bank only supports up to 1.8 V. + +# SPI SD +set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS18} [get_ports spi_csb_o] +set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS18} [get_ports spi_sck_o] +set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[0]}] +set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[1]}] +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[2]}] +set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS18} [get_ports {spi_sd_io[3]}] + +# GPIOs +set_property -dict {PACKAGE_PIN D11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[0]}] +set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[1]}] +set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[2]}] +set_property -dict {PACKAGE_PIN A7 IOSTANDARD LVCMOS18} [get_ports {gpio_io[3]}] +set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS18} [get_ports {gpio_io[4]}] +set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[5]}] +set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[6]}] +set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS18} [get_ports {gpio_io[7]}] +set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[8]}] +set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS18} [get_ports {gpio_io[9]}] +set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[10]}] +set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS18} [get_ports {gpio_io[11]}] +set_property -dict {PACKAGE_PIN F11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[12]}] +set_property -dict {PACKAGE_PIN E10 IOSTANDARD LVCMOS18} [get_ports {gpio_io[13]}] +set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[14]}] +set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS18} [get_ports {gpio_io[15]}] +set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS18} [get_ports {gpio_io[16]}] +set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS18} [get_ports {gpio_io[17]}] + +# PDM2PCM +set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_clk_io] +set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS18} [get_ports pdm2pcm_pdm_io] + +# I2S +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS18} [get_ports i2s_sck_io] +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS18} [get_ports i2s_ws_io] +set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS18} [get_ports i2s_sd_io] + +# SPI2 +set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[0]}] +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS18} [get_ports {spi2_csb_o[1]}] +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS18} [get_ports spi2_sck_o] +set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[0]}] +set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[1]}] +set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[2]}] +set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {spi2_sd_io[3]}] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_inout_xilinx.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_inout_xilinx.sv index 69ee4e7e..5c68364b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_inout_xilinx.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_inout_xilinx.sv @@ -3,7 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 module pad_cell_inout #( - parameter PADATTR = 16 + parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP ) ( input logic pad_in_i, input logic pad_oe_i, diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_input_xilinx.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_input_xilinx.sv index 989aad1c..470a651a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_input_xilinx.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_input_xilinx.sv @@ -3,7 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 module pad_cell_input #( - parameter PADATTR = 16 + parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP ) ( input logic pad_in_i, input logic pad_oe_i, diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_output_xilinx.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_output_xilinx.sv index 3620ad1b..43592acd 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_output_xilinx.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/pad_cell_output_xilinx.sv @@ -3,7 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 module pad_cell_output #( - parameter PADATTR = 16 + parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP ) ( input logic pad_in_i, input logic pad_oe_i, diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv index 35165b88..2893d666 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/prim_xilinx_clk.sv @@ -9,15 +9,12 @@ module xilinx_clk_gating ( output logic clk_o ); - logic clk_en; - - // Use a latch based clock gate instead of BUFGCE. Otherwise we quickly run out of BUFGCTRL cells on the FPGAs. - always_latch begin - if (clk_i == 1'b0) clk_en <= en_i | test_en_i; - end - - assign clk_o = clk_i & clk_en; - + // In Zynq7000, just bypass the clock gating because there are not enough BUFGs that can be + // cascaded with the BUFG of the MMCM. + // In the Zynq UltraScale+, it can be implemented as BUFGCE without trouble, since there + // are > 500 BUFGCEs and the rules for cascading are more relaxed. + // NOTE: This **cannot** be substituted by a latch+and + assign clk_o = clk_i; endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl deleted file mode 100644 index 7ba6d975..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl +++ /dev/null @@ -1,27 +0,0 @@ - -set ipName xilinx_mem_gen_0 - -create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name $ipName - -set_property -dict [list CONFIG.Enable_32bit_Address {false} \ - CONFIG.Use_Byte_Write_Enable {true} \ - CONFIG.Byte_Size {8} \ - CONFIG.Algorithm {Minimum_Area} \ - CONFIG.Primitive {2kx9} \ - CONFIG.Write_Width_A {32} \ - CONFIG.Write_Depth_A {8192} \ - CONFIG.Read_Width_A {32} \ - CONFIG.Enable_A {Use_ENA_Pin} \ - CONFIG.Write_Width_B {32} \ - CONFIG.Read_Width_B {32} \ - CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ - CONFIG.Use_RSTA_Pin {false} \ - CONFIG.EN_SAFETY_CKT {false}] [get_ips $ipName] - -#generate_target {instantiation_template} [get_ips $ipName] - -#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet - -create_ip_run [get_ips $ipName] -launch_run -jobs 8 ${ipName}_synth_1 -wait_on_run ${ipName}_synth_1 diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl.tpl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl.tpl new file mode 100644 index 00000000..e8e6cbb4 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/generate_sram.tcl.tpl @@ -0,0 +1,50 @@ +% for num_words in xheep.iter_bank_numwords(): + +set ipName xilinx_mem_gen_${num_words} + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name $ipName + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \\ + + CONFIG.Use_Byte_Write_Enable {true} \\ + + CONFIG.Byte_Size {8} \\ + + CONFIG.Algorithm {Minimum_Area} \\ + + CONFIG.Primitive {2kx9} \\ + + CONFIG.Write_Width_A {32} \\ + + CONFIG.Write_Depth_A {${num_words}} \\ + + CONFIG.Read_Width_A {32} \\ + + CONFIG.Enable_A {Use_ENA_Pin} \\ + + CONFIG.Write_Width_B {32} \\ + + CONFIG.Read_Width_B {32} \\ + + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \\ + + CONFIG.Use_RSTA_Pin {false} \\ + + CONFIG.EN_SAFETY_CKT {false}] [get_ips $ipName] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips $ipName] + +% endfor + +<%ips = "" +for num_words in xheep.iter_bank_numwords(): + ips += f" xilinx_mem_gen_{num_words}_synth_1"%> +launch_runs -jobs 8 ${ips} + +% for num_words in xheep.iter_bank_numwords(): +wait_on_run xilinx_mem_gen_${num_words}_synth_1 +% endfor diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl deleted file mode 100644 index 544cd11b..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/nexys/set_board.tcl +++ /dev/null @@ -1,3 +0,0 @@ -# Select board -set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] -set_property -name "board_part" -value "digilentinc.com:nexys-a7-100t:part0:1.3" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl deleted file mode 100644 index f16f754f..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/pynq-z2/set_board.tcl +++ /dev/null @@ -1,3 +0,0 @@ -# Select board -set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] -set_property -name "board_part" -value "tul.com.tw:pynq-z2:part0:1.0" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl b/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl deleted file mode 100644 index 0108a4c8..00000000 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/scripts/zcu104/set_board.tcl +++ /dev/null @@ -1,3 +0,0 @@ -# Select board -set_property -name "board_part_repo_paths" -value "[file normalize "../../../hw/fpga/board_files/"]" -objects [current_project] -set_property -name "board_part" -value "xilinx.com:zcu104:part0:1.0" -objects [current_project] diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv.tpl similarity index 66% rename from hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv rename to hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv.tpl index 44fb5687..6d518136 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/sram_wrapper.sv.tpl @@ -22,19 +22,32 @@ module sram_wrapper #( input logic [AddrWidth-1:0] addr_i, input logic [31:0] wdata_i, input logic [3:0] be_i, - input logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] set_retentive_ni, + // power manager signals that goes to the ASIC macros + input logic pwrgate_ni, + output logic pwrgate_ack_no, + input logic set_retentive_ni, // output ports output logic [31:0] rdata_o ); - xilinx_mem_gen_0 tc_ram_i ( - .clka (clk_i), - .ena (req_i), - .wea ({4{req_i & we_i}} & be_i), - .addra(addr_i), - .dina (wdata_i), - // output ports - .douta(rdata_o) - ); +assign pwrgate_ack_no = pwrgate_ni; +<%el = ""%> +% for num_words in xheep.iter_bank_numwords(): + ${el}if (NumWords == 32'd${num_words}) begin + xilinx_mem_gen_${num_words} tc_ram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end +<%el = "else "%> +% endfor + else begin + $error("Bank size not generated."); + end endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson index d37d92f7..58f6d3a0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson @@ -33,13 +33,24 @@ { bits: "31:0", name: "PTR_ADDR", desc: "Address data pointer (word aligned) - used only in Address mode" } ] }, - { name: "SIZE", - desc: "Number of bytes to copy - Once a value is written, the copy starts", + { name: "SIZE_D1", + desc: "Number of bytes to copy from, defined with respect to the first dimension - Once a value is written, the copy starts", swaccess: "rw", hwaccess: "hro", hwqe: "true", // enable `qe` latched signal of software write pulse + // Dimensioned to 16 bits to allow for 64kB transfers on 1D fields: [ - { bits: "31:0", name: "SIZE", desc: "DMA counter and start" } + { bits: "15:0", name: "SIZE", desc: "DMA counter D1 and start" } + ] + }, + { name: "SIZE_D2", + desc: "Number of bytes to copy from, defined with respect to the second dimension", + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse + // Dimensioned to 16 bits to allow for 64kB transfers on 2D + fields: [ + { bits: "15:0", name: "SIZE", desc: "DMA counter D2" } ] }, { name: "STATUS", @@ -50,23 +61,56 @@ hwre: "true", // enable `re` latched signal of software read pulse resval: 1, fields: [ - { bits: "0", name: "READY", desc: "Transaction iss done"}, + { bits: "0", name: "READY", desc: "Transaction is done"}, { bits: "1", name: "WINDOW_DONE", desc: "set if DMA is copying second half"}, ] }, - { name: "PTR_INC", - desc: "Increment number of src/dst pointer every time a word is copied", + { name: "SRC_PTR_INC_D1", + desc: "Increment the D1 source pointer every time a word is copied", swaccess: "rw", hwaccess: "hro", + // Dimensioned to allow a maximum of a 15 element stride for a data_type_word case fields: [ - { bits: "7:0", - name: "SRC_PTR_INC", - desc: "Source pointer increment", + { bits: "5:0", + name: "INC", + desc: "Source pointer d1 increment", resval:4 - }, - { bits: "15:8", - name: "DST_PTR_INC", - desc: "Destination pointer increment", + } + ] + }, + { name: "SRC_PTR_INC_D2", + desc: "Increment the D2 source pointer every time a word is copied", + swaccess: "rw", + hwaccess: "hro", + // Dimensioned to allow a maximum of 15 element stride for a data_type_word + fields: [ + { bits: "22:0", + name: "INC", + desc: "Source pointer d2 increment", + resval:4 + } + ] + }, + { name: "DST_PTR_INC_D1", + desc: "Increment the D1 destination pointer every time a word is copied", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "5:0", + name: "INC", + desc: "Destination pointer d1 increment", + resval:4 + } + ] + }, + { name: "DST_PTR_INC_D2", + desc: "Increment the D2 destination pointer every time a word is copied", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "22:0", + name: "INC", + desc: "Destination pointer d2 increment", resval:4 } ] @@ -87,8 +131,25 @@ } ] }, - { name: "DATA_TYPE", - desc: '''Width/type of the data to transfer''', + { name: "SRC_DATA_TYPE", + desc: '''Width/type of the source data to transfer''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "1:0", name: "DATA_TYPE", + desc: "Data type", + enum: [ + { value: "0", name: "DMA_32BIT_WORD", desc: "Transfers 32 bits"}, + { value: "1", name: "DMA_16BIT_WORD", desc: "Transfers 16 bits"}, + { value: "2", name: "DMA_8BIT_WORD" , desc: "Transfers 8 bits"}, + { value: "3", name: "DMA_8BIT_WORD_2",desc: "Transfers 8 bits"}, + ] + } + ] + }, + { name: "DST_DATA_TYPE", + desc: '''Width/type of the destination data to transfer''', swaccess: "rw", hwaccess: "hro", resval: 0, @@ -104,6 +165,22 @@ } ] }, + { + name: "SIGN_EXT", + desc: '''Is the data to be sign extended? (Checked only if the dst data type is wider than the src data type)''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "0", name: "SIGNED", + desc: "Extend the sign to the destination data", + enum: [ + { value: "0", name: "NO_EXTEND", desc: "Does not extend the sign"}, + { value: "1", name: "EXTEND", desc: "Extends the sign"}, + ] + } + ] + }, { name: "MODE", desc: '''Set the operational mode of the DMA''', swaccess: "rw", @@ -119,13 +196,71 @@ } ] }, + { name: "DIM_CONFIG", + desc: '''Set the dimensionality of the DMA''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "0", name: "DMA_DIM", desc: "DMA transfer dimensionality"} + ] + }, + { name: "DIM_INV", + desc: '''DMA dimensionality inversion selector''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "0", name: "SEL", desc: "DMA dimensionality inversion, used to perform transposition"} + ] + }, + { name: "PAD_TOP", + desc: '''Set the top padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Top margin padding (2D)"} + ] + }, + { name: "PAD_BOTTOM", + desc: '''Set the bottom padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Bottom margin padding (2D)"} + ] + }, + { name: "PAD_RIGHT", + desc: '''Set the right padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Right margin padding (1D/2D)"} + ] + }, + { name: "PAD_LEFT", + desc: '''Set the left padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Left margin padding (1D/2D)"} + ] + }, { name: "WINDOW_SIZE", desc: '''Will trigger a every "WINDOW_SIZE" writes Set to 0 to disable.''', swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "31:0", name: "WINDOW_SIZE", desc: ""} + { bits: "12:0", name: "WINDOW_SIZE", desc: ""} ] }, { name: "WINDOW_COUNT", @@ -136,7 +271,7 @@ hwaccess: "hrw", resval: 0, fields: [ - { bits: "31:0", name: "WINDOW_COUNT", desc: "Number of windows transferred in the transaction" } + { bits: "7:0", name: "WINDOW_COUNT", desc: "Number of windows transferred in the transaction" } ] }, { name: "INTERRUPT_EN", @@ -148,6 +283,28 @@ { bits: "0", name: "TRANSACTION_DONE", desc: "Enables transaction done interrupt" } { bits: "1", name: "WINDOW_DONE", desc: "Enables window done interrupt" } ] + }, + { name: "TRANSACTION_IFR", + desc: '''Interrupt Flag Register for transactions''', + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + hwre: "true", // latched signal of software write pulse + resval: 0, + fields: [ + { bits: "0", name: "FLAG", desc: "Set for transaction done interrupt" } + ] + }, + { name: "WINDOW_IFR", + desc: '''Interrupt Flag Register for windows''', + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + hwre: "true", // latched signal of software write pulse + resval: 0, + fields: [ + { bits: "0", name: "FLAG", desc: "Set for window done interrupt" } + ] } ] } diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core index 0a06c35d..86255b7a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core @@ -1,7 +1,7 @@ CAPI=2: name: "x-heep:ip:dma" -description: "core-v-mini-mcu dma peripheral" +description: "core-v-mini-mcu dma channel" # Copyright 2021 OpenHW Group # Solderpad Hardware License, Version 2.1, see LICENSE.md for details. diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv index c4f5e2ea..4bfe0219 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv @@ -1,8 +1,10 @@ -// Copyright 2022 EPFL -// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +/* + * Copyright 2022 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + */ -// DMA assume a read request is not granted before previous request rvalid is asserted +/* DMA assume a read request is not granted before previous request rvalid is asserted */ module dma #( parameter int unsigned FIFO_DEPTH = 4, @@ -15,6 +17,8 @@ module dma #( input logic clk_i, input logic rst_ni, + input logic ext_dma_stop_i, + input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, @@ -41,14 +45,15 @@ module dma #( dma_reg2hw_t reg2hw; dma_hw2reg_t hw2reg; + logic [ 31:0] src_ptr_reg; logic [ 31:0] read_ptr_reg; logic [ 31:0] addr_ptr_reg; logic [ 31:0] read_ptr_valid_reg; logic [ 31:0] write_ptr_reg; logic [ 31:0] write_address; - logic [ 31:0] dma_cnt; logic [ 31:0] dma_addr_cnt; - logic [ 2:0] dma_cnt_dec; + logic [ 2:0] dma_src_cnt_du; + logic [ 2:0] dma_dst_cnt_du; logic dma_start; logic dma_done; logic dma_window_event; @@ -86,6 +91,70 @@ module dma #( logic data_out_rvalid; logic [ 31:0] data_out_rdata; + /* Sign extension signals */ + logic sign_extend; + + /* 2D signals */ + + /* Dimensionality configuration */ + logic dma_conf_1d; // Dimensionality configuration: 0-> 1D, 1-> 2D + logic dma_conf_2d; // Dimensionality configuration: 0-> 1D, 1-> 2D + + /* Counters */ + logic [ 16:0] dma_src_cnt_d1; // d1 src counter + logic [ 16:0] dma_src_cnt_d2; // d2 src counter + logic [ 16:0] dma_dst_cnt_d1; // d2 dst counter + + /* Increments */ + logic [ 5:0] dma_src_d1_inc; // d1 source increment + logic [ 22:0] dma_src_d2_inc; // d2 source increment + logic [ 5:0] dma_dst_d1_inc; // d1 destination increment + logic [ 22:0] dma_dst_d2_inc; // d2 destination increment + + /* Flags */ + logic pad_fifo_on; // Padding flag for FIFO + logic pad_cnt_on; // Padding flag for counters + logic read_ptr_update_sel; // Select the read pointer update source + + /* Padding FSM conditions */ + logic idle_to_left_ex; + logic idle_to_top_ex; + logic idle_to_right_ex; + logic idle_to_bottom_ex; + logic top_ex_to_top_dn; + logic top_ex_to_left_ex; + logic top_dn_to_right_ex; + logic top_dn_to_bottom_ex; + logic top_dn_to_idle; + logic left_ex_to_left_dn; + logic left_dn_to_left_ex; + logic left_dn_to_right_ex; + logic left_dn_to_bottom_ex; + logic left_dn_to_idle; + logic right_ex_to_right_dn; + logic right_ex_to_left_ex; + logic right_dn_to_right_ex; + logic right_dn_to_idle; + logic right_ex_to_bottom_ex; + logic bottom_ex_to_idle; + + /* Padding synchronization signals */ + logic data_in_rvalid_virt; + logic data_in_rvalid_virt_n; + logic data_in_rvalid_virt_n_n; + logic data_in_gnt_virt; + logic data_in_gnt_virt_n; + logic data_in_gnt_virt_n_n; + + /* Interrupt Flag Register signals */ + logic transaction_ifr; + logic dma_done_intr_n; + logic dma_done_intr; + logic window_ifr; + logic dma_window_intr; + logic dma_window_intr_n; + + /* FIFO signals */ logic fifo_flush; logic fifo_full; logic fifo_empty; @@ -94,22 +163,30 @@ module dma #( logic fifo_addr_full; logic fifo_addr_empty, fifo_addr_empty_check; - logic wait_for_rx; - logic wait_for_tx; + logic wait_for_rx; + logic wait_for_tx; + + typedef enum logic [1:0] { + DMA_DATA_TYPE_WORD, + DMA_DATA_TYPE_HALF_WORD, + DMA_DATA_TYPE_BYTE, + DMA_DATA_TYPE_BYTE_ + } dma_data_type_t; - logic [ 1:0] data_type; + dma_data_type_t dst_data_type; + dma_data_type_t src_data_type; - logic [31:0] fifo_input; - logic [31:0] fifo_addr_input; - logic [31:0] fifo_output; - logic [31:0] fifo_addr_output; + logic [31:0] fifo_input; + logic [31:0] fifo_addr_input; + logic [31:0] fifo_output; + logic [31:0] fifo_addr_output; - logic [ 3:0] byte_enable_out; + logic [ 3:0] byte_enable_out; - logic circular_mode; - logic address_mode; + logic circular_mode; + logic address_mode; - logic dma_start_pending; + logic dma_start_pending; enum { DMA_READY, @@ -118,7 +195,20 @@ module dma #( } dma_state_q, dma_state_d; - logic [Addr_Fifo_Depth-1:0] outstanding_req, outstanding_addr_req; + /* Padding FSM states */ + + enum { + PAD_IDLE, + TOP_PAD_EXEC, + LEFT_PAD_EXEC, + RIGHT_PAD_EXEC, + BOTTOM_PAD_EXEC, + TOP_PAD_DONE, + LEFT_PAD_DONE, + RIGHT_PAD_DONE, + BOTTOM_PAD_DONE + } + pad_state_q, pad_state_d, pad_state_x; enum logic { DMA_READ_FSM_IDLE, @@ -132,14 +222,17 @@ module dma #( } dma_write_fsm_state, dma_write_fsm_n_state; - assign dma_read_ch0_req_o.req = data_in_req; + logic [Addr_Fifo_Depth-1:0] outstanding_req, outstanding_addr_req; + logic [31:0] window_counter; + + assign dma_read_ch0_req_o.req = data_in_req && ~pad_fifo_on; assign dma_read_ch0_req_o.we = data_in_we; assign dma_read_ch0_req_o.be = data_in_be; assign dma_read_ch0_req_o.addr = data_in_addr; assign dma_read_ch0_req_o.wdata = 32'h0; - assign data_in_gnt = dma_read_ch0_resp_i.gnt; - assign data_in_rvalid = dma_read_ch0_resp_i.rvalid; + assign data_in_gnt = dma_read_ch0_resp_i.gnt || (data_in_gnt_virt & pad_fifo_on); + assign data_in_rvalid = dma_read_ch0_resp_i.rvalid || (data_in_rvalid_virt & pad_fifo_on); assign data_in_rdata = dma_read_ch0_resp_i.rdata; assign dma_addr_ch0_req_o.req = data_addr_in_req; @@ -162,14 +255,16 @@ module dma #( assign data_out_rvalid = dma_write_ch0_resp_i.rvalid; assign data_out_rdata = dma_write_ch0_resp_i.rdata; - assign dma_done_intr_o = dma_done & reg2hw.interrupt_en.transaction_done.q; - assign dma_window_intr_o = dma_window_event & reg2hw.interrupt_en.window_done.q; - - - logic [31:0] window_counter; + assign dma_done_intr = transaction_ifr; + assign dma_window_intr = window_ifr; + assign dma_done_intr_o = dma_done_intr_n; + assign hw2reg.transaction_ifr.d = transaction_ifr; + assign dma_window_intr_o = dma_window_intr_n; + assign hw2reg.window_ifr.d = window_ifr; - assign data_type = reg2hw.data_type.q; + assign dst_data_type = dma_data_type_t'(reg2hw.dst_data_type.q); + assign src_data_type = dma_data_type_t'(reg2hw.src_data_type.q); assign hw2reg.status.ready.d = (dma_state_q == DMA_READY); @@ -178,6 +273,84 @@ module dma #( assign circular_mode = reg2hw.mode.q == 1; assign address_mode = reg2hw.mode.q == 2; + /* DMA Dimensionality configuration flags */ + assign dma_conf_1d = reg2hw.dim_config.q == 0; + assign dma_conf_2d = reg2hw.dim_config.q == 1; + + /* DMA read pointer source selection */ + assign read_ptr_update_sel = reg2hw.dim_inv.q; + + /* DMA 2D increment */ + assign dma_src_d2_inc = reg2hw.src_ptr_inc_d2.q; + assign dma_src_d1_inc = reg2hw.src_ptr_inc_d1.q; + assign dma_dst_d2_inc = reg2hw.dst_ptr_inc_d2.q; + assign dma_dst_d1_inc = reg2hw.dst_ptr_inc_d1.q; + + /* Sign extend flag */ + + assign sign_extend = reg2hw.sign_ext.q & ( (src_data_type[1] & ~dst_data_type[1]) | ((src_data_type[1] == dst_data_type[1]) & (src_data_type[0] & ~dst_data_type[0]))); + + /* Padding FSM conditions assignments */ + + assign idle_to_top_ex = {|reg2hw.pad_top.q == 1'b1 && dma_start == 1'b1}; + assign idle_to_left_ex = { + |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b1 && dma_start == 1'b1 + }; + assign idle_to_right_ex = { + |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 + && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) + }; + assign idle_to_bottom_ex = { + |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 + && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) + }; + assign top_ex_to_top_dn = { + dma_src_cnt_d2 == ({1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 + }; + assign top_ex_to_left_ex = { + dma_src_cnt_d2 == ({1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b1 + }; + assign top_dn_to_right_ex = { + |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) + }; + assign top_dn_to_bottom_ex = { + |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) + }; + assign top_dn_to_idle = { + |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0 + }; + assign left_ex_to_left_dn = { + dma_src_cnt_d1 == ({1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) + }; + assign left_dn_to_left_ex = { + dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({14'h0, dma_dst_cnt_du} + {11'h0, reg2hw.pad_bottom.q}) && |reg2hw.pad_right.q == 1'b0 + }; + assign left_dn_to_right_ex = { + |reg2hw.pad_right.q == 1'b1 && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) + }; + assign left_dn_to_bottom_ex = { + |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) + }; + assign left_dn_to_idle = { + |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0 + }; + assign right_ex_to_right_dn = { + dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 + }; + assign right_ex_to_left_ex = { + dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b1 + }; + assign right_ex_to_bottom_ex = { + |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) + }; + assign right_dn_to_right_ex = { + dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 + }; + assign right_dn_to_idle = {|reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0}; + assign bottom_ex_to_idle = { + dma_src_cnt_d1 == {14'h0, dma_dst_cnt_du} && dma_src_cnt_d2 == {14'h0, dma_dst_cnt_du} + }; + assign write_address = address_mode ? fifo_addr_output : write_ptr_reg; assign wait_for_rx = |(reg2hw.slot.rx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); @@ -198,6 +371,7 @@ module dma #( // RUNNING : waiting for transaction finish // when `dma_done` rises either enter ready or restart in circular mode // + always_comb begin dma_state_d = dma_state_q; case (dma_state_q) @@ -218,7 +392,7 @@ module dma #( endcase end - // update state + /* Update DMA state */ always_ff @(posedge clk_i, negedge rst_ni) begin if (~rst_ni) begin dma_state_q <= DMA_READY; @@ -227,21 +401,20 @@ module dma #( end end - - // DMA pulse start when dma_start register is written + /* DMA pulse start when dma_start register is written */ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_start if (~rst_ni) begin dma_start_pending <= 1'b0; end else begin if (dma_start == 1'b1) begin dma_start_pending <= 1'b0; - end else if (reg2hw.size.qe & |reg2hw.size.q) begin + end else if ((reg2hw.size_d1.qe & |reg2hw.size_d1.q)) begin dma_start_pending <= 1'b1; end end end - // Store input data pointer and increment everytime read request is granted + /*/ Store input data pointer and increment everytime read request is granted */ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_in_reg if (~rst_ni) begin read_ptr_reg <= '0; @@ -249,7 +422,44 @@ module dma #( if (dma_start == 1'b1) begin read_ptr_reg <= reg2hw.src_ptr.q; end else if (data_in_gnt == 1'b1) begin - read_ptr_reg <= read_ptr_reg + {24'h0, reg2hw.ptr_inc.src_ptr_inc.q}; + if (dma_conf_1d == 1'b1) begin + /* Increase the pointer by the amount written in ptr_inc */ + read_ptr_reg <= read_ptr_reg + {26'h0, dma_src_d1_inc}; + end else if (dma_conf_2d == 1'b1 && pad_cnt_on == 1'b0) begin + if (read_ptr_update_sel == 1'b0) begin + if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1) begin + /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d1)*data_unit */ + read_ptr_reg <= read_ptr_reg + {9'h0, dma_src_d2_inc}; + end else begin + read_ptr_reg <= read_ptr_reg + {26'h0, dma_src_d1_inc}; /* Increment of the d1 increment (stride) */ + end + end else begin + if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1) begin + /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d2)*data_unit */ + read_ptr_reg <= src_ptr_reg; + end else begin + read_ptr_reg <= read_ptr_reg + {9'h0, dma_src_d2_inc}; /* Increment of the d1 increment (stride) */ + end + end + end + end + end + end + + /* + * Store input data pointer in source_ptr_reg and increment it every time read request is granted, + * if the d1 has finished reading and the read pointer update is set to 1'b1 + */ + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_src_ptr_reg + if (~rst_ni) begin + src_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + src_ptr_reg <= reg2hw.src_ptr.q + {26'h0, dma_src_d1_inc}; + end else if (data_in_gnt == 1'b1 && dma_conf_2d == 1'b1 && pad_cnt_on == 1'b0 && read_ptr_update_sel == 1'b1 && + (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1)) begin + src_ptr_reg <= src_ptr_reg + {26'h0, dma_src_d1_inc}; end end end @@ -267,7 +477,9 @@ module dma #( end end - // Only update read_ptr_valid_reg when the data is stored in the fifo + // Only update read_ptr_valid_reg when the data is stored in the fifo. + // Since every input grant is followed by a rvalid, the read_ptr_valid_reg is a mere sample of the read_ptr_reg + // synched with the rvalid signal. always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_valid_in_reg if (~rst_ni) begin read_ptr_valid_reg <= '0; @@ -275,7 +487,7 @@ module dma #( if (dma_start == 1'b1) begin read_ptr_valid_reg <= reg2hw.src_ptr.q; end else if (data_in_rvalid == 1'b1) begin - read_ptr_valid_reg <= read_ptr_valid_reg + {24'h0, reg2hw.ptr_inc.src_ptr_inc.q}; + read_ptr_valid_reg <= read_ptr_reg; end end end @@ -288,20 +500,74 @@ module dma #( if (dma_start == 1'b1) begin write_ptr_reg <= reg2hw.dst_ptr.q; end else if (data_out_gnt == 1'b1) begin - write_ptr_reg <= write_ptr_reg + {24'h0, reg2hw.ptr_inc.dst_ptr_inc.q}; + if (dma_conf_1d == 1'b1) begin + write_ptr_reg <= write_ptr_reg + {26'h0, dma_dst_d1_inc}; + end else if (dma_conf_2d == 1'b1) begin + if (dma_dst_cnt_d1 == {14'h0, dma_dst_cnt_du}) begin + // In this case, the d1 is finished, so we need to increment the pointer by sizeof(d1)*data_unit*strides + write_ptr_reg <= write_ptr_reg + {9'h0, dma_dst_d2_inc}; + end else begin + write_ptr_reg <= write_ptr_reg + {26'h0, dma_dst_d1_inc}; // Increment just of one du, since we need to increase the 1d + end + end end end end - // Store dma transfer size and decrement it everytime input data rvalid is asserted - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_cnt_reg + // Store dma transfer size and decrement it everytime input data rvalid is asserted. + // Perform additional checks for 2D DMA + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_src_cnt_reg if (~rst_ni) begin - dma_cnt <= '0; + dma_src_cnt_d1 <= '0; + dma_src_cnt_d2 <= '0; end else begin if (dma_start == 1'b1) begin - dma_cnt <= reg2hw.size.q; + dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + dma_src_cnt_d2 <= {1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_top.q} + {11'h0, reg2hw.pad_bottom.q}; end else if (data_in_gnt == 1'b1) begin - dma_cnt <= dma_cnt - {29'h0, dma_cnt_dec}; + if (dma_conf_1d == 1'b1) begin + // 1D case + dma_src_cnt_d1 <= dma_src_cnt_d1 - {14'h0, dma_src_cnt_du}; + end else if (dma_conf_2d == 1'b1) begin + // 2D case + if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du}) begin + // In this case, the d1 is finished, so we need to decrement the d2 size and reset the d2 size + dma_src_cnt_d2 <= dma_src_cnt_d2 - {14'h0, dma_src_cnt_du}; + dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else begin + // In this case, the d1 isn't finished, so we need to decrement the d1 size + dma_src_cnt_d1 <= dma_src_cnt_d1 - {14'h0, dma_src_cnt_du}; + end + end + end + end + end + + // Store dma transfer size and decrement it everytime input data write request is granted. + // The need for two separate counters for reading and writing operations is due to the lack of synchronization between them. + // Since the check on the read side is done on the rvalid signal, we need only an additional counter, for d1. + // Performs additional checks for 2D DMA. + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_dst_cnt_reg + if (~rst_ni) begin + dma_dst_cnt_d1 <= '0; + end else begin + if (dma_start == 1'b1) begin + dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else if (data_out_gnt == 1'b1) begin + if (dma_conf_1d == 1'b1) begin + // 1D case + dma_dst_cnt_d1 <= dma_dst_cnt_d1 - {14'h0, dma_dst_cnt_du}; + end else if (dma_conf_2d == 1'b1) begin + // 2D case + if (dma_dst_cnt_d1 == {14'h0, dma_dst_cnt_du}) begin + // In this case, the d1 is finished, so we need to reset the d2 size + dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else begin + // In this case, the d1 isn't finished, so we need to decrement the d1 size + dma_dst_cnt_d1 <= dma_dst_cnt_d1 - {14'h0, dma_dst_cnt_du}; + end + end end end end @@ -312,7 +578,7 @@ module dma #( dma_addr_cnt <= '0; end else begin if (dma_start == 1'b1 && address_mode) begin - dma_addr_cnt <= reg2hw.size.q; + dma_addr_cnt <= {16'h0, reg2hw.size_d1.q}; end else if (data_addr_in_gnt == 1'b1 && address_mode) begin dma_addr_cnt <= dma_addr_cnt - 32'h4; //address always 32b end @@ -320,18 +586,26 @@ module dma #( end always_comb begin - case (data_type) - 2'b00: dma_cnt_dec = 3'h4; - 2'b01: dma_cnt_dec = 3'h2; - 2'b10, 2'b11: dma_cnt_dec = 3'h1; + case (dst_data_type) + DMA_DATA_TYPE_WORD: dma_dst_cnt_du = 3'h4; + DMA_DATA_TYPE_HALF_WORD: dma_dst_cnt_du = 3'h2; + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: dma_dst_cnt_du = 3'h1; + endcase + end + + always_comb begin + case (src_data_type) + DMA_DATA_TYPE_WORD: dma_src_cnt_du = 3'h4; + DMA_DATA_TYPE_HALF_WORD: dma_src_cnt_du = 3'h2; + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: dma_src_cnt_du = 3'h1; endcase end always_comb begin : proc_byte_enable_out - case (data_type) // Data type 00 Word, 01 Half word, 11,10 byte - 2'b00: byte_enable_out = 4'b1111; // Writing a word (32 bits) + case (dst_data_type) // Data type 00 Word, 01 Half word, 11,10 byte + DMA_DATA_TYPE_WORD: byte_enable_out = 4'b1111; // Writing a word (32 bits) - 2'b01: begin // Writing a half-word (16 bits) + DMA_DATA_TYPE_HALF_WORD: begin // Writing a half-word (16 bits) case (write_address[1]) 1'b0: byte_enable_out = 4'b0011; 1'b1: byte_enable_out = 4'b1100; @@ -339,7 +613,7 @@ module dma #( ; // case(write_address[1:0]) end - 2'b10, 2'b11: begin // Writing a byte (8 bits) + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: begin // Writing a byte (8 bits) case (write_address[1:0]) 2'b00: byte_enable_out = 4'b0001; 2'b01: byte_enable_out = 4'b0010; @@ -349,7 +623,7 @@ module dma #( ; // case(write_address[1:0]) end endcase - ; // case (data_type) + ; // case (dst_data_type) end // Output data shift @@ -361,41 +635,118 @@ module dma #( data_out_wdata[31:24] = fifo_output[31:24]; case (write_address[1:0]) - 2'b00: ; - - 2'b01: data_out_wdata[15:8] = fifo_output[7:0]; - - 2'b10: begin + 2'b00: begin + if (sign_extend) begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; + { + DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:16] = {16{fifo_output[15]}}; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:8] = {24{fifo_output[7]}}; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[15:8] = {8{fifo_output[7]}}; + default: ; + endcase + end else begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD} : data_out_wdata[31:16] = 16'b0; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:8] = 24'b0; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[15:8] = 8'b0; + default: ; + endcase + end + end + 2'b01: data_out_wdata[15:8] = fifo_output[7:0]; // Writing a byte, no need for sign extension + 2'b10: begin // Writing a half-word or a byte data_out_wdata[23:16] = fifo_output[7:0]; data_out_wdata[31:24] = fifo_output[15:8]; - end - 2'b11: data_out_wdata[31:24] = fifo_output[7:0]; + if (sign_extend) begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[31:24] = {8{fifo_output[7]}}; + default: ; + endcase + end else begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[31:24] = 8'b0; + default: ; + endcase + end + end + 2'b11: + data_out_wdata[31:24] = fifo_output[7:0]; // Writing a byte, no need for sign extension endcase end + assign fifo_addr_input = data_addr_in_rdata; //never misaligned, always 32b // Input data shift: shift the input data to be on the LSB of the fifo always_comb begin : proc_input_data - fifo_input[7:0] = data_in_rdata[7:0]; - fifo_input[15:8] = data_in_rdata[15:8]; - fifo_input[23:16] = data_in_rdata[23:16]; - fifo_input[31:24] = data_in_rdata[31:24]; - - case (read_ptr_valid_reg[1:0]) - 2'b00: ; - - 2'b01: fifo_input[7:0] = data_in_rdata[15:8]; - - 2'b10: begin - fifo_input[7:0] = data_in_rdata[23:16]; - fifo_input[15:8] = data_in_rdata[31:24]; - end + if (pad_fifo_on) begin + fifo_input = 32'h0; + end else begin + fifo_input[7:0] = data_in_rdata[7:0]; + fifo_input[15:8] = data_in_rdata[15:8]; + fifo_input[23:16] = data_in_rdata[23:16]; + fifo_input[31:24] = data_in_rdata[31:24]; + + case (read_ptr_valid_reg[1:0]) + 2'b00: ; + 2'b01: fifo_input[7:0] = data_in_rdata[15:8]; + + 2'b10: begin + fifo_input[7:0] = data_in_rdata[23:16]; + fifo_input[15:8] = data_in_rdata[31:24]; + end - 2'b11: fifo_input[7:0] = data_in_rdata[31:24]; - endcase + 2'b11: fifo_input[7:0] = data_in_rdata[31:24]; + endcase + end end // FSM state update @@ -410,6 +761,7 @@ module dma #( dma_read_fsm_state <= dma_read_fsm_n_state; dma_write_fsm_state <= dma_write_fsm_n_state; dma_read_addr_fsm_state <= dma_read_addr_fsm_n_state; + outstanding_req <= outstanding_req + (data_in_req && data_in_gnt) - data_in_rvalid; if (address_mode) @@ -418,6 +770,250 @@ module dma #( end end + /* Padding synchronization signal generation + * When the pad_fifo_on is asserted, this logic mimics the behaviour of the data_in_rvalid and data_in_gnt signals + * coming from the memory. This is done in order to keep the read/write operations working even without an + * actual response from memory, reducing power consumptionnby avoiding unnecessary memory accesses. + */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_pad_sync_signal + if (~rst_ni) begin + data_in_rvalid_virt <= 1'b0; + data_in_rvalid_virt_n <= 1'b1; + data_in_rvalid_virt_n_n <= 1'b0; + data_in_gnt_virt <= 1'b1; + data_in_gnt_virt_n <= 1'b0; + data_in_gnt_virt_n_n <= 1'b0; + end else begin + if (data_in_req == 1'b1 && pad_fifo_on == 1'b1) begin + data_in_rvalid_virt <= data_in_rvalid_virt_n; + data_in_rvalid_virt_n <= data_in_rvalid_virt_n_n; + data_in_rvalid_virt_n_n <= data_in_rvalid; + data_in_gnt_virt <= data_in_gnt_virt_n; + data_in_gnt_virt_n <= data_in_gnt_virt_n_n; + data_in_gnt_virt_n_n <= data_in_gnt; + end else begin + data_in_rvalid_virt <= 1'b0; + data_in_rvalid_virt_n <= 1'b1; + data_in_rvalid_virt_n_n <= 1'b0; + data_in_gnt_virt <= 1'b1; + data_in_gnt_virt_n <= 1'b0; + data_in_gnt_virt_n_n <= 1'b0; + end + end + end + + // Padding FSM state update + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_pad_state + if (~rst_ni) begin + pad_state_q <= PAD_IDLE; + pad_state_x <= PAD_IDLE; + end else if (dma_conf_2d == 1'b1) begin + if (dma_start == 1'b1 && |reg2hw.pad_top.q == 1'b1) begin + pad_state_q <= TOP_PAD_EXEC; + pad_state_x <= TOP_PAD_EXEC; + end else if (dma_start == 1'b1 && |reg2hw.pad_left.q == 1'b1) begin + pad_state_q <= LEFT_PAD_EXEC; + pad_state_x <= LEFT_PAD_EXEC; + end else begin + pad_state_x <= pad_state_d; + if (data_in_rvalid == 1'b1) begin + pad_state_q <= pad_state_x; + end + end + end + end + + // Pad fifo flag logic + always_comb begin : proc_pad_fifo_on + if (dma_conf_2d == 1'b1) begin + case (pad_state_q) + TOP_PAD_EXEC, LEFT_PAD_EXEC, RIGHT_PAD_EXEC, BOTTOM_PAD_EXEC: pad_fifo_on = 1'b1; + + default: pad_fifo_on = 1'b0; + endcase + end else begin + pad_fifo_on = 1'b0; + end + end + + // Pad counter flag logic + always_comb begin : proc_pad_cnt_on + case (pad_state_q) + PAD_IDLE: begin + if (idle_to_right_ex || idle_to_bottom_ex || idle_to_left_ex || idle_to_top_ex) begin + pad_cnt_on = 1'b1; + end else begin + pad_cnt_on = pad_fifo_on; + end + end + + TOP_PAD_DONE: begin + if (top_dn_to_right_ex) begin + pad_cnt_on = 1'b1; + end else begin + pad_cnt_on = pad_fifo_on; + end + end + + LEFT_PAD_DONE: begin + if (left_dn_to_right_ex) begin + pad_cnt_on = 1'b1; + end else begin + pad_cnt_on = pad_fifo_on; + end + end + + RIGHT_PAD_DONE: begin + if (right_dn_to_right_ex) begin + pad_cnt_on = 1'b1; + end else begin + pad_cnt_on = pad_fifo_on; + end + end + + RIGHT_PAD_EXEC: begin + if (right_ex_to_right_dn || right_ex_to_left_ex) begin + pad_cnt_on = 1'b0; + end else begin + pad_cnt_on = pad_fifo_on; + end + end + + default: pad_cnt_on = pad_fifo_on; + endcase + end + + // Padding FSM logic + always_comb begin : proc_pad_fsm_logic + if (dma_conf_1d == 1'b1) begin + pad_state_d = PAD_IDLE; + end else begin + if (dma_start == 1'b1 && |reg2hw.pad_top.q == 1'b1) begin + pad_state_d = TOP_PAD_EXEC; + end else if (dma_start == 1'b1 && |reg2hw.pad_left.q == 1'b1) begin + pad_state_d = LEFT_PAD_EXEC; + end else begin + pad_state_d = pad_state_x; + end + end + + unique case (pad_state_x) + PAD_IDLE: begin + if (idle_to_top_ex) begin + pad_state_d = TOP_PAD_EXEC; + end else if (idle_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (idle_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (idle_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end + end + + TOP_PAD_EXEC: begin + if (top_ex_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (top_ex_to_top_dn) begin + pad_state_d = TOP_PAD_DONE; + end + end + TOP_PAD_DONE: begin + if (top_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (top_dn_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end else if (top_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + LEFT_PAD_EXEC: begin + if (left_ex_to_left_dn) begin + pad_state_d = LEFT_PAD_DONE; + end + end + LEFT_PAD_DONE: begin + if (left_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (left_dn_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end else if (left_dn_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (left_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + RIGHT_PAD_EXEC: begin + if (right_ex_to_right_dn) begin + pad_state_d = RIGHT_PAD_DONE; + end else if (right_ex_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (right_ex_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end + end + RIGHT_PAD_DONE: begin + if (right_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end else if (right_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end + end + BOTTOM_PAD_EXEC: begin + if (bottom_ex_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + endcase + end + + /* Transaction IFR update */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_transaction_ifr + if (~rst_ni) begin + transaction_ifr <= '0; + end else if (reg2hw.interrupt_en.transaction_done.q == 1'b1) begin + // Enter here only if the transaction_done interrupt is enabled + if (dma_done == 1'b1) begin + transaction_ifr <= 1'b1; + end else if (reg2hw.transaction_ifr.re == 1'b1) begin + // If the IFR bit is read, we must clear the transaction_ifr + transaction_ifr <= 1'b0; + end + end + end + + /* Delayed transaction interrupt signals */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_intr + if (~rst_ni) begin + dma_done_intr_n <= '0; + end else begin + dma_done_intr_n <= dma_done_intr; + end + end + + /* Window IFR update */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_window_ifr + if (~rst_ni) begin + window_ifr <= '0; + end else if (reg2hw.interrupt_en.window_done.q == 1'b1) begin + // Enter here only if the window_done interrupt is enabled + if (dma_window_event == 1'b1) begin + window_ifr <= 1'b1; + end else if (reg2hw.window_ifr.re == 1'b1) begin + // If the IFR bit is read, we must clear the window_ifr + window_ifr <= 1'b0; + end + end + end + + /* Delayed window interrupt signals */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_window_intr + if (~rst_ni) begin + dma_window_intr_n <= '0; + end else begin + dma_window_intr_n <= dma_window_intr; + end + end + // Read master FSM always_comb begin : proc_dma_read_fsm_logic @@ -444,17 +1040,39 @@ module dma #( // Read one word DMA_READ_FSM_ON: begin // If all input data read exit - if (|dma_cnt == 1'b0) begin - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - end else begin - dma_read_fsm_n_state = DMA_READ_FSM_ON; - // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). - if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin - data_in_req = 1'b1; - data_in_we = 1'b0; - data_in_be = 4'b1111; // always read all bytes - data_in_addr = read_ptr_reg; + if (ext_dma_stop_i == 1'b0) begin + if (dma_conf_1d == 1'b1) begin + // 1D DMA case + if (|dma_src_cnt_d1 == 1'b0) begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). + if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin + data_in_req = 1'b1; + data_in_we = 1'b0; + data_in_be = 4'b1111; // always read all bytes + data_in_addr = read_ptr_reg; + end + end + end else if (dma_conf_2d == 1'b1) begin + // 2D DMA case: exit only if both 1d and 2d counters are at 0 + if (dma_src_cnt_d1 == {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q} && |dma_src_cnt_d2 == 1'b0) begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + // The read operation is the same in both cases + dma_read_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). + if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin + data_in_req = 1'b1; + data_in_we = 1'b0; + data_in_be = 4'b1111; // always read all bytes + data_in_addr = read_ptr_reg; + end + end end + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; end end endcase @@ -528,6 +1146,8 @@ module dma #( // If all input data read exit if (fifo_empty == 1'b1 && dma_read_fsm_state == DMA_READ_FSM_IDLE) begin dma_done = outstanding_req == '0 && outstanding_addr_req == '0; + // If all input data has been read (dma_read_fsm_state == DMA_READ_FSM_IDLE, set when all data has been read) + // and all requests have been granted, (outstanding_req == 0) then we are done dma_write_fsm_n_state = dma_done ? DMA_WRITE_FSM_IDLE : DMA_WRITE_FSM_ON; end else begin dma_write_fsm_n_state = DMA_WRITE_FSM_ON; @@ -596,9 +1216,9 @@ module dma #( // WINDOW EVENT // Count gnt write transaction and generate event pulse if WINDOW_SIZE is reached - assign dma_window_event = |reg2hw.window_size.q & data_out_gnt & (window_counter + 'h1 >= reg2hw.window_size.q); + assign dma_window_event = |reg2hw.window_size.q & data_out_gnt & (window_counter + 'h1 >= {19'h0, reg2hw.window_size.q}); - always_ff @(posedge clk_i, negedge rst_ni) begin + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_dma_window_cnt if (~rst_ni) begin window_counter <= 'h0; end else begin @@ -606,7 +1226,7 @@ module dma #( if (dma_start | dma_done) begin window_counter <= 'h0; end else if (data_out_gnt) begin - if (window_counter + 'h1 >= reg2hw.window_size.q) begin + if (window_counter + 'h1 >= {19'h0, reg2hw.window_size.q}) begin window_counter <= 'h0; end else begin window_counter <= window_counter + 'h1; @@ -617,7 +1237,7 @@ module dma #( end // Update WINDOW_COUNT register - always_comb begin + always_comb begin : proc_dma_window_cnt_reg hw2reg.window_count.d = reg2hw.window_count.q + 'h1; hw2reg.window_count.de = 1'b0; if (dma_start) begin @@ -631,7 +1251,7 @@ module dma #( // update window_done flag // set on dma_window_event // reset on read - always_ff @(posedge clk_i, negedge rst_ni) begin + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_dma_window_done if (~rst_ni) begin window_done_q <= 1'b0; end else begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv index e4e31fe2..f2fe4761 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -7,7 +7,7 @@ package dma_reg_pkg; // Address widths within the block - parameter int BlockAw = 6; + parameter int BlockAw = 7; //////////////////////////// // Typedefs for registers // @@ -20,9 +20,14 @@ package dma_reg_pkg; typedef struct packed {logic [31:0] q;} dma_reg2hw_addr_ptr_reg_t; typedef struct packed { - logic [31:0] q; + logic [15:0] q; logic qe; - } dma_reg2hw_size_reg_t; + } dma_reg2hw_size_d1_reg_t; + + typedef struct packed { + logic [15:0] q; + logic qe; + } dma_reg2hw_size_d2_reg_t; typedef struct packed { struct packed { @@ -35,110 +40,217 @@ package dma_reg_pkg; } window_done; } dma_reg2hw_status_reg_t; - typedef struct packed { - struct packed {logic [7:0] q;} src_ptr_inc; - struct packed {logic [7:0] q;} dst_ptr_inc; - } dma_reg2hw_ptr_inc_reg_t; + typedef struct packed {logic [5:0] q;} dma_reg2hw_src_ptr_inc_d1_reg_t; + + typedef struct packed {logic [22:0] q;} dma_reg2hw_src_ptr_inc_d2_reg_t; + + typedef struct packed {logic [5:0] q;} dma_reg2hw_dst_ptr_inc_d1_reg_t; + + typedef struct packed {logic [22:0] q;} dma_reg2hw_dst_ptr_inc_d2_reg_t; typedef struct packed { struct packed {logic [15:0] q;} rx_trigger_slot; struct packed {logic [15:0] q;} tx_trigger_slot; } dma_reg2hw_slot_reg_t; - typedef struct packed {logic [1:0] q;} dma_reg2hw_data_type_reg_t; + typedef struct packed {logic [1:0] q;} dma_reg2hw_src_data_type_reg_t; + + typedef struct packed {logic [1:0] q;} dma_reg2hw_dst_data_type_reg_t; + + typedef struct packed {logic q;} dma_reg2hw_sign_ext_reg_t; typedef struct packed {logic [1:0] q;} dma_reg2hw_mode_reg_t; - typedef struct packed {logic [31:0] q;} dma_reg2hw_window_size_reg_t; + typedef struct packed {logic q;} dma_reg2hw_dim_config_reg_t; + + typedef struct packed {logic q;} dma_reg2hw_dim_inv_reg_t; - typedef struct packed {logic [31:0] q;} dma_reg2hw_window_count_reg_t; + typedef struct packed { + logic [5:0] q; + logic qe; + } dma_reg2hw_pad_top_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } dma_reg2hw_pad_bottom_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } dma_reg2hw_pad_right_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } dma_reg2hw_pad_left_reg_t; + + typedef struct packed {logic [12:0] q;} dma_reg2hw_window_size_reg_t; + + typedef struct packed {logic [7:0] q;} dma_reg2hw_window_count_reg_t; typedef struct packed { struct packed {logic q;} transaction_done; struct packed {logic q;} window_done; } dma_reg2hw_interrupt_en_reg_t; + typedef struct packed { + logic q; + logic re; + } dma_reg2hw_transaction_ifr_reg_t; + + typedef struct packed { + logic q; + logic re; + } dma_reg2hw_window_ifr_reg_t; + typedef struct packed { struct packed {logic d;} ready; struct packed {logic d;} window_done; } dma_hw2reg_status_reg_t; typedef struct packed { - logic [31:0] d; - logic de; + logic [7:0] d; + logic de; } dma_hw2reg_window_count_reg_t; + typedef struct packed {logic d;} dma_hw2reg_transaction_ifr_reg_t; + + typedef struct packed {logic d;} dma_hw2reg_window_ifr_reg_t; + // Register -> HW type typedef struct packed { - dma_reg2hw_src_ptr_reg_t src_ptr; // [250:219] - dma_reg2hw_dst_ptr_reg_t dst_ptr; // [218:187] - dma_reg2hw_addr_ptr_reg_t addr_ptr; // [186:155] - dma_reg2hw_size_reg_t size; // [154:122] - dma_reg2hw_status_reg_t status; // [121:118] - dma_reg2hw_ptr_inc_reg_t ptr_inc; // [117:102] - dma_reg2hw_slot_reg_t slot; // [101:70] - dma_reg2hw_data_type_reg_t data_type; // [69:68] - dma_reg2hw_mode_reg_t mode; // [67:66] - dma_reg2hw_window_size_reg_t window_size; // [65:34] - dma_reg2hw_window_count_reg_t window_count; // [33:2] - dma_reg2hw_interrupt_en_reg_t interrupt_en; // [1:0] + dma_reg2hw_src_ptr_reg_t src_ptr; // [287:256] + dma_reg2hw_dst_ptr_reg_t dst_ptr; // [255:224] + dma_reg2hw_addr_ptr_reg_t addr_ptr; // [223:192] + dma_reg2hw_size_d1_reg_t size_d1; // [191:175] + dma_reg2hw_size_d2_reg_t size_d2; // [174:158] + dma_reg2hw_status_reg_t status; // [157:154] + dma_reg2hw_src_ptr_inc_d1_reg_t src_ptr_inc_d1; // [153:148] + dma_reg2hw_src_ptr_inc_d2_reg_t src_ptr_inc_d2; // [147:125] + dma_reg2hw_dst_ptr_inc_d1_reg_t dst_ptr_inc_d1; // [124:119] + dma_reg2hw_dst_ptr_inc_d2_reg_t dst_ptr_inc_d2; // [118:96] + dma_reg2hw_slot_reg_t slot; // [95:64] + dma_reg2hw_src_data_type_reg_t src_data_type; // [63:62] + dma_reg2hw_dst_data_type_reg_t dst_data_type; // [61:60] + dma_reg2hw_sign_ext_reg_t sign_ext; // [59:59] + dma_reg2hw_mode_reg_t mode; // [58:57] + dma_reg2hw_dim_config_reg_t dim_config; // [56:56] + dma_reg2hw_dim_inv_reg_t dim_inv; // [55:55] + dma_reg2hw_pad_top_reg_t pad_top; // [54:48] + dma_reg2hw_pad_bottom_reg_t pad_bottom; // [47:41] + dma_reg2hw_pad_right_reg_t pad_right; // [40:34] + dma_reg2hw_pad_left_reg_t pad_left; // [33:27] + dma_reg2hw_window_size_reg_t window_size; // [26:14] + dma_reg2hw_window_count_reg_t window_count; // [13:6] + dma_reg2hw_interrupt_en_reg_t interrupt_en; // [5:4] + dma_reg2hw_transaction_ifr_reg_t transaction_ifr; // [3:2] + dma_reg2hw_window_ifr_reg_t window_ifr; // [1:0] } dma_reg2hw_t; // HW -> register type typedef struct packed { - dma_hw2reg_status_reg_t status; // [34:33] - dma_hw2reg_window_count_reg_t window_count; // [32:0] + dma_hw2reg_status_reg_t status; // [12:11] + dma_hw2reg_window_count_reg_t window_count; // [10:2] + dma_hw2reg_transaction_ifr_reg_t transaction_ifr; // [1:1] + dma_hw2reg_window_ifr_reg_t window_ifr; // [0:0] } dma_hw2reg_t; // Register offsets - parameter logic [BlockAw-1:0] DMA_SRC_PTR_OFFSET = 6'h0; - parameter logic [BlockAw-1:0] DMA_DST_PTR_OFFSET = 6'h4; - parameter logic [BlockAw-1:0] DMA_ADDR_PTR_OFFSET = 6'h8; - parameter logic [BlockAw-1:0] DMA_SIZE_OFFSET = 6'hc; - parameter logic [BlockAw-1:0] DMA_STATUS_OFFSET = 6'h10; - parameter logic [BlockAw-1:0] DMA_PTR_INC_OFFSET = 6'h14; - parameter logic [BlockAw-1:0] DMA_SLOT_OFFSET = 6'h18; - parameter logic [BlockAw-1:0] DMA_DATA_TYPE_OFFSET = 6'h1c; - parameter logic [BlockAw-1:0] DMA_MODE_OFFSET = 6'h20; - parameter logic [BlockAw-1:0] DMA_WINDOW_SIZE_OFFSET = 6'h24; - parameter logic [BlockAw-1:0] DMA_WINDOW_COUNT_OFFSET = 6'h28; - parameter logic [BlockAw-1:0] DMA_INTERRUPT_EN_OFFSET = 6'h2c; + parameter logic [BlockAw-1:0] DMA_SRC_PTR_OFFSET = 7'h0; + parameter logic [BlockAw-1:0] DMA_DST_PTR_OFFSET = 7'h4; + parameter logic [BlockAw-1:0] DMA_ADDR_PTR_OFFSET = 7'h8; + parameter logic [BlockAw-1:0] DMA_SIZE_D1_OFFSET = 7'hc; + parameter logic [BlockAw-1:0] DMA_SIZE_D2_OFFSET = 7'h10; + parameter logic [BlockAw-1:0] DMA_STATUS_OFFSET = 7'h14; + parameter logic [BlockAw-1:0] DMA_SRC_PTR_INC_D1_OFFSET = 7'h18; + parameter logic [BlockAw-1:0] DMA_SRC_PTR_INC_D2_OFFSET = 7'h1c; + parameter logic [BlockAw-1:0] DMA_DST_PTR_INC_D1_OFFSET = 7'h20; + parameter logic [BlockAw-1:0] DMA_DST_PTR_INC_D2_OFFSET = 7'h24; + parameter logic [BlockAw-1:0] DMA_SLOT_OFFSET = 7'h28; + parameter logic [BlockAw-1:0] DMA_SRC_DATA_TYPE_OFFSET = 7'h2c; + parameter logic [BlockAw-1:0] DMA_DST_DATA_TYPE_OFFSET = 7'h30; + parameter logic [BlockAw-1:0] DMA_SIGN_EXT_OFFSET = 7'h34; + parameter logic [BlockAw-1:0] DMA_MODE_OFFSET = 7'h38; + parameter logic [BlockAw-1:0] DMA_DIM_CONFIG_OFFSET = 7'h3c; + parameter logic [BlockAw-1:0] DMA_DIM_INV_OFFSET = 7'h40; + parameter logic [BlockAw-1:0] DMA_PAD_TOP_OFFSET = 7'h44; + parameter logic [BlockAw-1:0] DMA_PAD_BOTTOM_OFFSET = 7'h48; + parameter logic [BlockAw-1:0] DMA_PAD_RIGHT_OFFSET = 7'h4c; + parameter logic [BlockAw-1:0] DMA_PAD_LEFT_OFFSET = 7'h50; + parameter logic [BlockAw-1:0] DMA_WINDOW_SIZE_OFFSET = 7'h54; + parameter logic [BlockAw-1:0] DMA_WINDOW_COUNT_OFFSET = 7'h58; + parameter logic [BlockAw-1:0] DMA_INTERRUPT_EN_OFFSET = 7'h5c; + parameter logic [BlockAw-1:0] DMA_TRANSACTION_IFR_OFFSET = 7'h60; + parameter logic [BlockAw-1:0] DMA_WINDOW_IFR_OFFSET = 7'h64; // Reset values for hwext registers and their fields parameter logic [1:0] DMA_STATUS_RESVAL = 2'h1; parameter logic [0:0] DMA_STATUS_READY_RESVAL = 1'h1; parameter logic [0:0] DMA_STATUS_WINDOW_DONE_RESVAL = 1'h0; + parameter logic [0:0] DMA_TRANSACTION_IFR_RESVAL = 1'h0; + parameter logic [0:0] DMA_TRANSACTION_IFR_FLAG_RESVAL = 1'h0; + parameter logic [0:0] DMA_WINDOW_IFR_RESVAL = 1'h0; + parameter logic [0:0] DMA_WINDOW_IFR_FLAG_RESVAL = 1'h0; // Register index typedef enum int { DMA_SRC_PTR, DMA_DST_PTR, DMA_ADDR_PTR, - DMA_SIZE, + DMA_SIZE_D1, + DMA_SIZE_D2, DMA_STATUS, - DMA_PTR_INC, + DMA_SRC_PTR_INC_D1, + DMA_SRC_PTR_INC_D2, + DMA_DST_PTR_INC_D1, + DMA_DST_PTR_INC_D2, DMA_SLOT, - DMA_DATA_TYPE, + DMA_SRC_DATA_TYPE, + DMA_DST_DATA_TYPE, + DMA_SIGN_EXT, DMA_MODE, + DMA_DIM_CONFIG, + DMA_DIM_INV, + DMA_PAD_TOP, + DMA_PAD_BOTTOM, + DMA_PAD_RIGHT, + DMA_PAD_LEFT, DMA_WINDOW_SIZE, DMA_WINDOW_COUNT, - DMA_INTERRUPT_EN + DMA_INTERRUPT_EN, + DMA_TRANSACTION_IFR, + DMA_WINDOW_IFR } dma_id_e; // Register width information to check illegal writes - parameter logic [3:0] DMA_PERMIT[12] = '{ + parameter logic [3:0] DMA_PERMIT[26] = '{ 4'b1111, // index[ 0] DMA_SRC_PTR 4'b1111, // index[ 1] DMA_DST_PTR 4'b1111, // index[ 2] DMA_ADDR_PTR - 4'b1111, // index[ 3] DMA_SIZE - 4'b0001, // index[ 4] DMA_STATUS - 4'b0011, // index[ 5] DMA_PTR_INC - 4'b1111, // index[ 6] DMA_SLOT - 4'b0001, // index[ 7] DMA_DATA_TYPE - 4'b0001, // index[ 8] DMA_MODE - 4'b1111, // index[ 9] DMA_WINDOW_SIZE - 4'b1111, // index[10] DMA_WINDOW_COUNT - 4'b0001 // index[11] DMA_INTERRUPT_EN + 4'b0011, // index[ 3] DMA_SIZE_D1 + 4'b0011, // index[ 4] DMA_SIZE_D2 + 4'b0001, // index[ 5] DMA_STATUS + 4'b0001, // index[ 6] DMA_SRC_PTR_INC_D1 + 4'b0111, // index[ 7] DMA_SRC_PTR_INC_D2 + 4'b0001, // index[ 8] DMA_DST_PTR_INC_D1 + 4'b0111, // index[ 9] DMA_DST_PTR_INC_D2 + 4'b1111, // index[10] DMA_SLOT + 4'b0001, // index[11] DMA_SRC_DATA_TYPE + 4'b0001, // index[12] DMA_DST_DATA_TYPE + 4'b0001, // index[13] DMA_SIGN_EXT + 4'b0001, // index[14] DMA_MODE + 4'b0001, // index[15] DMA_DIM_CONFIG + 4'b0001, // index[16] DMA_DIM_INV + 4'b0001, // index[17] DMA_PAD_TOP + 4'b0001, // index[18] DMA_PAD_BOTTOM + 4'b0001, // index[19] DMA_PAD_RIGHT + 4'b0001, // index[20] DMA_PAD_LEFT + 4'b0011, // index[21] DMA_WINDOW_SIZE + 4'b0001, // index[22] DMA_WINDOW_COUNT + 4'b0001, // index[23] DMA_INTERRUPT_EN + 4'b0001, // index[24] DMA_TRANSACTION_IFR + 4'b0001 // index[25] DMA_WINDOW_IFR }; endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv index 4a3ff6d0..a4004830 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv @@ -10,7 +10,7 @@ module dma_reg_top #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, - parameter int AW = 6 + parameter int AW = 7 ) ( input logic clk_i, input logic rst_ni, @@ -77,41 +77,78 @@ module dma_reg_top #( logic [31:0] addr_ptr_qs; logic [31:0] addr_ptr_wd; logic addr_ptr_we; - logic [31:0] size_qs; - logic [31:0] size_wd; - logic size_we; + logic [15:0] size_d1_qs; + logic [15:0] size_d1_wd; + logic size_d1_we; + logic [15:0] size_d2_qs; + logic [15:0] size_d2_wd; + logic size_d2_we; logic status_ready_qs; logic status_ready_re; logic status_window_done_qs; logic status_window_done_re; - logic [7:0] ptr_inc_src_ptr_inc_qs; - logic [7:0] ptr_inc_src_ptr_inc_wd; - logic ptr_inc_src_ptr_inc_we; - logic [7:0] ptr_inc_dst_ptr_inc_qs; - logic [7:0] ptr_inc_dst_ptr_inc_wd; - logic ptr_inc_dst_ptr_inc_we; + logic [5:0] src_ptr_inc_d1_qs; + logic [5:0] src_ptr_inc_d1_wd; + logic src_ptr_inc_d1_we; + logic [22:0] src_ptr_inc_d2_qs; + logic [22:0] src_ptr_inc_d2_wd; + logic src_ptr_inc_d2_we; + logic [5:0] dst_ptr_inc_d1_qs; + logic [5:0] dst_ptr_inc_d1_wd; + logic dst_ptr_inc_d1_we; + logic [22:0] dst_ptr_inc_d2_qs; + logic [22:0] dst_ptr_inc_d2_wd; + logic dst_ptr_inc_d2_we; logic [15:0] slot_rx_trigger_slot_qs; logic [15:0] slot_rx_trigger_slot_wd; logic slot_rx_trigger_slot_we; logic [15:0] slot_tx_trigger_slot_qs; logic [15:0] slot_tx_trigger_slot_wd; logic slot_tx_trigger_slot_we; - logic [1:0] data_type_qs; - logic [1:0] data_type_wd; - logic data_type_we; + logic [1:0] src_data_type_qs; + logic [1:0] src_data_type_wd; + logic src_data_type_we; + logic [1:0] dst_data_type_qs; + logic [1:0] dst_data_type_wd; + logic dst_data_type_we; + logic sign_ext_qs; + logic sign_ext_wd; + logic sign_ext_we; logic [1:0] mode_qs; logic [1:0] mode_wd; logic mode_we; - logic [31:0] window_size_qs; - logic [31:0] window_size_wd; + logic dim_config_qs; + logic dim_config_wd; + logic dim_config_we; + logic dim_inv_qs; + logic dim_inv_wd; + logic dim_inv_we; + logic [5:0] pad_top_qs; + logic [5:0] pad_top_wd; + logic pad_top_we; + logic [5:0] pad_bottom_qs; + logic [5:0] pad_bottom_wd; + logic pad_bottom_we; + logic [5:0] pad_right_qs; + logic [5:0] pad_right_wd; + logic pad_right_we; + logic [5:0] pad_left_qs; + logic [5:0] pad_left_wd; + logic pad_left_we; + logic [12:0] window_size_qs; + logic [12:0] window_size_wd; logic window_size_we; - logic [31:0] window_count_qs; + logic [7:0] window_count_qs; logic interrupt_en_transaction_done_qs; logic interrupt_en_transaction_done_wd; logic interrupt_en_transaction_done_we; logic interrupt_en_window_done_qs; logic interrupt_en_window_done_wd; logic interrupt_en_window_done_we; + logic transaction_ifr_qs; + logic transaction_ifr_re; + logic window_ifr_qs; + logic window_ifr_re; // Register instances // R[src_ptr]: V(False) @@ -195,30 +232,57 @@ module dma_reg_top #( ); - // R[size]: V(False) + // R[size_d1]: V(False) prim_subreg #( - .DW (32), + .DW (16), .SWACCESS("RW"), - .RESVAL (32'h0) - ) u_size ( + .RESVAL (16'h0) + ) u_size_d1 ( .clk_i (clk_i), .rst_ni(rst_ni), // from register interface - .we(size_we), - .wd(size_wd), + .we(size_d1_we), + .wd(size_d1_wd), // from internal hardware .de(1'b0), .d ('0), // to internal hardware - .qe(reg2hw.size.qe), - .q (reg2hw.size.q), + .qe(reg2hw.size_d1.qe), + .q (reg2hw.size_d1.q), // to register interface (read) - .qs(size_qs) + .qs(size_d1_qs) + ); + + + // R[size_d2]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_size_d2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(size_d2_we), + .wd(size_d2_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.size_d2.qe), + .q (reg2hw.size_d2.q), + + // to register interface (read) + .qs(size_d2_qs) ); @@ -254,20 +318,19 @@ module dma_reg_top #( ); - // R[ptr_inc]: V(False) + // R[src_ptr_inc_d1]: V(False) - // F[src_ptr_inc]: 7:0 prim_subreg #( - .DW (8), + .DW (6), .SWACCESS("RW"), - .RESVAL (8'h4) - ) u_ptr_inc_src_ptr_inc ( + .RESVAL (6'h4) + ) u_src_ptr_inc_d1 ( .clk_i (clk_i), .rst_ni(rst_ni), // from register interface - .we(ptr_inc_src_ptr_inc_we), - .wd(ptr_inc_src_ptr_inc_wd), + .we(src_ptr_inc_d1_we), + .wd(src_ptr_inc_d1_wd), // from internal hardware .de(1'b0), @@ -275,25 +338,53 @@ module dma_reg_top #( // to internal hardware .qe(), - .q (reg2hw.ptr_inc.src_ptr_inc.q), + .q (reg2hw.src_ptr_inc_d1.q), // to register interface (read) - .qs(ptr_inc_src_ptr_inc_qs) + .qs(src_ptr_inc_d1_qs) ); - // F[dst_ptr_inc]: 15:8 + // R[src_ptr_inc_d2]: V(False) + prim_subreg #( - .DW (8), + .DW (23), + .SWACCESS("RW"), + .RESVAL (23'h4) + ) u_src_ptr_inc_d2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(src_ptr_inc_d2_we), + .wd(src_ptr_inc_d2_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.src_ptr_inc_d2.q), + + // to register interface (read) + .qs(src_ptr_inc_d2_qs) + ); + + + // R[dst_ptr_inc_d1]: V(False) + + prim_subreg #( + .DW (6), .SWACCESS("RW"), - .RESVAL (8'h4) - ) u_ptr_inc_dst_ptr_inc ( + .RESVAL (6'h4) + ) u_dst_ptr_inc_d1 ( .clk_i (clk_i), .rst_ni(rst_ni), // from register interface - .we(ptr_inc_dst_ptr_inc_we), - .wd(ptr_inc_dst_ptr_inc_wd), + .we(dst_ptr_inc_d1_we), + .wd(dst_ptr_inc_d1_wd), // from internal hardware .de(1'b0), @@ -301,10 +392,37 @@ module dma_reg_top #( // to internal hardware .qe(), - .q (reg2hw.ptr_inc.dst_ptr_inc.q), + .q (reg2hw.dst_ptr_inc_d1.q), // to register interface (read) - .qs(ptr_inc_dst_ptr_inc_qs) + .qs(dst_ptr_inc_d1_qs) + ); + + + // R[dst_ptr_inc_d2]: V(False) + + prim_subreg #( + .DW (23), + .SWACCESS("RW"), + .RESVAL (23'h4) + ) u_dst_ptr_inc_d2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(dst_ptr_inc_d2_we), + .wd(dst_ptr_inc_d2_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.dst_ptr_inc_d2.q), + + // to register interface (read) + .qs(dst_ptr_inc_d2_qs) ); @@ -362,19 +480,46 @@ module dma_reg_top #( ); - // R[data_type]: V(False) + // R[src_data_type]: V(False) + + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_src_data_type ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(src_data_type_we), + .wd(src_data_type_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.src_data_type.q), + + // to register interface (read) + .qs(src_data_type_qs) + ); + + + // R[dst_data_type]: V(False) prim_subreg #( .DW (2), .SWACCESS("RW"), .RESVAL (2'h0) - ) u_data_type ( + ) u_dst_data_type ( .clk_i (clk_i), .rst_ni(rst_ni), // from register interface - .we(data_type_we), - .wd(data_type_wd), + .we(dst_data_type_we), + .wd(dst_data_type_wd), // from internal hardware .de(1'b0), @@ -382,10 +527,37 @@ module dma_reg_top #( // to internal hardware .qe(), - .q (reg2hw.data_type.q), + .q (reg2hw.dst_data_type.q), // to register interface (read) - .qs(data_type_qs) + .qs(dst_data_type_qs) + ); + + + // R[sign_ext]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_sign_ext ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(sign_ext_we), + .wd(sign_ext_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.sign_ext.q), + + // to register interface (read) + .qs(sign_ext_qs) ); @@ -416,12 +588,174 @@ module dma_reg_top #( ); + // R[dim_config]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_dim_config ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(dim_config_we), + .wd(dim_config_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.dim_config.q), + + // to register interface (read) + .qs(dim_config_qs) + ); + + + // R[dim_inv]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_dim_inv ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(dim_inv_we), + .wd(dim_inv_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.dim_inv.q), + + // to register interface (read) + .qs(dim_inv_qs) + ); + + + // R[pad_top]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_top ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_top_we), + .wd(pad_top_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_top.qe), + .q (reg2hw.pad_top.q), + + // to register interface (read) + .qs(pad_top_qs) + ); + + + // R[pad_bottom]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_bottom ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_bottom_we), + .wd(pad_bottom_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_bottom.qe), + .q (reg2hw.pad_bottom.q), + + // to register interface (read) + .qs(pad_bottom_qs) + ); + + + // R[pad_right]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_right ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_right_we), + .wd(pad_right_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_right.qe), + .q (reg2hw.pad_right.q), + + // to register interface (read) + .qs(pad_right_qs) + ); + + + // R[pad_left]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_left ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_left_we), + .wd(pad_left_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_left.qe), + .q (reg2hw.pad_left.q), + + // to register interface (read) + .qs(pad_left_qs) + ); + + // R[window_size]: V(False) prim_subreg #( - .DW (32), + .DW (13), .SWACCESS("RW"), - .RESVAL (32'h0) + .RESVAL (13'h0) ) u_window_size ( .clk_i (clk_i), .rst_ni(rst_ni), @@ -446,9 +780,9 @@ module dma_reg_top #( // R[window_count]: V(False) prim_subreg #( - .DW (32), + .DW (8), .SWACCESS("RO"), - .RESVAL (32'h0) + .RESVAL (8'h0) ) u_window_count ( .clk_i (clk_i), .rst_ni(rst_ni), @@ -523,23 +857,69 @@ module dma_reg_top #( ); + // R[transaction_ifr]: V(True) + prim_subreg_ext #( + .DW(1) + ) u_transaction_ifr ( + .re (transaction_ifr_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.transaction_ifr.d), + .qre(reg2hw.transaction_ifr.re), + .qe (), + .q (reg2hw.transaction_ifr.q), + .qs (transaction_ifr_qs) + ); + + + // R[window_ifr]: V(True) + + prim_subreg_ext #( + .DW(1) + ) u_window_ifr ( + .re (window_ifr_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.window_ifr.d), + .qre(reg2hw.window_ifr.re), + .qe (), + .q (reg2hw.window_ifr.q), + .qs (window_ifr_qs) + ); - logic [11:0] addr_hit; + + + + logic [25:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[0] = (reg_addr == DMA_SRC_PTR_OFFSET); addr_hit[1] = (reg_addr == DMA_DST_PTR_OFFSET); addr_hit[2] = (reg_addr == DMA_ADDR_PTR_OFFSET); - addr_hit[3] = (reg_addr == DMA_SIZE_OFFSET); - addr_hit[4] = (reg_addr == DMA_STATUS_OFFSET); - addr_hit[5] = (reg_addr == DMA_PTR_INC_OFFSET); - addr_hit[6] = (reg_addr == DMA_SLOT_OFFSET); - addr_hit[7] = (reg_addr == DMA_DATA_TYPE_OFFSET); - addr_hit[8] = (reg_addr == DMA_MODE_OFFSET); - addr_hit[9] = (reg_addr == DMA_WINDOW_SIZE_OFFSET); - addr_hit[10] = (reg_addr == DMA_WINDOW_COUNT_OFFSET); - addr_hit[11] = (reg_addr == DMA_INTERRUPT_EN_OFFSET); + addr_hit[3] = (reg_addr == DMA_SIZE_D1_OFFSET); + addr_hit[4] = (reg_addr == DMA_SIZE_D2_OFFSET); + addr_hit[5] = (reg_addr == DMA_STATUS_OFFSET); + addr_hit[6] = (reg_addr == DMA_SRC_PTR_INC_D1_OFFSET); + addr_hit[7] = (reg_addr == DMA_SRC_PTR_INC_D2_OFFSET); + addr_hit[8] = (reg_addr == DMA_DST_PTR_INC_D1_OFFSET); + addr_hit[9] = (reg_addr == DMA_DST_PTR_INC_D2_OFFSET); + addr_hit[10] = (reg_addr == DMA_SLOT_OFFSET); + addr_hit[11] = (reg_addr == DMA_SRC_DATA_TYPE_OFFSET); + addr_hit[12] = (reg_addr == DMA_DST_DATA_TYPE_OFFSET); + addr_hit[13] = (reg_addr == DMA_SIGN_EXT_OFFSET); + addr_hit[14] = (reg_addr == DMA_MODE_OFFSET); + addr_hit[15] = (reg_addr == DMA_DIM_CONFIG_OFFSET); + addr_hit[16] = (reg_addr == DMA_DIM_INV_OFFSET); + addr_hit[17] = (reg_addr == DMA_PAD_TOP_OFFSET); + addr_hit[18] = (reg_addr == DMA_PAD_BOTTOM_OFFSET); + addr_hit[19] = (reg_addr == DMA_PAD_RIGHT_OFFSET); + addr_hit[20] = (reg_addr == DMA_PAD_LEFT_OFFSET); + addr_hit[21] = (reg_addr == DMA_WINDOW_SIZE_OFFSET); + addr_hit[22] = (reg_addr == DMA_WINDOW_COUNT_OFFSET); + addr_hit[23] = (reg_addr == DMA_INTERRUPT_EN_OFFSET); + addr_hit[24] = (reg_addr == DMA_TRANSACTION_IFR_OFFSET); + addr_hit[25] = (reg_addr == DMA_WINDOW_IFR_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0; @@ -558,7 +938,21 @@ module dma_reg_top #( (addr_hit[ 8] & (|(DMA_PERMIT[ 8] & ~reg_be))) | (addr_hit[ 9] & (|(DMA_PERMIT[ 9] & ~reg_be))) | (addr_hit[10] & (|(DMA_PERMIT[10] & ~reg_be))) | - (addr_hit[11] & (|(DMA_PERMIT[11] & ~reg_be))))); + (addr_hit[11] & (|(DMA_PERMIT[11] & ~reg_be))) | + (addr_hit[12] & (|(DMA_PERMIT[12] & ~reg_be))) | + (addr_hit[13] & (|(DMA_PERMIT[13] & ~reg_be))) | + (addr_hit[14] & (|(DMA_PERMIT[14] & ~reg_be))) | + (addr_hit[15] & (|(DMA_PERMIT[15] & ~reg_be))) | + (addr_hit[16] & (|(DMA_PERMIT[16] & ~reg_be))) | + (addr_hit[17] & (|(DMA_PERMIT[17] & ~reg_be))) | + (addr_hit[18] & (|(DMA_PERMIT[18] & ~reg_be))) | + (addr_hit[19] & (|(DMA_PERMIT[19] & ~reg_be))) | + (addr_hit[20] & (|(DMA_PERMIT[20] & ~reg_be))) | + (addr_hit[21] & (|(DMA_PERMIT[21] & ~reg_be))) | + (addr_hit[22] & (|(DMA_PERMIT[22] & ~reg_be))) | + (addr_hit[23] & (|(DMA_PERMIT[23] & ~reg_be))) | + (addr_hit[24] & (|(DMA_PERMIT[24] & ~reg_be))) | + (addr_hit[25] & (|(DMA_PERMIT[25] & ~reg_be))))); end assign src_ptr_we = addr_hit[0] & reg_we & !reg_error; @@ -570,40 +964,77 @@ module dma_reg_top #( assign addr_ptr_we = addr_hit[2] & reg_we & !reg_error; assign addr_ptr_wd = reg_wdata[31:0]; - assign size_we = addr_hit[3] & reg_we & !reg_error; - assign size_wd = reg_wdata[31:0]; + assign size_d1_we = addr_hit[3] & reg_we & !reg_error; + assign size_d1_wd = reg_wdata[15:0]; + + assign size_d2_we = addr_hit[4] & reg_we & !reg_error; + assign size_d2_wd = reg_wdata[15:0]; + + assign status_ready_re = addr_hit[5] & reg_re & !reg_error; - assign status_ready_re = addr_hit[4] & reg_re & !reg_error; + assign status_window_done_re = addr_hit[5] & reg_re & !reg_error; - assign status_window_done_re = addr_hit[4] & reg_re & !reg_error; + assign src_ptr_inc_d1_we = addr_hit[6] & reg_we & !reg_error; + assign src_ptr_inc_d1_wd = reg_wdata[5:0]; - assign ptr_inc_src_ptr_inc_we = addr_hit[5] & reg_we & !reg_error; - assign ptr_inc_src_ptr_inc_wd = reg_wdata[7:0]; + assign src_ptr_inc_d2_we = addr_hit[7] & reg_we & !reg_error; + assign src_ptr_inc_d2_wd = reg_wdata[22:0]; - assign ptr_inc_dst_ptr_inc_we = addr_hit[5] & reg_we & !reg_error; - assign ptr_inc_dst_ptr_inc_wd = reg_wdata[15:8]; + assign dst_ptr_inc_d1_we = addr_hit[8] & reg_we & !reg_error; + assign dst_ptr_inc_d1_wd = reg_wdata[5:0]; - assign slot_rx_trigger_slot_we = addr_hit[6] & reg_we & !reg_error; + assign dst_ptr_inc_d2_we = addr_hit[9] & reg_we & !reg_error; + assign dst_ptr_inc_d2_wd = reg_wdata[22:0]; + + assign slot_rx_trigger_slot_we = addr_hit[10] & reg_we & !reg_error; assign slot_rx_trigger_slot_wd = reg_wdata[15:0]; - assign slot_tx_trigger_slot_we = addr_hit[6] & reg_we & !reg_error; + assign slot_tx_trigger_slot_we = addr_hit[10] & reg_we & !reg_error; assign slot_tx_trigger_slot_wd = reg_wdata[31:16]; - assign data_type_we = addr_hit[7] & reg_we & !reg_error; - assign data_type_wd = reg_wdata[1:0]; + assign src_data_type_we = addr_hit[11] & reg_we & !reg_error; + assign src_data_type_wd = reg_wdata[1:0]; + + assign dst_data_type_we = addr_hit[12] & reg_we & !reg_error; + assign dst_data_type_wd = reg_wdata[1:0]; - assign mode_we = addr_hit[8] & reg_we & !reg_error; + assign sign_ext_we = addr_hit[13] & reg_we & !reg_error; + assign sign_ext_wd = reg_wdata[0]; + + assign mode_we = addr_hit[14] & reg_we & !reg_error; assign mode_wd = reg_wdata[1:0]; - assign window_size_we = addr_hit[9] & reg_we & !reg_error; - assign window_size_wd = reg_wdata[31:0]; + assign dim_config_we = addr_hit[15] & reg_we & !reg_error; + assign dim_config_wd = reg_wdata[0]; + + assign dim_inv_we = addr_hit[16] & reg_we & !reg_error; + assign dim_inv_wd = reg_wdata[0]; - assign interrupt_en_transaction_done_we = addr_hit[11] & reg_we & !reg_error; + assign pad_top_we = addr_hit[17] & reg_we & !reg_error; + assign pad_top_wd = reg_wdata[5:0]; + + assign pad_bottom_we = addr_hit[18] & reg_we & !reg_error; + assign pad_bottom_wd = reg_wdata[5:0]; + + assign pad_right_we = addr_hit[19] & reg_we & !reg_error; + assign pad_right_wd = reg_wdata[5:0]; + + assign pad_left_we = addr_hit[20] & reg_we & !reg_error; + assign pad_left_wd = reg_wdata[5:0]; + + assign window_size_we = addr_hit[21] & reg_we & !reg_error; + assign window_size_wd = reg_wdata[12:0]; + + assign interrupt_en_transaction_done_we = addr_hit[23] & reg_we & !reg_error; assign interrupt_en_transaction_done_wd = reg_wdata[0]; - assign interrupt_en_window_done_we = addr_hit[11] & reg_we & !reg_error; + assign interrupt_en_window_done_we = addr_hit[23] & reg_we & !reg_error; assign interrupt_en_window_done_wd = reg_wdata[1]; + assign transaction_ifr_re = addr_hit[24] & reg_re & !reg_error; + + assign window_ifr_re = addr_hit[25] & reg_re & !reg_error; + // Read data return always_comb begin reg_rdata_next = '0; @@ -621,45 +1052,100 @@ module dma_reg_top #( end addr_hit[3]: begin - reg_rdata_next[31:0] = size_qs; + reg_rdata_next[15:0] = size_d1_qs; end addr_hit[4]: begin - reg_rdata_next[0] = status_ready_qs; - reg_rdata_next[1] = status_window_done_qs; + reg_rdata_next[15:0] = size_d2_qs; end addr_hit[5]: begin - reg_rdata_next[7:0] = ptr_inc_src_ptr_inc_qs; - reg_rdata_next[15:8] = ptr_inc_dst_ptr_inc_qs; + reg_rdata_next[0] = status_ready_qs; + reg_rdata_next[1] = status_window_done_qs; end addr_hit[6]: begin - reg_rdata_next[15:0] = slot_rx_trigger_slot_qs; - reg_rdata_next[31:16] = slot_tx_trigger_slot_qs; + reg_rdata_next[5:0] = src_ptr_inc_d1_qs; end addr_hit[7]: begin - reg_rdata_next[1:0] = data_type_qs; + reg_rdata_next[22:0] = src_ptr_inc_d2_qs; end addr_hit[8]: begin - reg_rdata_next[1:0] = mode_qs; + reg_rdata_next[5:0] = dst_ptr_inc_d1_qs; end addr_hit[9]: begin - reg_rdata_next[31:0] = window_size_qs; + reg_rdata_next[22:0] = dst_ptr_inc_d2_qs; end addr_hit[10]: begin - reg_rdata_next[31:0] = window_count_qs; + reg_rdata_next[15:0] = slot_rx_trigger_slot_qs; + reg_rdata_next[31:16] = slot_tx_trigger_slot_qs; end addr_hit[11]: begin + reg_rdata_next[1:0] = src_data_type_qs; + end + + addr_hit[12]: begin + reg_rdata_next[1:0] = dst_data_type_qs; + end + + addr_hit[13]: begin + reg_rdata_next[0] = sign_ext_qs; + end + + addr_hit[14]: begin + reg_rdata_next[1:0] = mode_qs; + end + + addr_hit[15]: begin + reg_rdata_next[0] = dim_config_qs; + end + + addr_hit[16]: begin + reg_rdata_next[0] = dim_inv_qs; + end + + addr_hit[17]: begin + reg_rdata_next[5:0] = pad_top_qs; + end + + addr_hit[18]: begin + reg_rdata_next[5:0] = pad_bottom_qs; + end + + addr_hit[19]: begin + reg_rdata_next[5:0] = pad_right_qs; + end + + addr_hit[20]: begin + reg_rdata_next[5:0] = pad_left_qs; + end + + addr_hit[21]: begin + reg_rdata_next[12:0] = window_size_qs; + end + + addr_hit[22]: begin + reg_rdata_next[7:0] = window_count_qs; + end + + addr_hit[23]: begin reg_rdata_next[0] = interrupt_en_transaction_done_qs; reg_rdata_next[1] = interrupt_en_window_done_qs; end + addr_hit[24]: begin + reg_rdata_next[0] = transaction_ifr_qs; + end + + addr_hit[25]: begin + reg_rdata_next[0] = window_ifr_qs; + end + default: begin reg_rdata_next = '1; end @@ -681,7 +1167,7 @@ module dma_reg_top #( endmodule module dma_reg_top_intf #( - parameter int AW = 6, + parameter int AW = 7, localparam int DW = 32 ) ( input logic clk_i, diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core new file mode 100644 index 00000000..1fa1b17b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core @@ -0,0 +1,21 @@ +CAPI=2: + +name: "x-heep:ip:dma_subsystem" +description: "core-v-mini-mcu dma peripheral" + +# Copyright 2021 OpenHW Group +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +filesets: + files_rtl: + depend: + - pulp-platform.org::common_cells + files: + - rtl/dma_subsystem.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.vlt new file mode 100644 index 00000000..a914d355 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.vlt @@ -0,0 +1,10 @@ +// Copyright 2022 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +`verilator_config + +lint_off -rule UNUSED -file "*/rtl/dma_subsystem.sv" -match "Signal is not used: 'data_out_rvalid'" +lint_off -rule UNUSED -file "*/rtl/dma_subsystem.sv" -match "Signal is not used: 'data_out_rdata'" + +lint_off -rule UNUSED -file "*/rtl/dma_subsystem.sv" -match "Bits of signal are not used: *" diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv new file mode 100644 index 00000000..22274b69 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv @@ -0,0 +1,198 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * Info: DMA subsystem, it instantiates 1 to 8 DMA channels and manages the data transfers. + */ + + +module dma_subsystem #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter type obi_req_t = logic, + parameter type obi_resp_t = logic, + parameter int unsigned GLOBAL_SLOT_NUM = 0, + parameter int unsigned EXT_SLOT_NUM = 0 +) ( + input logic clk_i, + input logic rst_ni, + + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + output obi_req_t dma_read_ch0_req_o, + input obi_resp_t dma_read_ch0_resp_i, + + output obi_req_t dma_write_ch0_req_o, + input obi_resp_t dma_write_ch0_resp_i, + + output obi_req_t dma_addr_ch0_req_o, + input obi_resp_t dma_addr_ch0_resp_i, + + input logic [GLOBAL_SLOT_NUM-1:0] global_trigger_slot_i, + input logic [EXT_SLOT_NUM-1:0] ext_trigger_slot_i, + + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, + + output dma_done_intr_o, + output dma_window_intr_o +); + + + import obi_pkg::*; + import reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Masters requests to the bus */ + obi_req_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_write_req; + obi_req_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_read_req; + obi_req_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_address_req; + + /* Masters response from the bus*/ + obi_resp_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_write_resp; + obi_resp_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_read_resp; + obi_resp_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] xbar_address_resp; + + /* Interrupt signals */ + logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_trans_done; + logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_window_done; + + /* Register interfaces from register demux to DMAs */ + reg_pkg::reg_req_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] submodules_req; + reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] submodules_rsp; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Module instantiation */ + + /* DMA modules */ + generate + for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_CH_NUM; i++) begin : dma_i_gen + dma #( + .reg_req_t (reg_pkg::reg_req_t), + .reg_rsp_t (reg_pkg::reg_rsp_t), + .obi_req_t (obi_pkg::obi_req_t), + .obi_resp_t(obi_pkg::obi_resp_t), + .SLOT_NUM (GLOBAL_SLOT_NUM + 2) + ) dma_i ( + .clk_i, + .rst_ni, + .ext_dma_stop_i(ext_dma_stop_i[i]), + .reg_req_i(submodules_req[i]), + .reg_rsp_o(submodules_rsp[i]), + .dma_read_ch0_req_o(xbar_read_req[i]), + .dma_read_ch0_resp_i(xbar_read_resp[i]), + .dma_write_ch0_req_o(xbar_write_req[i]), + .dma_write_ch0_resp_i(xbar_write_resp[i]), + .dma_addr_ch0_req_o(xbar_address_req[i]), + .dma_addr_ch0_resp_i(xbar_address_resp[i]), + .trigger_slot_i({ + ext_trigger_slot_i[2*i+1], ext_trigger_slot_i[2*i], global_trigger_slot_i + }), + .dma_done_intr_o(dma_trans_done[i]), + .dma_window_intr_o(dma_window_done[i]) + ); + end + endgenerate + + + generate + if (core_v_mini_mcu_pkg::DMA_CH_NUM > 1) begin : xbar_varlat_n_to_one_gen + + /* Register interface routing signals */ + logic [core_v_mini_mcu_pkg::DMA_CH_PORT_SEL_WIDTH-1:0] submodules_select; + + /* Read, write & address mode operations xbar*/ + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_read_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_read_req), + .master_resp_o(xbar_read_resp), + .slave_req_o (dma_read_ch0_req_o), + .slave_resp_i (dma_read_ch0_resp_i) + ); + + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_write_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_write_req), + .master_resp_o(xbar_write_resp), + .slave_req_o (dma_write_ch0_req_o), + .slave_resp_i (dma_write_ch0_resp_i) + ); + + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_address_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_address_req), + .master_resp_o(xbar_address_resp), + .slave_req_o (dma_addr_ch0_req_o), + .slave_resp_i (dma_addr_ch0_resp_i) + ); + + /* Internal address decoder */ + addr_decode #( + .NoIndices(core_v_mini_mcu_pkg::DMA_CH_NUM), + .NoRules(core_v_mini_mcu_pkg::DMA_CH_NUM), + .addr_t(logic [7:0]), + .rule_t(addr_map_rule_pkg::addr_map_rule_8bit_t) + ) addr_dec_i ( + .addr_i(reg_req_i.addr[15:8]), + .addr_map_i(core_v_mini_mcu_pkg::DMA_ADDR_RULES), + .idx_o(submodules_select), + .dec_valid_o(), + .dec_error_o(), + .en_default_idx_i(1'b0), + .default_idx_i('0) + ); + + /* Register demux */ + reg_demux #( + .NoPorts(core_v_mini_mcu_pkg::DMA_CH_NUM), + .req_t (reg_pkg::reg_req_t), + .rsp_t (reg_pkg::reg_rsp_t) + ) reg_demux_i ( + .clk_i, + .rst_ni, + .in_select_i(submodules_select), + .in_req_i(reg_req_i), + .in_rsp_o(reg_rsp_o), + .out_req_o(submodules_req), + .out_rsp_i(submodules_rsp) + ); + + end else begin + + /* Bus ports routing in the case of a single DMA */ + assign dma_read_ch0_req_o = xbar_read_req[0]; + assign xbar_read_resp[0] = dma_read_ch0_resp_i; + assign dma_write_ch0_req_o = xbar_write_req[0]; + assign xbar_write_resp[0] = dma_write_ch0_resp_i; + assign dma_addr_ch0_req_o = xbar_address_req[0]; + assign xbar_address_resp[0] = dma_addr_ch0_resp_i; + assign submodules_req[0] = reg_req_i; + assign reg_rsp_o = submodules_rsp[0]; + end + endgenerate + + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + assign dma_done_intr_o = |(dma_trans_done); + assign dma_window_intr_o = |(dma_window_done); + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_rx_channel.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_rx_channel.sv index 3c0066a7..52e48f9d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_rx_channel.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/i2s/rtl/i2s_rx_channel.sv @@ -153,7 +153,7 @@ module i2s_rx_channel #( // worst case drop even number of samples always_ff @(posedge sck_i, negedge rst_ni) begin if (~rst_ni) begin - last_data_ws <= ~start_channel_i; + last_data_ws <= 1'b0; end else begin if (~en) begin last_data_ws <= ~start_channel_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/fir.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/fir.sv index 6d22d673..ce17a7a6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/fir.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/fir.sv @@ -48,7 +48,9 @@ module fir #( genvar k; generate for (k = 0; k < TOTCOEFS; k = k + 1) begin : coeffs_mapping - assign coeffs[k] = freecoeffs[int'($floor($sqrt($pow((TOTCOEFS-1)/2.0-k, 2))))]; + // Remove $pow function to avoid errors in Synopsys DC + // assign coeffs[k] = freecoeffs[int'($floor($sqrt($pow((TOTCOEFS-1)/2.0-k, 2))))]; + assign coeffs[k] = freecoeffs[int'($floor($sqrt(((TOTCOEFS-1)/2.0-k)*((TOTCOEFS-1)/2.0-k))))]; end endgenerate diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/halfband.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/halfband.sv index 9d9355c8..a0710c58 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/halfband.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/pdm2pcm/rtl/halfband.sv @@ -63,7 +63,11 @@ module halfband #( genvar k; generate for (k = 0; k < TOTCOEFS; k = k + 1) begin : coeffs_mapping - assign coeffs[k] = lessfreecoeffs[int'($floor($sqrt($pow((TOTCOEFS-1)/2.0-k, 2))))]; + // Remove $pow function to avoid errors in Synopsys DC + // assign coeffs[k] = lessfreecoeffs[int'($floor($sqrt($pow((TOTCOEFS-1)/2.0-k, 2))))]; + assign coeffs[k] = lessfreecoeffs[int'($floor( + $sqrt(((TOTCOEFS-1)/2.0-k)*((TOTCOEFS-1)/2.0-k)) + ))]; end endgenerate diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl index fb544a59..0d336255 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl @@ -19,12 +19,22 @@ } { name: "RESTORE_ADDRESS", - desc: "Restore xddress value", + desc: "Restore address value", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "31:0", name: "RESTORE_XDDRESS", desc: "Restore xddress Reg, used by BOOTROM" } + { bits: "31:0", name: "RESTORE_ADDRESS", desc: "Restore address Reg, used by BOOTROM" } + ] + } + + { name: "GLOBAL_POINTER", + desc: "Global Pointer value", + resval: "0x00000000" + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", name: "GLOBAL_POINTER", desc: "Global Reg, used by power manager HAL" } ] } @@ -214,64 +224,64 @@ } -% for bank in range(ram_numbanks): - { name: "RAM_${bank}_CLK_GATE", - desc: "Clock-gates the RAM_${bank} domain", +% for bank in xheep.iter_ram_banks(): + { name: "RAM_${bank.name()}_CLK_GATE", + desc: "Clock-gates the RAM_${bank.name()} domain", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "0", name: "RAM_${bank}_CLK_GATE", desc: "Clock-gates the RAM_${bank} domain" } + { bits: "0", name: "RAM_${bank.name()}_CLK_GATE", desc: "Clock-gates the RAM_${bank.name()} domain" } ] } - { name: "POWER_GATE_RAM_BLOCK_${bank}_ACK", - desc: "Used by the ram ${bank} switch to ack the power manager", + { name: "POWER_GATE_RAM_BLOCK_${bank.name()}_ACK", + desc: "Used by the ram ${bank.name()} switch to ack the power manager", resval: "0x00000000" swaccess: "ro", hwaccess: "hrw", fields: [ - { bits: "0", name: "POWER_GATE_RAM_BLOCK_${bank}_ACK", desc: "Power Gate Ram Block ${bank} Ack Reg" } + { bits: "0", name: "POWER_GATE_RAM_BLOCK_${bank.name()}_ACK", desc: "Power Gate Ram Block ${bank.name()} Ack Reg" } ] } - { name: "RAM_${bank}_SWITCH", - desc: "Switch off the RAM_${bank} domain", + { name: "RAM_${bank.name()}_SWITCH", + desc: "Switch off the RAM_${bank.name()} domain", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "0", name: "RAM_${bank}_SWITCH", desc: "Switch off RAM_${bank} domain" } + { bits: "0", name: "RAM_${bank.name()}_SWITCH", desc: "Switch off RAM_${bank.name()} domain" } ] } - { name: "RAM_${bank}_WAIT_ACK_SWITCH_ON", - desc: "Wait for the RAM_${bank} domain switch ack", + { name: "RAM_${bank.name()}_WAIT_ACK_SWITCH_ON", + desc: "Wait for the RAM_${bank.name()} domain switch ack", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "0", name: "RAM_${bank}_WAIT_ACK_SWITCH_ON", desc: "Wait RAM_${bank} domain switch ack" } + { bits: "0", name: "RAM_${bank.name()}_WAIT_ACK_SWITCH_ON", desc: "Wait RAM_${bank.name()} domain switch ack" } ] } - { name: "RAM_${bank}_ISO", - desc: "Set on the isolation of the RAM_${bank} domain", + { name: "RAM_${bank.name()}_ISO", + desc: "Set on the isolation of the RAM_${bank.name()} domain", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "0", name: "RAM_${bank}_ISO", desc: "Set on isolation of RAM_${bank} domain" } + { bits: "0", name: "RAM_${bank.name()}_ISO", desc: "Set on isolation of RAM_${bank.name()} domain" } ] } - { name: "RAM_${bank}_RETENTIVE", - desc: "Set on retentive mode for the RAM_${bank} domain", + { name: "RAM_${bank.name()}_RETENTIVE", + desc: "Set on retentive mode for the RAM_${bank.name()} domain", resval: "0x00000000" swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "0", name: "RAM_${bank}_RETENTIVE", desc: "Set on retentive mode for RAM_${bank} domain" } + { bits: "0", name: "RAM_${bank.name()}_RETENTIVE", desc: "Set on retentive mode for RAM_${bank.name()} domain" } ] } @@ -368,14 +378,14 @@ ] } -% for bank in range(ram_numbanks): - { name: "MONITOR_POWER_GATE_RAM_BLOCK_${bank}", - desc: "Used to monitor the signals to power gate ram block ${bank}", +% for bank in xheep.iter_ram_banks(): + { name: "MONITOR_POWER_GATE_RAM_BLOCK_${bank.name()}", + desc: "Used to monitor the signals to power gate ram block ${bank.name()}", resval: "0x00000000" swaccess: "ro", hwaccess: "hwo", fields: [ - { bits: "1:0", name: "MONITOR_POWER_GATE_RAM_BLOCK_${bank}", desc: "Monitor Signals Power Gate Ram Block ${bank} Reg" } + { bits: "1:0", name: "MONITOR_POWER_GATE_RAM_BLOCK_${bank.name()}", desc: "Monitor Signals Power Gate Ram Block ${bank.name()} Reg" } ] } diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl index 4b8ba22b..0e126670 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl @@ -4,7 +4,7 @@ `include "common_cells/assertions.svh" -module power_manager #( +module power_manager import power_manager_pkg::*; #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, parameter logic SWITCH_IDLE_VALUE = 1'b1, //the value to have Vdd.daughter = Vdd.mother, i.e. on state @@ -44,29 +44,18 @@ module power_manager #( // External interrupts input logic [NEXT_INT_RND-1:0] ext_irq_i, - // Clock gating signals - output logic peripheral_subsystem_clkgate_en_no, - output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0]memory_subsystem_clkgate_en_no, - output logic [EXT_DOMAINS_RND-1:0]external_subsystem_clkgate_en_no, - - // Power gating signals - output logic cpu_subsystem_powergate_switch_no, - input logic cpu_subsystem_powergate_switch_ack_ni, - output logic cpu_subsystem_powergate_iso_no, - output logic cpu_subsystem_rst_no, - output logic peripheral_subsystem_powergate_switch_no, - input logic peripheral_subsystem_powergate_switch_ack_ni, - output logic peripheral_subsystem_powergate_iso_no, - output logic peripheral_subsystem_rst_no, - output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_no, - input logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_ack_ni, - output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_iso_no, - output logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_set_retentive_no, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_switch_no, - input logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_switch_ack_ni, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_powergate_iso_no, - output logic [EXT_DOMAINS_RND-1:0] external_subsystem_rst_no, - output logic [EXT_DOMAINS_RND-1:0] external_ram_banks_set_retentive_no + // Power Manager output signals + output power_manager_out_t cpu_subsystem_pwr_ctrl_o, + output power_manager_out_t peripheral_subsystem_pwr_ctrl_o, + output power_manager_out_t memory_subsystem_pwr_ctrl_o[core_v_mini_mcu_pkg::NUM_BANKS-1:0], + output power_manager_out_t external_subsystem_pwr_ctrl_o[EXT_DOMAINS_RND-1:0], + + // Power Manager input signals + input power_manager_in_t cpu_subsystem_pwr_ctrl_i, + input power_manager_in_t peripheral_subsystem_pwr_ctrl_i, + input power_manager_in_t memory_subsystem_pwr_ctrl_i[core_v_mini_mcu_pkg::NUM_BANKS-1:0], + input power_manager_in_t external_subsystem_pwr_ctrl_i[EXT_DOMAINS_RND-1:0] + ); import power_manager_reg_pkg::*; @@ -123,37 +112,38 @@ module power_manager #( logic [core_v_mini_mcu_pkg::EXTERNAL_DOMAINS-1:0] external_subsystem_rst_n; % endif - assign cpu_subsystem_powergate_switch_no = cpu_subsystem_powergate_switch_n; - assign cpu_subsystem_powergate_iso_no = cpu_subsystem_powergate_iso_n; - assign cpu_subsystem_rst_no = cpu_subsystem_rst_n; - assign peripheral_subsystem_powergate_switch_no = peripheral_subsystem_powergate_switch_n; - assign peripheral_subsystem_powergate_iso_no = peripheral_subsystem_powergate_iso_n; - assign peripheral_subsystem_rst_no = peripheral_subsystem_rst_n; - assign memory_subsystem_banks_powergate_switch_no = memory_subsystem_banks_powergate_switch_n; - assign memory_subsystem_banks_powergate_iso_no = memory_subsystem_banks_powergate_iso_n; -% if external_domains != 0: - assign external_subsystem_powergate_switch_no = external_subsystem_powergate_switch_n; - assign external_subsystem_powergate_iso_no = external_subsystem_powergate_iso_n; - assign external_subsystem_rst_no = external_subsystem_rst_n; -% else: - assign external_subsystem_powergate_switch_no = '0; - assign external_subsystem_powergate_iso_no = '0; - assign external_subsystem_rst_no = '0; -% endif - - // -------------------------------------------------------------------------------------- - // CLK_GATING - // -------------------------------------------------------------------------------------- - - assign peripheral_subsystem_clkgate_en_no = ~reg2hw.periph_clk_gate.q; - -% for bank in range(ram_numbanks): - assign memory_subsystem_clkgate_en_no[${bank}] = ~reg2hw.ram_${bank}_clk_gate.q; + assign cpu_subsystem_pwr_ctrl_o.pwrgate_en_n = cpu_subsystem_powergate_switch_n; + assign cpu_subsystem_pwr_ctrl_o.isogate_en_n = cpu_subsystem_powergate_iso_n; + assign cpu_subsystem_pwr_ctrl_o.rst_n = cpu_subsystem_rst_n; + assign cpu_subsystem_pwr_ctrl_o.clkgate_en_n = 1'b1; //unused, the CPU clk gates itself via WFI + assign cpu_subsystem_pwr_ctrl_o.retentive_en_n = 1'b1; //unused + + assign peripheral_subsystem_pwr_ctrl_o.pwrgate_en_n = peripheral_subsystem_powergate_switch_n; + assign peripheral_subsystem_pwr_ctrl_o.isogate_en_n = peripheral_subsystem_powergate_iso_n; + assign peripheral_subsystem_pwr_ctrl_o.rst_n = peripheral_subsystem_rst_n; + assign peripheral_subsystem_pwr_ctrl_o.retentive_en_n = 1'b1; //unused + assign peripheral_subsystem_pwr_ctrl_o.clkgate_en_n = ~reg2hw.periph_clk_gate.q; + +% for bank in xheep.iter_ram_banks(): + assign memory_subsystem_pwr_ctrl_o[${bank.name()}].pwrgate_en_n = memory_subsystem_banks_powergate_switch_n[${bank.name()}]; + assign memory_subsystem_pwr_ctrl_o[${bank.name()}].isogate_en_n = memory_subsystem_banks_powergate_iso_n[${bank.name()}]; + assign memory_subsystem_pwr_ctrl_o[${bank.name()}].rst_n = 1'b1; + assign memory_subsystem_pwr_ctrl_o[${bank.name()}].clkgate_en_n = ~reg2hw.ram_${bank.name()}_clk_gate.q; % endfor +% if external_domains != 0: % for ext in range(external_domains): - assign external_subsystem_clkgate_en_no[${ext}] = ~reg2hw.external_${ext}_clk_gate.q; + assign external_subsystem_pwr_ctrl_o[${ext}].pwrgate_en_n = external_subsystem_powergate_switch_n[${ext}]; + assign external_subsystem_pwr_ctrl_o[${ext}].isogate_en_n = external_subsystem_powergate_iso_n[${ext}]; + assign external_subsystem_pwr_ctrl_o[${ext}].rst_n = external_subsystem_rst_n[${ext}]; + assign external_subsystem_pwr_ctrl_o[${ext}].clkgate_en_n = ~reg2hw.external_${ext}_clk_gate.q; % endfor +% else: + assign external_subsystem_pwr_ctrl_o[0].pwrgate_en_n = 1'b1; + assign external_subsystem_pwr_ctrl_o[0].isogate_en_n = 1'b1; + assign external_subsystem_pwr_ctrl_o[0].rst_n = 1'b1; + assign external_subsystem_pwr_ctrl_o[0].clkgate_en_n = 1'b1; +% endif // -------------------------------------------------------------------------------------- // CPU_SUBSYSTEM DOMAIN @@ -166,7 +156,7 @@ module power_manager #( ) sync_cpu_ack_i ( .clk_i, .rst_ni, - .serial_i(cpu_subsystem_powergate_switch_ack_ni), + .serial_i(cpu_subsystem_pwr_ctrl_i.pwrgate_ack_n), .serial_o(cpu_subsystem_powergate_switch_ack_sync) ); @@ -358,7 +348,7 @@ module power_manager #( ) sync_periph_ack_i ( .clk_i, .rst_ni, - .serial_i(peripheral_subsystem_powergate_switch_ack_ni), + .serial_i(peripheral_subsystem_pwr_ctrl_i.pwrgate_ack_n), .serial_o(peripheral_subsystem_powergate_switch_ack_sync) ); @@ -417,75 +407,75 @@ module power_manager #( .switch_onoff_signal_o(peripheral_subsystem_powergate_iso_n) ); -% for bank in range(ram_numbanks): +% for bank in xheep.iter_ram_banks(): // -------------------------------------------------------------------------------------- - // RAM_${bank} DOMAIN + // RAM_${bank.name()} DOMAIN // -------------------------------------------------------------------------------------- - logic ram_${bank}_subsystem_powergate_switch_ack_sync; + logic ram_${bank.name()}_subsystem_powergate_switch_ack_sync; sync #( .ResetValue(1'b0) - ) sync_ram_${bank}_ack_i ( + ) sync_ram_${bank.name()}_ack_i ( .clk_i, .rst_ni, - .serial_i(memory_subsystem_banks_powergate_switch_ack_ni[${bank}]), - .serial_o(ram_${bank}_subsystem_powergate_switch_ack_sync) + .serial_i(memory_subsystem_pwr_ctrl_i[${bank.name()}].pwrgate_ack_n), + .serial_o(ram_${bank.name()}_subsystem_powergate_switch_ack_sync) ); - assign hw2reg.power_gate_ram_block_${bank}_ack.de = 1'b1; - assign hw2reg.power_gate_ram_block_${bank}_ack.d = ram_${bank}_subsystem_powergate_switch_ack_sync; + assign hw2reg.power_gate_ram_block_${bank.name()}_ack.de = 1'b1; + assign hw2reg.power_gate_ram_block_${bank.name()}_ack.d = ram_${bank.name()}_subsystem_powergate_switch_ack_sync; //if you want to wait for ACK, or just bypass it - logic ram_${bank}_switch_wait_ack; - assign ram_${bank}_switch_wait_ack = reg2hw.ram_${bank}_wait_ack_switch_on.q ? reg2hw.power_gate_ram_block_${bank}_ack.q == SWITCH_IDLE_VALUE : 1'b1; + logic ram_${bank.name()}_switch_wait_ack; + assign ram_${bank.name()}_switch_wait_ack = reg2hw.ram_${bank.name()}_wait_ack_switch_on.q ? reg2hw.power_gate_ram_block_${bank.name()}_ack.q == SWITCH_IDLE_VALUE : 1'b1; power_manager_sequence #( .IDLE_VALUE(SWITCH_IDLE_VALUE), .ONOFF_AT_RESET(SWITCH_VALUE_AT_RESET) - ) power_manager_sequence_ram_${bank}_switch_i ( + ) power_manager_sequence_ram_${bank.name()}_switch_i ( .clk_i, .rst_ni, // trigger to start the sequence - .start_off_sequence_i(reg2hw.ram_${bank}_switch.q), - .start_on_sequence_i (~reg2hw.ram_${bank}_switch.q), + .start_off_sequence_i(reg2hw.ram_${bank.name()}_switch.q), + .start_on_sequence_i (~reg2hw.ram_${bank.name()}_switch.q), .switch_ack_i (1'b1), // switch on and off signal, 1 means on - .switch_onoff_signal_o(memory_subsystem_banks_powergate_switch_n[${bank}]) + .switch_onoff_signal_o(memory_subsystem_banks_powergate_switch_n[${bank.name()}]) ); power_manager_sequence #( .IDLE_VALUE(ISO_IDLE_VALUE), .ONOFF_AT_RESET(ISO_VALUE_AT_RESET) - ) power_manager_sequence_ram_${bank}_iso_i ( + ) power_manager_sequence_ram_${bank.name()}_iso_i ( .clk_i, .rst_ni, // trigger to start the sequence - .start_off_sequence_i(reg2hw.ram_${bank}_iso.q), - .start_on_sequence_i (~reg2hw.ram_${bank}_iso.q), - .switch_ack_i (ram_${bank}_switch_wait_ack), + .start_off_sequence_i(reg2hw.ram_${bank.name()}_iso.q), + .start_on_sequence_i (~reg2hw.ram_${bank.name()}_iso.q), + .switch_ack_i (ram_${bank.name()}_switch_wait_ack), // switch on and off signal, 1 means on - .switch_onoff_signal_o(memory_subsystem_banks_powergate_iso_n[${bank}]) + .switch_onoff_signal_o(memory_subsystem_banks_powergate_iso_n[${bank.name()}]) ); power_manager_sequence #( .IDLE_VALUE(ISO_IDLE_VALUE), .ONOFF_AT_RESET(ISO_VALUE_AT_RESET) - ) power_manager_sequence_ram_${bank}_retentive_i ( + ) power_manager_sequence_ram_${bank.name()}_retentive_i ( .clk_i, .rst_ni, // trigger to start the sequence - .start_off_sequence_i(reg2hw.ram_${bank}_retentive.q), - .start_on_sequence_i (~reg2hw.ram_${bank}_retentive.q), + .start_off_sequence_i(reg2hw.ram_${bank.name()}_retentive.q), + .start_on_sequence_i (~reg2hw.ram_${bank.name()}_retentive.q), .switch_ack_i (1'b1), // switch on and off signal, 1 means on - .switch_onoff_signal_o(memory_subsystem_banks_set_retentive_no[${bank}]) + .switch_onoff_signal_o(memory_subsystem_pwr_ctrl_o[${bank.name()}].retentive_en_n) ); % endfor @@ -501,7 +491,7 @@ module power_manager #( ) sync_external_${ext}_ack_i ( .clk_i, .rst_ni, - .serial_i(external_subsystem_powergate_switch_ack_ni[${ext}]), + .serial_i(external_subsystem_pwr_ctrl_i[${ext}].pwrgate_ack_n), .serial_o(external_${ext}_subsystem_powergate_switch_ack_sync) ); @@ -573,7 +563,7 @@ module power_manager #( .switch_ack_i (1'b1), // switch on and off signal, 1 means on - .switch_onoff_signal_o(external_ram_banks_set_retentive_no[${ext}]) + .switch_onoff_signal_o(external_subsystem_pwr_ctrl_o[${ext}].retentive_en_n) ); % endfor @@ -587,9 +577,9 @@ module power_manager #( assign hw2reg.monitor_power_gate_periph.de = 1'b1; assign hw2reg.monitor_power_gate_periph.d = {peripheral_subsystem_rst_n, peripheral_subsystem_powergate_iso_n, peripheral_subsystem_powergate_switch_n}; -% for bank in range(ram_numbanks): - assign hw2reg.monitor_power_gate_ram_block_${bank}.de = 1'b1; - assign hw2reg.monitor_power_gate_ram_block_${bank}.d = {memory_subsystem_banks_powergate_iso_n[${bank}], memory_subsystem_banks_powergate_switch_n[${bank}]}; +% for bank in xheep.iter_ram_banks(): + assign hw2reg.monitor_power_gate_ram_block_${bank.name()}.de = 1'b1; + assign hw2reg.monitor_power_gate_ram_block_${bank.name()}.d = {memory_subsystem_banks_powergate_iso_n[${bank.name()}], memory_subsystem_banks_powergate_switch_n[${bank.name()}]}; % endfor diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager.vlt index d0b73948..c9c6f472 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager.vlt @@ -12,6 +12,6 @@ lint_off -rule LITENDIAN -file "*/power_manager.sv" -match "*" lint_off -rule UNDRIVEN -file "*/power_manager.sv" -match "Signal is not driven: 'external_subsystem_powergate_switch*" lint_off -rule UNDRIVEN -file "*/power_manager.sv" -match "Signal is not driven: 'external_subsystem_powergate_iso*" lint_off -rule UNDRIVEN -file "*/power_manager.sv" -match "Signal is not driven: 'external_subsystem_rst_n*" -lint_off -rule UNUSED -file "*/power_manager.sv" -match "Signal is not used: 'external_subsystem_powergate_switch_ack*" +lint_off -rule UNUSED -file "*/power_manager.sv" -match "Signal is not used: 'external_subsystem_pwr_ctrl_i*" lint_off -rule WIDTH -file "*/power_manager.sv" -match "Operator ASSIGNW expects 16 bits on*" lint_off -rule DECLFILENAME -file "*/power_manager_reg_top.sv" -match "Filename 'power_manager_reg_top' does not match MODULE name: 'power_manager_reg_top_intf'" diff --git a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_inout.sv b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_inout.sv index 5dcc5449..3529b257 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_inout.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_inout.sv @@ -5,6 +5,7 @@ /* verilator lint_off UNUSED */ module pad_cell_inout #( parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP, //do not touch these parameters parameter PADATTR_RND = PADATTR == 0 ? 1 : PADATTR ) ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_input.sv b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_input.sv index cfd9c426..5a7b053a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_input.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_input.sv @@ -5,6 +5,7 @@ /* verilator lint_off UNUSED */ module pad_cell_input #( parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP, //do not touch these parameters parameter PADATTR_RND = PADATTR == 0 ? 1 : PADATTR ) ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_output.sv b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_output.sv index cc4960ea..794e177d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_output.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/simulation/pad_cell_output.sv @@ -5,6 +5,7 @@ /* verilator lint_off UNUSED */ module pad_cell_output #( parameter PADATTR = 16, + parameter core_v_mini_mcu_pkg::pad_side_e SIDE = core_v_mini_mcu_pkg::TOP, //do not touch these parameters parameter PADATTR_RND = PADATTR == 0 ? 1 : PADATTR ) ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/simulation/simulation.vlt b/hw/vendor/esl_epfl_x_heep/hw/simulation/simulation.vlt index 79d2edf4..0b30dd69 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/simulation/simulation.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/simulation/simulation.vlt @@ -5,3 +5,5 @@ `verilator_config lint_off -rule UNOPTFLAT -file "*/hw/simulation/pad_cell_*.sv" -match "Signal unoptimizable*" +lint_off -rule UNUSED -file "*/hw/simulation/sram_wrapper.sv" -match "Signal is not used: 'pwrgate_ni*" +lint_off -rule UNDRIVEN -file "*/hw/simulation/sram_wrapper.sv" -match "Signal is not driven: 'pwrgate_ack_no*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/simulation/sram_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/simulation/sram_wrapper.sv index 7be64dcf..0986b3e2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/simulation/sram_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/simulation/sram_wrapper.sv @@ -22,6 +22,9 @@ module sram_wrapper #( input logic [AddrWidth-1:0] addr_i, input logic [31:0] wdata_i, input logic [3:0] be_i, + // power manager signals that goes to the ASIC macros + input logic pwrgate_ni, + output logic pwrgate_ack_no, input logic set_retentive_ni, // output ports output logic [31:0] rdata_o diff --git a/hw/vendor/esl_epfl_x_heep/hw/system/pad_control/data/pad_control.hjson.tpl b/hw/vendor/esl_epfl_x_heep/hw/system/pad_control/data/pad_control.hjson.tpl index 605843dc..466fd7d4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/system/pad_control/data/pad_control.hjson.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/system/pad_control/data/pad_control.hjson.tpl @@ -26,7 +26,7 @@ % for pad in total_pad_list: { name: "PAD_ATTRIBUTE_${pad.name.upper()}", desc: "${pad.name} Attributes (Pull Up En, Pull Down En, etc. It is technology specific.", - resval: "0x00" + resval: "${pads_attributes['resval']}" swaccess: "rw", hwaccess: "hro", fields: [ diff --git a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl index c88bdaca..e77bd1b4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl @@ -48,8 +48,9 @@ module x_heep_system output logic [31:0] exit_value_o, - input logic ext_dma_slot_tx_i, - input logic ext_dma_slot_rx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, // eXtension interface if_xif.cpu_compressed xif_compressed_if, @@ -66,13 +67,22 @@ ${pad.x_heep_system_interface} import core_v_mini_mcu_pkg::*; + + localparam EXT_HARTS = 0; + + //do not touch these parameter + localparam EXT_HARTS_RND = EXT_HARTS == 0 ? 1 : EXT_HARTS; + + + logic [EXT_HARTS_RND-1:0] ext_debug_req; + logic ext_cpu_subsystem_rst_n; + logic ext_debug_reset_n; + // PM signals logic cpu_subsystem_powergate_switch_n; logic cpu_subsystem_powergate_switch_ack_n; logic peripheral_subsystem_powergate_switch_n; logic peripheral_subsystem_powergate_switch_ack_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_n; - logic [core_v_mini_mcu_pkg::NUM_BANKS-1:0] memory_subsystem_banks_powergate_switch_ack_n; // PAD controller reg_req_t pad_req; @@ -91,12 +101,18 @@ ${pad.x_heep_system_interface} ${pad.internal_signals} % endfor +`ifdef FPGA_SYNTHESIS + assign cpu_subsystem_powergate_switch_ack_n = cpu_subsystem_powergate_switch_n; + assign peripheral_subsystem_powergate_switch_ack_n = peripheral_subsystem_powergate_switch_n; +`endif + core_v_mini_mcu #( .COREV_PULP(COREV_PULP), .FPU(FPU), .ZFINX(ZFINX), .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER), - .X_EXT(X_EXT) + .X_EXT(X_EXT), + .EXT_HARTS(EXT_HARTS) ) core_v_mini_mcu_i ( .rst_ni(rst_ngen), @@ -126,18 +142,20 @@ ${pad.core_v_mini_mcu_bonding} .ext_dma_write_ch0_resp_i, .ext_dma_addr_ch0_req_o, .ext_dma_addr_ch0_resp_i, + .ext_dma_stop_i, .ext_peripheral_slave_req_o, .ext_peripheral_slave_resp_i, + .ext_debug_req_o(ext_debug_req), + .ext_debug_reset_no(ext_debug_reset_n), .cpu_subsystem_powergate_switch_no(cpu_subsystem_powergate_switch_n), .cpu_subsystem_powergate_switch_ack_ni(cpu_subsystem_powergate_switch_ack_n), .peripheral_subsystem_powergate_switch_no(peripheral_subsystem_powergate_switch_n), .peripheral_subsystem_powergate_switch_ack_ni(peripheral_subsystem_powergate_switch_ack_n), - .memory_subsystem_banks_powergate_switch_no(memory_subsystem_banks_powergate_switch_n), - .memory_subsystem_banks_powergate_switch_ack_ni(memory_subsystem_banks_powergate_switch_ack_n), .external_subsystem_powergate_switch_no, .external_subsystem_powergate_switch_ack_ni, .external_subsystem_powergate_iso_no, .external_subsystem_rst_no, + .ext_cpu_subsystem_rst_no(ext_cpu_subsystem_rst_n), .external_ram_banks_set_retentive_no, .external_subsystem_clkgate_en_no, .exit_value_o, diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson index 7248758f..2871b8ed 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/cv32e40px.git - rev: 49770e7dd5d569f440810866f4f33ce6a4f7ef1f + rev: 15b9dd6077513342cf44e6853a5fc33098f2e73b } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson index 547959fe..d0e289ae 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/esl-epfl/cv32e40px.git", - rev: "49770e7dd5d569f440810866f4f33ce6a4f7ef1f", + rev: "15b9dd6077513342cf44e6853a5fc33098f2e73b", }, exclude_from_upstream: [ diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/.gitignore b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/.gitignore index ef351b19..6c2cd791 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/.gitignore +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/.gitignore @@ -18,3 +18,11 @@ TAGS /build /Bender.lock /Bender.local +golden_reference_design +ref_design +golden.src +revised.src +cadence_conformal +synopsys_formality +questa_autocheck +reports diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh index a89ed4e4..355bc738 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_instr_trace.svh @@ -1,23 +1,37 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. // -// Licensed under the Solderpad Hardware Licence, 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 +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"). // -// https://solderpad.org/licenses/ +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// +// You may obtain a copy of the License at: +// +// https://solderpad.org/licenses/SHL-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. +// and hardware implementations thereof distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// // See the License for the specific language governing permissions and // limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Tracer data structures and functions -// -// Contributors: Steve Richmond, Silicon Labs -// Pascal Gouedo, Dolphin Design +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Steve Richmond - steve.richmond@silabs.com // +// // +// Design Name: cv32e40p_tracer data structures // +// Project Name: CV32E40P // +// Language: SystemVerilog // +// // +// Description: Moves the class definition for instr_trace_t out of the // +// tracer module for readability and code partitioning // +// // +// Includes various enhancements to make the instr_trace_t // +// class more comprehensive // +// // +//////////////////////////////////////////////////////////////////////////////// typedef struct { logic [5:0] addr; @@ -35,9 +49,13 @@ typedef struct { class instr_trace_t; time simtime; + time stoptime; + bit external_time; int cycles; + int stopcycles; logic [31:0] pc; logic [31:0] instr; + string ctx; //Used to add context in the trace log file (Canceled, debug, interrput,....) bit compressed; bit wb_bypass; bit misaligned; @@ -56,10 +74,15 @@ class instr_trace_t; regs_read = {}; regs_write = {}; mem_access = {}; + external_time = 0; + stoptime = 0; + stopcycles = 0; endfunction function void init(int unsigned cycles, bit [31:0] pc, bit compressed, bit [31:0] instr); - this.simtime = $time; + if(!this.external_time) begin + this.simtime = $time; + end this.cycles = cycles; this.pc = pc; this.compressed = compressed; @@ -308,7 +331,23 @@ class instr_trace_t; begin string insn_str; // Accumulate writes into a single string to enable single $fwrite - insn_str = $sformatf("%t %15d %h %h %-36s", simtime, cycles, pc, instr, str); + if(simtime < 100ns) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else begin + insn_str = $sformatf("%t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end foreach (regs_write[i]) begin if (regs_write[i].addr != 0) @@ -330,6 +369,12 @@ class instr_trace_t; insn_str = $sformatf("%s PA:%08x", insn_str, mem_acc.addr); end + casex (instr) + INSTR_FDIV: insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + INSTR_FSQRT:insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + default: ; + endcase + $fwrite(f, "%s\n", insn_str); end endfunction @@ -489,7 +534,7 @@ class instr_trace_t; begin mnemonic = {compressed ? "c." : "", mnemonic}; regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %s, %0d", mnemonic, regAddrToStr(rs1), $signed(imm_sb_type)); + str = $sformatf("%-16s %s, %0d, %0d", mnemonic, regAddrToStr(rs1), $signed(imm_s2_type), $signed(imm_sb_type)); end endfunction // printSBInstr @@ -587,14 +632,14 @@ class instr_trace_t; // immediate post-incremented load regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %0d(x%0d!)", mnemonic, regAddrToStr(rd), $signed(imm_i_type), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %0d", mnemonic, regAddrToStr(rd), rs1, $signed(imm_i_type)); end else if (instr[6:0] == OPCODE_CUSTOM_1) begin if (instr[27] == 1'b0) begin // reg-reg post-incremented load regs_read.push_back('{rs2, rs2_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %s(x%0d!)", mnemonic, regAddrToStr(rd), regAddrToStr(rs2), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rd), rs1, regAddrToStr(rs2)); end else begin // reg-reg indexed load regs_read.push_back('{rs2, rs2_value, 0}); @@ -637,7 +682,7 @@ class instr_trace_t; regs_read.push_back('{rs2, rs2_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-14s %s, %0d(x%0d!)", mnemonic, regAddrToStr(rs2), $signed(imm_s_type), rs1); + str = $sformatf("cv.%-14s %s, (x%0d), %0d", mnemonic, regAddrToStr(rs2), rs1, $signed(imm_s_type)); end else if (instr[31:28] == 4'b0010) begin if (instr[27] == 1'b0) begin // reg-reg post-incremented store @@ -645,7 +690,7 @@ class instr_trace_t; regs_read.push_back('{rs3, rs3_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %s(x%0d!)", mnemonic, regAddrToStr(rs2), regAddrToStr(rs3), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rs2), rs1, regAddrToStr(rs3)); end else begin // reg-reg indexed store regs_read.push_back('{rs2, rs2_value, 0}); @@ -757,238 +802,429 @@ class instr_trace_t; else str_hb = ".h"; // set mnemonic - case (instr[31:26]) - 6'b000000: begin + case (instr) + INSTR_CVADDH , + INSTR_CVADDSCH , + INSTR_CVADDSCIH, + INSTR_CVADDB , + INSTR_CVADDSCB , + INSTR_CVADDSCIB : begin mnemonic = "cv.add"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000010: begin + INSTR_CVSUBH , + INSTR_CVSUBSCH , + INSTR_CVSUBSCIH, + INSTR_CVSUBB , + INSTR_CVSUBSCB , + INSTR_CVSUBSCIB : begin mnemonic = "cv.sub"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000100: begin + INSTR_CVAVGH , + INSTR_CVAVGSCH , + INSTR_CVAVGSCIH , + INSTR_CVAVGB , + INSTR_CVAVGSCB , + INSTR_CVAVGSCIB : begin mnemonic = "cv.avg"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000110: begin + INSTR_CVAVGUH , + INSTR_CVAVGUSCH , + INSTR_CVAVGUSCIH, + INSTR_CVAVGUB , + INSTR_CVAVGUSCB , + INSTR_CVAVGUSCIB : begin mnemonic = "cv.avgu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001000: begin + INSTR_CVMINH , + INSTR_CVMINSCH , + INSTR_CVMINSCIH, + INSTR_CVMINB , + INSTR_CVMINSCB , + INSTR_CVMINSCIB : begin mnemonic = "cv.min"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001010: begin + INSTR_CVMINUH , + INSTR_CVMINUSCH , + INSTR_CVMINUSCIH, + INSTR_CVMINUB , + INSTR_CVMINUSCB , + INSTR_CVMINUSCIB : begin mnemonic = "cv.minu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001100: begin + INSTR_CVMAXH , + INSTR_CVMAXSCH , + INSTR_CVMAXSCIH , + INSTR_CVMAXB , + INSTR_CVMAXSCB , + INSTR_CVMAXSCIB : begin mnemonic = "cv.max"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001110: begin + INSTR_CVMAXUH , + INSTR_CVMAXUSCH , + INSTR_CVMAXUSCIH , + INSTR_CVMAXUB , + INSTR_CVMAXUSCB , + INSTR_CVMAXUSCIB : begin mnemonic = "cv.maxu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010000: begin + INSTR_CVSRLH , + INSTR_CVSRLSCH , + INSTR_CVSRLSCIH , + INSTR_CVSRLB , + INSTR_CVSRLSCB , + INSTR_CVSRLSCIB : begin mnemonic = "cv.srl"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010010: begin + INSTR_CVSRAH , + INSTR_CVSRASCH , + INSTR_CVSRASCIH, + INSTR_CVSRAB , + INSTR_CVSRASCB , + INSTR_CVSRASCIB : begin mnemonic = "cv.sra"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010100: begin + INSTR_CVSLLH , + INSTR_CVSLLSCH , + INSTR_CVSLLSCIH, + INSTR_CVSLLB , + INSTR_CVSLLSCB , + INSTR_CVSLLSCIB : begin mnemonic = "cv.sll"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010110: begin + INSTR_CVORH , + INSTR_CVORSCH , + INSTR_CVORSCIH, + INSTR_CVORB , + INSTR_CVORSCB , + INSTR_CVORSCIB : begin mnemonic = "cv.or"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011000: begin + INSTR_CVXORH , + INSTR_CVXORSCH , + INSTR_CVXORSCIH , + INSTR_CVXORB , + INSTR_CVXORSCB , + INSTR_CVXORSCIB : begin mnemonic = "cv.xor"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011010: begin + INSTR_CVANDH , + INSTR_CVANDSCH , + INSTR_CVANDSCIH , + INSTR_CVANDB , + INSTR_CVANDSCB , + INSTR_CVANDSCIB : begin mnemonic = "cv.and"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011100: begin + INSTR_CVABSH, + INSTR_CVABSB : begin mnemonic = "cv.abs"; str_imm = $sformatf("0x%0h", imm_vs_type); end // dot products - 6'b100000: begin + INSTR_CVDOTUPH , + INSTR_CVDOTUPSCH , + INSTR_CVDOTUPSCIH, + INSTR_CVDOTUPB , + INSTR_CVDOTUPSCB , + INSTR_CVDOTUPSCIB : begin mnemonic = "cv.dotup"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b100010: begin + INSTR_CVDOTUSPH , + INSTR_CVDOTUSPSCH , + INSTR_CVDOTUSPSCIH, + INSTR_CVDOTUSPB , + INSTR_CVDOTUSPSCB , + INSTR_CVDOTUSPSCIB : begin mnemonic = "cv.dotusp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b100100: begin + INSTR_CVDOTSPH , + INSTR_CVDOTSPSCH , + INSTR_CVDOTSPSCIH, + INSTR_CVDOTSPB , + INSTR_CVDOTSPSCB , + INSTR_CVDOTSPSCIB : begin mnemonic = "cv.dotsp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b100110: begin + INSTR_CVSDOTUPH , + INSTR_CVSDOTUPSCH , + INSTR_CVSDOTUPSCIH, + INSTR_CVSDOTUPB , + INSTR_CVSDOTUPSCB , + INSTR_CVSDOTUPSCIB : begin mnemonic = "cv.sdotup"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b101000: begin + INSTR_CVSDOTUSPH , + INSTR_CVSDOTUSPSCH , + INSTR_CVSDOTUSPSCIH, + INSTR_CVSDOTUSPB , + INSTR_CVSDOTUSPSCB , + INSTR_CVSDOTUSPSCIB : begin mnemonic = "cv.sdotusp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b101010: begin + INSTR_CVSDOTSPH , + INSTR_CVSDOTSPSCH , + INSTR_CVSDOTSPSCIH, + INSTR_CVSDOTSPB , + INSTR_CVSDOTSPSCB , + INSTR_CVSDOTSPSCIB : begin mnemonic = "cv.sdotsp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b101110: begin - case (instr[14:13]) - 2'b00 : begin - mnemonic = "cv.extract"; - str_imm = $sformatf("0x%0h", imm_vs_type); - end - 2'b01 : begin - mnemonic = "cv.extractu"; - str_imm = $sformatf("0x%0h", imm_vu_type); - end - 2'b10 : begin - mnemonic = "cv.insert"; - str_imm = $sformatf("0x%0h", imm_vs_type); - end - endcase - str_sci = ""; + INSTR_CVEXTRACTH, + INSTR_CVEXTRACTB : begin + mnemonic = "cv.extract"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; + end + INSTR_CVEXTRACTUH, + INSTR_CVEXTRACTUB : begin + mnemonic = "cv.extractu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + str_sci = ""; + end + INSTR_CVINSERTH, + INSTR_CVINSERTB : begin + mnemonic = "cv.insert"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; end // shuffle/pack - 6'b110000: begin - if (instr[14:12] == 3'b111) begin - mnemonic = "cv.shuffleI0"; - str_imm = $sformatf("0x%8h", imm_shuffle_type); - end else begin + INSTR_CVSHUFFLEH , + INSTR_CVSHUFFLESCIH, + INSTR_CVSHUFFLEB : begin mnemonic = "cv.shuffle"; if (instr[14:12] == 3'b110) begin str_imm = $sformatf("0x%8h", imm_shuffle_type); end - end end - 6'b110010: begin + + INSTR_CVSHUFFLEL0SCIB : begin + mnemonic = "cv.shuffleI0"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLEL1SCIB : begin mnemonic = "cv.shuffleI1"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b110100: begin + INSTR_CVSHUFFLEL2SCIB : begin mnemonic = "cv.shuffleI2"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b110110: begin + INSTR_CVSHUFFLEL3SCIB : begin mnemonic = "cv.shuffleI3"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b111000: begin + INSTR_CVSHUFFLE2H, + INSTR_CVSHUFFLE2B : begin mnemonic = "cv.shuffle2"; end - 6'b111100: begin + INSTR_CVPACK, + INSTR_CVPACKH : begin mnemonic = "cv.pack"; if (instr[25] == 1'b0) begin str_hb = ""; end end - 6'b111110: begin - mnemonic = instr[25] ? "cv.packhi" : "cv.packlo"; - end + INSTR_CVPACKHIB : mnemonic = "cv.packhi"; + INSTR_CVPACKLOB : mnemonic = "cv.packlo"; // comparisons - 6'b000001: begin + INSTR_CVCMPEQH , + INSTR_CVCMPEQSCH , + INSTR_CVCMPEQSCIH, + INSTR_CVCMPEQB , + INSTR_CVCMPEQSCB , + INSTR_CVCMPEQSCIB : begin mnemonic = "cv.cmpeq"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000011: begin + INSTR_CVCMPNEH , + INSTR_CVCMPNESCH , + INSTR_CVCMPNESCIH, + INSTR_CVCMPNEB , + INSTR_CVCMPNESCB , + INSTR_CVCMPNESCIB : begin mnemonic = "cv.cmpne"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000101: begin + INSTR_CVCMPGTH , + INSTR_CVCMPGTSCH , + INSTR_CVCMPGTSCIH, + INSTR_CVCMPGTB , + INSTR_CVCMPGTSCB , + INSTR_CVCMPGTSCIB : begin mnemonic = "cv.cmpgt"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000111: begin + INSTR_CVCMPGEH , + INSTR_CVCMPGESCH , + INSTR_CVCMPGESCIH, + INSTR_CVCMPGEB , + INSTR_CVCMPGESCB , + INSTR_CVCMPGESCIB : begin mnemonic = "cv.cmpge"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001001: begin + INSTR_CVCMPLTH , + INSTR_CVCMPLTSCH , + INSTR_CVCMPLTSCIH, + INSTR_CVCMPLTB , + INSTR_CVCMPLTSCB , + INSTR_CVCMPLTSCIB : begin mnemonic = "cv.cmplt"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001011: begin + INSTR_CVCMPLEH , + INSTR_CVCMPLESCH , + INSTR_CVCMPLESCIH, + INSTR_CVCMPLEB , + INSTR_CVCMPLESCB , + INSTR_CVCMPLESCIB : begin mnemonic = "cv.cmple"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001101: begin + INSTR_CVCMPGTUH , + INSTR_CVCMPGTUSCH , + INSTR_CVCMPGTUSCIH, + INSTR_CVCMPGTUB , + INSTR_CVCMPGTUSCB , + INSTR_CVCMPGTUSCIB : begin mnemonic = "cv.cmpgtu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001111: begin + INSTR_CVCMPGEUH , + INSTR_CVCMPGEUSCH , + INSTR_CVCMPGEUSCIH, + INSTR_CVCMPGEUB , + INSTR_CVCMPGEUSCB , + INSTR_CVCMPGEUSCIB : begin mnemonic = "cv.cmpgeu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010001: begin + INSTR_CVCMPLTUH , + INSTR_CVCMPLTUSCH , + INSTR_CVCMPLTUSCIH, + INSTR_CVCMPLTUB , + INSTR_CVCMPLTUSCB , + INSTR_CVCMPLTUSCIB : begin mnemonic = "cv.cmpltu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010011: begin + INSTR_CVCMPLEUH , + INSTR_CVCMPLEUSCH , + INSTR_CVCMPLEUSCIH, + INSTR_CVCMPLEUB , + INSTR_CVCMPLEUSCB , + INSTR_CVCMPLEUSCIB : begin mnemonic = "cv.cmpleu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010101: begin - unique case (instr[14:13]) - 2'b00: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r" : "cv.cplxmul.i"; - 2'b01: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div2" : "cv.cplxmul.i.div2"; - 2'b10: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div4" : "cv.cplxmul.i.div4"; - 2'b11: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div8" : "cv.cplxmul.i.div8"; - endcase + INSTR_CVCPLXMULR, + INSTR_CVCPLXMULI : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r" : "cv.cplxmul.i"; str_sci = ""; str_hb = ""; end - - 6'b010111: begin - mnemonic = "cv.cplxconj"; - str_sci = ""; + INSTR_CVCPLXMULRDIV2, + INSTR_CVCPLXMULIDIV2 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div2" : "cv.cplxmul.i.div2"; + str_sci = ""; str_hb = ""; end - - 6'b011001: begin - unique case (instr[14:13]) - 2'b00: mnemonic = "cv.subrotmj"; - 2'b01: mnemonic = "cv.subrotmj.div2"; - 2'b10: mnemonic = "cv.subrotmj.div4"; - 2'b11: mnemonic = "cv.subrotmj.div8"; - endcase + INSTR_CVCPLXMULRDIV4, + INSTR_CVCPLXMULIDIV4 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div4" : "cv.cplxmul.i.div4"; str_sci = ""; str_hb = ""; end - - 6'b011011: begin - unique case (instr[14:13]) - 2'b01: mnemonic = "cv.add.div2"; - 2'b10: mnemonic = "cv.add.div4"; - 2'b11: mnemonic = "cv.add.div8"; - endcase + INSTR_CVCPLXMULRDIV8, + INSTR_CVCPLXMULIDIV8 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div8" : "cv.cplxmul.i.div8"; str_sci = ""; str_hb = ""; end - 6'b011101: begin - unique case (instr[14:13]) - 2'b01: mnemonic = "cv.sub.div2"; - 2'b10: mnemonic = "cv.sub.div4"; - 2'b11: mnemonic = "cv.sub.div8"; - endcase - str_sci = ""; + INSTR_CVCPLXCONJ : begin + mnemonic = "cv.cplxconj"; + str_sci = ""; str_hb = ""; end + INSTR_CVSUBROTMJ : begin + mnemonic = "cv.subrotmj"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV2 : begin + mnemonic = "cv.subrotmj.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV4 : begin + mnemonic = "cv.subrotmj.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV8 : begin + mnemonic = "cv.subrotmj.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVADDIV2 : begin + mnemonic = "cv.add.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV4 : begin + mnemonic = "cv.add.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV8 : begin + mnemonic = "cv.add.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVSUBIV2 : begin + mnemonic = "cv.sub.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV4 : begin + mnemonic = "cv.sub.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV8 : begin + mnemonic = "cv.sub.div8"; + str_sci = ""; + str_hb = ""; + end + default: begin printMnemonic("INVALID"); return; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv index 4effb2b8..3675a950 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi.sv @@ -1,24 +1,28 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P RVFI interface -// -// Contributors: Davide Schiavone, OpenHW Group -// Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: CV32E40P RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// `include "cv32e40px_rvfi_pkg.sv" @@ -27,7 +31,8 @@ module cv32e40px_rvfi import cv32e40px_rvfi_pkg::*; #( parameter FPU = 0, - parameter ZFINX = 0 + parameter ZFINX = 0, + parameter NUM_MHPMCOUNTERS = 1 ) ( input logic clk_i, input logic rst_ni, @@ -290,7 +295,7 @@ module cv32e40px_rvfi // performance counters // cycle, instret, hpcounter, cycleh, instreth, hpcounterh // mcycle, minstret, mhpcounter, mcycleh, minstreth, mhpcounterh - input logic [31:0][MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_q_i, + input logic [63:0][MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_q_i, input logic [31:0] csr_mhpmcounter_write_lower_i, input logic [31:0] csr_mhpmcounter_write_upper_i, @@ -327,6 +332,10 @@ module cv32e40px_rvfi // the convention of RISC-V Formal Interface Specification. output logic [ 0:0] rvfi_valid, output logic [63:0] rvfi_order, + output integer rvfi_start_cycle, + output time rvfi_start_time, + output integer rvfi_stop_cycle, + output time rvfi_stop_time, output logic [31:0] rvfi_insn, output rvfi_trap_t rvfi_trap, output logic [ 0:0] rvfi_halt, @@ -346,6 +355,7 @@ module cv32e40px_rvfi output logic rvfi_frd_wvalid [1:0], output logic [ 4:0] rvfi_frd_addr [1:0], output logic [31:0] rvfi_frd_wdata [1:0], + output logic rvfi_2_rd, output logic [ 4:0] rvfi_rs1_addr, output logic [ 4:0] rvfi_rs2_addr, output logic [ 4:0] rvfi_rs3_addr, @@ -366,8 +376,8 @@ module cv32e40px_rvfi output logic [31:0] rvfi_pc_wdata, output logic [31:0] rvfi_mem_addr, - output logic [ 3:0] rvfi_mem_rmask, - output logic [ 3:0] rvfi_mem_wmask, + output logic [31:0] rvfi_mem_rmask, + output logic [31:0] rvfi_mem_wmask, output logic [31:0] rvfi_mem_rdata, output logic [31:0] rvfi_mem_wdata, @@ -618,6 +628,13 @@ module cv32e40px_rvfi bit clk_i_d; assign #0.01 clk_i_d = clk_i; + integer cycles; + // cycle counter + always_ff @(posedge clk_i_d, negedge rst_ni) begin + if (rst_ni == 1'b0) cycles <= 0; + else cycles <= cycles + 1; + end + logic pc_mux_debug; logic pc_mux_dret; logic pc_mux_exception; @@ -626,6 +643,9 @@ module cv32e40px_rvfi logic pc_mux_nmi; localparam logic [31:0] MSTATUS_WRITE_MASK = 32'h0000_6088; + localparam logic [31:0] MCOUNTINHIBIT_WRITE_MASK = {{(29-NUM_MHPMCOUNTERS){1'b0}}, {(NUM_MHPMCOUNTERS){1'b1}}, 3'b101}; + localparam NUM_HPM_EVENTS = 16; + localparam logic [31:0] MHPMEVENT_WRITE_MASK = {{(31-NUM_HPM_EVENTS){1'b0}}, {(NUM_HPM_EVENTS){1'b1}}}; `include "pipe_freeze_trace.sv" @@ -747,6 +767,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end rvfi_order = new_rvfi_trace.m_order; + rvfi_start_cycle = new_rvfi_trace.m_start_cycle; + rvfi_start_time = new_rvfi_trace.m_start_time; + rvfi_stop_cycle = new_rvfi_trace.m_stop_cycle; + rvfi_stop_time = new_rvfi_trace.m_stop_time; rvfi_pc_rdata = new_rvfi_trace.m_pc_rdata; rvfi_insn = new_rvfi_trace.m_insn; @@ -801,6 +825,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; rvfi_frd_addr[1] = '0; rvfi_frd_wdata[1] = '0; + rvfi_2_rd = new_rvfi_trace.m_2_rd_insn; if (new_rvfi_trace.m_rd_addr[0][5] == 1'b0) begin rvfi_rd_addr[0] = new_rvfi_trace.m_rd_addr[0][4:0]; rvfi_rd_wdata[0] = new_rvfi_trace.m_rd_wdata[0]; @@ -905,15 +930,50 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `SET_RVFI_CSR_FROM_INSN(misa) `SET_RVFI_CSR_FROM_INSN(mie) `SET_RVFI_CSR_FROM_INSN(mtvec) - `SET_RVFI_CSR_FROM_INSN(mcountinhibit) + + rvfi_csr_mcountinhibit_rdata = new_rvfi_trace.m_csr.mcountinhibit_rdata; + rvfi_csr_mcountinhibit_rmask = new_rvfi_trace.m_csr.mcountinhibit_rmask; + rvfi_csr_mcountinhibit_wdata = new_rvfi_trace.m_csr.mcountinhibit_wdata; + rvfi_csr_mcountinhibit_wmask = new_rvfi_trace.m_csr.mcountinhibit_wmask & MCOUNTINHIBIT_WRITE_MASK; + `SET_RVFI_CSR_FROM_INSN(mscratch) `SET_RVFI_CSR_FROM_INSN(mepc) `SET_RVFI_CSR_FROM_INSN(mcause) + `SET_RVFI_CSR_FROM_INSN(mcycle) `SET_RVFI_CSR_FROM_INSN(minstret) + `SET_RVFI_CSR_FROM_INSN(minstreth) + + // `SET_RVFI_CSR_FROM_INSN(cycle) + // `SET_RVFI_CSR_FROM_INSN(instret) + rvfi_csr_instret_rdata = new_rvfi_trace.m_csr.minstret_rdata; + rvfi_csr_instret_rmask = new_rvfi_trace.m_csr.minstret_rmask; + rvfi_csr_instret_wdata = new_rvfi_trace.m_csr.minstret_wdata; + rvfi_csr_instret_wmask = new_rvfi_trace.m_csr.minstret_wmask; + + for(int idx=3; idx<32; idx++) begin + rvfi_csr_mhpmcounter_rmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_rmask[idx][31:0]; + rvfi_csr_mhpmcounter_wmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_wmask[idx][31:0]; + rvfi_csr_mhpmcounter_rdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_rdata[idx][31:0]; + rvfi_csr_mhpmcounter_wdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_wdata[idx][31:0]; + + rvfi_csr_mhpmcounterh_rmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_rmask[idx][63:32]; + rvfi_csr_mhpmcounterh_wmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_wmask[idx][63:32]; + rvfi_csr_mhpmcounterh_rdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_rdata[idx][63:32]; + rvfi_csr_mhpmcounterh_wdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_wdata[idx][63:32]; + + rvfi_csr_mhpmevent_rmask[idx] = new_rvfi_trace.m_csr.mhpmevent_rmask[idx]; + rvfi_csr_mhpmevent_wmask[idx] = new_rvfi_trace.m_csr.mhpmevent_wmask[idx] & MHPMEVENT_WRITE_MASK; + rvfi_csr_mhpmevent_rdata[idx] = new_rvfi_trace.m_csr.mhpmevent_rdata[idx]; + rvfi_csr_mhpmevent_wdata[idx] = new_rvfi_trace.m_csr.mhpmevent_wdata[idx]; + end + // `SET_RVFI_CSR_FROM_INSN(instreth) + rvfi_csr_instreth_rdata = new_rvfi_trace.m_csr.minstreth_rdata; + rvfi_csr_instreth_rmask = new_rvfi_trace.m_csr.minstreth_rmask; + rvfi_csr_instreth_wdata = new_rvfi_trace.m_csr.minstreth_wdata; + rvfi_csr_instreth_wmask = new_rvfi_trace.m_csr.minstreth_wmask; + `SET_RVFI_CSR_FROM_INSN(mip) - // if(rvfi_order == 64'h00000000_00000167) begin - // rvfi_csr_mip_rdata = 32'h0010_0000; - // end + rvfi_csr_tdata_rdata[0] = 'Z; rvfi_csr_tdata_rmask[0] = '0; // Does not exist rvfi_csr_tdata_wdata[0] = 'Z; // Does not exist @@ -959,36 +1019,134 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; endfunction // set_rvfi - function void minstret_to_id(); - trace_id.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; - trace_id.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2]; - trace_id.m_csr.minstret_rmask = '1; - trace_id.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q; - trace_id.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + function void sample_perf_counter_to_id(int idx); + trace_id.m_csr.mhpmcounter_rdata[idx][31:0] = r_pipe_freeze_trace.csr.mhpmcounter_q[idx][31:0]; + trace_id.m_csr.mhpmcounter_rmask[idx][31:0] = '1; endfunction - function void minstret_to_ex(); - trace_ex.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; - trace_ex.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2]; - trace_ex.m_csr.minstret_rmask = '1; - trace_ex.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q; - trace_ex.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + function void perf_counter_to_id(int idx); + if(!trace_id.m_csr.mhpmcounter_we[idx][0]) begin + trace_id.m_csr.mhpmcounter_wdata[idx][31:0] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + trace_id.m_csr.mhpmcounter_we[idx][0] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]; + trace_id.m_csr.mhpmcounter_wdata[idx][31:0] = r_pipe_freeze_trace.csr.wdata_int; + trace_id.m_csr.mhpmcounter_wmask[idx][31:0] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx] ? '1 : '0; + end + sample_perf_counter_to_id(idx); endfunction - function void tinfo_to_id(); - trace_id.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; - trace_id.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; - trace_id.m_csr.tinfo_rmask = '1; - trace_id.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; - trace_id.m_csr.tinfo_wmask = '0; + function void sample_perf_event_to_trace(int idx, insn_trace_t m_trace); + m_trace.m_csr.mhpmevent_rdata[idx] = r_pipe_freeze_trace.csr.mhpmevent_q[idx]; + m_trace.m_csr.mhpmevent_rmask[idx] = '1; endfunction - function void tinfo_to_ex(); - trace_ex.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; - trace_ex.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; - trace_ex.m_csr.tinfo_rmask = '1; - trace_ex.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; - trace_ex.m_csr.tinfo_wmask = '0; + function void perf_event_to_trace(int idx, insn_trace_t m_trace); + if(!m_trace.m_csr.mhpmevent_we[idx]) begin + m_trace.m_csr.mhpmevent_wdata[idx] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmevent_we[idx]) begin + m_trace.m_csr.mhpmevent_we[idx] = r_pipe_freeze_trace.csr.mhpmevent_we[idx]; + m_trace.m_csr.mhpmevent_wdata[idx] = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.mhpmevent_wmask[idx] = r_pipe_freeze_trace.csr.mhpmevent_we[idx] ? '1 : '0; + end + sample_perf_event_to_trace(idx, m_trace); + endfunction + + function void sample_minstret_to_trace(insn_trace_t m_trace); + m_trace.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2][31:0]; + m_trace.m_csr.minstret_rmask = '1; + endfunction + + function void minstret_to_trace(insn_trace_t m_trace); + if(!m_trace.m_csr.minstret_we) begin + m_trace.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]) begin + m_trace.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; + m_trace.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + end + sample_minstret_to_trace(m_trace); + endfunction + + function void sample_perf_counter_h_to_id(int idx); + trace_id.m_csr.mhpmcounter_rdata[idx][63:32] = r_pipe_freeze_trace.csr.mhpmcounter_q[idx][63:0]; + trace_id.m_csr.mhpmcounter_rmask[idx][63:32] = '1; + endfunction + + function void perf_counter_h_to_id(int idx); + if(!trace_id.m_csr.mhpmcounter_we[idx][1]) begin + trace_id.m_csr.mhpmcounter_wdata[idx][63:32] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + trace_id.m_csr.mhpmcounter_we[idx][1] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]; + trace_id.m_csr.mhpmcounter_wdata[idx][63:32] = r_pipe_freeze_trace.csr.wdata_int; + trace_id.m_csr.mhpmcounter_wmask[idx][63:32] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx] ? '1 : '0; + end + sample_perf_counter_h_to_id(idx); + endfunction + + function void sample_minstreth_to_trace(insn_trace_t m_trace); + m_trace.m_csr.minstreth_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2][63:32]; + m_trace.m_csr.minstreth_rmask = '1; + endfunction + + function void sample_mcycle_to_trace(insn_trace_t m_trace); + m_trace.m_csr.mcycle_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[0]; + m_trace.m_csr.mcycle_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[0][31:0]; + m_trace.m_csr.mcycle_rmask = '1; + m_trace.m_csr.mcycle_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q[31:0]; + m_trace.m_csr.mcycle_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[0] ? '1 : '0; + endfunction + + function void minstreth_to_trace(insn_trace_t m_trace); + if(!m_trace.m_csr.minstreth_we) begin + m_trace.m_csr.minstreth_wdata = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]) begin + m_trace.m_csr.minstreth_we = r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]; + m_trace.m_csr.minstreth_wdata = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.minstreth_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2] ? '1 : '0; + end + sample_minstreth_to_trace(m_trace); + endfunction + + function void sample_perf_counter_to_trace(insn_trace_t m_trace); + sample_minstret_to_trace(m_trace); + sample_minstreth_to_trace(m_trace); + sample_mcycle_to_trace(m_trace); + for(int idx=3; idx<32; idx++)begin + sample_perf_event_to_trace(idx, m_trace); //TO CHANGE + end + endfunction + + function void perf_counter_to_trace(insn_trace_t m_trace); + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]) begin + minstret_to_trace(m_trace); + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]) begin + minstreth_to_trace(m_trace); + end + for(int idx=3; idx<32; idx++) begin + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + perf_counter_to_id(idx); + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[idx]) begin + perf_counter_h_to_id(idx); + end + if(r_pipe_freeze_trace.csr.mhpmevent_we[idx]) begin + perf_event_to_trace(idx, m_trace); + end + end + endfunction + + function void tinfo_to_trace(insn_trace_t m_trace); + m_trace.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; + m_trace.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; + m_trace.m_csr.tinfo_rmask = '1; + m_trace.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; + m_trace.m_csr.tinfo_wmask = '0; endfunction function void mtvec_to_id(); @@ -1083,8 +1241,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; lpcount1_to_id(); lpend1_to_id(); lpstart1_to_id(); - - endfunction bit s_was_flush; //debug exception is flagged as trap only if preceed by a flush @@ -1155,7 +1311,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; e_dev_commit_rf_to_ex_3, e_dev_commit_rf_to_ex_4, e_dev_commit_rf_to_ex_5; - event e_if_2_id_1, e_if_2_id_2, e_if_2_id_3; + event e_if_2_id_1, e_if_2_id_2, e_if_2_id_3, e_if_2_id_4; event e_ex_to_wb_1, e_ex_to_wb_2; event e_id_to_ex_1, e_id_to_ex_2; event e_commit_dpc; @@ -1257,6 +1413,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end csr_to_apu_resp(); + + trace_apu_resp.m_stop_cycle = cycles; + trace_apu_resp.m_stop_time = $time; send_rvfi(trace_apu_resp); ->e_send_rvfi_trace_apu_resp; end @@ -1272,35 +1431,47 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_id_done; function void if_to_id(); if (trace_id.m_valid) begin - minstret_to_id(); `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) - tinfo_to_id(); + tinfo_to_trace(trace_id); `CSR_FROM_PIPE(id, mip) send_rvfi(trace_id); end trace_id.init(trace_if); trace_id.m_trap = ~r_pipe_freeze_trace.minstret; - trace_id.m_is_illegal = r_pipe_freeze_trace.is_illegal; + trace_id.m_is_illegal = trace_id.m_is_illegal | r_pipe_freeze_trace.is_illegal; + `CSR_FROM_PIPE(id, dpc) s_is_pc_set = 1'b0; s_is_irq_start = 1'b0; trace_if.m_valid = 1'b0; s_id_done = 1'b0; - `CSR_FROM_PIPE(id, dpc) endfunction function logic [31:0] be_to_mask(logic [3:0] be); logic [31:0] mask; - mask[7:0] = be[0] ? 8'hFF : 8'h00; - mask[15:8] = be[0] ? 8'hFF : 8'h00; - mask[23:16] = be[0] ? 8'hFF : 8'h00; - mask[31:24] = be[0] ? 8'hFF : 8'h00; + mask[7:0] = (be[0] == 1'b1) ? 8'hFF : 8'h00; + mask[15:8] = (be[1] == 1'b1) ? 8'hFF : 8'h00; + mask[23:16] = (be[2] == 1'b1) ? 8'hFF : 8'h00; + mask[31:24] = (be[3] == 1'b1) ? 8'hFF : 8'h00; be_to_mask = mask; return mask; endfunction + function void commit_rf_to_trace(insn_trace_t m_trace); + if (m_trace.m_got_ex_reg) begin + m_trace.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + m_trace.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + m_trace.m_2_rd_insn = 1'b1; + m_trace.m_got_first_data = 1'b1; + end else begin + m_trace.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; + m_trace.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; + m_trace.m_got_first_data = 1'b1; + end + endfunction + task compute_pipeline(); bit s_new_valid_insn; bit s_ex_valid_adjusted; @@ -1320,6 +1491,8 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; bit s_ex_reg_we_adjusted; //ex_reg_we bit s_rf_we_wb_adjusted; // + bit s_dont_override_mstatus_fs_id; + trace_if = new(); trace_id = new(); trace_ex = new(); @@ -1352,6 +1525,8 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; s_ex_reg_we_adjusted = 1'b0; s_rf_we_wb_adjusted = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; + forever begin wait(e_pipe_monitor_ok.triggered); // event triggered #1; @@ -1368,23 +1543,11 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end if (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID && r_pipe_freeze_trace.ebrk_insn_dec) begin - if (trace_wb.m_valid) begin - send_rvfi(trace_wb); - trace_wb.m_valid = 1'b0; - ->e_send_rvfi_trace_wb_1; - end - if (trace_ex.m_valid) begin - send_rvfi(trace_ex); - trace_ex.m_valid = 1'b0; - ->e_send_rvfi_trace_ex_1; - end if (trace_id.m_valid) begin - - minstret_to_id(); `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) - tinfo_to_id(); + tinfo_to_trace(trace_id); `CSR_FROM_PIPE(id, mip) end end @@ -1418,7 +1581,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (trace_ex.m_valid & s_wb_valid_adjusted) begin // Used flopped values in case write happened before wb_valid - minstret_to_ex(); + sample_perf_counter_to_trace(trace_ex); trace_ex.m_csr.got_minstret = '1; end @@ -1494,14 +1657,15 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end if (trace_ex.m_valid) begin - - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); + if(trace_ex.m_instret_smaple_trigger == 1) begin //time to sample instret + sample_perf_counter_to_trace(trace_ex); end + trace_ex.m_instret_smaple_trigger = trace_ex.m_instret_smaple_trigger + 1; + `CSR_FROM_PIPE(ex, misa) `CSR_FROM_PIPE(ex, tdata1) `CSR_FROM_PIPE(ex, tdata2) - tinfo_to_ex(); + tinfo_to_trace(trace_ex); if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_4; @@ -1524,29 +1688,20 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_valid = 1'b0; ->e_send_rvfi_trace_ex_2; end else begin - if (!s_ex_valid_adjusted & !trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_1; - if (trace_ex.m_got_ex_reg) begin - trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_2_rd_insn = 1'b1; - trace_ex.m_got_first_data = 1'b1; - end else begin - trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_got_first_data = 1'b1; - end + commit_rf_to_trace(trace_ex); - if (r_pipe_freeze_trace.csr.fregs_we) begin + if (r_pipe_freeze_trace.csr.fregs_we && (r_pipe_freeze_trace.rf_we_wb && r_pipe_freeze_trace.rf_addr_wb[5])) begin //Catching mstatus_fs updates caused by flw `CSR_FROM_PIPE(ex, mstatus_fs) trace_ex.m_csr.mstatus_fs_we = 1'b1; trace_ex.m_csr.mstatus_fs_wmask = '1; if(r_pipe_freeze_trace.csr.we && r_pipe_freeze_trace.csr.mstatus_fs_we) begin //In this specific case, two writes to mstatus_fs happen at the same time. We need to recreate the writes caused by fregs_we trace_ex.m_csr.mstatus_fs_wdata = FS_DIRTY; + end else begin + trace_id.m_csr.mstatus_fs_rdata = trace_ex.m_csr.mstatus_fs_wdata; + s_dont_override_mstatus_fs_id = 1'b1; end ->e_fregs_dirty_3; end @@ -1559,9 +1714,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; ->e_ex_to_wb_1; trace_wb.move_down_pipe(trace_ex); end else begin - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end send_rvfi(trace_ex); ->e_send_rvfi_trace_ex_6; end @@ -1570,31 +1722,41 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end else if (s_rf_we_wb_adjusted && !s_was_flush) begin ->e_dev_commit_rf_to_ex_2; - if (trace_ex.m_got_ex_reg) begin - trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_2_rd_insn = 1'b1; - trace_ex.m_got_first_data = 1'b1; - end else begin - trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_got_first_data = 1'b1; - end + commit_rf_to_trace(trace_ex); end end // If mret, we need to keep the instruction in Id during flush_ex because mstatus update happens at that time - s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || ((r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) && !r_pipe_freeze_trace.mret_insn_dec)) && (!r_pipe_freeze_trace.apu_rvalid || r_pipe_freeze_trace.data_req_ex); + s_ex_valid_adjusted = (r_pipe_freeze_trace.ex_valid && r_pipe_freeze_trace.ex_ready) && (s_core_is_decoding || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_IF) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_TAKEN_ID) || (r_pipe_freeze_trace.ctrl_fsm_cs == DBG_FLUSH) || ((r_pipe_freeze_trace.ctrl_fsm_cs == FLUSH_EX) && !r_pipe_freeze_trace.mret_insn_dec)); //EX_STAGE + if (trace_id.m_valid) begin + if(trace_id.m_instret_smaple_trigger == 1) begin //time to sample instret + sample_perf_counter_to_trace(trace_id); + for(int idx=3; idx<32; idx++) begin + sample_perf_counter_to_id(idx); + sample_perf_counter_h_to_id(idx); + sample_perf_event_to_trace(idx, trace_id); + end + end + trace_id.m_instret_smaple_trigger = trace_id.m_instret_smaple_trigger + 1; if(trace_id.m_sample_csr_write_in_ex && !csr_is_irq && !s_is_irq_start) begin //First cycle after id_ready, csr write is asserted in this cycle `CSR_FROM_PIPE(id, mstatus) - `CSR_FROM_PIPE(id, mstatus_fs) + if(!s_dont_override_mstatus_fs_id) begin + `CSR_FROM_PIPE(id, mstatus_fs) + end `CSR_FROM_PIPE(id, mepc) `CSR_FROM_PIPE(id, mcause) `CSR_FROM_PIPE(id, dscratch0) `CSR_FROM_PIPE(id, dscratch1) + if(r_pipe_freeze_trace.csr.we && (r_pipe_freeze_trace.csr.addr == CSR_DPC)) begin + `CSR_FROM_PIPE(id, dpc) + end + + `CSR_FROM_PIPE(id, mcountinhibit) + + perf_counter_to_trace(trace_id); ->e_csr_in_ex; end @@ -1614,10 +1776,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(id, frm) `CSR_FROM_PIPE(id, fcsr) - if (r_pipe_freeze_trace.csr.we) begin - `CSR_FROM_PIPE(id, dpc) - end - if (r_pipe_freeze_trace.csr.dcsr_we) begin dcsr_to_id(); end @@ -1638,6 +1796,15 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_csr.frm_wmask = '0; trace_ex.m_csr.fcsr_wmask = '0; + if(r_pipe_freeze_trace.ctrl_fsm_cs == XRET_JUMP) begin //xret exit pipeline + tinfo_to_trace(trace_id); + `CSR_FROM_PIPE(id, tdata1) + `CSR_FROM_PIPE(id, tdata2) + send_rvfi(trace_id); + trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; + end + if (r_pipe_freeze_trace.apu_req && r_pipe_freeze_trace.apu_gnt) begin trace_id.m_is_apu = 1'b1; trace_id.m_apu_req_id = cnt_apu_req; @@ -1647,6 +1814,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_apu_req.set_to_apu(); apu_trace_q.push_back(trace_apu_req); trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; if(r_pipe_freeze_trace.apu_rvalid && (cnt_apu_req == cnt_apu_resp)) begin//APU return in the same cycle apu_resp(); @@ -1702,6 +1870,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; hwloop_to_id(); trace_ex.move_down_pipe(trace_id); // The instruction moves forward from ID to EX trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; ->e_id_to_ex_1; end else if (r_pipe_freeze_trace.ex_reg_we && r_pipe_freeze_trace.rf_alu_we_ex) begin @@ -1725,9 +1894,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (s_new_valid_insn) begin // There is a new valid instruction if (trace_id.m_valid) begin if (trace_ex.m_valid) begin - if (!trace_ex.m_csr.got_minstret) begin - minstret_to_ex(); - end if (trace_wb.m_valid) begin send_rvfi(trace_ex); ->e_send_rvfi_trace_ex_4; @@ -1769,6 +1935,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; hwloop_to_id(); trace_ex.move_down_pipe(trace_id); trace_id.m_valid = 1'b0; + s_dont_override_mstatus_fs_id = 1'b0; ->e_id_to_ex_2; end if_to_id(); @@ -1786,18 +1953,24 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end //IF_STAGE - if (r_pipe_freeze_trace.if_valid && r_pipe_freeze_trace.if_ready) begin + if(trace_if.m_valid) begin + if(r_pipe_freeze_trace.is_illegal && r_pipe_freeze_trace.is_decoding) begin + trace_if.m_is_illegal = 1'b1; + end + end + + if (r_pipe_freeze_trace.if_valid && r_pipe_freeze_trace.if_ready && r_pipe_freeze_trace.instr_valid_if) begin if (trace_if.m_valid) begin if (r_pipe_freeze_trace.id_valid && r_pipe_freeze_trace.id_ready && !trace_id.m_valid && r_pipe_freeze_trace.ebrk_insn_dec) begin if_to_id(); trace_id.m_is_ebreak = '1; //trace_if.m_is_ebreak; ->e_if_2_id_2; - end else if (r_pipe_freeze_trace.is_illegal) begin + end else if (trace_if.m_is_illegal) begin if_to_id(); - trace_id.m_is_illegal = 1'b1; ->e_if_2_id_3; end else if (r_pipe_freeze_trace.ecall_insn_dec) begin if_to_id(); + ->e_if_2_id_4; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi_trace.sv index bfb02579..bdbe6127 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_rvfi_trace.sv @@ -1,26 +1,31 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P RVFI interface -// -// Contributors: Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: CV32E40P RVFI tracer // +// // +//////////////////////////////////////////////////////////////////////////////////// module cv32e40px_rvfi_trace import cv32e40px_pkg::*; + import cv32e40px_rvfi_pkg::*; #( parameter FPU = 0, parameter ZFINX = 0 @@ -32,9 +37,14 @@ module cv32e40px_rvfi_trace input logic [31:0] imm_s3_type, - input logic rvfi_valid, - input logic [31:0] rvfi_insn, - input logic [31:0] rvfi_pc_rdata, + input logic rvfi_valid, + input logic [31:0] rvfi_insn, + input integer rvfi_start_cycle, + input time rvfi_start_time, + input integer rvfi_stop_cycle, + input time rvfi_stop_time, + input logic [31:0] rvfi_pc_rdata, + input rvfi_trap_t rvfi_trap, input logic [ 4:0] rvfi_rd_addr [1:0], input logic [31:0] rvfi_rd_wdata[1:0], @@ -42,6 +52,7 @@ module cv32e40px_rvfi_trace input logic rvfi_frd_wvalid[1:0], input logic [ 4:0] rvfi_frd_addr [1:0], input logic [31:0] rvfi_frd_wdata [1:0], + input logic rvfi_2_rd, input logic [ 4:0] rvfi_rs1_addr, input logic [ 4:0] rvfi_rs2_addr, @@ -61,8 +72,8 @@ module cv32e40px_rvfi_trace input logic [31:0] rvfi_frs3_rdata, input logic [31:0] rvfi_mem_addr, - input logic [ 3:0] rvfi_mem_rmask, - input logic [ 3:0] rvfi_mem_wmask, + input logic [31:0] rvfi_mem_rmask, + input logic [31:0] rvfi_mem_wmask, input logic [31:0] rvfi_mem_rdata, input logic [31:0] rvfi_mem_wdata ); @@ -74,7 +85,7 @@ module cv32e40px_rvfi_trace integer f; //file pointer string fn; - integer cycles; + // integer cycles; string info_tag; logic is_compressed; @@ -125,7 +136,13 @@ module cv32e40px_rvfi_trace rs3_value = rvfi_rs3_rdata; end - if (rvfi_frd_wvalid[0]) begin + if (rvfi_2_rd) begin + if (rvfi_frd_wvalid[1]) begin + rd = {1'b1, rvfi_frd_addr[1]}; + end else begin + rd = {1'b0, rvfi_rd_addr[1]}; + end + end else if (rvfi_frd_wvalid[0]) begin rd = {1'b1, rvfi_frd_addr[0]}; end else begin rd = {1'b0, rvfi_rd_addr[0]}; @@ -134,57 +151,69 @@ module cv32e40px_rvfi_trace assign rs4 = rs3; - assign imm_i_type = {{20{rvfi_insn[31]}}, rvfi_insn[31:20]}; - assign imm_iz_type = {20'b0, rvfi_insn[31:20]}; - assign imm_s_type = {{20{rvfi_insn[31]}}, rvfi_insn[31:25], rvfi_insn[11:7]}; + cv32e40p_compressed_decoder #( + .FPU(FPU) + ) rvfi_trace_decompress_i ( + .instr_i(rvfi_insn), + .instr_o(decomp_insn), + .is_compressed_o(is_compressed) + ); + + assign imm_i_type = {{20{decomp_insn[31]}}, decomp_insn[31:20]}; + assign imm_iz_type = {20'b0, decomp_insn[31:20]}; + assign imm_s_type = {{20{decomp_insn[31]}}, decomp_insn[31:25], decomp_insn[11:7]}; assign imm_sb_type = { - {19{rvfi_insn[31]}}, rvfi_insn[31], rvfi_insn[7], rvfi_insn[30:25], rvfi_insn[11:8], 1'b0 + {19{decomp_insn[31]}}, + decomp_insn[31], + decomp_insn[7], + decomp_insn[30:25], + decomp_insn[11:8], + 1'b0 }; - assign imm_u_type = {rvfi_insn[31:12], 12'b0}; + assign imm_u_type = {decomp_insn[31:12], 12'b0}; assign imm_uj_type = { - {12{rvfi_insn[31]}}, rvfi_insn[19:12], rvfi_insn[20], rvfi_insn[30:21], 1'b0 + {12{decomp_insn[31]}}, decomp_insn[19:12], decomp_insn[20], decomp_insn[30:21], 1'b0 }; - assign imm_z_type = '0; //{27'b0, rvfi_insn[REG_S1_MSB:REG_S1_LSB]}; + assign imm_z_type = '0; //{27'b0, decomp_insn[REG_S1_MSB:REG_S1_LSB]}; - assign imm_s2_type = {27'b0, rvfi_insn[24:20]}; + assign imm_s2_type = {27'b0, decomp_insn[24:20]}; assign imm_vs_type = '0; assign imm_vu_type = '0; assign imm_shuffle_type = '0; assign imm_clip_type = '0; - cv32e40px_compressed_decoder #( - .FPU(FPU) - ) rvfi_trace_decompress_i ( - .instr_i(rvfi_insn), - .instr_o(decomp_insn), - .is_compressed_o(is_compressed) - ); - `include "cv32e40px_instr_trace.svh" instr_trace_t trace_retire; function instr_trace_t trace_new_instr(); instr_trace_t trace; trace = new(); - trace.init(.cycles(cycles), .pc(rvfi_pc_rdata), .compressed(is_compressed), + trace.external_time = 1; + trace.simtime = rvfi_start_time - 1ns; + trace.stoptime = rvfi_stop_time; + trace.stopcycles = rvfi_stop_cycle; + trace.ctx = (rvfi_trap.trap) ? "(C)" : ""; + trace.init(.cycles(rvfi_start_cycle), .pc(rvfi_pc_rdata), .compressed(is_compressed), .instr(decomp_insn)); return trace; endfunction : trace_new_instr function void apply_reg_write(); foreach (trace_retire.regs_write[i]) begin - if (rvfi_frd_wvalid[0] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[0]})) begin - trace_retire.regs_write[i].value = rvfi_frd_wdata[0]; - end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[0]) begin - trace_retire.regs_write[i].value = rvfi_rd_wdata[0]; - end if (rvfi_frd_wvalid[1] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[1]})) begin trace_retire.regs_write[i].value = rvfi_frd_wdata[1]; end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[1]) begin trace_retire.regs_write[i].value = rvfi_rd_wdata[1]; end end + foreach (trace_retire.regs_write[i]) begin + if (rvfi_frd_wvalid[0] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[0]})) begin + trace_retire.regs_write[i].value = rvfi_frd_wdata[0]; + end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[0]) begin + trace_retire.regs_write[i].value = rvfi_rd_wdata[0]; + end + end endfunction : apply_reg_write function void apply_mem_access(); @@ -202,11 +231,9 @@ instr_trace_t trace_retire; end endfunction : apply_mem_access - // cycle counter - always_ff @(posedge clk_i, negedge rst_ni) begin - if (rst_ni == 1'b0) cycles <= 0; - else cycles <= cycles + 1; - end + string insn_disas; + logic [31:0] insn_pc; + logic [31:0] insn_val; always @(posedge clk_i) begin if (rvfi_valid) begin @@ -214,6 +241,9 @@ instr_trace_t trace_retire; apply_reg_write(); apply_mem_access(); trace_retire.printInstrTrace(); + insn_disas = trace_retire.str; + insn_pc = trace_retire.pc; + insn_val = trace_retire.instr; end end @@ -223,7 +253,8 @@ instr_trace_t trace_retire; $sformat(info_tag, "CORE_TRACER %2d", hart_id_i); $display("[%s] Output filename is: %s", info_tag, fn); f = $fopen(fn, "w"); - $fwrite(f, "Time\tCycle\tPC\tInstr\tDecoded instruction\tRegister and memory contents\n"); + $fwrite(f, + " Time Cycle PC Instr Ctx Decoded instruction Register and memory contents Stop cycle Stop time\n"); end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv index d4aa94dc..c14b131b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tb_wrapper.sv @@ -1,45 +1,49 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Wrapper for a cv32e40px, containing cv32e40px_top, and rvfi_tracer -// -// Contributors: Davide Schiavone, OpenHW Group -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Yoann Pruvost, Dolphin Design // +// // +// Description: Test-bench wrapper for cv32e40px_top, tracer and and rvfi_tracer // +// // +//////////////////////////////////////////////////////////////////////////////////// -`ifdef CV32E40P_ASSERT_ON +`ifdef CV32E40PX_ASSERT_ON `include "cv32e40px_prefetch_controller_sva.sv" `endif -`ifdef CV32E40P_CORE_LOG +`ifdef CV32E40PX_CORE_LOG `include "cv32e40px_core_log.sv" `endif -`ifdef CV32E40P_APU_TRACE +`ifdef CV32E40PX_APU_TRACE `include "cv32e40px_apu_tracer.sv" `endif -`ifdef CV32E40P_TRACE_EXECUTION +`ifdef CV32E40PX_TRACE_EXECUTION `include "cv32e40px_tracer.sv" `endif -`ifdef CV32E40P_RVFI +`ifdef CV32E40PX_RVFI `include "cv32e40px_rvfi.sv" `endif -`ifdef CV32E40P_RVFI_TRACE_EXECUTION +`ifdef CV32E40PX_RVFI_TRACE_EXECUTION `include "cv32e40px_rvfi_trace.sv" `endif @@ -101,7 +105,7 @@ module cv32e40px_tb_wrapper output logic core_sleep_o ); -`ifdef CV32E40P_ASSERT_ON +`ifdef CV32E40PX_ASSERT_ON // RTL Assertions bind cv32e40px_prefetch_controller: @@ -114,9 +118,9 @@ module cv32e40px_tb_wrapper .FIFO_ADDR_DEPTH(FIFO_ADDR_DEPTH) ) prefetch_controller_sva (.*); -`endif // CV32E40P_ASSERT_ON +`endif // CV32E40PX_ASSERT_ON -`ifdef CV32E40P_CORE_LOG +`ifdef CV32E40PX_CORE_LOG cv32e40px_core_log #( .COREV_PULP (COREV_PULP), .COREV_CLUSTER (COREV_CLUSTER), @@ -130,9 +134,9 @@ module cv32e40px_tb_wrapper .hart_id_i (cv32e40px_top_i.core_i.hart_id_i), .pc_id_i (cv32e40px_top_i.core_i.pc_id) ); -`endif // CV32E40P_CORE_LOG +`endif // CV32E40PX_CORE_LOG -`ifdef CV32E40P_APU_TRACE +`ifdef CV32E40PX_APU_TRACE cv32e40px_apu_tracer apu_tracer_i ( .clk_i (cv32e40px_top_i.core_i.rst_ni), .rst_n (cv32e40px_top_i.core_i.clk_i), @@ -143,7 +147,7 @@ module cv32e40px_tb_wrapper ); `endif -`ifdef CV32E40P_TRACE_EXECUTION +`ifdef CV32E40PX_TRACE_EXECUTION cv32e40px_tracer #( .FPU (FPU), .ZFINX(ZFINX) @@ -210,11 +214,11 @@ module cv32e40px_tb_wrapper .apu_en_i (cv32e40px_top_i.apu_req), .apu_singlecycle_i(cv32e40px_top_i.core_i.ex_stage_i.apu_singlecycle), .apu_multicycle_i (cv32e40px_top_i.core_i.ex_stage_i.apu_multicycle), - .apu_rvalid_i (cv32e40px_top_i.apu_rvalid) + .apu_rvalid_i (cv32e40px_top_i.core_i.ex_stage_i.apu_valid) ); `endif -`ifdef CV32E40P_RVFI +`ifdef CV32E40PX_RVFI logic [1:0][31:0] hwlp_start_q; logic [1:0][31:0] hwlp_end_q; logic [1:0][31:0] hwlp_counter_q; @@ -234,8 +238,9 @@ module cv32e40px_tb_wrapper endgenerate cv32e40px_rvfi #( - .FPU (FPU), - .ZFINX(ZFINX) + .FPU(FPU), + .ZFINX(ZFINX), + .NUM_MHPMCOUNTERS(NUM_MHPMCOUNTERS) ) rvfi_i ( .clk_i (cv32e40px_top_i.core_i.clk_i), .rst_ni(cv32e40px_top_i.core_i.rst_ni), @@ -399,6 +404,9 @@ module cv32e40px_tb_wrapper .csr_mcountinhibit_n_i (cv32e40px_top_i.core_i.cs_registers_i.mcountinhibit_n), .csr_mcountinhibit_we_i(cv32e40px_top_i.core_i.cs_registers_i.mcountinhibit_we), + .csr_mhpmevent_n_i(cv32e40px_top_i.core_i.cs_registers_i.mhpmevent_n), + .csr_mhpmevent_q_i(cv32e40px_top_i.core_i.cs_registers_i.mhpmevent_q), + .csr_mhpmevent_we_i(cv32e40px_top_i.core_i.cs_registers_i.mhpmevent_we), .csr_mscratch_q_i(cv32e40px_top_i.core_i.cs_registers_i.mscratch_q), .csr_mscratch_n_i(cv32e40px_top_i.core_i.cs_registers_i.mscratch_n), .csr_mepc_q_i(cv32e40px_top_i.core_i.cs_registers_i.mepc_q), @@ -441,8 +449,7 @@ module cv32e40px_tb_wrapper ); `endif - -`ifdef CV32E40P_RVFI_TRACE_EXECUTION +`ifdef CV32E40PX_RVFI_TRACE_EXECUTION bind cv32e40px_rvfi: rvfi_i cv32e40px_rvfi_trace #( .FPU (FPU), .ZFINX(ZFINX) @@ -455,22 +462,38 @@ module cv32e40px_tb_wrapper .rvfi_valid(rvfi_valid), .rvfi_insn(rvfi_insn), + .rvfi_start_cycle(rvfi_start_cycle), + .rvfi_start_time(rvfi_start_time), + .rvfi_stop_cycle(rvfi_stop_cycle), + .rvfi_stop_time(rvfi_stop_time), .rvfi_pc_rdata(rvfi_pc_rdata), + .rvfi_trap(rvfi_trap), .rvfi_rd_addr(rvfi_rd_addr), .rvfi_rd_wdata(rvfi_rd_wdata), .rvfi_frd_wvalid(rvfi_frd_wvalid), .rvfi_frd_addr(rvfi_frd_addr), .rvfi_frd_wdata(rvfi_frd_wdata), + .rvfi_2_rd(rvfi_2_rd), .rvfi_rs1_addr(rvfi_rs1_addr), .rvfi_rs2_addr(rvfi_rs2_addr), + .rvfi_rs3_addr(rvfi_rs3_addr), .rvfi_rs1_rdata(rvfi_rs1_rdata), .rvfi_rs2_rdata(rvfi_rs2_rdata), + .rvfi_rs3_rdata(rvfi_rs3_rdata), .rvfi_frs1_addr(rvfi_frs1_addr), .rvfi_frs2_addr(rvfi_frs2_addr), + .rvfi_frs3_addr(rvfi_frs3_addr), .rvfi_frs1_rvalid(rvfi_frs1_rvalid), .rvfi_frs2_rvalid(rvfi_frs2_rvalid), + .rvfi_frs3_rvalid(rvfi_frs3_rvalid), .rvfi_frs1_rdata(rvfi_frs1_rdata), - .rvfi_frs2_rdata(rvfi_frs2_rdata) + .rvfi_frs2_rdata(rvfi_frs2_rdata), + .rvfi_frs3_rdata(rvfi_frs3_rdata), + .rvfi_mem_addr(rvfi_mem_addr), + .rvfi_mem_rmask(rvfi_mem_rmask), + .rvfi_mem_wmask(rvfi_mem_wmask), + .rvfi_mem_rdata(rvfi_mem_rdata), + .rvfi_mem_wdata(rvfi_mem_wdata) ); `endif // Instantiate the Core and the optinal FPU diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tracer.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tracer.sv index c0c13315..9254ccea 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tracer.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/cv32e40px_tracer.sv @@ -1,24 +1,26 @@ -// Copyright (c) 2020 OpenHW Group -// -// Licensed under the Solderpad Hardware Licence, 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 -// -// https://solderpad.org/licenses/ -// -// 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 - -// Traces the executed instructions -// -// Contributors: Andreas Traber, ETHZ -// Davide Schiavone, OpenHW Group -// Pascal Gouedo, Dolphin Design +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch // +// // +// Additional contributions by: // +// Davide Schiavone - pschiavo@iis.ee.ethz.ch // +// // +// Design Name: RISC-V Tracer // +// Project Name: RI5CY // +// Language: SystemVerilog // +// // +// Description: Traces the executed instructions // +// // +//////////////////////////////////////////////////////////////////////////////// `ifdef CV32E40P_TRACE_EXECUTION @@ -183,7 +185,8 @@ module cv32e40px_tracer $sformat(info_tag, "CORE_TRACER %2d", hart_id_i); $display("[%s] Output filename is: %s", info_tag, fn); f = $fopen(fn, "w"); - $fwrite(f, "Time\tCycle\tPC\tInstr\tDecoded instruction\tRegister and memory contents\n"); + $fwrite(f, + " Time Cycle PC Instr Ctx Decoded instruction Register and memory contents\n"); end //initial begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_rvfi_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_rvfi_pkg.sv index 9a131a68..5a43daf6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_rvfi_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_rvfi_pkg.sv @@ -1,24 +1,28 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Includes to print info about the RVFI output -// -// Contributors: Davide Schiavone, OpenHW Group -// Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: Package to print info on RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// package cv32e40px_rvfi_pkg; import cv32e40px_pkg::*; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv index 90ee5be9..2046dd74 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/include/cv32e40px_tracer_pkg.sv @@ -1,23 +1,13 @@ -// Copyright (c) 2020 OpenHW Group -// -// Licensed under the Solderpad Hardware Licence, 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 -// -// https://solderpad.org/licenses/ -// -// 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 - -// Tracer package -// -// Contributors: Steve Richmond, Silicon Labs -// Pascal Gouedo, Dolphin Design +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + package cv32e40px_tracer_pkg; import cv32e40px_pkg::*; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv index 3fe7c184..8cdc06d9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/insn_trace.sv @@ -1,5 +1,26 @@ -// Copyright 2022 Dolphin Design -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// Copyright 2024 OpenHW Group and Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// 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. + +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Yoann Pruvost, Dolphin Design // +// // +// Description: Macros and Functions to print information on RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// `define DEFINE_CSR(CSR_NAME) \ logic ``CSR_NAME``_we; \ @@ -23,6 +44,10 @@ class insn_trace_t; bit m_valid; logic [63:0] m_order; + integer m_start_cycle; + integer m_stop_cycle; + time m_start_time; + time m_stop_time; bit m_skip_order; //next order was used by trap; logic [31:0] m_pc_rdata; logic [31:0] m_insn; @@ -65,14 +90,15 @@ bit m_move_down_pipe; int m_instret_cnt; + int m_instret_smaple_trigger; //We need to sample minstret from csr 2 cycle after id is doen bit m_sample_csr_write_in_ex; struct { logic [31:0] addr ; - logic [ 3:0] rmask; + logic [31:0] rmask; logic [31:0] rdata; - logic [ 3:0] wmask; + logic [31:0] wmask; logic [31:0] wdata; } m_mem; @@ -102,9 +128,28 @@ `DEFINE_CSR(mscratch) `DEFINE_CSR(mepc) `DEFINE_CSR(mcause) + `DEFINE_CSR(mcycle) `DEFINE_CSR(minstret) bit got_minstret; - + `DEFINE_CSR(mcycleh) + `DEFINE_CSR(minstreth) + `DEFINE_CSR(cycle) + `DEFINE_CSR(instret) + // bit got_minstret; + `DEFINE_CSR(cycleh) + `DEFINE_CSR(instreth) + + logic [31:0][ 1:0] mhpmcounter_we; + logic [31:0][63:0] mhpmcounter_rdata; + logic [31:0][63:0] mhpmcounter_rmask; + logic [31:0][63:0] mhpmcounter_wdata; + logic [31:0][63:0] mhpmcounter_wmask; + + logic [31:0] mhpmevent_we; + logic [31:0][31:0] mhpmevent_rdata; + logic [31:0][31:0] mhpmevent_rmask; + logic [31:0][31:0] mhpmevent_wdata; + logic [31:0][31:0] mhpmevent_wmask; `DEFINE_CSR(mip) //mnxti //mintstatus @@ -148,6 +193,10 @@ function new(); this.m_order = 0; + this.m_start_cycle = 0; + this.m_stop_cycle = 0; + this.m_start_time = 0; + this.m_stop_time = 0; this.m_skip_order = 1'b0; this.m_valid = 1'b0; this.m_move_down_pipe = 1'b0; @@ -173,6 +222,7 @@ this.m_frm_we_non_apu = 1'b0; this.m_fcsr_we_non_apu = 1'b0; this.m_instret_cnt = 0; + this.m_instret_smaple_trigger = 0; this.m_sample_csr_write_in_ex = 1'b1; endfunction @@ -613,12 +663,12 @@ INSTR_CVCMPLEB : this.m_mnemonic = "cv.cmple.b"; INSTR_CVCMPLESCB : this.m_mnemonic = "cv.cmple.sc.b"; INSTR_CVCMPLESCIB : this.m_mnemonic = "cv.cmple.sci.b"; - INSTR_CVCMPGTUH : this.m_mnemonic = "cv.cmptu.h"; - INSTR_CVCMPGTUSCH : this.m_mnemonic = "cv.cmptu.sc.h"; - INSTR_CVCMPGTUSCIH : this.m_mnemonic = "cv.cmptu.sci.h"; - INSTR_CVCMPGTUB : this.m_mnemonic = "cv.cmptu.b"; - INSTR_CVCMPGTUSCB : this.m_mnemonic = "cv.cmptu.sc.b"; - INSTR_CVCMPGTUSCIB : this.m_mnemonic = "cv.cmptu.sci.b"; + INSTR_CVCMPGTUH : this.m_mnemonic = "cv.cmpgtu.h"; + INSTR_CVCMPGTUSCH : this.m_mnemonic = "cv.cmpgtu.sc.h"; + INSTR_CVCMPGTUSCIH : this.m_mnemonic = "cv.cmpgtu.sci.h"; + INSTR_CVCMPGTUB : this.m_mnemonic = "cv.cmpgtu.b"; + INSTR_CVCMPGTUSCB : this.m_mnemonic = "cv.cmpgtu.sc.b"; + INSTR_CVCMPGTUSCIB : this.m_mnemonic = "cv.cmpgtu.sci.b"; INSTR_CVCMPGEUH : this.m_mnemonic = "cv.cmpgeu.h"; INSTR_CVCMPGEUSCH : this.m_mnemonic = "cv.cmpgeu.sc.h"; INSTR_CVCMPGEUSCIH : this.m_mnemonic = "cv.cmpgeu.sci.h"; @@ -847,7 +897,18 @@ `INIT_CSR(mscratch) `INIT_CSR(mepc) `INIT_CSR(mcause) + `INIT_CSR(mcycle) `INIT_CSR(minstret) + `INIT_CSR(mcycleh) + `INIT_CSR(minstreth) + `INIT_CSR(cycle) + `INIT_CSR(instret) + `INIT_CSR(cycleh) + `INIT_CSR(instreth) + this.m_csr.mhpmcounter_we = '0; + this.m_csr.mhpmcounter_wmask = '0; + this.m_csr.mhpmevent_we = '0; + this.m_csr.mhpmevent_wmask = '0; `INIT_CSR(mip) `INIT_CSR(tdata1) `INIT_CSR(tdata2) @@ -875,6 +936,10 @@ this.m_valid = 1'b1; this.m_stage = ID; this.m_order = this.m_order + 64'h1; + this.m_start_cycle = cycles; + this.m_stop_cycle = 0; + this.m_start_time = $time; + this.m_stop_time = 0; if(this.m_skip_order) begin this.m_order = this.m_order + 64'h1; end @@ -896,6 +961,7 @@ this.m_got_regs_write = 1'b0; this.m_move_down_pipe = 1'b0; this.m_instret_cnt = 0; + this.m_instret_smaple_trigger = 0; this.m_sample_csr_write_in_ex = 1'b1; this.m_rd_addr[0] = '0; this.m_rd_addr[1] = '0; @@ -951,6 +1017,10 @@ this.m_valid = m_source.m_valid; this.m_stage = m_source.m_stage; this.m_order = m_source.m_order; + this.m_start_cycle = m_source.m_start_cycle; + this.m_stop_cycle = m_source.m_stop_cycle; + this.m_start_time = m_source.m_start_time; + this.m_stop_time = m_source.m_stop_time; this.m_pc_rdata = m_source.m_pc_rdata; this.m_insn = m_source.m_insn; this.m_mnemonic = m_source.m_mnemonic; @@ -970,6 +1040,7 @@ this.m_is_illegal = m_source.m_is_illegal; this.m_is_irq = m_source.m_is_irq; this.m_instret_cnt = m_source.m_instret_cnt; + this.m_instret_smaple_trigger = m_source.m_instret_smaple_trigger; this.m_sample_csr_write_in_ex = m_source.m_sample_csr_write_in_ex; this.m_rs1_addr = m_source.m_rs1_addr; this.m_rs2_addr = m_source.m_rs2_addr; @@ -1000,8 +1071,26 @@ `ASSIGN_CSR(mscratch) `ASSIGN_CSR(mepc) `ASSIGN_CSR(mcause) + `ASSIGN_CSR(mcycle) `ASSIGN_CSR(minstret) this.m_csr.got_minstret = m_source.m_csr.got_minstret; + `ASSIGN_CSR(mcycleh) + `ASSIGN_CSR(minstreth) + `ASSIGN_CSR(cycle) + `ASSIGN_CSR(instret) + // this.m_csr.got_minstret = m_source.m_csr.got_minstret; + `ASSIGN_CSR(cycleh) + `ASSIGN_CSR(instreth) + this.m_csr.mhpmcounter_we = m_source.m_csr.mhpmcounter_we; + this.m_csr.mhpmcounter_rdata = m_source.m_csr.mhpmcounter_rdata; + this.m_csr.mhpmcounter_rmask = m_source.m_csr.mhpmcounter_rmask; + this.m_csr.mhpmcounter_wdata = m_source.m_csr.mhpmcounter_wdata; + this.m_csr.mhpmcounter_wmask = m_source.m_csr.mhpmcounter_wmask; + this.m_csr.mhpmevent_we = m_source.m_csr.mhpmevent_we; + this.m_csr.mhpmevent_rdata = m_source.m_csr.mhpmevent_rdata; + this.m_csr.mhpmevent_rmask = m_source.m_csr.mhpmevent_rmask; + this.m_csr.mhpmevent_wdata = m_source.m_csr.mhpmevent_wdata; + this.m_csr.mhpmevent_wmask = m_source.m_csr.mhpmevent_wmask; `ASSIGN_CSR(mip) `ASSIGN_CSR(tdata1) `ASSIGN_CSR(tdata2) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv index 88d65d0b..39a16fa6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/bhv/pipe_freeze_trace.sv @@ -1,27 +1,29 @@ -// Copyright (c) 2023 OpenHW Group +// Copyright 2024 OpenHW Group and Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P -// -// Contributors: Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Yoann Pruvost, Dolphin Design // +// // +// Description: Structures, Functions and Task used to store all information // +// coming from the core pipeline at every posedge. // +// Those information will then be processed by RVFI. // +// // +//////////////////////////////////////////////////////////////////////////////////// -/* - * This struct is used to store all information comming from the core at every posedge - * The information will then be processed - */ typedef struct { logic is_decoding; logic is_illegal; @@ -349,6 +351,7 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.fflags_we = 1'b0; r_pipe_freeze_trace.csr.frm_we = 1'b0; r_pipe_freeze_trace.csr.fcsr_we = 1'b0; + r_pipe_freeze_trace.csr.mhpmevent_we = '0; r_pipe_freeze_trace.csr.dpc_we = csr_dpc_we_i; if (r_pipe_freeze_trace.csr.we) begin case (r_pipe_freeze_trace.csr.addr) @@ -366,7 +369,10 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.fflags_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; end - CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; + CSR_FRM: begin + r_pipe_freeze_trace.csr.frm_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end CSR_FCSR: begin r_pipe_freeze_trace.csr.fcsr_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; @@ -376,6 +382,10 @@ function compute_csr_we(); CSR_DSCRATCH1: r_pipe_freeze_trace.csr.dscratch1_we = 1'b1; endcase end + + if (csr_mhpmevent_we_i) begin + r_pipe_freeze_trace.csr.mhpmevent_we[r_pipe_freeze_trace.csr.addr[4:0]] = 1'b1; + end // CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = r_pipe_freeze_trace.csr.mcause_n != r_pipe_freeze_trace.csr.mcause_q; //for debug purpose endfunction /* @@ -573,7 +583,6 @@ task monitor_pipeline(); r_pipe_freeze_trace.csr.mcountinhibit_we = csr_mcountinhibit_we_i; r_pipe_freeze_trace.csr.mhpmevent_n = csr_mhpmevent_n_i; r_pipe_freeze_trace.csr.mhpmevent_q = csr_mhpmevent_q_i; - r_pipe_freeze_trace.csr.mhpmevent_we = csr_mhpmevent_we_i; r_pipe_freeze_trace.csr.mscratch_n = csr_mscratch_n_i; r_pipe_freeze_trace.csr.mscratch_q = csr_mscratch_q_i; r_pipe_freeze_trace.csr.mepc_n = csr_mepc_n_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv index a3e3bac9..e9807a38 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv @@ -597,7 +597,17 @@ module cv32e40px_controller import cv32e40px_pkg::*; csr_status_i: begin halt_if_o = 1'b1; - ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE; + if (~id_ready_i) begin + ctrl_fsm_ns = DECODE; + end else begin + ctrl_fsm_ns = FLUSH_EX; + if (hwlp_end0_eq_pc) begin + hwlp_dec_cnt_o[0] = 1'b1; + end + if (hwlp_end1_eq_pc) begin + hwlp_dec_cnt_o[1] = 1'b1; + end + end end data_load_event_i: begin @@ -617,7 +627,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; ctrl_fsm_ns = hwlp_end0_eq_pc_plus4 || hwlp_end1_eq_pc_plus4 ? DECODE : DECODE_HWLOOP; // we can be at the end of HWloop due to a return from interrupt or ecall or ebreak or exceptions - if(hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin + if (hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin pc_mux_o = PC_HWLOOP; if (~jump_done_q) begin pc_set_o = 1'b1; @@ -791,7 +801,17 @@ module cv32e40px_controller import cv32e40px_pkg::*; csr_status_i: begin halt_if_o = 1'b1; - ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; + if (~id_ready_i) begin + ctrl_fsm_ns = DECODE_HWLOOP; + end else begin + ctrl_fsm_ns = FLUSH_EX; + if (hwlp_end0_eq_pc) begin + hwlp_dec_cnt_o[0] = 1'b1; + end + if (hwlp_end1_eq_pc) begin + hwlp_dec_cnt_o[1] = 1'b1; + end + end end data_load_event_i: begin @@ -1067,16 +1087,10 @@ module cv32e40px_controller import cv32e40px_pkg::*; end csr_status_i: begin - - if(hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin - pc_mux_o = PC_HWLOOP; - pc_set_o = 1'b1; - hwlp_dec_cnt_o[0] = 1'b1; - end - if(hwlp_end1_eq_pc && hwlp_counter1_gt_1) begin - pc_mux_o = PC_HWLOOP; - pc_set_o = 1'b1; - hwlp_dec_cnt_o[1] = 1'b1; + if ((hwlp_end0_eq_pc && !hwlp_counter0_eq_0) || + (hwlp_end1_eq_pc && !hwlp_counter1_eq_0)) begin + pc_mux_o = PC_HWLOOP; + pc_set_o = 1'b1; end end @@ -1561,7 +1575,7 @@ endgenerate // HWLoop 0 and 1 having target address constraints property p_hwlp_same_target_address; - @(posedge clk) (hwlp_counter_i[1] > 1 && hwlp_counter_i[0] > 1) |-> ( hwlp_end_addr_i[1] - 4 >= hwlp_end_addr_i[0] - 4 + 8 ); + @(posedge clk) (hwlp_counter_i[1] > 1 && hwlp_counter_i[0] > 1 && pc_id_i >= hwlp_start_addr_i[0] && pc_id_i <= hwlp_end_addr_i[0] - 4) |-> ( hwlp_end_addr_i[1] - 4 >= hwlp_end_addr_i[0] - 4 + 8 ); endproperty a_hwlp_same_target_address : assert property(p_hwlp_same_target_address) else $warning("%t, HWLoops target address do not respect constraints", $time); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv index 25aa6cc9..91c4eb8d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_core.sv @@ -72,7 +72,8 @@ module cv32e40px_core output logic [31:0] data_wdata_o, input logic [31:0] data_rdata_i, - // apu-interconnect + // CVFPU interface + output logic apu_busy_o, // handshake signals output logic apu_req_o, input logic apu_gnt_i, @@ -199,7 +200,6 @@ module cv32e40px_core logic ctrl_busy; logic if_busy; logic lsu_busy; - logic apu_busy; logic [31:0] pc_ex; // PC of last executed branch or cv.elw @@ -445,7 +445,7 @@ module cv32e40px_core .if_busy_i (if_busy), .ctrl_busy_i(ctrl_busy), .lsu_busy_i (lsu_busy), - .apu_busy_i (apu_busy), + .apu_busy_i (apu_busy_o), // PULP cluster .pulp_clock_en_i (pulp_clock_en_i), @@ -690,7 +690,7 @@ module cv32e40px_core .apu_write_regs_valid_o (apu_write_regs_valid), .apu_write_dep_i (apu_write_dep), .apu_perf_dep_o (perf_apu_dep), - .apu_busy_i (apu_busy), + .apu_busy_i (apu_busy_o), // CORE-V-XIF // Compressed Interface @@ -909,9 +909,9 @@ module cv32e40px_core .apu_perf_cont_o(perf_apu_cont), .apu_perf_wb_o (perf_apu_wb), .apu_ready_wb_o (apu_ready_wb), - .apu_busy_o (apu_busy), + .apu_busy_o (apu_busy_o), - // apu-interconnect + // CVFPU interface // handshake signals .apu_req_o (apu_req_o), .apu_gnt_i (apu_gnt_i), @@ -1160,9 +1160,9 @@ module cv32e40px_core assign csr_addr_int = csr_num_e'(csr_access_ex ? alu_operand_b_ex[11:0] : '0); // Floating-Point registers write - assign fregs_we = (FPU & !ZFINX) ? ((regfile_alu_we_fw && regfile_alu_waddr_fw[5]) || - (regfile_we_wb && regfile_waddr_fw_wb_o[5])) - : 1'b0; + assign fregs_we = (FPU == 1 & ZFINX == 0) ? ((regfile_alu_we_fw && regfile_alu_waddr_fw[5]) || + (regfile_we_wb && regfile_waddr_fw_wb_o[5])) + : 1'b0; /////////////////////////// // ____ __ __ ____ // diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv index f24b3bf9..53005725 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_cs_registers.sv @@ -509,7 +509,7 @@ module cv32e40px_cs_registers // mimpid, Machine Implementation ID CSR_MIMPID: begin - csr_rdata_int = (FPU || COREV_PULP || COREV_CLUSTER) ? 32'h1 : 'b0; + csr_rdata_int = (FPU == 1 || COREV_PULP == 1 || COREV_CLUSTER == 1) ? 32'h1 : 'b0; end // unimplemented, read 0 CSRs diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_decoder.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_decoder.sv index 3d55fdbc..c8e11cc3 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_decoder.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_decoder.sv @@ -1057,7 +1057,6 @@ module cv32e40px_decoder 5'b00000: begin fpu_op = cv32e40px_fpu_pkg::ADD; fp_op_group = ADDMUL; - apu_op_o = 2'b0; alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; alu_op_c_mux_sel_o = OP_C_REGB_OR_FWD; end @@ -1066,7 +1065,6 @@ module cv32e40px_decoder fpu_op = cv32e40px_fpu_pkg::ADD; fpu_op_mod = 1'b1; fp_op_group = ADDMUL; - apu_op_o = 2'b1; alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; alu_op_c_mux_sel_o = OP_C_REGB_OR_FWD; end @@ -1085,7 +1083,6 @@ module cv32e40px_decoder regb_used_o = 1'b0; fpu_op = cv32e40px_fpu_pkg::SQRT; fp_op_group = DIVSQRT; - apu_op_o = 1'b1; // rs2 must be zero if (instr_rdata_i[24:20] != 5'b00000) illegal_insn_o = 1'b1; end @@ -1213,7 +1210,6 @@ module cv32e40px_decoder fpu_op = cv32e40px_fpu_pkg::F2I; fp_op_group = CONV; fpu_op_mod = instr_rdata_i[20]; // signed/unsigned switch - apu_op_o = 2'b1; unique case (instr_rdata_i[26:25]) //fix for casting to different formats other than FP32 2'b00: begin @@ -1249,7 +1245,6 @@ module cv32e40px_decoder fpu_op = cv32e40px_fpu_pkg::I2F; fp_op_group = CONV; fpu_op_mod = instr_rdata_i[20]; // signed/unsigned switch - apu_op_o = 2'b0; // bits [21:20] used, other bits must be 0 if (instr_rdata_i[24:21]) illegal_insn_o = 1'b1; // in RV32, no casts to L allowed. end @@ -1323,20 +1318,20 @@ module cv32e40px_decoder // check rounding mode if (check_fprm) begin unique case (instr_rdata_i[14:12]) inside - [3'b000:3'b100]: ; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~C_XF16ALT || fpu_dst_fmt_o != cv32e40px_fpu_pkg::FP16ALT) illegal_insn_o = 1'b1; // actual rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes - default : illegal_insn_o = 1'b1; + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes + default : illegal_insn_o = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes - default : illegal_insn_o = 1'b1; + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes + default : illegal_insn_o = 1'b1; endcase end default : illegal_insn_o = 1'b1; @@ -1364,6 +1359,7 @@ module cv32e40px_decoder NONCOMP : apu_lat_o = (FPU_OTHERS_LAT<2) ? FPU_OTHERS_LAT+1 : 2'h3; // CONV uses the same latency for all formats CONV : apu_lat_o = (FPU_OTHERS_LAT<2) ? FPU_OTHERS_LAT+1 : 2'h3; + default: ; endcase // Set FPnew OP and OPMOD as the APU op @@ -1425,25 +1421,21 @@ module cv32e40px_decoder unique case (instr_rdata_i[6:0]) // fmadd.fmt - FP Fused multiply-add OPCODE_OP_FMADD : begin - fpu_op = cv32e40px_fpu_pkg::FMADD; - apu_op_o = 2'b00; + fpu_op = cv32e40px_fpu_pkg::FMADD; end // fmsub.fmt - FP Fused multiply-subtract OPCODE_OP_FMSUB : begin - fpu_op = cv32e40px_fpu_pkg::FMADD; - fpu_op_mod = 1'b1; - apu_op_o = 2'b01; + fpu_op = cv32e40px_fpu_pkg::FMADD; + fpu_op_mod = 1'b1; end // fnmsub.fmt - FP Negated fused multiply-subtract OPCODE_OP_FNMSUB : begin - fpu_op = cv32e40px_fpu_pkg::FNMSUB; - apu_op_o = 2'b10; + fpu_op = cv32e40px_fpu_pkg::FNMSUB; end // fnmadd.fmt - FP Negated fused multiply-add OPCODE_OP_FNMADD : begin - fpu_op = cv32e40px_fpu_pkg::FNMSUB; - fpu_op_mod = 1'b1; - apu_op_o = 2'b11; + fpu_op = cv32e40px_fpu_pkg::FNMSUB; + fpu_op_mod = 1'b1; end default : ; endcase @@ -1459,19 +1451,19 @@ module cv32e40px_decoder // check rounding mode unique case (instr_rdata_i[14:12]) inside - [3'b000:3'b100]: ; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~C_XF16ALT || fpu_dst_fmt_o != cv32e40px_fpu_pkg::FP16ALT) illegal_insn_o = 1'b1; // actual rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes default : illegal_insn_o = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes default : illegal_insn_o = 1'b1; endcase end @@ -1493,6 +1485,7 @@ module cv32e40px_decoder // Set FPnew OP and OPMOD as the APU op apu_op_o = {fpu_vec_op, fpu_op_mod, fpu_op}; + // No FPU or (ZFINX == 0 && MSTATUS.FS == FS_OFF) end else begin illegal_insn_o = 1'b1; @@ -1900,15 +1893,14 @@ module cv32e40px_decoder alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; unique case (instr_rdata_i[27:25]) - 3'b000: alu_operator_o = ALU_ADD; // cv.addNr - 3'b001: alu_operator_o = ALU_ADDU; // cv.adduNr - 3'b010: alu_operator_o = ALU_ADDR; // cv.addRNr - 3'b011: alu_operator_o = ALU_ADDUR; // cv.adduRNr - 3'b100: alu_operator_o = ALU_SUB; // cv.subNr - 3'b101: alu_operator_o = ALU_SUBU; // cv.subuNr - 3'b110: alu_operator_o = ALU_SUBR; // cv.subRNr - 3'b111: alu_operator_o = ALU_SUBUR; // cv.subuRNr - default: alu_operator_o = ALU_ADD; + 3'b001: alu_operator_o = ALU_ADDU; // cv.adduNr + 3'b010: alu_operator_o = ALU_ADDR; // cv.addRNr + 3'b011: alu_operator_o = ALU_ADDUR; // cv.adduRNr + 3'b100: alu_operator_o = ALU_SUB; // cv.subNr + 3'b101: alu_operator_o = ALU_SUBU; // cv.subuNr + 3'b110: alu_operator_o = ALU_SUBR; // cv.subRNr + 3'b111: alu_operator_o = ALU_SUBUR; // cv.subuRNr + default: alu_operator_o = ALU_ADD; // cv.addNr endcase end @@ -2085,7 +2077,6 @@ module cv32e40px_decoder // decide between using unsigned and rounding, and combinations unique case ({instr_rdata_i[31:30], instr_rdata_i[12]}) - {2'b00, 1'b0}: alu_operator_o = ALU_ADD; // cv.addN {2'b01, 1'b0}: alu_operator_o = ALU_ADDU; // cv.adduN {2'b10, 1'b0}: alu_operator_o = ALU_ADDR; // cv.addRN {2'b11, 1'b0}: alu_operator_o = ALU_ADDUR; // cv.adduRN @@ -2093,12 +2084,12 @@ module cv32e40px_decoder {2'b01, 1'b1}: alu_operator_o = ALU_SUBU; // cv.subuN {2'b10, 1'b1}: alu_operator_o = ALU_SUBR; // cv.subRN {2'b11, 1'b1}: alu_operator_o = ALU_SUBUR; // cv.subuRN - default : alu_operator_o = ALU_ADD; + default : alu_operator_o = ALU_ADD; // cv.addN endcase end - 2'b10, 2'b11: begin + default: begin // MUL/MAC with subword selection alu_en = 1'b0; mult_int_en = 1'b1; @@ -2126,7 +2117,6 @@ module cv32e40px_decoder mult_operator_o = MUL_I; end end - default: illegal_insn_o = 1'b1; endcase end else begin illegal_insn_o = 1'b1; @@ -2267,6 +2257,11 @@ module cv32e40px_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01001_0: begin // cv.sra alu_operator_o = ALU_SRA; @@ -2278,6 +2273,11 @@ module cv32e40px_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01010_0: begin // cv.sll alu_operator_o = ALU_SLL; @@ -2289,6 +2289,11 @@ module cv32e40px_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01011_0: begin // cv.or alu_operator_o = ALU_OR; @@ -2425,6 +2430,11 @@ module cv32e40px_decoder end default: illegal_insn_o = 1'b1; endcase + // Imm6 restrictions + if ((instr_rdata_i[12] == 1'b0 && instr_rdata_i[24:20] != 5'b0) || + (instr_rdata_i[12] == 1'b1 && instr_rdata_i[24:21] != 4'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b11000_0: begin // cv.shuffle, cv.shuffleI0 alu_operator_o = ALU_SHUF; @@ -2439,6 +2449,10 @@ module cv32e40px_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restriction + if (instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:21] != 4'b0) begin + illegal_insn_o = 1'b1; + end end 6'b11001_0, 6'b11010_0, diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv index 3beaf022..02876108 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_ex_stage.sv @@ -266,7 +266,7 @@ module cv32e40px_ex_stage if (regfile_we_lsu) begin regfile_we_wb_o = 1'b1; - regfile_we_wb_power_o = !COREV_PULP ? 1'b1 : ~data_misaligned_ex_i & wb_ready_i; + regfile_we_wb_power_o = (COREV_PULP == 0) ? 1'b1 : ~data_misaligned_ex_i & wb_ready_i; if (apu_valid & (!apu_singlecycle & !apu_multicycle)) begin wb_contention_lsu = 1'b1; end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv index 54add99d..126a1f44 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_fp_wrapper.sv @@ -14,7 +14,7 @@ module cv32e40px_fp_wrapper import cv32e40px_apu_core_pkg::*; #( - parameter FPU_ADDMUL_LAT = 0, // Floating-Point ADDition/MULtiplication computing lane pipeline registers number + parameter FPU_ADDMUL_LAT = 0, // Floating-Point ADDition/MULtiplication computing lane pipeline registers number parameter FPU_OTHERS_LAT = 0 // Floating-Point COMParison/CONVersion computing lanes pipeline registers number ) ( // Clock and Reset diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv index 6e996c32..9f1f668b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv @@ -1772,9 +1772,13 @@ module cv32e40px_id_stage if (id_valid_o) begin // unstall the whole pipeline alu_en_ex_o <= alu_en; if (alu_en) begin - alu_operator_ex_o <= alu_operator; - alu_operand_a_ex_o <= alu_operand_a; - alu_operand_b_ex_o <= alu_operand_b; + alu_operator_ex_o <= alu_operator; + alu_operand_a_ex_o <= alu_operand_a; + if (alu_op_b_mux_sel == OP_B_REGB_OR_FWD && (alu_operator == ALU_CLIP || alu_operator == ALU_CLIPU)) begin + alu_operand_b_ex_o <= {1'b0, alu_operand_b[30:0]}; + end else begin + alu_operand_b_ex_o <= alu_operand_b; + end alu_operand_c_ex_o <= alu_operand_c; bmask_a_ex_o <= bmask_a_id; bmask_b_ex_o <= bmask_b_id; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_load_store_unit.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_load_store_unit.sv index 674da664..92194ccd 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_load_store_unit.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_load_store_unit.sv @@ -121,18 +121,18 @@ module cv32e40px_load_store_unit #( 2'b00: begin // Writing a word if (misaligned_st == 1'b0) begin // non-misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b1111; - 2'b01: data_be = 4'b1110; - 2'b10: data_be = 4'b1100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b1111; + 2'b01: data_be = 4'b1110; + 2'b10: data_be = 4'b1100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end else begin // misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0000; // this is not used, but included for completeness - 2'b01: data_be = 4'b0001; - 2'b10: data_be = 4'b0011; - 2'b11: data_be = 4'b0111; + 2'b01: data_be = 4'b0001; + 2'b10: data_be = 4'b0011; + 2'b11: data_be = 4'b0111; + default: data_be = 4'b0000; // this is not used, but included for completeness endcase ; // case (data_addr_int[1:0]) end @@ -141,10 +141,10 @@ module cv32e40px_load_store_unit #( 2'b01: begin // Writing a half word if (misaligned_st == 1'b0) begin // non-misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0011; - 2'b01: data_be = 4'b0110; - 2'b10: data_be = 4'b1100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b0011; + 2'b01: data_be = 4'b0110; + 2'b10: data_be = 4'b1100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end else begin // misaligned case @@ -154,10 +154,10 @@ module cv32e40px_load_store_unit #( 2'b10, 2'b11: begin // Writing a byte case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0001; - 2'b01: data_be = 4'b0010; - 2'b10: data_be = 4'b0100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b0001; + 2'b01: data_be = 4'b0010; + 2'b10: data_be = 4'b0100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv index 217150c0..63a23228 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_register_file_latch.sv @@ -203,8 +203,8 @@ module cv32e40px_register_file #( mem[0] = '0; for (k = 1; k < NUM_WORDS; k++) begin : w_WordIter - if (~rst_n) mem[k] = '0; - else if (mem_clocks[k] == 1'b1) mem[k] = waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q; + if (~rst_n) mem[k] <= '0; + else if (mem_clocks[k] == 1'b1) mem[k] <= waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q; end end @@ -213,9 +213,9 @@ module cv32e40px_register_file #( always_latch begin : latch_wdata_fp if (FPU == 1) begin for (l = 0; l < NUM_FP_WORDS; l++) begin : w_WordIter - if (~rst_n) mem_fp[l] = '0; + if (~rst_n) mem_fp[l] <= '0; else if (mem_clocks[l+NUM_WORDS] == 1'b1) - mem_fp[l] = waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q; + mem_fp[l] <= waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q; end end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_top.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_top.sv index ad3dc986..03b99626 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_top.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_top.sv @@ -1,15 +1,27 @@ -// Copyright 2018 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this 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. - -// Top file instantiating a CV32E40P core and an optional FPU -// Contributor: Davide Schiavone +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// 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. + +///////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Pascal Gouedo, Dolphin Design // +// // +// Description: Top level module of CV32E40P instantiating the Core and // +// an optional CVFPU with its clock gating cell. // +// // +///////////////////////////////////////////////////////////////////////////// module cv32e40px_top import cv32e40px_core_v_xif_pkg::*; @@ -105,7 +117,7 @@ module cv32e40px_top import cv32e40px_apu_core_pkg::*; // Core to FPU - logic clk; + logic apu_busy; logic apu_req; logic [ APU_NARGS_CPU-1:0][31:0] apu_operands; logic [ APU_WOP_CPU-1:0] apu_op; @@ -117,6 +129,8 @@ module cv32e40px_top logic [ 31:0] apu_rdata; logic [APU_NUSFLAGS_CPU-1:0] apu_rflags; + logic apu_clk_en, apu_clk; + // Instantiate the Core cv32e40px_core #( .COREV_X_IF (COREV_X_IF), @@ -155,6 +169,7 @@ module cv32e40px_top .data_wdata_o (data_wdata_o), .data_rdata_i (data_rdata_i), + .apu_busy_o (apu_busy), .apu_req_o (apu_req), .apu_gnt_i (apu_gnt), .apu_operands_o(apu_operands), @@ -211,12 +226,15 @@ module cv32e40px_top generate if (FPU) begin : fpu_gen + + assign apu_clk_en = apu_req | apu_busy; + // FPU clock gate cv32e40px_clock_gate core_clock_gate_i ( .clk_i (clk_i), - .en_i (!core_sleep_o), + .en_i (apu_clk_en), .scan_cg_en_i(scan_cg_en_i), - .clk_o (clk) + .clk_o (apu_clk) ); // Instantiate the FPU wrapper @@ -224,7 +242,7 @@ module cv32e40px_top .FPU_ADDMUL_LAT(FPU_ADDMUL_LAT), .FPU_OTHERS_LAT(FPU_OTHERS_LAT) ) fp_wrapper_i ( - .clk_i (clk), + .clk_i (apu_clk), .rst_ni (rst_ni), .apu_req_i (apu_req), .apu_gnt_o (apu_gnt), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv index fe147124..dc890797 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv @@ -8,16 +8,16 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -//////////////////////////////////////////////////////////////////////////////// -// Engineer: Moritz Imfeld - moimfeld@student.ethz.ch // -// // -// Design Name: x-interface dispatcher // -// Project Name: cv32e40px // -// Language: SystemVerilog // -// // -// Description: Dispatcher for sending instructions to the x-interface. // -// // -//////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Engineer: Moritz Imfeld - moimfeld@ee.ethz.ch // +// // +// Design Name: x-interface dispatcher // +// Project Name: cv32e40px // +// Language: SystemVerilog // +// // +// Description: Dispatcher for sending instructions to the x-interface. // +// // +///////////////////////////////////////////////////////////////////////////// module cv32e40px_x_disp import cv32e40px_core_v_xif_pkg::*; @@ -107,6 +107,7 @@ module cv32e40px_x_disp logic x_if_not_ready; logic x_if_memory_instr; logic illegal_forwarding_prevention; + logic x_issue_illegal; // issue interface assign x_issue_valid_o = x_illegal_insn_dec_i & ~branch_or_jump_i & ~instr_offloaded_q & instr_valid_i & ~illegal_forwarding_prevention; @@ -243,10 +244,11 @@ module cv32e40px_x_disp end end - // illegal instruction assertion + // illegal instruction assignment + assign x_issue_illegal = x_illegal_insn_dec_i & ~instr_offloaded_q & instr_valid_i; always_comb begin x_illegal_insn_o = 1'b0; - if (x_issue_valid_o & x_issue_ready_i & ~x_issue_resp_accept_i) begin + if (x_issue_illegal & x_issue_ready_i & ~x_issue_resp_accept_i) begin x_illegal_insn_o = 1'b1; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv index 4f79b67f..aff3d0d4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_core.sv @@ -625,14 +625,12 @@ module cve2_core import cve2_pkg::*; #( assign outstanding_store_id = id_stage_i.instr_executing & id_stage_i.lsu_req_dec & id_stage_i.lsu_we; - begin : gen_no_wb_stage - // Without writeback stage only look into whether load or store is in ID to determine if - // a response is expected. - assign outstanding_load_resp = outstanding_load_id; - assign outstanding_store_resp = outstanding_store_id; + // Without writeback stage only look into whether load or store is in ID to determine if + // a response is expected. + assign outstanding_load_resp = outstanding_load_id; + assign outstanding_store_resp = outstanding_store_id; - `ASSERT(NoMemRFWriteWithoutPendingLoad, rf_we_lsu |-> outstanding_load_id, clk_i, !rst_ni) - end + `ASSERT(NoMemRFWriteWithoutPendingLoad, rf_we_lsu |-> outstanding_load_id, clk_i, !rst_ni) `ASSERT(NoMemResponseWithoutPendingAccess, data_rvalid_i |-> outstanding_load_resp | outstanding_store_resp, clk_i, !rst_ni) @@ -1094,6 +1092,9 @@ module cve2_core import cve2_pkg::*; #( rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o; end + else begin + rvfi_stage_trap[i] <= 0; + end end else begin rvfi_stage_halt[i] <= rvfi_stage_halt[i-1]; rvfi_stage_trap[i] <= rvfi_stage_trap[i-1]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv index dfce0985..9678638d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_cs_registers.sv @@ -24,6 +24,7 @@ module cve2_cs_registers #( parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast, parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone ) ( + // Clock and Reset input logic clk_i, input logic rst_ni, @@ -103,7 +104,7 @@ module cve2_cs_registers #( input logic div_wait_i // core waiting for divide ); - import cve2_pkg::*; +import cve2_pkg::*; localparam int unsigned RV32BEnabled = (RV32B == RV32BNone) ? 0 : 1; localparam int unsigned RV32MEnabled = (RV32M == RV32MNone) ? 0 : 1; @@ -1444,7 +1445,83 @@ module cve2_cs_registers #( // CPU control register // ////////////////////////// - // Removed +`ifdef RVFI + logic [63:0] mstatus_extended_read; + logic [63:0] mstatus_extended_write; + + assign mstatus_extended_read[CSR_MSTATUS_MIE_BIT] = mstatus_q.mie; + assign mstatus_extended_read[CSR_MSTATUS_MPIE_BIT] = mstatus_q.mpie; + assign mstatus_extended_read[CSR_MSTATUS_MPP_BIT_HIGH:CSR_MSTATUS_MPP_BIT_LOW] = mstatus_q.mpp; + assign mstatus_extended_read[CSR_MSTATUS_MPRV_BIT] = mstatus_q.mprv; + assign mstatus_extended_read[CSR_MSTATUS_TW_BIT] = mstatus_q.tw; + + assign mstatus_extended_write[CSR_MSTATUS_MIE_BIT] = mstatus_d.mie; + assign mstatus_extended_write[CSR_MSTATUS_MPIE_BIT] = mstatus_d.mpie; + assign mstatus_extended_write[CSR_MSTATUS_MPP_BIT_HIGH:CSR_MSTATUS_MPP_BIT_LOW] = mstatus_d.mpp; + assign mstatus_extended_write[CSR_MSTATUS_MPRV_BIT] = mstatus_d.mprv; + assign mstatus_extended_write[CSR_MSTATUS_TW_BIT] = mstatus_d.tw; + + wire [63:0] rvfi_csr_bypass; + + assign rvfi_csr_bypass = csr_save_cause_i; + + bit [63:0] rvfi_csr_addr; + bit [63:0] rvfi_csr_rdata; + bit [63:0] rvfi_csr_wdata; + bit [63:0] rvfi_csr_rmask; + bit [63:0] rvfi_csr_wmask; + wire [63:0] rvfi_csr_wmask_q; + wire [63:0] rvfi_csr_rmask_q; + assign rvfi_csr_if.rvfi_csr_addr = rvfi_csr_addr; + assign rvfi_csr_if.rvfi_csr_rdata = rvfi_csr_rdata; + assign rvfi_csr_if.rvfi_csr_wdata = rvfi_csr_wdata; + assign rvfi_csr_if.rvfi_csr_rmask = rvfi_csr_rmask; + assign rvfi_csr_if.rvfi_csr_wmask = rvfi_csr_wmask; + assign rvfi_csr_rmask_q = ((~csr_wr & csr_op_en_i & ~illegal_csr_insn_o)) ? -1 : 0; + assign rvfi_csr_wmask_q = ((csr_wr & csr_op_en_i & ~illegal_csr_insn_o)) ? -1 : 0; + always @(posedge clknrst_if.clk) begin + rvfi_csr_addr = csr_addr_i; + rvfi_csr_rdata = csr_rdata_int; + rvfi_csr_wdata = csr_wdata_int; + rvfi_csr_rmask = (rvfi_csr_rmask_q); + rvfi_csr_wmask = (rvfi_csr_wmask_q); + end + +`define RVFI_CONNECT(CSR_ADDR, CSR_NAME, CSR_RDATA, CSR_WDATA, CSR_RMASK, CSR_WMASK) \ + bit [63:0] rvfi_``CSR_NAME``_csr_rdata;\ + bit [63:0] rvfi_``CSR_NAME``_csr_wdata;\ + bit [63:0] rvfi_``CSR_NAME``_csr_rmask;\ + bit [63:0] rvfi_``CSR_NAME``_csr_wmask;\ + wire [63:0] rvfi_``CSR_NAME``_csr_wmask_q; \ + wire [63:0] rvfi_``CSR_NAME``_csr_rmask_q; \ + assign rvfi_csr_if.rvfi_named_csr_rdata[CSR_ADDR] = (!rvfi_csr_bypass) ? rvfi_``CSR_NAME``_csr_rdata : ``CSR_RDATA``; \ + assign rvfi_csr_if.rvfi_named_csr_wdata[CSR_ADDR] = (!rvfi_csr_bypass) ? rvfi_``CSR_NAME``_csr_wdata : ``CSR_WDATA``; \ + assign rvfi_csr_if.rvfi_named_csr_rmask[CSR_ADDR] = (!rvfi_csr_bypass) ? rvfi_``CSR_NAME``_csr_rmask : rvfi_``CSR_NAME``_csr_rmask_q; \ + assign rvfi_csr_if.rvfi_named_csr_wmask[CSR_ADDR] = (!rvfi_csr_bypass) ? rvfi_``CSR_NAME``_csr_wmask : rvfi_``CSR_NAME``_csr_wmask_q; \ + assign rvfi_``CSR_NAME``_csr_rmask_q = ((~csr_wr & csr_op_en_i & ~illegal_csr_insn_o & (csr_addr_i == CSR_ADDR)) CSR_RMASK) ? -1 : 0; \ + assign rvfi_``CSR_NAME``_csr_wmask_q = ((csr_wr & csr_op_en_i & ~illegal_csr_insn_o & (csr_addr_i == CSR_ADDR)) CSR_WMASK) ? -1 : 0; \ + always @(posedge clknrst_if.clk) begin \ + rvfi_``CSR_NAME``_csr_rdata = ``CSR_RDATA``; \ + rvfi_``CSR_NAME``_csr_wdata = ``CSR_WDATA``; \ + rvfi_``CSR_NAME``_csr_rmask = (rvfi_``CSR_NAME``_csr_rmask_q); \ + rvfi_``CSR_NAME``_csr_wmask = (rvfi_``CSR_NAME``_csr_wmask_q); \ + end + + `RVFI_CONNECT( CSR_MSTATUS, mstatus , mstatus_extended_read , mstatus_extended_write , , || mstatus_en) + `RVFI_CONNECT( CSR_MIE, mie , mie_q , mie_d , , || mie_en ) + `RVFI_CONNECT( CSR_MIP, mip , mip , csr_wdata_i , , ) + `RVFI_CONNECT( CSR_MISA, misa , MISA_VALUE , csr_wdata_i , , ) + `RVFI_CONNECT( CSR_MTVEC, mtvec , mtvec_q , mtvec_d , , || mtvec_en ) + `RVFI_CONNECT( CSR_MEPC, mepc , mepc_q , mepc_d , , || mepc_en ) + `RVFI_CONNECT( CSR_MCAUSE, mcause , mcause_q , mcause_d , , || mcause_en ) + `RVFI_CONNECT( CSR_MTVAL, mtval , mtval_q , mtval_d , , || mtval_en ) + `RVFI_CONNECT( CSR_MSTATUSH, mstatush , 'h0 , csr_wdata_i , , ) + `RVFI_CONNECT( CSR_DCSR, dcsr , dcsr_q , dcsr_d , , || dcsr_en) + `RVFI_CONNECT( CSR_DPC, dpc , depc_q , depc_d , , || depc_en) + `RVFI_CONNECT( CSR_DSCRATCH0, dscratch0 , dscratch0_q , csr_wdata_i , , || dscratch0_en) + `RVFI_CONNECT( CSR_DSCRATCH1, dscratch1 , dscratch1_q , csr_wdata_i , , || dscratch1_en) + +`endif //////////////// // Assertions // diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv index 20b2b62b..60933a03 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_fetch_fifo.sv @@ -225,7 +225,6 @@ module cve2_fetch_fifo #( end for (genvar i = 0; i < DEPTH; i++) begin : g_fifo_regs - begin : g_rdata always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rdata_q[i] <= '0; @@ -235,7 +234,6 @@ module cve2_fetch_fifo #( err_q[i] <= err_d[i]; end end - end end //////////////// diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv index e989ff29..e7ebf52c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_id_stage.sv @@ -755,6 +755,7 @@ module cve2_id_stage #( // Signal which instructions to count as retired in minstret, all traps along with ebrk and // ecall instructions are not counted. assign instr_perf_count_id_o = ~ebrk_insn & ~ecall_insn_dec & ~illegal_insn_dec & + ~(dret_insn_dec & ~debug_mode_o) & ~illegal_csr_insn_i & ~instr_fetch_err_i; // An instruction is ready to move to the writeback diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv index 6cd8f4b1..2e5b3535 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_pkg.sv @@ -574,5 +574,85 @@ package cve2_pkg; // alter this to point to their system specific configuration data structure. localparam logic [31:0] CSR_MCONFIGPTR_VALUE = 32'b0; + // RVFI CSR element + typedef struct packed { + bit [63:0] rdata; + bit [63:0] rmask; + bit [63:0] wdata; + bit [63:0] wmask; + } rvfi_csr_elmt_t; + + // RVFI CSR structure + typedef struct packed { + rvfi_csr_elmt_t fflags; + rvfi_csr_elmt_t frm; + rvfi_csr_elmt_t fcsr; + rvfi_csr_elmt_t ftran; + rvfi_csr_elmt_t dcsr; + rvfi_csr_elmt_t dpc; + rvfi_csr_elmt_t dscratch0; + rvfi_csr_elmt_t dscratch1; + rvfi_csr_elmt_t sstatus; + rvfi_csr_elmt_t sie; + rvfi_csr_elmt_t sip; + rvfi_csr_elmt_t stvec; + rvfi_csr_elmt_t scounteren; + rvfi_csr_elmt_t sscratch; + rvfi_csr_elmt_t sepc; + rvfi_csr_elmt_t scause; + rvfi_csr_elmt_t stval; + rvfi_csr_elmt_t satp; + rvfi_csr_elmt_t mstatus; + rvfi_csr_elmt_t mstatush; + rvfi_csr_elmt_t misa; + rvfi_csr_elmt_t medeleg; + rvfi_csr_elmt_t mideleg; + rvfi_csr_elmt_t mie; + rvfi_csr_elmt_t mtvec; + rvfi_csr_elmt_t mcounteren; + rvfi_csr_elmt_t mscratch; + rvfi_csr_elmt_t mepc; + rvfi_csr_elmt_t mcause; + rvfi_csr_elmt_t mtval; + rvfi_csr_elmt_t mip; + rvfi_csr_elmt_t menvcfg; + rvfi_csr_elmt_t menvcfgh; + rvfi_csr_elmt_t mvendorid; + rvfi_csr_elmt_t marchid; + rvfi_csr_elmt_t mhartid; + rvfi_csr_elmt_t mcountinhibit; + rvfi_csr_elmt_t mcycle; + rvfi_csr_elmt_t mcycleh; + rvfi_csr_elmt_t minstret; + rvfi_csr_elmt_t minstreth; + rvfi_csr_elmt_t cycle; + rvfi_csr_elmt_t cycleh; + rvfi_csr_elmt_t instret; + rvfi_csr_elmt_t instreth; + rvfi_csr_elmt_t dcache; + rvfi_csr_elmt_t icache; + rvfi_csr_elmt_t acc_cons; + rvfi_csr_elmt_t pmpcfg0; + rvfi_csr_elmt_t pmpcfg1; + rvfi_csr_elmt_t pmpcfg2; + rvfi_csr_elmt_t pmpcfg3; + rvfi_csr_elmt_t pmpaddr0; + rvfi_csr_elmt_t pmpaddr1; + rvfi_csr_elmt_t pmpaddr2; + rvfi_csr_elmt_t pmpaddr3; + rvfi_csr_elmt_t pmpaddr4; + rvfi_csr_elmt_t pmpaddr5; + rvfi_csr_elmt_t pmpaddr6; + rvfi_csr_elmt_t pmpaddr7; + rvfi_csr_elmt_t pmpaddr8; + rvfi_csr_elmt_t pmpaddr9; + rvfi_csr_elmt_t pmpaddr10; + rvfi_csr_elmt_t pmpaddr11; + rvfi_csr_elmt_t pmpaddr12; + rvfi_csr_elmt_t pmpaddr13; + rvfi_csr_elmt_t pmpaddr14; + rvfi_csr_elmt_t pmpaddr15; + } rvfi_csr_t; + endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv index 989e83d7..7589bc3a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e20/rtl/cve2_top_tracing.sv @@ -11,7 +11,6 @@ module cve2_top_tracing import cve2_pkg::*; #( parameter int unsigned MHPMCounterWidth = 40, parameter bit RV32E = 1'b0, parameter rv32m_e RV32M = RV32MFast, - parameter bit BranchPredictor = 1'b0, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -112,7 +111,6 @@ module cve2_top_tracing import cve2_pkg::*; #( .MHPMCounterWidth ( MHPMCounterWidth ), .RV32E ( RV32E ), .RV32M ( RV32M ), - .BranchPredictor ( BranchPredictor ), .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) ) u_cve2_top ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson index b122083e..fcaf1619 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/openhwgroup/cv32e40p.git - rev: 370cf19b3b60cbdc847ff102551392dd501029a2 + rev: a43277c0dc64c02be3f5d713438f315ecffde2b9 } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson index 5b2ce889..9712edb0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/openhwgroup/cv32e40p.git", - rev: "370cf19b3b60cbdc847ff102551392dd501029a2", + rev: "a43277c0dc64c02be3f5d713438f315ecffde2b9", }, patch_dir: "patches/openhwgroup_cv32e40p", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore index 66eb251a..6c2cd791 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/.gitignore @@ -19,8 +19,10 @@ TAGS /Bender.lock /Bender.local golden_reference_design +ref_design golden.src revised.src cadence_conformal synopsys_formality questa_autocheck +reports diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh index a89ed4e4..355bc738 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_instr_trace.svh @@ -1,23 +1,37 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2020 Silicon Labs, Inc. // -// Licensed under the Solderpad Hardware Licence, 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 +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"). // -// https://solderpad.org/licenses/ +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// +// You may obtain a copy of the License at: +// +// https://solderpad.org/licenses/SHL-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. +// and hardware implementations thereof distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// // See the License for the specific language governing permissions and // limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Tracer data structures and functions -// -// Contributors: Steve Richmond, Silicon Labs -// Pascal Gouedo, Dolphin Design +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Steve Richmond - steve.richmond@silabs.com // +// // +// Design Name: cv32e40p_tracer data structures // +// Project Name: CV32E40P // +// Language: SystemVerilog // +// // +// Description: Moves the class definition for instr_trace_t out of the // +// tracer module for readability and code partitioning // +// // +// Includes various enhancements to make the instr_trace_t // +// class more comprehensive // +// // +//////////////////////////////////////////////////////////////////////////////// typedef struct { logic [5:0] addr; @@ -35,9 +49,13 @@ typedef struct { class instr_trace_t; time simtime; + time stoptime; + bit external_time; int cycles; + int stopcycles; logic [31:0] pc; logic [31:0] instr; + string ctx; //Used to add context in the trace log file (Canceled, debug, interrput,....) bit compressed; bit wb_bypass; bit misaligned; @@ -56,10 +74,15 @@ class instr_trace_t; regs_read = {}; regs_write = {}; mem_access = {}; + external_time = 0; + stoptime = 0; + stopcycles = 0; endfunction function void init(int unsigned cycles, bit [31:0] pc, bit compressed, bit [31:0] instr); - this.simtime = $time; + if(!this.external_time) begin + this.simtime = $time; + end this.cycles = cycles; this.pc = pc; this.compressed = compressed; @@ -308,7 +331,23 @@ class instr_trace_t; begin string insn_str; // Accumulate writes into a single string to enable single $fwrite - insn_str = $sformatf("%t %15d %h %h %-36s", simtime, cycles, pc, instr, str); + if(simtime < 100ns) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100us) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 1ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 10ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else if (simtime < 100ms) begin + insn_str = $sformatf(" %t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end else begin + insn_str = $sformatf("%t %15d %h %h %-3s %-36s", simtime, cycles, pc, instr, ctx, str); + end foreach (regs_write[i]) begin if (regs_write[i].addr != 0) @@ -330,6 +369,12 @@ class instr_trace_t; insn_str = $sformatf("%s PA:%08x", insn_str, mem_acc.addr); end + casex (instr) + INSTR_FDIV: insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + INSTR_FSQRT:insn_str = $sformatf("%s %15d %t", insn_str, stopcycles, stoptime); + default: ; + endcase + $fwrite(f, "%s\n", insn_str); end endfunction @@ -489,7 +534,7 @@ class instr_trace_t; begin mnemonic = {compressed ? "c." : "", mnemonic}; regs_read.push_back('{rs1, rs1_value, 0}); - str = $sformatf("%-16s %s, %0d", mnemonic, regAddrToStr(rs1), $signed(imm_sb_type)); + str = $sformatf("%-16s %s, %0d, %0d", mnemonic, regAddrToStr(rs1), $signed(imm_s2_type), $signed(imm_sb_type)); end endfunction // printSBInstr @@ -587,14 +632,14 @@ class instr_trace_t; // immediate post-incremented load regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %0d(x%0d!)", mnemonic, regAddrToStr(rd), $signed(imm_i_type), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %0d", mnemonic, regAddrToStr(rd), rs1, $signed(imm_i_type)); end else if (instr[6:0] == OPCODE_CUSTOM_1) begin if (instr[27] == 1'b0) begin // reg-reg post-incremented load regs_read.push_back('{rs2, rs2_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %s(x%0d!)", mnemonic, regAddrToStr(rd), regAddrToStr(rs2), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rd), rs1, regAddrToStr(rs2)); end else begin // reg-reg indexed load regs_read.push_back('{rs2, rs2_value, 0}); @@ -637,7 +682,7 @@ class instr_trace_t; regs_read.push_back('{rs2, rs2_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-14s %s, %0d(x%0d!)", mnemonic, regAddrToStr(rs2), $signed(imm_s_type), rs1); + str = $sformatf("cv.%-14s %s, (x%0d), %0d", mnemonic, regAddrToStr(rs2), rs1, $signed(imm_s_type)); end else if (instr[31:28] == 4'b0010) begin if (instr[27] == 1'b0) begin // reg-reg post-incremented store @@ -645,7 +690,7 @@ class instr_trace_t; regs_read.push_back('{rs3, rs3_value, 0}); regs_read.push_back('{rs1, rs1_value, 0}); regs_write.push_back('{rs1, 'x, 0}); - str = $sformatf("cv.%-13s %s, %s(x%0d!)", mnemonic, regAddrToStr(rs2), regAddrToStr(rs3), rs1); + str = $sformatf("cv.%-13s %s, (x%0d), %s", mnemonic, regAddrToStr(rs2), rs1, regAddrToStr(rs3)); end else begin // reg-reg indexed store regs_read.push_back('{rs2, rs2_value, 0}); @@ -757,238 +802,429 @@ class instr_trace_t; else str_hb = ".h"; // set mnemonic - case (instr[31:26]) - 6'b000000: begin + case (instr) + INSTR_CVADDH , + INSTR_CVADDSCH , + INSTR_CVADDSCIH, + INSTR_CVADDB , + INSTR_CVADDSCB , + INSTR_CVADDSCIB : begin mnemonic = "cv.add"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000010: begin + INSTR_CVSUBH , + INSTR_CVSUBSCH , + INSTR_CVSUBSCIH, + INSTR_CVSUBB , + INSTR_CVSUBSCB , + INSTR_CVSUBSCIB : begin mnemonic = "cv.sub"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000100: begin + INSTR_CVAVGH , + INSTR_CVAVGSCH , + INSTR_CVAVGSCIH , + INSTR_CVAVGB , + INSTR_CVAVGSCB , + INSTR_CVAVGSCIB : begin mnemonic = "cv.avg"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000110: begin + INSTR_CVAVGUH , + INSTR_CVAVGUSCH , + INSTR_CVAVGUSCIH, + INSTR_CVAVGUB , + INSTR_CVAVGUSCB , + INSTR_CVAVGUSCIB : begin mnemonic = "cv.avgu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001000: begin + INSTR_CVMINH , + INSTR_CVMINSCH , + INSTR_CVMINSCIH, + INSTR_CVMINB , + INSTR_CVMINSCB , + INSTR_CVMINSCIB : begin mnemonic = "cv.min"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001010: begin + INSTR_CVMINUH , + INSTR_CVMINUSCH , + INSTR_CVMINUSCIH, + INSTR_CVMINUB , + INSTR_CVMINUSCB , + INSTR_CVMINUSCIB : begin mnemonic = "cv.minu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001100: begin + INSTR_CVMAXH , + INSTR_CVMAXSCH , + INSTR_CVMAXSCIH , + INSTR_CVMAXB , + INSTR_CVMAXSCB , + INSTR_CVMAXSCIB : begin mnemonic = "cv.max"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001110: begin + INSTR_CVMAXUH , + INSTR_CVMAXUSCH , + INSTR_CVMAXUSCIH , + INSTR_CVMAXUB , + INSTR_CVMAXUSCB , + INSTR_CVMAXUSCIB : begin mnemonic = "cv.maxu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010000: begin + INSTR_CVSRLH , + INSTR_CVSRLSCH , + INSTR_CVSRLSCIH , + INSTR_CVSRLB , + INSTR_CVSRLSCB , + INSTR_CVSRLSCIB : begin mnemonic = "cv.srl"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010010: begin + INSTR_CVSRAH , + INSTR_CVSRASCH , + INSTR_CVSRASCIH, + INSTR_CVSRAB , + INSTR_CVSRASCB , + INSTR_CVSRASCIB : begin mnemonic = "cv.sra"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010100: begin + INSTR_CVSLLH , + INSTR_CVSLLSCH , + INSTR_CVSLLSCIH, + INSTR_CVSLLB , + INSTR_CVSLLSCB , + INSTR_CVSLLSCIB : begin mnemonic = "cv.sll"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b010110: begin + INSTR_CVORH , + INSTR_CVORSCH , + INSTR_CVORSCIH, + INSTR_CVORB , + INSTR_CVORSCB , + INSTR_CVORSCIB : begin mnemonic = "cv.or"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011000: begin + INSTR_CVXORH , + INSTR_CVXORSCH , + INSTR_CVXORSCIH , + INSTR_CVXORB , + INSTR_CVXORSCB , + INSTR_CVXORSCIB : begin mnemonic = "cv.xor"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011010: begin + INSTR_CVANDH , + INSTR_CVANDSCH , + INSTR_CVANDSCIH , + INSTR_CVANDB , + INSTR_CVANDSCB , + INSTR_CVANDSCIB : begin mnemonic = "cv.and"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b011100: begin + INSTR_CVABSH, + INSTR_CVABSB : begin mnemonic = "cv.abs"; str_imm = $sformatf("0x%0h", imm_vs_type); end // dot products - 6'b100000: begin + INSTR_CVDOTUPH , + INSTR_CVDOTUPSCH , + INSTR_CVDOTUPSCIH, + INSTR_CVDOTUPB , + INSTR_CVDOTUPSCB , + INSTR_CVDOTUPSCIB : begin mnemonic = "cv.dotup"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b100010: begin + INSTR_CVDOTUSPH , + INSTR_CVDOTUSPSCH , + INSTR_CVDOTUSPSCIH, + INSTR_CVDOTUSPB , + INSTR_CVDOTUSPSCB , + INSTR_CVDOTUSPSCIB : begin mnemonic = "cv.dotusp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b100100: begin + INSTR_CVDOTSPH , + INSTR_CVDOTSPSCH , + INSTR_CVDOTSPSCIH, + INSTR_CVDOTSPB , + INSTR_CVDOTSPSCB , + INSTR_CVDOTSPSCIB : begin mnemonic = "cv.dotsp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b100110: begin + INSTR_CVSDOTUPH , + INSTR_CVSDOTUPSCH , + INSTR_CVSDOTUPSCIH, + INSTR_CVSDOTUPB , + INSTR_CVSDOTUPSCB , + INSTR_CVSDOTUPSCIB : begin mnemonic = "cv.sdotup"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b101000: begin + INSTR_CVSDOTUSPH , + INSTR_CVSDOTUSPSCH , + INSTR_CVSDOTUSPSCIH, + INSTR_CVSDOTUSPB , + INSTR_CVSDOTUSPSCB , + INSTR_CVSDOTUSPSCIB : begin mnemonic = "cv.sdotusp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b101010: begin + INSTR_CVSDOTSPH , + INSTR_CVSDOTSPSCH , + INSTR_CVSDOTSPSCIH, + INSTR_CVSDOTSPB , + INSTR_CVSDOTSPSCB , + INSTR_CVSDOTSPSCIB : begin mnemonic = "cv.sdotsp"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b101110: begin - case (instr[14:13]) - 2'b00 : begin - mnemonic = "cv.extract"; - str_imm = $sformatf("0x%0h", imm_vs_type); - end - 2'b01 : begin - mnemonic = "cv.extractu"; - str_imm = $sformatf("0x%0h", imm_vu_type); - end - 2'b10 : begin - mnemonic = "cv.insert"; - str_imm = $sformatf("0x%0h", imm_vs_type); - end - endcase - str_sci = ""; + INSTR_CVEXTRACTH, + INSTR_CVEXTRACTB : begin + mnemonic = "cv.extract"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; + end + INSTR_CVEXTRACTUH, + INSTR_CVEXTRACTUB : begin + mnemonic = "cv.extractu"; + str_imm = $sformatf("0x%0h", imm_vu_type); + str_sci = ""; + end + INSTR_CVINSERTH, + INSTR_CVINSERTB : begin + mnemonic = "cv.insert"; + str_imm = $sformatf("0x%0h", imm_vs_type); + str_sci = ""; end // shuffle/pack - 6'b110000: begin - if (instr[14:12] == 3'b111) begin - mnemonic = "cv.shuffleI0"; - str_imm = $sformatf("0x%8h", imm_shuffle_type); - end else begin + INSTR_CVSHUFFLEH , + INSTR_CVSHUFFLESCIH, + INSTR_CVSHUFFLEB : begin mnemonic = "cv.shuffle"; if (instr[14:12] == 3'b110) begin str_imm = $sformatf("0x%8h", imm_shuffle_type); end - end end - 6'b110010: begin + + INSTR_CVSHUFFLEL0SCIB : begin + mnemonic = "cv.shuffleI0"; + str_imm = $sformatf("0x%8h", imm_shuffle_type); + end + INSTR_CVSHUFFLEL1SCIB : begin mnemonic = "cv.shuffleI1"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b110100: begin + INSTR_CVSHUFFLEL2SCIB : begin mnemonic = "cv.shuffleI2"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b110110: begin + INSTR_CVSHUFFLEL3SCIB : begin mnemonic = "cv.shuffleI3"; str_imm = $sformatf("0x%8h", imm_shuffle_type); end - 6'b111000: begin + INSTR_CVSHUFFLE2H, + INSTR_CVSHUFFLE2B : begin mnemonic = "cv.shuffle2"; end - 6'b111100: begin + INSTR_CVPACK, + INSTR_CVPACKH : begin mnemonic = "cv.pack"; if (instr[25] == 1'b0) begin str_hb = ""; end end - 6'b111110: begin - mnemonic = instr[25] ? "cv.packhi" : "cv.packlo"; - end + INSTR_CVPACKHIB : mnemonic = "cv.packhi"; + INSTR_CVPACKLOB : mnemonic = "cv.packlo"; // comparisons - 6'b000001: begin + INSTR_CVCMPEQH , + INSTR_CVCMPEQSCH , + INSTR_CVCMPEQSCIH, + INSTR_CVCMPEQB , + INSTR_CVCMPEQSCB , + INSTR_CVCMPEQSCIB : begin mnemonic = "cv.cmpeq"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000011: begin + INSTR_CVCMPNEH , + INSTR_CVCMPNESCH , + INSTR_CVCMPNESCIH, + INSTR_CVCMPNEB , + INSTR_CVCMPNESCB , + INSTR_CVCMPNESCIB : begin mnemonic = "cv.cmpne"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000101: begin + INSTR_CVCMPGTH , + INSTR_CVCMPGTSCH , + INSTR_CVCMPGTSCIH, + INSTR_CVCMPGTB , + INSTR_CVCMPGTSCB , + INSTR_CVCMPGTSCIB : begin mnemonic = "cv.cmpgt"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b000111: begin + INSTR_CVCMPGEH , + INSTR_CVCMPGESCH , + INSTR_CVCMPGESCIH, + INSTR_CVCMPGEB , + INSTR_CVCMPGESCB , + INSTR_CVCMPGESCIB : begin mnemonic = "cv.cmpge"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001001: begin + INSTR_CVCMPLTH , + INSTR_CVCMPLTSCH , + INSTR_CVCMPLTSCIH, + INSTR_CVCMPLTB , + INSTR_CVCMPLTSCB , + INSTR_CVCMPLTSCIB : begin mnemonic = "cv.cmplt"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001011: begin + INSTR_CVCMPLEH , + INSTR_CVCMPLESCH , + INSTR_CVCMPLESCIH, + INSTR_CVCMPLEB , + INSTR_CVCMPLESCB , + INSTR_CVCMPLESCIB : begin mnemonic = "cv.cmple"; str_imm = $sformatf("0x%0h", imm_vs_type); end - 6'b001101: begin + INSTR_CVCMPGTUH , + INSTR_CVCMPGTUSCH , + INSTR_CVCMPGTUSCIH, + INSTR_CVCMPGTUB , + INSTR_CVCMPGTUSCB , + INSTR_CVCMPGTUSCIB : begin mnemonic = "cv.cmpgtu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b001111: begin + INSTR_CVCMPGEUH , + INSTR_CVCMPGEUSCH , + INSTR_CVCMPGEUSCIH, + INSTR_CVCMPGEUB , + INSTR_CVCMPGEUSCB , + INSTR_CVCMPGEUSCIB : begin mnemonic = "cv.cmpgeu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010001: begin + INSTR_CVCMPLTUH , + INSTR_CVCMPLTUSCH , + INSTR_CVCMPLTUSCIH, + INSTR_CVCMPLTUB , + INSTR_CVCMPLTUSCB , + INSTR_CVCMPLTUSCIB : begin mnemonic = "cv.cmpltu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010011: begin + INSTR_CVCMPLEUH , + INSTR_CVCMPLEUSCH , + INSTR_CVCMPLEUSCIH, + INSTR_CVCMPLEUB , + INSTR_CVCMPLEUSCB , + INSTR_CVCMPLEUSCIB : begin mnemonic = "cv.cmpleu"; str_imm = $sformatf("0x%0h", imm_vu_type); end - 6'b010101: begin - unique case (instr[14:13]) - 2'b00: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r" : "cv.cplxmul.i"; - 2'b01: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div2" : "cv.cplxmul.i.div2"; - 2'b10: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div4" : "cv.cplxmul.i.div4"; - 2'b11: mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div8" : "cv.cplxmul.i.div8"; - endcase + INSTR_CVCPLXMULR, + INSTR_CVCPLXMULI : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r" : "cv.cplxmul.i"; str_sci = ""; str_hb = ""; end - - 6'b010111: begin - mnemonic = "cv.cplxconj"; - str_sci = ""; + INSTR_CVCPLXMULRDIV2, + INSTR_CVCPLXMULIDIV2 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div2" : "cv.cplxmul.i.div2"; + str_sci = ""; str_hb = ""; end - - 6'b011001: begin - unique case (instr[14:13]) - 2'b00: mnemonic = "cv.subrotmj"; - 2'b01: mnemonic = "cv.subrotmj.div2"; - 2'b10: mnemonic = "cv.subrotmj.div4"; - 2'b11: mnemonic = "cv.subrotmj.div8"; - endcase + INSTR_CVCPLXMULRDIV4, + INSTR_CVCPLXMULIDIV4 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div4" : "cv.cplxmul.i.div4"; str_sci = ""; str_hb = ""; end - - 6'b011011: begin - unique case (instr[14:13]) - 2'b01: mnemonic = "cv.add.div2"; - 2'b10: mnemonic = "cv.add.div4"; - 2'b11: mnemonic = "cv.add.div8"; - endcase + INSTR_CVCPLXMULRDIV8, + INSTR_CVCPLXMULIDIV8 : begin + mnemonic = instr[25] == 1'b0 ? "cv.cplxmul.r.div8" : "cv.cplxmul.i.div8"; str_sci = ""; str_hb = ""; end - 6'b011101: begin - unique case (instr[14:13]) - 2'b01: mnemonic = "cv.sub.div2"; - 2'b10: mnemonic = "cv.sub.div4"; - 2'b11: mnemonic = "cv.sub.div8"; - endcase - str_sci = ""; + INSTR_CVCPLXCONJ : begin + mnemonic = "cv.cplxconj"; + str_sci = ""; str_hb = ""; end + INSTR_CVSUBROTMJ : begin + mnemonic = "cv.subrotmj"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV2 : begin + mnemonic = "cv.subrotmj.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV4 : begin + mnemonic = "cv.subrotmj.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBROTMJDIV8 : begin + mnemonic = "cv.subrotmj.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVADDIV2 : begin + mnemonic = "cv.add.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV4 : begin + mnemonic = "cv.add.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVADDIV8 : begin + mnemonic = "cv.add.div8"; + str_sci = ""; + str_hb = ""; + end + + INSTR_CVSUBIV2 : begin + mnemonic = "cv.sub.div2"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV4 : begin + mnemonic = "cv.sub.div4"; + str_sci = ""; + str_hb = ""; + end + INSTR_CVSUBIV8 : begin + mnemonic = "cv.sub.div8"; + str_sci = ""; + str_hb = ""; + end + default: begin printMnemonic("INVALID"); return; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv index 13a5beb0..99429d90 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi.sv @@ -1,24 +1,28 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P RVFI interface -// -// Contributors: Davide Schiavone, OpenHW Group -// Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: CV32E40P RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// `include "cv32e40p_rvfi_pkg.sv" @@ -27,7 +31,8 @@ module cv32e40p_rvfi import cv32e40p_rvfi_pkg::*; #( parameter FPU = 0, - parameter ZFINX = 0 + parameter ZFINX = 0, + parameter NUM_MHPMCOUNTERS = 1 ) ( input logic clk_i, input logic rst_ni, @@ -290,7 +295,7 @@ module cv32e40p_rvfi // performance counters // cycle, instret, hpcounter, cycleh, instreth, hpcounterh // mcycle, minstret, mhpcounter, mcycleh, minstreth, mhpcounterh - input logic [31:0][MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_q_i, + input logic [63:0][MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_q_i, input logic [31:0] csr_mhpmcounter_write_lower_i, input logic [31:0] csr_mhpmcounter_write_upper_i, @@ -327,6 +332,10 @@ module cv32e40p_rvfi // the convention of RISC-V Formal Interface Specification. output logic [ 0:0] rvfi_valid, output logic [63:0] rvfi_order, + output integer rvfi_start_cycle, + output time rvfi_start_time, + output integer rvfi_stop_cycle, + output time rvfi_stop_time, output logic [31:0] rvfi_insn, output rvfi_trap_t rvfi_trap, output logic [ 0:0] rvfi_halt, @@ -346,6 +355,7 @@ module cv32e40p_rvfi output logic rvfi_frd_wvalid [1:0], output logic [ 4:0] rvfi_frd_addr [1:0], output logic [31:0] rvfi_frd_wdata [1:0], + output logic rvfi_2_rd, output logic [ 4:0] rvfi_rs1_addr, output logic [ 4:0] rvfi_rs2_addr, output logic [ 4:0] rvfi_rs3_addr, @@ -366,8 +376,8 @@ module cv32e40p_rvfi output logic [31:0] rvfi_pc_wdata, output logic [31:0] rvfi_mem_addr, - output logic [ 3:0] rvfi_mem_rmask, - output logic [ 3:0] rvfi_mem_wmask, + output logic [31:0] rvfi_mem_rmask, + output logic [31:0] rvfi_mem_wmask, output logic [31:0] rvfi_mem_rdata, output logic [31:0] rvfi_mem_wdata, @@ -618,6 +628,13 @@ module cv32e40p_rvfi bit clk_i_d; assign #0.01 clk_i_d = clk_i; + integer cycles; + // cycle counter + always_ff @(posedge clk_i_d, negedge rst_ni) begin + if (rst_ni == 1'b0) cycles <= 0; + else cycles <= cycles + 1; + end + logic pc_mux_debug; logic pc_mux_dret; logic pc_mux_exception; @@ -626,6 +643,9 @@ module cv32e40p_rvfi logic pc_mux_nmi; localparam logic [31:0] MSTATUS_WRITE_MASK = 32'h0000_6088; + localparam logic [31:0] MCOUNTINHIBIT_WRITE_MASK = {{(29-NUM_MHPMCOUNTERS){1'b0}}, {(NUM_MHPMCOUNTERS){1'b1}}, 3'b101}; + localparam NUM_HPM_EVENTS = 16; + localparam logic [31:0] MHPMEVENT_WRITE_MASK = {{(31-NUM_HPM_EVENTS){1'b0}}, {(NUM_HPM_EVENTS){1'b1}}}; `include "pipe_freeze_trace.sv" @@ -747,6 +767,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end rvfi_order = new_rvfi_trace.m_order; + rvfi_start_cycle = new_rvfi_trace.m_start_cycle; + rvfi_start_time = new_rvfi_trace.m_start_time; + rvfi_stop_cycle = new_rvfi_trace.m_stop_cycle; + rvfi_stop_time = new_rvfi_trace.m_stop_time; rvfi_pc_rdata = new_rvfi_trace.m_pc_rdata; rvfi_insn = new_rvfi_trace.m_insn; @@ -801,6 +825,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; rvfi_frd_addr[1] = '0; rvfi_frd_wdata[1] = '0; + rvfi_2_rd = new_rvfi_trace.m_2_rd_insn; if (new_rvfi_trace.m_rd_addr[0][5] == 1'b0) begin rvfi_rd_addr[0] = new_rvfi_trace.m_rd_addr[0][4:0]; rvfi_rd_wdata[0] = new_rvfi_trace.m_rd_wdata[0]; @@ -905,15 +930,50 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `SET_RVFI_CSR_FROM_INSN(misa) `SET_RVFI_CSR_FROM_INSN(mie) `SET_RVFI_CSR_FROM_INSN(mtvec) - `SET_RVFI_CSR_FROM_INSN(mcountinhibit) + + rvfi_csr_mcountinhibit_rdata = new_rvfi_trace.m_csr.mcountinhibit_rdata; + rvfi_csr_mcountinhibit_rmask = new_rvfi_trace.m_csr.mcountinhibit_rmask; + rvfi_csr_mcountinhibit_wdata = new_rvfi_trace.m_csr.mcountinhibit_wdata; + rvfi_csr_mcountinhibit_wmask = new_rvfi_trace.m_csr.mcountinhibit_wmask & MCOUNTINHIBIT_WRITE_MASK; + `SET_RVFI_CSR_FROM_INSN(mscratch) `SET_RVFI_CSR_FROM_INSN(mepc) `SET_RVFI_CSR_FROM_INSN(mcause) + `SET_RVFI_CSR_FROM_INSN(mcycle) `SET_RVFI_CSR_FROM_INSN(minstret) + `SET_RVFI_CSR_FROM_INSN(minstreth) + + // `SET_RVFI_CSR_FROM_INSN(cycle) + // `SET_RVFI_CSR_FROM_INSN(instret) + rvfi_csr_instret_rdata = new_rvfi_trace.m_csr.minstret_rdata; + rvfi_csr_instret_rmask = new_rvfi_trace.m_csr.minstret_rmask; + rvfi_csr_instret_wdata = new_rvfi_trace.m_csr.minstret_wdata; + rvfi_csr_instret_wmask = new_rvfi_trace.m_csr.minstret_wmask; + + for(int idx=3; idx<32; idx++) begin + rvfi_csr_mhpmcounter_rmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_rmask[idx][31:0]; + rvfi_csr_mhpmcounter_wmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_wmask[idx][31:0]; + rvfi_csr_mhpmcounter_rdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_rdata[idx][31:0]; + rvfi_csr_mhpmcounter_wdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_wdata[idx][31:0]; + + rvfi_csr_mhpmcounterh_rmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_rmask[idx][63:32]; + rvfi_csr_mhpmcounterh_wmask[idx] = new_rvfi_trace.m_csr.mhpmcounter_wmask[idx][63:32]; + rvfi_csr_mhpmcounterh_rdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_rdata[idx][63:32]; + rvfi_csr_mhpmcounterh_wdata[idx] = new_rvfi_trace.m_csr.mhpmcounter_wdata[idx][63:32]; + + rvfi_csr_mhpmevent_rmask[idx] = new_rvfi_trace.m_csr.mhpmevent_rmask[idx]; + rvfi_csr_mhpmevent_wmask[idx] = new_rvfi_trace.m_csr.mhpmevent_wmask[idx] & MHPMEVENT_WRITE_MASK; + rvfi_csr_mhpmevent_rdata[idx] = new_rvfi_trace.m_csr.mhpmevent_rdata[idx]; + rvfi_csr_mhpmevent_wdata[idx] = new_rvfi_trace.m_csr.mhpmevent_wdata[idx]; + end + // `SET_RVFI_CSR_FROM_INSN(instreth) + rvfi_csr_instreth_rdata = new_rvfi_trace.m_csr.minstreth_rdata; + rvfi_csr_instreth_rmask = new_rvfi_trace.m_csr.minstreth_rmask; + rvfi_csr_instreth_wdata = new_rvfi_trace.m_csr.minstreth_wdata; + rvfi_csr_instreth_wmask = new_rvfi_trace.m_csr.minstreth_wmask; + `SET_RVFI_CSR_FROM_INSN(mip) - // if(rvfi_order == 64'h00000000_00000167) begin - // rvfi_csr_mip_rdata = 32'h0010_0000; - // end + rvfi_csr_tdata_rdata[0] = 'Z; rvfi_csr_tdata_rmask[0] = '0; // Does not exist rvfi_csr_tdata_wdata[0] = 'Z; // Does not exist @@ -959,36 +1019,134 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; endfunction // set_rvfi - function void minstret_to_id(); - trace_id.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; - trace_id.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2]; - trace_id.m_csr.minstret_rmask = '1; - trace_id.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q; - trace_id.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + function void sample_perf_counter_to_id(int idx); + trace_id.m_csr.mhpmcounter_rdata[idx][31:0] = r_pipe_freeze_trace.csr.mhpmcounter_q[idx][31:0]; + trace_id.m_csr.mhpmcounter_rmask[idx][31:0] = '1; + endfunction + + function void perf_counter_to_id(int idx); + if(!trace_id.m_csr.mhpmcounter_we[idx][0]) begin + trace_id.m_csr.mhpmcounter_wdata[idx][31:0] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + trace_id.m_csr.mhpmcounter_we[idx][0] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]; + trace_id.m_csr.mhpmcounter_wdata[idx][31:0] = r_pipe_freeze_trace.csr.wdata_int; + trace_id.m_csr.mhpmcounter_wmask[idx][31:0] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx] ? '1 : '0; + end + sample_perf_counter_to_id(idx); + endfunction + + function void sample_perf_event_to_trace(int idx, insn_trace_t m_trace); + m_trace.m_csr.mhpmevent_rdata[idx] = r_pipe_freeze_trace.csr.mhpmevent_q[idx]; + m_trace.m_csr.mhpmevent_rmask[idx] = '1; + endfunction + + function void perf_event_to_trace(int idx, insn_trace_t m_trace); + if(!m_trace.m_csr.mhpmevent_we[idx]) begin + m_trace.m_csr.mhpmevent_wdata[idx] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmevent_we[idx]) begin + m_trace.m_csr.mhpmevent_we[idx] = r_pipe_freeze_trace.csr.mhpmevent_we[idx]; + m_trace.m_csr.mhpmevent_wdata[idx] = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.mhpmevent_wmask[idx] = r_pipe_freeze_trace.csr.mhpmevent_we[idx] ? '1 : '0; + end + sample_perf_event_to_trace(idx, m_trace); + endfunction + + function void sample_minstret_to_trace(insn_trace_t m_trace); + m_trace.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2][31:0]; + m_trace.m_csr.minstret_rmask = '1; + endfunction + + function void minstret_to_trace(insn_trace_t m_trace); + if(!m_trace.m_csr.minstret_we) begin + m_trace.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]) begin + m_trace.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; + m_trace.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + end + sample_minstret_to_trace(m_trace); + endfunction + + function void sample_perf_counter_h_to_id(int idx); + trace_id.m_csr.mhpmcounter_rdata[idx][63:32] = r_pipe_freeze_trace.csr.mhpmcounter_q[idx][63:0]; + trace_id.m_csr.mhpmcounter_rmask[idx][63:32] = '1; + endfunction + + function void perf_counter_h_to_id(int idx); + if(!trace_id.m_csr.mhpmcounter_we[idx][1]) begin + trace_id.m_csr.mhpmcounter_wdata[idx][63:32] = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + trace_id.m_csr.mhpmcounter_we[idx][1] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]; + trace_id.m_csr.mhpmcounter_wdata[idx][63:32] = r_pipe_freeze_trace.csr.wdata_int; + trace_id.m_csr.mhpmcounter_wmask[idx][63:32] = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx] ? '1 : '0; + end + sample_perf_counter_h_to_id(idx); + endfunction + + function void sample_minstreth_to_trace(insn_trace_t m_trace); + m_trace.m_csr.minstreth_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2][63:32]; + m_trace.m_csr.minstreth_rmask = '1; endfunction - function void minstret_to_ex(); - trace_ex.m_csr.minstret_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]; - trace_ex.m_csr.minstret_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[2]; - trace_ex.m_csr.minstret_rmask = '1; - trace_ex.m_csr.minstret_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q; - trace_ex.m_csr.minstret_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2] ? '1 : '0; + function void sample_mcycle_to_trace(insn_trace_t m_trace); + m_trace.m_csr.mcycle_we = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[0]; + m_trace.m_csr.mcycle_rdata = r_pipe_freeze_trace.csr.mhpmcounter_q[0][31:0]; + m_trace.m_csr.mcycle_rmask = '1; + m_trace.m_csr.mcycle_wdata = r_pipe_freeze_trace.csr.mhpmcounter_q[31:0]; + m_trace.m_csr.mcycle_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_lower[0] ? '1 : '0; endfunction - function void tinfo_to_id(); - trace_id.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; - trace_id.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; - trace_id.m_csr.tinfo_rmask = '1; - trace_id.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; - trace_id.m_csr.tinfo_wmask = '0; + function void minstreth_to_trace(insn_trace_t m_trace); + if(!m_trace.m_csr.minstreth_we) begin + m_trace.m_csr.minstreth_wdata = r_pipe_freeze_trace.csr.wdata_int; + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]) begin + m_trace.m_csr.minstreth_we = r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]; + m_trace.m_csr.minstreth_wdata = r_pipe_freeze_trace.csr.wdata_int; + m_trace.m_csr.minstreth_wmask = r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2] ? '1 : '0; + end + sample_minstreth_to_trace(m_trace); endfunction - function void tinfo_to_ex(); - trace_ex.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; - trace_ex.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; - trace_ex.m_csr.tinfo_rmask = '1; - trace_ex.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; - trace_ex.m_csr.tinfo_wmask = '0; + function void sample_perf_counter_to_trace(insn_trace_t m_trace); + sample_minstret_to_trace(m_trace); + sample_minstreth_to_trace(m_trace); + sample_mcycle_to_trace(m_trace); + for(int idx=3; idx<32; idx++)begin + sample_perf_event_to_trace(idx, m_trace); //TO CHANGE + end + endfunction + + function void perf_counter_to_trace(insn_trace_t m_trace); + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[2]) begin + minstret_to_trace(m_trace); + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[2]) begin + minstreth_to_trace(m_trace); + end + for(int idx=3; idx<32; idx++) begin + if(r_pipe_freeze_trace.csr.mhpmcounter_write_lower[idx]) begin + perf_counter_to_id(idx); + end + if(r_pipe_freeze_trace.csr.mhpmcounter_write_upper[idx]) begin + perf_counter_h_to_id(idx); + end + if(r_pipe_freeze_trace.csr.mhpmevent_we[idx]) begin + perf_event_to_trace(idx, m_trace); + end + end + endfunction + + function void tinfo_to_trace(insn_trace_t m_trace); + m_trace.m_csr.tinfo_we = '0; // READ ONLY csr_tinfo_we_i; + m_trace.m_csr.tinfo_rdata = r_pipe_freeze_trace.csr.tinfo_q; + m_trace.m_csr.tinfo_rmask = '1; + m_trace.m_csr.tinfo_wdata = r_pipe_freeze_trace.csr.tinfo_n; + m_trace.m_csr.tinfo_wmask = '0; endfunction function void mtvec_to_id(); @@ -1083,8 +1241,6 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; lpcount1_to_id(); lpend1_to_id(); lpstart1_to_id(); - - endfunction bit s_was_flush; //debug exception is flagged as trap only if preceed by a flush @@ -1257,6 +1413,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end csr_to_apu_resp(); + + trace_apu_resp.m_stop_cycle = cycles; + trace_apu_resp.m_stop_time = $time; send_rvfi(trace_apu_resp); ->e_send_rvfi_trace_apu_resp; end @@ -1275,7 +1434,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) - tinfo_to_id(); + tinfo_to_trace(trace_id); `CSR_FROM_PIPE(id, mip) send_rvfi(trace_id); end @@ -1291,15 +1450,28 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; function logic [31:0] be_to_mask(logic [3:0] be); logic [31:0] mask; - mask[7:0] = be[0] ? 8'hFF : 8'h00; - mask[15:8] = be[0] ? 8'hFF : 8'h00; - mask[23:16] = be[0] ? 8'hFF : 8'h00; - mask[31:24] = be[0] ? 8'hFF : 8'h00; + mask[7:0] = (be[0] == 1'b1) ? 8'hFF : 8'h00; + mask[15:8] = (be[1] == 1'b1) ? 8'hFF : 8'h00; + mask[23:16] = (be[2] == 1'b1) ? 8'hFF : 8'h00; + mask[31:24] = (be[3] == 1'b1) ? 8'hFF : 8'h00; be_to_mask = mask; return mask; endfunction + function void commit_rf_to_trace(insn_trace_t m_trace); + if (m_trace.m_got_ex_reg) begin + m_trace.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; + m_trace.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; + m_trace.m_2_rd_insn = 1'b1; + m_trace.m_got_first_data = 1'b1; + end else begin + m_trace.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; + m_trace.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; + m_trace.m_got_first_data = 1'b1; + end + endfunction + task compute_pipeline(); bit s_new_valid_insn; bit s_ex_valid_adjusted; @@ -1375,7 +1547,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; `CSR_FROM_PIPE(id, misa) `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) - tinfo_to_id(); + tinfo_to_trace(trace_id); `CSR_FROM_PIPE(id, mip) end end @@ -1409,7 +1581,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (trace_ex.m_valid & s_wb_valid_adjusted) begin // Used flopped values in case write happened before wb_valid - minstret_to_ex(); + sample_perf_counter_to_trace(trace_ex); trace_ex.m_csr.got_minstret = '1; end @@ -1486,14 +1658,14 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (trace_ex.m_valid) begin if(trace_ex.m_instret_smaple_trigger == 1) begin //time to sample instret - minstret_to_ex(); + sample_perf_counter_to_trace(trace_ex); end trace_ex.m_instret_smaple_trigger = trace_ex.m_instret_smaple_trigger + 1; `CSR_FROM_PIPE(ex, misa) `CSR_FROM_PIPE(ex, tdata1) `CSR_FROM_PIPE(ex, tdata2) - tinfo_to_ex(); + tinfo_to_trace(trace_ex); if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_4; @@ -1519,18 +1691,9 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (s_rf_we_wb_adjusted) begin ->e_dev_commit_rf_to_ex_1; - if (trace_ex.m_got_ex_reg) begin - trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_2_rd_insn = 1'b1; - trace_ex.m_got_first_data = 1'b1; - end else begin - trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_got_first_data = 1'b1; - end + commit_rf_to_trace(trace_ex); - if (r_pipe_freeze_trace.csr.fregs_we && !r_pipe_freeze_trace.apu_rvalid) begin //Catching mstatus_fs updates caused by flw + if (r_pipe_freeze_trace.csr.fregs_we && (r_pipe_freeze_trace.rf_we_wb && r_pipe_freeze_trace.rf_addr_wb[5])) begin //Catching mstatus_fs updates caused by flw `CSR_FROM_PIPE(ex, mstatus_fs) trace_ex.m_csr.mstatus_fs_we = 1'b1; trace_ex.m_csr.mstatus_fs_wmask = '1; @@ -1559,16 +1722,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; end end else if (s_rf_we_wb_adjusted && !s_was_flush) begin ->e_dev_commit_rf_to_ex_2; - if (trace_ex.m_got_ex_reg) begin - trace_ex.m_rd_addr[1] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[1] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_2_rd_insn = 1'b1; - trace_ex.m_got_first_data = 1'b1; - end else begin - trace_ex.m_rd_addr[0] = r_pipe_freeze_trace.rf_addr_wb; - trace_ex.m_rd_wdata[0] = r_pipe_freeze_trace.rf_wdata_wb; - trace_ex.m_got_first_data = 1'b1; - end + commit_rf_to_trace(trace_ex); end end @@ -1578,7 +1732,12 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if (trace_id.m_valid) begin if(trace_id.m_instret_smaple_trigger == 1) begin //time to sample instret - minstret_to_id(); + sample_perf_counter_to_trace(trace_id); + for(int idx=3; idx<32; idx++) begin + sample_perf_counter_to_id(idx); + sample_perf_counter_h_to_id(idx); + sample_perf_event_to_trace(idx, trace_id); + end end trace_id.m_instret_smaple_trigger = trace_id.m_instret_smaple_trigger + 1; @@ -1594,6 +1753,10 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; if(r_pipe_freeze_trace.csr.we && (r_pipe_freeze_trace.csr.addr == CSR_DPC)) begin `CSR_FROM_PIPE(id, dpc) end + + `CSR_FROM_PIPE(id, mcountinhibit) + + perf_counter_to_trace(trace_id); ->e_csr_in_ex; end @@ -1634,7 +1797,7 @@ insn_trace_t trace_if, trace_id, trace_ex, trace_ex_next, trace_wb; trace_ex.m_csr.fcsr_wmask = '0; if(r_pipe_freeze_trace.ctrl_fsm_cs == XRET_JUMP) begin //xret exit pipeline - tinfo_to_id(); + tinfo_to_trace(trace_id); `CSR_FROM_PIPE(id, tdata1) `CSR_FROM_PIPE(id, tdata2) send_rvfi(trace_id); diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi_trace.sv index 417f562a..adf85175 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_rvfi_trace.sv @@ -1,26 +1,31 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P RVFI interface -// -// Contributors: Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: CV32E40P RVFI tracer // +// // +//////////////////////////////////////////////////////////////////////////////////// module cv32e40p_rvfi_trace import cv32e40p_pkg::*; + import cv32e40p_rvfi_pkg::*; #( parameter FPU = 0, parameter ZFINX = 0 @@ -32,9 +37,14 @@ module cv32e40p_rvfi_trace input logic [31:0] imm_s3_type, - input logic rvfi_valid, - input logic [31:0] rvfi_insn, - input logic [31:0] rvfi_pc_rdata, + input logic rvfi_valid, + input logic [31:0] rvfi_insn, + input integer rvfi_start_cycle, + input time rvfi_start_time, + input integer rvfi_stop_cycle, + input time rvfi_stop_time, + input logic [31:0] rvfi_pc_rdata, + input rvfi_trap_t rvfi_trap, input logic [ 4:0] rvfi_rd_addr [1:0], input logic [31:0] rvfi_rd_wdata[1:0], @@ -42,6 +52,7 @@ module cv32e40p_rvfi_trace input logic rvfi_frd_wvalid[1:0], input logic [ 4:0] rvfi_frd_addr [1:0], input logic [31:0] rvfi_frd_wdata [1:0], + input logic rvfi_2_rd, input logic [ 4:0] rvfi_rs1_addr, input logic [ 4:0] rvfi_rs2_addr, @@ -61,8 +72,8 @@ module cv32e40p_rvfi_trace input logic [31:0] rvfi_frs3_rdata, input logic [31:0] rvfi_mem_addr, - input logic [ 3:0] rvfi_mem_rmask, - input logic [ 3:0] rvfi_mem_wmask, + input logic [31:0] rvfi_mem_rmask, + input logic [31:0] rvfi_mem_wmask, input logic [31:0] rvfi_mem_rdata, input logic [31:0] rvfi_mem_wdata ); @@ -74,7 +85,7 @@ module cv32e40p_rvfi_trace integer f; //file pointer string fn; - integer cycles; + // integer cycles; string info_tag; logic is_compressed; @@ -125,7 +136,13 @@ module cv32e40p_rvfi_trace rs3_value = rvfi_rs3_rdata; end - if (rvfi_frd_wvalid[0]) begin + if (rvfi_2_rd) begin + if (rvfi_frd_wvalid[1]) begin + rd = {1'b1, rvfi_frd_addr[1]}; + end else begin + rd = {1'b0, rvfi_rd_addr[1]}; + end + end else if (rvfi_frd_wvalid[0]) begin rd = {1'b1, rvfi_frd_addr[0]}; end else begin rd = {1'b0, rvfi_rd_addr[0]}; @@ -134,57 +151,69 @@ module cv32e40p_rvfi_trace assign rs4 = rs3; - assign imm_i_type = {{20{rvfi_insn[31]}}, rvfi_insn[31:20]}; - assign imm_iz_type = {20'b0, rvfi_insn[31:20]}; - assign imm_s_type = {{20{rvfi_insn[31]}}, rvfi_insn[31:25], rvfi_insn[11:7]}; + cv32e40p_compressed_decoder #( + .FPU(FPU) + ) rvfi_trace_decompress_i ( + .instr_i(rvfi_insn), + .instr_o(decomp_insn), + .is_compressed_o(is_compressed) + ); + + assign imm_i_type = {{20{decomp_insn[31]}}, decomp_insn[31:20]}; + assign imm_iz_type = {20'b0, decomp_insn[31:20]}; + assign imm_s_type = {{20{decomp_insn[31]}}, decomp_insn[31:25], decomp_insn[11:7]}; assign imm_sb_type = { - {19{rvfi_insn[31]}}, rvfi_insn[31], rvfi_insn[7], rvfi_insn[30:25], rvfi_insn[11:8], 1'b0 + {19{decomp_insn[31]}}, + decomp_insn[31], + decomp_insn[7], + decomp_insn[30:25], + decomp_insn[11:8], + 1'b0 }; - assign imm_u_type = {rvfi_insn[31:12], 12'b0}; + assign imm_u_type = {decomp_insn[31:12], 12'b0}; assign imm_uj_type = { - {12{rvfi_insn[31]}}, rvfi_insn[19:12], rvfi_insn[20], rvfi_insn[30:21], 1'b0 + {12{decomp_insn[31]}}, decomp_insn[19:12], decomp_insn[20], decomp_insn[30:21], 1'b0 }; - assign imm_z_type = '0; //{27'b0, rvfi_insn[REG_S1_MSB:REG_S1_LSB]}; + assign imm_z_type = '0; //{27'b0, decomp_insn[REG_S1_MSB:REG_S1_LSB]}; - assign imm_s2_type = {27'b0, rvfi_insn[24:20]}; + assign imm_s2_type = {27'b0, decomp_insn[24:20]}; assign imm_vs_type = '0; assign imm_vu_type = '0; assign imm_shuffle_type = '0; assign imm_clip_type = '0; - cv32e40p_compressed_decoder #( - .FPU(FPU) - ) rvfi_trace_decompress_i ( - .instr_i(rvfi_insn), - .instr_o(decomp_insn), - .is_compressed_o(is_compressed) - ); - `include "cv32e40p_instr_trace.svh" instr_trace_t trace_retire; function instr_trace_t trace_new_instr(); instr_trace_t trace; trace = new(); - trace.init(.cycles(cycles), .pc(rvfi_pc_rdata), .compressed(is_compressed), + trace.external_time = 1; + trace.simtime = rvfi_start_time - 1ns; + trace.stoptime = rvfi_stop_time; + trace.stopcycles = rvfi_stop_cycle; + trace.ctx = (rvfi_trap.trap) ? "(C)" : ""; + trace.init(.cycles(rvfi_start_cycle), .pc(rvfi_pc_rdata), .compressed(is_compressed), .instr(decomp_insn)); return trace; endfunction : trace_new_instr function void apply_reg_write(); foreach (trace_retire.regs_write[i]) begin - if (rvfi_frd_wvalid[0] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[0]})) begin - trace_retire.regs_write[i].value = rvfi_frd_wdata[0]; - end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[0]) begin - trace_retire.regs_write[i].value = rvfi_rd_wdata[0]; - end if (rvfi_frd_wvalid[1] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[1]})) begin trace_retire.regs_write[i].value = rvfi_frd_wdata[1]; end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[1]) begin trace_retire.regs_write[i].value = rvfi_rd_wdata[1]; end end + foreach (trace_retire.regs_write[i]) begin + if (rvfi_frd_wvalid[0] && (trace_retire.regs_write[i].addr == {1'b1, rvfi_frd_addr[0]})) begin + trace_retire.regs_write[i].value = rvfi_frd_wdata[0]; + end else if (trace_retire.regs_write[i].addr == rvfi_rd_addr[0]) begin + trace_retire.regs_write[i].value = rvfi_rd_wdata[0]; + end + end endfunction : apply_reg_write function void apply_mem_access(); @@ -202,11 +231,9 @@ instr_trace_t trace_retire; end endfunction : apply_mem_access - // cycle counter - always_ff @(posedge clk_i, negedge rst_ni) begin - if (rst_ni == 1'b0) cycles <= 0; - else cycles <= cycles + 1; - end + string insn_disas; + logic [31:0] insn_pc; + logic [31:0] insn_val; always @(posedge clk_i) begin if (rvfi_valid) begin @@ -214,6 +241,9 @@ instr_trace_t trace_retire; apply_reg_write(); apply_mem_access(); trace_retire.printInstrTrace(); + insn_disas = trace_retire.str; + insn_pc = trace_retire.pc; + insn_val = trace_retire.instr; end end @@ -223,7 +253,8 @@ instr_trace_t trace_retire; $sformat(info_tag, "CORE_TRACER %2d", hart_id_i); $display("[%s] Output filename is: %s", info_tag, fn); f = $fopen(fn, "w"); - $fwrite(f, "Time\tCycle\tPC\tInstr\tDecoded instruction\tRegister and memory contents\n"); + $fwrite(f, + " Time Cycle PC Instr Ctx Decoded instruction Register and memory contents Stop cycle Stop time\n"); end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv index ca703682..25245407 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tb_wrapper.sv @@ -1,23 +1,27 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Wrapper for a cv32e40p, containing cv32e40p_top, and rvfi_tracer -// -// Contributors: Davide Schiavone, OpenHW Group -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Yoann Pruvost, Dolphin Design // +// // +// Description: Test-bench wrapper for cv32e40p_top, tracer and and rvfi_tracer // +// // +//////////////////////////////////////////////////////////////////////////////////// `ifdef CV32E40P_ASSERT_ON `include "cv32e40p_prefetch_controller_sva.sv" @@ -234,8 +238,9 @@ module cv32e40p_tb_wrapper endgenerate cv32e40p_rvfi #( - .FPU (FPU), - .ZFINX(ZFINX) + .FPU(FPU), + .ZFINX(ZFINX), + .NUM_MHPMCOUNTERS(NUM_MHPMCOUNTERS) ) rvfi_i ( .clk_i (cv32e40p_top_i.core_i.clk_i), .rst_ni(cv32e40p_top_i.core_i.rst_ni), @@ -399,6 +404,9 @@ module cv32e40p_tb_wrapper .csr_mcountinhibit_n_i (cv32e40p_top_i.core_i.cs_registers_i.mcountinhibit_n), .csr_mcountinhibit_we_i(cv32e40p_top_i.core_i.cs_registers_i.mcountinhibit_we), + .csr_mhpmevent_n_i(cv32e40p_top_i.core_i.cs_registers_i.mhpmevent_n), + .csr_mhpmevent_q_i(cv32e40p_top_i.core_i.cs_registers_i.mhpmevent_q), + .csr_mhpmevent_we_i(cv32e40p_top_i.core_i.cs_registers_i.mhpmevent_we), .csr_mscratch_q_i(cv32e40p_top_i.core_i.cs_registers_i.mscratch_q), .csr_mscratch_n_i(cv32e40p_top_i.core_i.cs_registers_i.mscratch_n), .csr_mepc_q_i(cv32e40p_top_i.core_i.cs_registers_i.mepc_q), @@ -454,12 +462,18 @@ module cv32e40p_tb_wrapper .rvfi_valid(rvfi_valid), .rvfi_insn(rvfi_insn), + .rvfi_start_cycle(rvfi_start_cycle), + .rvfi_start_time(rvfi_start_time), + .rvfi_stop_cycle(rvfi_stop_cycle), + .rvfi_stop_time(rvfi_stop_time), .rvfi_pc_rdata(rvfi_pc_rdata), + .rvfi_trap(rvfi_trap), .rvfi_rd_addr(rvfi_rd_addr), .rvfi_rd_wdata(rvfi_rd_wdata), .rvfi_frd_wvalid(rvfi_frd_wvalid), .rvfi_frd_addr(rvfi_frd_addr), .rvfi_frd_wdata(rvfi_frd_wdata), + .rvfi_2_rd(rvfi_2_rd), .rvfi_rs1_addr(rvfi_rs1_addr), .rvfi_rs2_addr(rvfi_rs2_addr), .rvfi_rs3_addr(rvfi_rs3_addr), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tracer.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tracer.sv index 8208f2e6..59ed6fd7 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tracer.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/cv32e40p_tracer.sv @@ -1,24 +1,26 @@ -// Copyright (c) 2020 OpenHW Group -// -// Licensed under the Solderpad Hardware Licence, 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 -// -// https://solderpad.org/licenses/ -// -// 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 - -// Traces the executed instructions -// -// Contributors: Andreas Traber, ETHZ -// Davide Schiavone, OpenHW Group -// Pascal Gouedo, Dolphin Design +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch // +// // +// Additional contributions by: // +// Davide Schiavone - pschiavo@iis.ee.ethz.ch // +// // +// Design Name: RISC-V Tracer // +// Project Name: RI5CY // +// Language: SystemVerilog // +// // +// Description: Traces the executed instructions // +// // +//////////////////////////////////////////////////////////////////////////////// `ifdef CV32E40P_TRACE_EXECUTION @@ -183,7 +185,8 @@ module cv32e40p_tracer $sformat(info_tag, "CORE_TRACER %2d", hart_id_i); $display("[%s] Output filename is: %s", info_tag, fn); f = $fopen(fn, "w"); - $fwrite(f, "Time\tCycle\tPC\tInstr\tDecoded instruction\tRegister and memory contents\n"); + $fwrite(f, + " Time Cycle PC Instr Ctx Decoded instruction Register and memory contents\n"); end //initial begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_rvfi_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_rvfi_pkg.sv index 68879569..f4044e6e 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_rvfi_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_rvfi_pkg.sv @@ -1,24 +1,28 @@ -// Copyright (c) 2020 OpenHW Group +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// Includes to print info about the RVFI output -// -// Contributors: Davide Schiavone, OpenHW Group -// Halfdan Bechmann, Silicon Labs -// Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Davide Schiavone, OpenHW Group // +// Halfdan Bechmann, Silicon Labs // +// Yoann Pruvost, Dolphin Design // +// // +// Description: Package to print info on RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// package cv32e40p_rvfi_pkg; import cv32e40p_pkg::*; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv index d026c4aa..b9ce57df 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/include/cv32e40p_tracer_pkg.sv @@ -1,23 +1,13 @@ -// Copyright (c) 2020 OpenHW Group -// -// Licensed under the Solderpad Hardware Licence, 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 -// -// https://solderpad.org/licenses/ -// -// 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 - -// Tracer package -// -// Contributors: Steve Richmond, Silicon Labs -// Pascal Gouedo, Dolphin Design +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + package cv32e40p_tracer_pkg; import cv32e40p_pkg::*; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv index 71cbaaff..8cdc06d9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/insn_trace.sv @@ -1,5 +1,26 @@ -// Copyright 2022 Dolphin Design -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 +// Copyright 2024 OpenHW Group and Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// 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. + +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Yoann Pruvost, Dolphin Design // +// // +// Description: Macros and Functions to print information on RVFI interface // +// // +//////////////////////////////////////////////////////////////////////////////////// `define DEFINE_CSR(CSR_NAME) \ logic ``CSR_NAME``_we; \ @@ -23,6 +44,10 @@ class insn_trace_t; bit m_valid; logic [63:0] m_order; + integer m_start_cycle; + integer m_stop_cycle; + time m_start_time; + time m_stop_time; bit m_skip_order; //next order was used by trap; logic [31:0] m_pc_rdata; logic [31:0] m_insn; @@ -71,9 +96,9 @@ struct { logic [31:0] addr ; - logic [ 3:0] rmask; + logic [31:0] rmask; logic [31:0] rdata; - logic [ 3:0] wmask; + logic [31:0] wmask; logic [31:0] wdata; } m_mem; @@ -103,9 +128,28 @@ `DEFINE_CSR(mscratch) `DEFINE_CSR(mepc) `DEFINE_CSR(mcause) + `DEFINE_CSR(mcycle) `DEFINE_CSR(minstret) bit got_minstret; - + `DEFINE_CSR(mcycleh) + `DEFINE_CSR(minstreth) + `DEFINE_CSR(cycle) + `DEFINE_CSR(instret) + // bit got_minstret; + `DEFINE_CSR(cycleh) + `DEFINE_CSR(instreth) + + logic [31:0][ 1:0] mhpmcounter_we; + logic [31:0][63:0] mhpmcounter_rdata; + logic [31:0][63:0] mhpmcounter_rmask; + logic [31:0][63:0] mhpmcounter_wdata; + logic [31:0][63:0] mhpmcounter_wmask; + + logic [31:0] mhpmevent_we; + logic [31:0][31:0] mhpmevent_rdata; + logic [31:0][31:0] mhpmevent_rmask; + logic [31:0][31:0] mhpmevent_wdata; + logic [31:0][31:0] mhpmevent_wmask; `DEFINE_CSR(mip) //mnxti //mintstatus @@ -149,6 +193,10 @@ function new(); this.m_order = 0; + this.m_start_cycle = 0; + this.m_stop_cycle = 0; + this.m_start_time = 0; + this.m_stop_time = 0; this.m_skip_order = 1'b0; this.m_valid = 1'b0; this.m_move_down_pipe = 1'b0; @@ -615,12 +663,12 @@ INSTR_CVCMPLEB : this.m_mnemonic = "cv.cmple.b"; INSTR_CVCMPLESCB : this.m_mnemonic = "cv.cmple.sc.b"; INSTR_CVCMPLESCIB : this.m_mnemonic = "cv.cmple.sci.b"; - INSTR_CVCMPGTUH : this.m_mnemonic = "cv.cmptu.h"; - INSTR_CVCMPGTUSCH : this.m_mnemonic = "cv.cmptu.sc.h"; - INSTR_CVCMPGTUSCIH : this.m_mnemonic = "cv.cmptu.sci.h"; - INSTR_CVCMPGTUB : this.m_mnemonic = "cv.cmptu.b"; - INSTR_CVCMPGTUSCB : this.m_mnemonic = "cv.cmptu.sc.b"; - INSTR_CVCMPGTUSCIB : this.m_mnemonic = "cv.cmptu.sci.b"; + INSTR_CVCMPGTUH : this.m_mnemonic = "cv.cmpgtu.h"; + INSTR_CVCMPGTUSCH : this.m_mnemonic = "cv.cmpgtu.sc.h"; + INSTR_CVCMPGTUSCIH : this.m_mnemonic = "cv.cmpgtu.sci.h"; + INSTR_CVCMPGTUB : this.m_mnemonic = "cv.cmpgtu.b"; + INSTR_CVCMPGTUSCB : this.m_mnemonic = "cv.cmpgtu.sc.b"; + INSTR_CVCMPGTUSCIB : this.m_mnemonic = "cv.cmpgtu.sci.b"; INSTR_CVCMPGEUH : this.m_mnemonic = "cv.cmpgeu.h"; INSTR_CVCMPGEUSCH : this.m_mnemonic = "cv.cmpgeu.sc.h"; INSTR_CVCMPGEUSCIH : this.m_mnemonic = "cv.cmpgeu.sci.h"; @@ -849,7 +897,18 @@ `INIT_CSR(mscratch) `INIT_CSR(mepc) `INIT_CSR(mcause) + `INIT_CSR(mcycle) `INIT_CSR(minstret) + `INIT_CSR(mcycleh) + `INIT_CSR(minstreth) + `INIT_CSR(cycle) + `INIT_CSR(instret) + `INIT_CSR(cycleh) + `INIT_CSR(instreth) + this.m_csr.mhpmcounter_we = '0; + this.m_csr.mhpmcounter_wmask = '0; + this.m_csr.mhpmevent_we = '0; + this.m_csr.mhpmevent_wmask = '0; `INIT_CSR(mip) `INIT_CSR(tdata1) `INIT_CSR(tdata2) @@ -877,6 +936,10 @@ this.m_valid = 1'b1; this.m_stage = ID; this.m_order = this.m_order + 64'h1; + this.m_start_cycle = cycles; + this.m_stop_cycle = 0; + this.m_start_time = $time; + this.m_stop_time = 0; if(this.m_skip_order) begin this.m_order = this.m_order + 64'h1; end @@ -954,6 +1017,10 @@ this.m_valid = m_source.m_valid; this.m_stage = m_source.m_stage; this.m_order = m_source.m_order; + this.m_start_cycle = m_source.m_start_cycle; + this.m_stop_cycle = m_source.m_stop_cycle; + this.m_start_time = m_source.m_start_time; + this.m_stop_time = m_source.m_stop_time; this.m_pc_rdata = m_source.m_pc_rdata; this.m_insn = m_source.m_insn; this.m_mnemonic = m_source.m_mnemonic; @@ -1004,8 +1071,26 @@ `ASSIGN_CSR(mscratch) `ASSIGN_CSR(mepc) `ASSIGN_CSR(mcause) + `ASSIGN_CSR(mcycle) `ASSIGN_CSR(minstret) this.m_csr.got_minstret = m_source.m_csr.got_minstret; + `ASSIGN_CSR(mcycleh) + `ASSIGN_CSR(minstreth) + `ASSIGN_CSR(cycle) + `ASSIGN_CSR(instret) + // this.m_csr.got_minstret = m_source.m_csr.got_minstret; + `ASSIGN_CSR(cycleh) + `ASSIGN_CSR(instreth) + this.m_csr.mhpmcounter_we = m_source.m_csr.mhpmcounter_we; + this.m_csr.mhpmcounter_rdata = m_source.m_csr.mhpmcounter_rdata; + this.m_csr.mhpmcounter_rmask = m_source.m_csr.mhpmcounter_rmask; + this.m_csr.mhpmcounter_wdata = m_source.m_csr.mhpmcounter_wdata; + this.m_csr.mhpmcounter_wmask = m_source.m_csr.mhpmcounter_wmask; + this.m_csr.mhpmevent_we = m_source.m_csr.mhpmevent_we; + this.m_csr.mhpmevent_rdata = m_source.m_csr.mhpmevent_rdata; + this.m_csr.mhpmevent_rmask = m_source.m_csr.mhpmevent_rmask; + this.m_csr.mhpmevent_wdata = m_source.m_csr.mhpmevent_wdata; + this.m_csr.mhpmevent_wmask = m_source.m_csr.mhpmevent_wmask; `ASSIGN_CSR(mip) `ASSIGN_CSR(tdata1) `ASSIGN_CSR(tdata2) diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv index 88d65d0b..39a16fa6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/bhv/pipe_freeze_trace.sv @@ -1,27 +1,29 @@ -// Copyright (c) 2023 OpenHW Group +// Copyright 2024 OpenHW Group and Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // -// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. // You may obtain a copy of the License at // -// https://solderpad.org/licenses/ +// https://solderpad.org/licenses/SHL-2.1/ // -// Unless required by applicable law or agreed to in writing, software +// Unless required by applicable law or agreed to in writing, any work // 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. -// -// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 -// CV32E40P -// -// Contributors: Yoann Pruvost, Dolphin Design +//////////////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Yoann Pruvost, Dolphin Design // +// // +// Description: Structures, Functions and Task used to store all information // +// coming from the core pipeline at every posedge. // +// Those information will then be processed by RVFI. // +// // +//////////////////////////////////////////////////////////////////////////////////// -/* - * This struct is used to store all information comming from the core at every posedge - * The information will then be processed - */ typedef struct { logic is_decoding; logic is_illegal; @@ -349,6 +351,7 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.fflags_we = 1'b0; r_pipe_freeze_trace.csr.frm_we = 1'b0; r_pipe_freeze_trace.csr.fcsr_we = 1'b0; + r_pipe_freeze_trace.csr.mhpmevent_we = '0; r_pipe_freeze_trace.csr.dpc_we = csr_dpc_we_i; if (r_pipe_freeze_trace.csr.we) begin case (r_pipe_freeze_trace.csr.addr) @@ -366,7 +369,10 @@ function compute_csr_we(); r_pipe_freeze_trace.csr.fflags_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; end - CSR_FRM: r_pipe_freeze_trace.csr.frm_we = 1'b1; + CSR_FRM: begin + r_pipe_freeze_trace.csr.frm_we = 1'b1; + r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; + end CSR_FCSR: begin r_pipe_freeze_trace.csr.fcsr_we = 1'b1; r_pipe_freeze_trace.csr.mstatus_fs_we = 1'b1; @@ -376,6 +382,10 @@ function compute_csr_we(); CSR_DSCRATCH1: r_pipe_freeze_trace.csr.dscratch1_we = 1'b1; endcase end + + if (csr_mhpmevent_we_i) begin + r_pipe_freeze_trace.csr.mhpmevent_we[r_pipe_freeze_trace.csr.addr[4:0]] = 1'b1; + end // CSR_MCAUSE: r_pipe_freeze_trace.csr.mcause_we = r_pipe_freeze_trace.csr.mcause_n != r_pipe_freeze_trace.csr.mcause_q; //for debug purpose endfunction /* @@ -573,7 +583,6 @@ task monitor_pipeline(); r_pipe_freeze_trace.csr.mcountinhibit_we = csr_mcountinhibit_we_i; r_pipe_freeze_trace.csr.mhpmevent_n = csr_mhpmevent_n_i; r_pipe_freeze_trace.csr.mhpmevent_q = csr_mhpmevent_q_i; - r_pipe_freeze_trace.csr.mhpmevent_we = csr_mhpmevent_we_i; r_pipe_freeze_trace.csr.mscratch_n = csr_mscratch_n_i; r_pipe_freeze_trace.csr.mscratch_q = csr_mscratch_q_i; r_pipe_freeze_trace.csr.mepc_n = csr_mepc_n_i; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv index a41e345d..d1c86d6c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_controller.sv @@ -597,7 +597,17 @@ module cv32e40p_controller import cv32e40p_pkg::*; csr_status_i: begin halt_if_o = 1'b1; - ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE; + if (~id_ready_i) begin + ctrl_fsm_ns = DECODE; + end else begin + ctrl_fsm_ns = FLUSH_EX; + if (hwlp_end0_eq_pc) begin + hwlp_dec_cnt_o[0] = 1'b1; + end + if (hwlp_end1_eq_pc) begin + hwlp_dec_cnt_o[1] = 1'b1; + end + end end data_load_event_i: begin @@ -617,7 +627,7 @@ module cv32e40p_controller import cv32e40p_pkg::*; ctrl_fsm_ns = hwlp_end0_eq_pc_plus4 || hwlp_end1_eq_pc_plus4 ? DECODE : DECODE_HWLOOP; // we can be at the end of HWloop due to a return from interrupt or ecall or ebreak or exceptions - if(hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin + if (hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin pc_mux_o = PC_HWLOOP; if (~jump_done_q) begin pc_set_o = 1'b1; @@ -791,7 +801,17 @@ module cv32e40p_controller import cv32e40p_pkg::*; csr_status_i: begin halt_if_o = 1'b1; - ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE_HWLOOP; + if (~id_ready_i) begin + ctrl_fsm_ns = DECODE_HWLOOP; + end else begin + ctrl_fsm_ns = FLUSH_EX; + if (hwlp_end0_eq_pc) begin + hwlp_dec_cnt_o[0] = 1'b1; + end + if (hwlp_end1_eq_pc) begin + hwlp_dec_cnt_o[1] = 1'b1; + end + end end data_load_event_i: begin @@ -1067,16 +1087,10 @@ module cv32e40p_controller import cv32e40p_pkg::*; end csr_status_i: begin - - if(hwlp_end0_eq_pc && hwlp_counter0_gt_1) begin - pc_mux_o = PC_HWLOOP; - pc_set_o = 1'b1; - hwlp_dec_cnt_o[0] = 1'b1; - end - if(hwlp_end1_eq_pc && hwlp_counter1_gt_1) begin - pc_mux_o = PC_HWLOOP; - pc_set_o = 1'b1; - hwlp_dec_cnt_o[1] = 1'b1; + if ((hwlp_end0_eq_pc && !hwlp_counter0_eq_0) || + (hwlp_end1_eq_pc && !hwlp_counter1_eq_0)) begin + pc_mux_o = PC_HWLOOP; + pc_set_o = 1'b1; end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv index d72fae9e..4275cf9c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_core.sv @@ -70,7 +70,8 @@ module cv32e40p_core output logic [31:0] data_wdata_o, input logic [31:0] data_rdata_i, - // apu-interconnect + // CVFPU interface + output logic apu_busy_o, // handshake signals output logic apu_req_o, input logic apu_gnt_i, @@ -163,7 +164,6 @@ module cv32e40p_core logic ctrl_busy; logic if_busy; logic lsu_busy; - logic apu_busy; logic [31:0] pc_ex; // PC of last executed branch or cv.elw @@ -399,7 +399,7 @@ module cv32e40p_core .if_busy_i (if_busy), .ctrl_busy_i(ctrl_busy), .lsu_busy_i (lsu_busy), - .apu_busy_i (apu_busy), + .apu_busy_i (apu_busy_o), // PULP cluster .pulp_clock_en_i (pulp_clock_en_i), @@ -634,7 +634,7 @@ module cv32e40p_core .apu_write_regs_valid_o (apu_write_regs_valid), .apu_write_dep_i (apu_write_dep), .apu_perf_dep_o (perf_apu_dep), - .apu_busy_i (apu_busy), + .apu_busy_i (apu_busy_o), // CSR ID/EX .csr_access_ex_o (csr_access_ex), @@ -818,9 +818,9 @@ module cv32e40p_core .apu_perf_cont_o(perf_apu_cont), .apu_perf_wb_o (perf_apu_wb), .apu_ready_wb_o (apu_ready_wb), - .apu_busy_o (apu_busy), + .apu_busy_o (apu_busy_o), - // apu-interconnect + // CVFPU interface // handshake signals .apu_req_o (apu_req_o), .apu_gnt_i (apu_gnt_i), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_decoder.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_decoder.sv index d03027ba..c1608eb4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_decoder.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_decoder.sv @@ -1057,7 +1057,6 @@ module cv32e40p_decoder 5'b00000: begin fpu_op = cv32e40p_fpu_pkg::ADD; fp_op_group = ADDMUL; - apu_op_o = 2'b0; alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; alu_op_c_mux_sel_o = OP_C_REGB_OR_FWD; end @@ -1066,7 +1065,6 @@ module cv32e40p_decoder fpu_op = cv32e40p_fpu_pkg::ADD; fpu_op_mod = 1'b1; fp_op_group = ADDMUL; - apu_op_o = 2'b1; alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; alu_op_c_mux_sel_o = OP_C_REGB_OR_FWD; end @@ -1085,7 +1083,6 @@ module cv32e40p_decoder regb_used_o = 1'b0; fpu_op = cv32e40p_fpu_pkg::SQRT; fp_op_group = DIVSQRT; - apu_op_o = 1'b1; // rs2 must be zero if (instr_rdata_i[24:20] != 5'b00000) illegal_insn_o = 1'b1; end @@ -1213,7 +1210,6 @@ module cv32e40p_decoder fpu_op = cv32e40p_fpu_pkg::F2I; fp_op_group = CONV; fpu_op_mod = instr_rdata_i[20]; // signed/unsigned switch - apu_op_o = 2'b1; unique case (instr_rdata_i[26:25]) //fix for casting to different formats other than FP32 2'b00: begin @@ -1249,7 +1245,6 @@ module cv32e40p_decoder fpu_op = cv32e40p_fpu_pkg::I2F; fp_op_group = CONV; fpu_op_mod = instr_rdata_i[20]; // signed/unsigned switch - apu_op_o = 2'b0; // bits [21:20] used, other bits must be 0 if (instr_rdata_i[24:21]) illegal_insn_o = 1'b1; // in RV32, no casts to L allowed. end @@ -1323,20 +1318,20 @@ module cv32e40p_decoder // check rounding mode if (check_fprm) begin unique case (instr_rdata_i[14:12]) inside - [3'b000:3'b100]: ; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~C_XF16ALT || fpu_dst_fmt_o != cv32e40p_fpu_pkg::FP16ALT) illegal_insn_o = 1'b1; // actual rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes - default : illegal_insn_o = 1'b1; + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes + default : illegal_insn_o = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes - default : illegal_insn_o = 1'b1; + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes + default : illegal_insn_o = 1'b1; endcase end default : illegal_insn_o = 1'b1; @@ -1364,6 +1359,7 @@ module cv32e40p_decoder NONCOMP : apu_lat_o = (FPU_OTHERS_LAT<2) ? FPU_OTHERS_LAT+1 : 2'h3; // CONV uses the same latency for all formats CONV : apu_lat_o = (FPU_OTHERS_LAT<2) ? FPU_OTHERS_LAT+1 : 2'h3; + default: ; endcase // Set FPnew OP and OPMOD as the APU op @@ -1425,25 +1421,21 @@ module cv32e40p_decoder unique case (instr_rdata_i[6:0]) // fmadd.fmt - FP Fused multiply-add OPCODE_OP_FMADD : begin - fpu_op = cv32e40p_fpu_pkg::FMADD; - apu_op_o = 2'b00; + fpu_op = cv32e40p_fpu_pkg::FMADD; end // fmsub.fmt - FP Fused multiply-subtract OPCODE_OP_FMSUB : begin - fpu_op = cv32e40p_fpu_pkg::FMADD; - fpu_op_mod = 1'b1; - apu_op_o = 2'b01; + fpu_op = cv32e40p_fpu_pkg::FMADD; + fpu_op_mod = 1'b1; end // fnmsub.fmt - FP Negated fused multiply-subtract OPCODE_OP_FNMSUB : begin - fpu_op = cv32e40p_fpu_pkg::FNMSUB; - apu_op_o = 2'b10; + fpu_op = cv32e40p_fpu_pkg::FNMSUB; end // fnmadd.fmt - FP Negated fused multiply-add OPCODE_OP_FNMADD : begin - fpu_op = cv32e40p_fpu_pkg::FNMSUB; - fpu_op_mod = 1'b1; - apu_op_o = 2'b11; + fpu_op = cv32e40p_fpu_pkg::FNMSUB; + fpu_op_mod = 1'b1; end default : ; endcase @@ -1459,19 +1451,19 @@ module cv32e40p_decoder // check rounding mode unique case (instr_rdata_i[14:12]) inside - [3'b000:3'b100]: ; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~C_XF16ALT || fpu_dst_fmt_o != cv32e40p_fpu_pkg::FP16ALT) illegal_insn_o = 1'b1; // actual rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes default : illegal_insn_o = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside - [3'b000:3'b100] : fp_rnd_mode_o = frm_i; //legal rounding modes + 3'b000, 3'b001, 3'b010, 3'b011, 3'b100 : fp_rnd_mode_o = frm_i; //legal rounding modes default : illegal_insn_o = 1'b1; endcase end @@ -1493,6 +1485,7 @@ module cv32e40p_decoder // Set FPnew OP and OPMOD as the APU op apu_op_o = {fpu_vec_op, fpu_op_mod, fpu_op}; + // No FPU or (ZFINX == 0 && MSTATUS.FS == FS_OFF) end else begin illegal_insn_o = 1'b1; @@ -1900,15 +1893,14 @@ module cv32e40p_decoder alu_op_b_mux_sel_o = OP_B_REGA_OR_FWD; unique case (instr_rdata_i[27:25]) - 3'b000: alu_operator_o = ALU_ADD; // cv.addNr - 3'b001: alu_operator_o = ALU_ADDU; // cv.adduNr - 3'b010: alu_operator_o = ALU_ADDR; // cv.addRNr - 3'b011: alu_operator_o = ALU_ADDUR; // cv.adduRNr - 3'b100: alu_operator_o = ALU_SUB; // cv.subNr - 3'b101: alu_operator_o = ALU_SUBU; // cv.subuNr - 3'b110: alu_operator_o = ALU_SUBR; // cv.subRNr - 3'b111: alu_operator_o = ALU_SUBUR; // cv.subuRNr - default: alu_operator_o = ALU_ADD; + 3'b001: alu_operator_o = ALU_ADDU; // cv.adduNr + 3'b010: alu_operator_o = ALU_ADDR; // cv.addRNr + 3'b011: alu_operator_o = ALU_ADDUR; // cv.adduRNr + 3'b100: alu_operator_o = ALU_SUB; // cv.subNr + 3'b101: alu_operator_o = ALU_SUBU; // cv.subuNr + 3'b110: alu_operator_o = ALU_SUBR; // cv.subRNr + 3'b111: alu_operator_o = ALU_SUBUR; // cv.subuRNr + default: alu_operator_o = ALU_ADD; // cv.addNr endcase end @@ -2085,7 +2077,6 @@ module cv32e40p_decoder // decide between using unsigned and rounding, and combinations unique case ({instr_rdata_i[31:30], instr_rdata_i[12]}) - {2'b00, 1'b0}: alu_operator_o = ALU_ADD; // cv.addN {2'b01, 1'b0}: alu_operator_o = ALU_ADDU; // cv.adduN {2'b10, 1'b0}: alu_operator_o = ALU_ADDR; // cv.addRN {2'b11, 1'b0}: alu_operator_o = ALU_ADDUR; // cv.adduRN @@ -2093,12 +2084,12 @@ module cv32e40p_decoder {2'b01, 1'b1}: alu_operator_o = ALU_SUBU; // cv.subuN {2'b10, 1'b1}: alu_operator_o = ALU_SUBR; // cv.subRN {2'b11, 1'b1}: alu_operator_o = ALU_SUBUR; // cv.subuRN - default : alu_operator_o = ALU_ADD; + default : alu_operator_o = ALU_ADD; // cv.addN endcase end - 2'b10, 2'b11: begin + default: begin // MUL/MAC with subword selection alu_en = 1'b0; mult_int_en = 1'b1; @@ -2126,7 +2117,6 @@ module cv32e40p_decoder mult_operator_o = MUL_I; end end - default: illegal_insn_o = 1'b1; endcase end else begin illegal_insn_o = 1'b1; @@ -2267,6 +2257,11 @@ module cv32e40p_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01001_0: begin // cv.sra alu_operator_o = ALU_SRA; @@ -2278,6 +2273,11 @@ module cv32e40p_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01010_0: begin // cv.sll alu_operator_o = ALU_SLL; @@ -2289,6 +2289,11 @@ module cv32e40p_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restrictions + if ((instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:23] != 2'b0) || + (instr_rdata_i[14:12] == 3'b111 && instr_rdata_i[24:22] != 3'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b01011_0: begin // cv.or alu_operator_o = ALU_OR; @@ -2425,6 +2430,11 @@ module cv32e40p_decoder end default: illegal_insn_o = 1'b1; endcase + // Imm6 restrictions + if ((instr_rdata_i[12] == 1'b0 && instr_rdata_i[24:20] != 5'b0) || + (instr_rdata_i[12] == 1'b1 && instr_rdata_i[24:21] != 4'b0)) begin + illegal_insn_o = 1'b1; + end end 6'b11000_0: begin // cv.shuffle, cv.shuffleI0 alu_operator_o = ALU_SHUF; @@ -2439,6 +2449,10 @@ module cv32e40p_decoder instr_rdata_i[25] != 1'b0) begin illegal_insn_o = 1'b1; end + // Imm6 restriction + if (instr_rdata_i[14:12] == 3'b110 && instr_rdata_i[24:21] != 4'b0) begin + illegal_insn_o = 1'b1; + end end 6'b11001_0, 6'b11010_0, diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv index 62ec46c2..839d58aa 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_fp_wrapper.sv @@ -14,7 +14,7 @@ module cv32e40p_fp_wrapper import cv32e40p_apu_core_pkg::*; #( - parameter FPU_ADDMUL_LAT = 0, // Floating-Point ADDition/MULtiplication computing lane pipeline registers number + parameter FPU_ADDMUL_LAT = 0, // Floating-Point ADDition/MULtiplication computing lane pipeline registers number parameter FPU_OTHERS_LAT = 0 // Floating-Point COMParison/CONVersion computing lanes pipeline registers number ) ( // Clock and Reset diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv index 93bb1380..f323cbe5 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_id_stage.sv @@ -1514,9 +1514,13 @@ module cv32e40p_id_stage if (id_valid_o) begin // unstall the whole pipeline alu_en_ex_o <= alu_en; if (alu_en) begin - alu_operator_ex_o <= alu_operator; - alu_operand_a_ex_o <= alu_operand_a; - alu_operand_b_ex_o <= alu_operand_b; + alu_operator_ex_o <= alu_operator; + alu_operand_a_ex_o <= alu_operand_a; + if (alu_op_b_mux_sel == OP_B_REGB_OR_FWD && (alu_operator == ALU_CLIP || alu_operator == ALU_CLIPU)) begin + alu_operand_b_ex_o <= {1'b0, alu_operand_b[30:0]}; + end else begin + alu_operand_b_ex_o <= alu_operand_b; + end alu_operand_c_ex_o <= alu_operand_c; bmask_a_ex_o <= bmask_a_id; bmask_b_ex_o <= bmask_b_id; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_load_store_unit.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_load_store_unit.sv index 7c08ffe1..f9c4db4a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_load_store_unit.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_load_store_unit.sv @@ -121,18 +121,18 @@ module cv32e40p_load_store_unit #( 2'b00: begin // Writing a word if (misaligned_st == 1'b0) begin // non-misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b1111; - 2'b01: data_be = 4'b1110; - 2'b10: data_be = 4'b1100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b1111; + 2'b01: data_be = 4'b1110; + 2'b10: data_be = 4'b1100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end else begin // misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0000; // this is not used, but included for completeness - 2'b01: data_be = 4'b0001; - 2'b10: data_be = 4'b0011; - 2'b11: data_be = 4'b0111; + 2'b01: data_be = 4'b0001; + 2'b10: data_be = 4'b0011; + 2'b11: data_be = 4'b0111; + default: data_be = 4'b0000; // this is not used, but included for completeness endcase ; // case (data_addr_int[1:0]) end @@ -141,10 +141,10 @@ module cv32e40p_load_store_unit #( 2'b01: begin // Writing a half word if (misaligned_st == 1'b0) begin // non-misaligned case case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0011; - 2'b01: data_be = 4'b0110; - 2'b10: data_be = 4'b1100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b0011; + 2'b01: data_be = 4'b0110; + 2'b10: data_be = 4'b1100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end else begin // misaligned case @@ -154,10 +154,10 @@ module cv32e40p_load_store_unit #( 2'b10, 2'b11: begin // Writing a byte case (data_addr_int[1:0]) - 2'b00: data_be = 4'b0001; - 2'b01: data_be = 4'b0010; - 2'b10: data_be = 4'b0100; - 2'b11: data_be = 4'b1000; + 2'b00: data_be = 4'b0001; + 2'b01: data_be = 4'b0010; + 2'b10: data_be = 4'b0100; + default: data_be = 4'b1000; endcase ; // case (data_addr_int[1:0]) end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_register_file_latch.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_register_file_latch.sv index d8e2f4aa..57383e6a 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_register_file_latch.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_register_file_latch.sv @@ -172,8 +172,8 @@ module cv32e40p_register_file #( mem[0] = '0; for (k = 1; k < NUM_WORDS; k++) begin : w_WordIter - if (~rst_n) mem[k] = '0; - else if (mem_clocks[k] == 1'b1) mem[k] = waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q; + if (~rst_n) mem[k] <= '0; + else if (mem_clocks[k] == 1'b1) mem[k] <= waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q; end end @@ -182,9 +182,9 @@ module cv32e40p_register_file #( always_latch begin : latch_wdata_fp if (FPU == 1) begin for (l = 0; l < NUM_FP_WORDS; l++) begin : w_WordIter - if (~rst_n) mem_fp[l] = '0; + if (~rst_n) mem_fp[l] <= '0; else if (mem_clocks[l+NUM_WORDS] == 1'b1) - mem_fp[l] = waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q; + mem_fp[l] <= waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q; end end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_top.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_top.sv index 7ddd2d5a..43eee77b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_top.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cv32e40p/rtl/cv32e40p_top.sv @@ -1,15 +1,27 @@ -// Copyright 2018 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this 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. - -// Top file instantiating a CV32E40P core and an optional FPU -// Contributor: Davide Schiavone +// Copyright 2024 Dolphin Design +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the "License"); +// you may not use this file except in compliance with the License, or, +// at your option, the Apache License version 2.0. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// 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. + +///////////////////////////////////////////////////////////////////////////// +// // +// Contributors: Pascal Gouedo, Dolphin Design // +// // +// Description: Top level module of CV32E40P instantiating the Core and // +// an optional CVFPU with its clock gating cell. // +// // +///////////////////////////////////////////////////////////////////////////// module cv32e40p_top #( parameter COREV_PULP = 0, // PULP ISA Extension (incl. custom CSRs and hardware loop, excl. cv.elw) @@ -70,7 +82,7 @@ module cv32e40p_top #( import cv32e40p_apu_core_pkg::*; // Core to FPU - logic clk; + logic apu_busy; logic apu_req; logic [ APU_NARGS_CPU-1:0][31:0] apu_operands; logic [ APU_WOP_CPU-1:0] apu_op; @@ -82,6 +94,8 @@ module cv32e40p_top #( logic [ 31:0] apu_rdata; logic [APU_NUSFLAGS_CPU-1:0] apu_rflags; + logic apu_clk_en, apu_clk; + // Instantiate the Core cv32e40p_core #( .COREV_PULP (COREV_PULP), @@ -119,6 +133,7 @@ module cv32e40p_top #( .data_wdata_o (data_wdata_o), .data_rdata_i (data_rdata_i), + .apu_busy_o (apu_busy), .apu_req_o (apu_req), .apu_gnt_i (apu_gnt), .apu_operands_o(apu_operands), @@ -143,12 +158,15 @@ module cv32e40p_top #( generate if (FPU) begin : fpu_gen + + assign apu_clk_en = apu_req | apu_busy; + // FPU clock gate cv32e40p_clock_gate core_clock_gate_i ( .clk_i (clk_i), - .en_i (!core_sleep_o), + .en_i (apu_clk_en), .scan_cg_en_i(scan_cg_en_i), - .clk_o (clk) + .clk_o (apu_clk) ); // Instantiate the FPU wrapper @@ -156,7 +174,7 @@ module cv32e40p_top #( .FPU_ADDMUL_LAT(FPU_ADDMUL_LAT), .FPU_OTHERS_LAT(FPU_OTHERS_LAT) ) fp_wrapper_i ( - .clk_i (clk), + .clk_i (apu_clk), .rst_ni (rst_ni), .apu_req_i (apu_req), .apu_gnt_o (apu_gnt), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson index a9251111..fc70c877 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/openhwgroup/cve2.git - rev: f5b21e71c9b511477b04ef81d1292858c51ac20c + rev: 7f3bb9fcb28e55b227c966734d8e81ddef58b7e3 } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson index d398c1eb..28cb1df6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/openhwgroup_cve2.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/openhwgroup/cve2.git", - rev: "f5b21e71c9b511477b04ef81d1292858c51ac20c", + rev: "7f3bb9fcb28e55b227c966734d8e81ddef58b7e3", }, patch_dir: "patches/openhwgroup_cv32e20", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_riscv_dbg/fix_nrharts.patch b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_riscv_dbg/fix_nrharts.patch new file mode 100644 index 00000000..ea96dec8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/patches/pulp_platform_riscv_dbg/fix_nrharts.patch @@ -0,0 +1,28 @@ +diff --git a/src/dm_csrs.sv b/src/dm_csrs.sv +index 59d1c90..2338028 100644 +--- a/src/dm_csrs.sv ++++ b/src/dm_csrs.sv +@@ -547,7 +547,7 @@ module dm_csrs #( + if (!dmcontrol_q.resumereq && dmcontrol_d.resumereq) begin + clear_resumeack_o = 1'b1; + end +- if (dmcontrol_q.resumereq && resumeack_i) begin ++ if (dmcontrol_q.resumereq && resumeack_i[selected_hart]) begin + dmcontrol_d.resumereq = 1'b0; + end + // static values for dcsr +diff --git a/src/dm_mem.sv b/src/dm_mem.sv +index 9ff3c86..8f97bec 100755 +--- a/src/dm_mem.sv ++++ b/src/dm_mem.sv +@@ -535,8 +535,8 @@ module dm_mem #( + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin +- halted_q <= 1'b0; +- resuming_q <= 1'b0; ++ halted_q <= '0; ++ resuming_q <= '0; + end else begin + halted_q <= SelectableHarts & halted_d; + resuming_q <= SelectableHarts & resuming_d; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson index 1c13cb43..9b0fb8b9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg.vendor.hjson @@ -10,6 +10,8 @@ rev: "358f90110220adf7a083f8b65d157e836d706236", }, + patch_dir: "patches/pulp_platform_riscv_dbg", + exclude_from_upstream: [ "ci", "tb", diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv index 59d1c90a..23380289 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_csrs.sv @@ -547,7 +547,7 @@ module dm_csrs #( if (!dmcontrol_q.resumereq && dmcontrol_d.resumereq) begin clear_resumeack_o = 1'b1; end - if (dmcontrol_q.resumereq && resumeack_i) begin + if (dmcontrol_q.resumereq && resumeack_i[selected_hart]) begin dmcontrol_d.resumereq = 1'b0; end // static values for dcsr diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv index 9ff3c86a..8f97bec7 100755 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_riscv_dbg/src/dm_mem.sv @@ -535,8 +535,8 @@ module dm_mem #( always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin - halted_q <= 1'b0; - resuming_q <= 1'b0; + halted_q <= '0; + resuming_q <= '0; end else begin halted_q <= SelectableHarts & halted_d; resuming_q <= SelectableHarts & resuming_d; diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40px.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40px.vlt index a6665860..f2eebf7b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40px.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/cv32e40px.vlt @@ -114,3 +114,6 @@ lint_off -rule WIDTH -file "*/rtl/cv32e40px_decoder.sv" -match "Logical operator lint_off -rule WIDTH -file "*/rtl/cv32e40px_controller.sv" -match "Logical operator LOGAND expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" lint_off -rule WIDTH -file "*/rtl/cv32e40px_cs_registers.sv" -match "Logical operator LOGOR expects 1 bit on the LHS, but LHS's VARREF 'FPU' generates 32 bits.*" lint_off -rule LATCH -file "*/rtl/cv32e40px_id_stage.sv" -match "Latch inferred for signal*apu_read_regs*" +lint_off -rule WIDTH -file "*/rtl/cv32e40px_register_file_ff.sv" -match "Logical operator COND expects 1 bit on the Conditional Test*" +lint_off -rule WIDTH -file "*/rtl/cv32e40px_decoder.sv" -match "Logical operator LOGNOT expects 1 bit on the LHS*" +lint_off -rule WIDTH -file "*/rtl/cv32e40px_ex_stage.sv" -match "Logical operator LOGNOT expects 1 bit on the LHS*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt index 6a33f058..2d2888d2 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/waiver/lint/riscv_dbg.vlt @@ -12,3 +12,4 @@ lint_off -rule DECLFILENAME -file "*/src/cdc_fifo_gray_clearable.sv" -match "Fil lint_off -rule WIDTH -file "*/src/cdc_2phase_clearable.sv" -match "Logical operator GENIF expects 1 bit on the If, but If's VARREF 'CLEAR_ON_ASYNC_RESET' generates 32 bits.*" lint_off -rule UNOPTFLAT -file "*/src/cdc_4phase.sv" -match "Signal unoptimizable*" lint_off -rule WIDTH -file "*/src/dm_mem.sv" -match "*" +lint_off -rule CMPCONST -file "*/src/dm_csrs.sv" -match "*" diff --git a/hw/vendor/esl_epfl_x_heep/logo/x-heep.png b/hw/vendor/esl_epfl_x_heep/logo/x-heep.png deleted file mode 100644 index 76814a075c16d37d0cb10d1c779a9b498d1f6a94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30569 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 diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson index f1d435df..df55d160 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson @@ -7,26 +7,7 @@ cpu_type: cv32e20 - bus_type: onetoM - - ram: { - address: 0x00000000, #only tried with 0, cannot be changed for now - numbanks: 2, #each bank is 32kB, cannot be changed for now - numbanks_interleaved: 0, - }, - linker_script: { - #value used for the on-chip linker script, the on-flash linker script is generated using FLASH values and the whole RAM values - onchip_ls: { - code: { - address: 0x00000000, - lenght: 0x00000C800, #minimum size for freeRTOS and clang - } - data: { - address: 0x00000C800, - lenght: whatisleft, #keyword used to calculate the size as: ram.length - code.lenght - } - }, stack_size: 0x800, heap_size: 0x800, } @@ -56,10 +37,12 @@ offset: 0x00028000, length: 0x00008000, }, - spi_host: { + dma: { offset: 0x00030000, length: 0x00010000, - path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" + ch_length: 0x100, + num_channels: 0x1, + path: "./hw/ip/dma/data/dma.hjson" }, power_manager: { offset: 0x00040000, @@ -70,30 +53,25 @@ offset: 0x00050000, length: 0x00010000, }, - dma: { - offset: 0x00060000, - length: 0x00010000, - path: "./hw/ip/dma/data/dma.hjson" - }, fast_intr_ctrl: { - offset: 0x00070000, + offset: 0x00060000, length: 0x00010000, path: "./hw/ip/fast_intr_ctrl/data/fast_intr_ctrl.hjson" }, ext_peripheral: { - offset: 0x00080000, + offset: 0x00070000, length: 0x00010000, }, pad_control: { - offset: 0x00090000, + offset: 0x00080000, length: 0x00010000, }, gpio_ao: { - offset: 0x000A0000, + offset: 0x00090000, length: 0x00010000, }, uart: { - offset: 0x000B0000, + offset: 0x000A0000, length: 0x00010000, path: "./hw/vendor/lowrisc_opentitan/hw/ip/uart/data/uart.hjson" }, @@ -108,6 +86,12 @@ is_included: "yes", path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson" }, + spi_host: { + offset: 0x00010000, + length: 0x00010000, + is_included: "yes", + path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" + }, gpio: { offset: 0x00020000, length: 0x00010000, @@ -143,6 +127,7 @@ is_included: "yes", path: "./hw/ip/i2s/data/i2s.hjson" }, + }, flash_mem: { diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson index 605ccbb2..0be257d7 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson @@ -7,26 +7,7 @@ cpu_type: cv32e20 - bus_type: onetoM - - ram: { - address: 0x00000000, #only tried with 0, cannot be changed for now - numbanks: 2, #each bank is 32kB, cannot be changed for now - numbanks_interleaved: 0, - }, - linker_script: { - #value used for the on-chip linker script, the on-flash linker script is generated using FLASH values and the whole RAM values - onchip_ls: { - code: { - address: 0x00000000, - lenght: 0x00000C800, #minimum size for freeRTOS and clang - } - data: { - address: 0x00000C800, - lenght: whatisleft, #keyword used to calculate the size as: ram.length - code.lenght - } - }, stack_size: 0x800, heap_size: 0x800, } @@ -56,10 +37,12 @@ offset: 0x00028000, length: 0x00008000, }, - spi_host: { + dma: { offset: 0x00030000, length: 0x00010000, - path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" + ch_length: 0x100, + num_channels: 0x1, + path: "./hw/ip/dma/data/dma.hjson" }, power_manager: { offset: 0x00040000, @@ -70,30 +53,25 @@ offset: 0x00050000, length: 0x00010000, }, - dma: { - offset: 0x00060000, - length: 0x00010000, - path: "./hw/ip/dma/data/dma.hjson" - }, fast_intr_ctrl: { - offset: 0x00070000, + offset: 0x00060000, length: 0x00010000, path: "./hw/ip/fast_intr_ctrl/data/fast_intr_ctrl.hjson" }, ext_peripheral: { - offset: 0x00080000, + offset: 0x00070000, length: 0x00010000, }, pad_control: { - offset: 0x00090000, + offset: 0x00080000, length: 0x00010000, }, gpio_ao: { - offset: 0x000A0000, + offset: 0x00090000, length: 0x00010000, }, uart: { - offset: 0x000B0000, + offset: 0x000A0000, length: 0x00010000, path: "./hw/vendor/lowrisc_opentitan/hw/ip/uart/data/uart.hjson" }, @@ -105,9 +83,15 @@ rv_plic: { offset: 0x00000000, length: 0x00010000, - is_included: "yes", + is_included: "no", path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_plic/data/rv_plic.hjson" }, + spi_host: { + offset: 0x00010000, + length: 0x00010000, + is_included: "no", + path: "./hw/vendor/lowrisc_opentitan_spi_host/data/spi_host.hjson" + }, gpio: { offset: 0x00020000, length: 0x00010000, @@ -123,7 +107,7 @@ rv_timer: { offset: 0x00040000, length: 0x00010000, - is_included: "yes", + is_included: "no", path: "./hw/vendor/lowrisc_opentitan/hw/ip/rv_timer/data/rv_timer.hjson" }, spi2: { diff --git a/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson b/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson index cc7303a1..1cfa8c79 100644 --- a/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson +++ b/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson @@ -2,11 +2,25 @@ // Solderpad Hardware License, Version 0.51, see LICENSE for details. // SPDX-License-Identifier: SHL-0.51 // Derived from Occamy: https://github.com/pulp-platform/snitch/blob/master/hw/system/occamy/src/occamy_cfg.hjson -// Peripherals configuration for core-v-mini-mcu. - +// +// Pads configuration for core-v-mini-mcu. Read by mcu_gen.py. +// +// The pads contains the list of all the pads available in the design. +// Each pad is defined by its name and can have the following attributes: +// num: (mandatory) - the number of pads of this type +// type: (mandatory) - the type of the pad +// num_offset: (optional) - the offset to the first pad of this type (default 0) +// mapping: (optional) - the mapping of the pad in the design. Useful for ASICs (default top) +// active: (optional) - the active level of the pad (default high) +// driven_manually: (optional) - the pad is driven manually (default False) +// mux: (optional) - the muxing options for the pad +// skip_declaration: (optional) - skip the declaration of the pad in the top level (default False) +// keep_internal: (optional) - keep the pad internal to the design (default False) +// // Add this field at the same level of pads (not inside) if you want to define PADs attributes // attributes: { // bits: 7:0 +// resval: 0x3 // }, { diff --git a/hw/vendor/esl_epfl_x_heep/scripts/synthesis/dc_shell/dc_script.tcl b/hw/vendor/esl_epfl_x_heep/scripts/synthesis/dc_shell/dc_script.tcl index 8edeb7f9..3a246ab8 100644 --- a/hw/vendor/esl_epfl_x_heep/scripts/synthesis/dc_shell/dc_script.tcl +++ b/hw/vendor/esl_epfl_x_heep/scripts/synthesis/dc_shell/dc_script.tcl @@ -10,11 +10,15 @@ remove_design -all source ${SET_LIBS} +define_design_lib WORK -path ./work + source ${READ_SOURCES}.tcl elaborate ${TOP_MODULE} link +load_upf ../../../core-v-mini-mcu.dc.upf + write -f ddc -hierarchy -output ${REPORT_DIR}/precompiled.ddc source ${CONSTRAINTS} diff --git a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt index ef5743c6..cdb2a8f7 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt +++ b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt @@ -42,7 +42,7 @@ if(NOT WIN32) endif() # set the project name -project(${PROJECT} ASM C) +project(${PROJECT} ASM C CXX) # set the required CMake standard set(CMAKE_CXX_STANDARD 14) @@ -89,17 +89,18 @@ FOREACH(file_path ${new_list}) # Add it to the string format list SET(dir_list_str ${dir_list_str} "-I ${dir_path} \ ") - string(REPLACE ";" "" dir_list_str ${dir_list_str}) - + # Add it to the header list SET(h_dir_list_ ${h_dir_list_} "${dir_path}") endif() ENDFOREACH() -LIST(REMOVE_DUPLICATES dir_list_str) +LIST(REMOVE_DUPLICATES dir_list_str) +string(REPLACE ";" "" dir_list_str ${dir_list_str}) #This has been moved here to avoid multiple includes of the same path, see: https://github.com/esl-epfl/x-heep/issues/470 LIST(REMOVE_DUPLICATES h_dir_list_) + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Add list to the directories to be included @@ -108,8 +109,7 @@ SET(INCLUDE_FOLDERS "-I ${RISCV}/${COMPILER_PREFIX}elf/include \ -I ${RISCV}/${COMPILER_PREFIX}elf/include/ \ -I ${ROOT_PROJECT} \ -I ${SOURCE_PATH} \ - ${dir_list_str}") - + ${dir_list_str}") ####################################################################### # FIND SOURCE FILES TO BE INCLUDED @@ -118,15 +118,25 @@ SET(INCLUDE_FOLDERS "-I ${RISCV}/${COMPILER_PREFIX}elf/include \ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Preliminary list of source files inside the source path -# Make a list of the source files that need to be linked -FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS ${SOURCE_PATH}*.c) +# Make a list of the .c source files that need to be linked +FILE(GLOB_RECURSE c_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.c) +# Make a list of the .s source files that need to be linked +FILE(GLOB_RECURSE s_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.s) +# Make a list of the .S source files that need to be linked +FILE(GLOB_RECURSE S_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.S) +# Make a list of the .cpp source files that need to be linked +FILE(GLOB_RECURSE cpp_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.cpp) +SET(new_list ${c_files} ${s_files} ${S_files} ${cpp_files}) + SET( c_dir_list "" ) SET( app_found 0 ) FOREACH(file_path IN LISTS new_list) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list if(${file_path} MATCHES "${SOURCE_PATH}device/") - SET(add 1) - elseif( ${file_path} MATCHES "${SOURCE_PATH}external/" ) + if(NOT ${file_path} MATCHES ".*/crt/.*") + SET(add 1) + endif() + elseif( (${file_path} MATCHES "${SOURCE_PATH}external/") AND ( NOT ${file_path} MATCHES "exclude" ) ) SET(add 1) elseif( ${file_path} MATCHES "${SOURCE_PATH}applications/${PROJECT}/.*${MAINFILE}\." ) # look for main.* SET(app_found 1) @@ -134,7 +144,7 @@ FOREACH(file_path IN LISTS new_list) SET(add 1) endif() - if( add EQUAL 1 ) # If the file path mathced one of the criterion, add it to the list + if( add EQUAL 1 ) # If the file path matched one of the criteria, add it to the list SET(c_dir_list ${c_dir_list} "${file_path}\ ") string(REPLACE ";" "" c_dir_list ${c_dir_list}) @@ -148,28 +158,39 @@ ENDFOREACH() if( app_found EQUAL 0 ) SET(SOURCE_PATH ${ROOT_PROJECT}) - # Make a list of the source files that need to be linked - FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS ${SOURCE_PATH}*.c) + # Make a list of the .c source files that need to be linked + FILE(GLOB_RECURSE c_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.c) + # Make a list of the .s source files that need to be linked + FILE(GLOB_RECURSE s_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.s) + # Make a list of the .S source files that need to be linked + FILE(GLOB_RECURSE S_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.S) + # Make a list of the .cpp source files that need to be linked + FILE(GLOB_RECURSE cpp_files FOLLOW_SYMLINKS ${SOURCE_PATH}*.cpp) + SET(new_list ${c_files} ${s_files} ${S_files} ${cpp_files}) + SET(c_dir_list "") FOREACH(file_path IN LISTS new_list) SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list if(${file_path} MATCHES "${ROOT_PROJECT}device/") - SET(add 1) - elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}/applications/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES "${ROOT_PROJECT}applications/${PROJECT}/.*${MAINFILE}\." ) ) + if(NOT ${file_path} MATCHES ".*/crt/.*") + SET(add 1) + endif() + elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}applications/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES "${ROOT_PROJECT}applications/${PROJECT}/.*${MAINFILE}\." ) AND ( NOT ${file_path} MATCHES "exclude" ) ) SET(add 1) endif() - if( add EQUAL 1 ) # If the file path mathced one of the criterion, add it to the list + if( add EQUAL 1 ) # If the file path matched one of the criteria, add it to the list SET(c_dir_list ${c_dir_list} "${file_path}\ ") string(REPLACE ";" "" c_dir_list ${c_dir_list}) endif() ENDFOREACH() -endif() - + endif() + LIST(REMOVE_DUPLICATES c_dir_list) + ####################################################################### # DETERMINE IF APP IS EXTERNAL ####################################################################### @@ -266,7 +287,7 @@ message( "${Magenta}Target: ${TARGET}${ColourReset}") SET(LINKED_FILES "${LIB_CRT_P} \ ${LIB_VCTR_P} \ ${LIB_CRT_EXT_P} \ - ${c_dir_list}") + ${c_dir_list}") message( "${Magenta}Linked files: ${LINKED_FILES}${ColourReset}") @@ -325,10 +346,10 @@ else() ") endif() set(CMAKE_C_FLAGS ${COMPILER_LINKER_FLAGS}) +set(CMAKE_CXX_FLAGS ${COMPILER_LINKER_FLAGS}) if (${COMPILER} MATCHES "clang") set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=riscv32 \ - -mabi=ilp32 \ --gcc-toolchain=${RISCV} \ --sysroot=${RISCV}/${COMPILER_PREFIX}elf \ -static \ @@ -347,8 +368,18 @@ endif() ####################################################################### # SET TARGETS ####################################################################### - -set(SOURCES ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.c) +if (${COMPILER} MATCHES "gcc") + set(SOURCES ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.c) + if(NOT EXISTS ${SOURCES}) + # If main.c does not exist, set the source file to main.cpp + set(SOURCES ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.cpp) + message("${Red}cpp SOURCES set") + endif() +elseif(${COMPILER} MATCHES "clang") + set(SOURCES ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.c) +elseif(${COMPILER} MATCHES "g\\+\\+.*$") + set(SOURCES ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.cpp) +endif() # add the executable add_executable(${MAINFILE}.elf ${SOURCES}) @@ -378,6 +409,7 @@ SET(CMAKE_EXE_LINKER_FLAGS "-T ${LINKER_SCRIPT} \ -Wl,-Map=${MAINFILE}.map \ -L ${RISCV}/${COMPILER_PREFIX}elf/lib \ -lc -lm -lgcc -flto \ + -fpermissive -fno-rtti -fno-exceptions -fno-threadsafe-statics \ -ffunction-sections -fdata-sections -specs=nano.specs") message( "${Magenta}Lib Folder RISCV-GCC: ${RISCV}/${COMPILER_PREFIX}elf/lib${ColourReset}") @@ -433,12 +465,31 @@ add_custom_command(TARGET ${MAINFILE}.elf POST_BUILD COMMENT "Invoking: Hexdump") # Pre-processing command to create disassembly for each source file -foreach (SRC_MODULE ${MAINFILE} ) +if ((${COMPILER} MATCHES "gcc") OR (${COMPILER} MATCHES "clang")) + if(EXISTS ${SOURCE_PATH}applications/${PROJECT}/${MAINFILE}.c) + foreach (SRC_MODULE ${MAINFILE} ) + add_custom_command(TARGET ${MAINFILE}.elf + PRE_LINK + COMMAND ${CMAKE_OBJDUMP} -S ${ROOT_PROJECT}build/CMakeFiles/${MAINFILE}.elf.dir/${OBJ_PATH}applications/${PROJECT}/${SRC_MODULE}.c.obj > ${SRC_MODULE}.s + COMMENT "Invoking: GCC C Disassemble ( CMakeFiles/${MAINFILE}.dir/${SRC_MODULE}.c.obj)") + endforeach() + else() #main.cpp targets + foreach (SRC_MODULE ${MAINFILE} ) + add_custom_command(TARGET ${MAINFILE}.elf + PRE_LINK + COMMAND ${CMAKE_OBJDUMP} -S ${ROOT_PROJECT}build/CMakeFiles/${MAINFILE}.elf.dir/${OBJ_PATH}applications/${PROJECT}/${SRC_MODULE}.cpp.obj > ${SRC_MODULE}.s + COMMENT "Invoking: GCC CPP Disassemble ( CMakeFiles/${MAINFILE}.dir/${SRC_MODULE}.cpp.obj)") + endforeach() + endif() +elseif(${COMPILER} MATCHES "g\\+\\+.*$") + foreach (SRC_MODULE ${MAINFILE} ) add_custom_command(TARGET ${MAINFILE}.elf PRE_LINK - COMMAND ${CMAKE_OBJDUMP} -S ${ROOT_PROJECT}build/CMakeFiles/${MAINFILE}.elf.dir/${OBJ_PATH}applications/${PROJECT}/${SRC_MODULE}.c.obj > ${SRC_MODULE}.s - COMMENT "Invoking: Disassemble ( CMakeFiles/${MAINFILE}.dir/${SRC_MODULE}.c.obj)") -endforeach() + COMMAND ${CMAKE_OBJDUMP} -S ${ROOT_PROJECT}build/CMakeFiles/${MAINFILE}.elf.dir/${OBJ_PATH}applications/${PROJECT}/${SRC_MODULE}.cpp.obj > ${SRC_MODULE}.s + COMMENT "Invoking: G++ Disassemble ( CMakeFiles/${MAINFILE}.dir/${SRC_MODULE}.cpp.obj)") + endforeach() +endif() + # Adding gdb command - TBD #add_custom_target(gdb DEPENDS ${MAINFILE}.elf) @@ -447,4 +498,4 @@ endforeach() SET(DCMAKE_EXPORT_COMPILE_COMMANDS ON) -#message( FATAL_ERROR "You can not do this at all, CMake will exit." ) +#message( FATAL_ERROR "You can not do this at all, CMake will exit." ) \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/Makefile b/hw/vendor/esl_epfl_x_heep/sw/Makefile index a36f5ead..e327138b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/Makefile +++ b/hw/vendor/esl_epfl_x_heep/sw/Makefile @@ -59,7 +59,7 @@ $(info $$You are fetching sources from $(source_path) ) SOURCE_PATH = $(source_path)/ ROOT_PROJECT = $(mkfile_path)/ INC_FOLDERS = $(mkfile_path)/device/target/$(TARGET)/ -LINK_FOLDER = $(mkfile_path)/linker +LINK_FOLDER ?= $(mkfile_path)/linker # CMake keyword CMAKE_DIR=cmake diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h index 1501da49..4f2b074d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/coremark/coremark.h @@ -64,7 +64,7 @@ Original Author: Shay Gal-on #if TARGET_SIM && PRINTF_IN_SIM #define ee_printf(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define ee_printf(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define ee_printf printf diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_ams_peripheral/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_ams_peripheral/main.c index accf4c4d..817cbff6 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_ams_peripheral/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_ams_peripheral/main.c @@ -10,7 +10,7 @@ #include "ams_regs.h" #include "mmio.h" -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA #error ( "This app does NOT work on the FPGA as it relies on the simulator testbench" ) #endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/add.s b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/add.s new file mode 100644 index 00000000..2e61b29a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/add.s @@ -0,0 +1,6 @@ + .section .text + .globl add_asm_function + +add_asm_function: + add a0, a0, a1 # Add the values in a0 and a1, store the result in a0 + ret # Return from the function \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/constants.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/constants.h new file mode 100644 index 00000000..58834c58 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/constants.h @@ -0,0 +1 @@ +#define MULTIPLY_CONSTANT 2 \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/main.c new file mode 100644 index 00000000..48ca9c9e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/main.c @@ -0,0 +1,31 @@ +#include +#include +#include "constants.h" +#include "x-heep.h" + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +extern int add_asm_function(int a, int b); +extern int mul_by_const_asm_function( int a); + +int main() { + int num1 = 10; + int num2 = 20; + int sum = add_asm_function(num1, num2); + int mul = mul_by_const_asm_function(num2); + + PRINTF("%d+%d=%d\n", num1, num2, sum); + PRINTF("%d*%d=%d\n", num2, MULTIPLY_CONSTANT, mul ); + + return (sum == num1+num2) && (mul == num2*MULTIPLY_CONSTANT) ? EXIT_SUCCESS : EXIT_FAILURE; +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/multiply.S b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/multiply.S new file mode 100644 index 00000000..7130f488 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_asm/multiply.S @@ -0,0 +1,9 @@ +#include "constants.h" + + .section .text + .globl mul_by_const_asm_function + +mul_by_const_asm_function: + li t0, MULTIPLY_CONSTANT # Load the constant into temporary register t0 + mul a0, a0, t0 # Multiply the value in a0 by the constant in t0 + ret # Return from the function \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_clock_gating/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_clock_gating/main.c deleted file mode 100644 index 958e0492..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_clock_gating/main.c +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - // Clock-gating the peripheral subsystem - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_CLK_GATE_REG_OFFSET), 0x1); - - // Clock-gating ram-banks - // We probably should not clockgate the bank where our RAM resides - for(uint32_t i = 2; i < MEMORY_BANKS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x1); - - // Clock-gating external subsystems - for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x1); - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop;"); - - // Enabling the peripheral subsystem - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_CLK_GATE_REG_OFFSET), 0x0); - - // Enabling ram-banks - for(uint32_t i = 2; i < MEMORY_BANKS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x0); - - // Enabling external subsystems - for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) - mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x0); - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.cpp b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.cpp new file mode 100644 index 00000000..00d1b576 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.cpp @@ -0,0 +1,21 @@ + +extern "C" { + #include + #include +} + +#include "MyClass.hpp" + +MyClass::MyClass(int initialValue) : value(initialValue) {} + +void MyClass::setValue(int newValue) { + value = newValue; +} + +int MyClass::getValue() { + return value*5; +} + +void MyClass::printValue() { + printf("Value: %d\n\r", value); +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.hpp b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.hpp new file mode 100644 index 00000000..82922878 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/MyClass.hpp @@ -0,0 +1,15 @@ +#ifndef MYCLASS_HPP +#define MYCLASS_HPP + +class MyClass { +public: + MyClass(int initialValue); // Constructor + void setValue(int newValue); // Setter + int getValue(); // Getter + void printValue(); // Method to print the value + +private: + int value; +}; + +#endif // MYCLASS_HPP diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.c deleted file mode 100644 index bbe2f071..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020 ETH Zurich - * - * 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. - * - * Author: Robert Balas - */ - -#include -#include - -int main(int argc, char *argv[]) -{ - /* write something to stdout */ - printf("hello world!\n"); - return EXIT_SUCCESS; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.cpp b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.cpp new file mode 100644 index 00000000..b314a2b8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/main.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2024 EPFL + * + * 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. + * + * Author: Juan Sapriza + */ + + + +extern "C" { + #include + #include +} + +#include "MyClass.hpp" +#include "core_v_mini_mcu.h" +#include "x-heep.h" + +#if TARGET_SIM && PRINTF_IN_SIM +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +int main() +{ + MyClass myObject(10); // Create an object with initial value 10 + myObject.printValue(); // Print the initial value + + myObject.setValue(20); // Change the value to 20 + myObject.printValue(); // Print the updated value + + int value = myObject.getValue(); // Get the value + PRINTF("Retrieved Value: %d\n\r" ,value); // Print the retrieved value + + return value == 20*5 ? EXIT_SUCCESS : EXIT_FAILURE; +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.cpp b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.cpp deleted file mode 100644 index 53d08e36..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2022 ESL EPFL - * - * 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. - * - * Author: Jose Miranda - */ - -extern "C" { - #include - #include - #include "test_cpp.h" -} - -#define LOOPS 5 -template -T mySum(T x, T y) -{ - return x+y; -} - -int test_numbers(void) -{ - int i = 0, a = 3, b = 7; - - while (i < LOOPS) - { - printf("Integer sum %d\n", mySum(a, b)); - i = i + 1; - } - - return 0; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.h deleted file mode 100644 index 31121435..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_cpp/test_cpp.h +++ /dev/null @@ -1,4 +0,0 @@ -/// @brief -/// @param -/// @return -int test_numbers(void); \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py new file mode 100644 index 00000000..5a4a6cd2 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +## Copyright 2024 EPFL +## Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +# type " python gen_stimuly.py " in the terminal to generate the matrices.h file + +import sys +import random +import numpy as np + +def write_arr(f, name, arr, ctype, size): + f.write("const " + ctype + " " + name + "[] = {\n") + + for row in arr: + for elem in row[:-1]: + f.write('%d,' % (elem)) + f.write('%d,\n' % (row[-1])) + + f.write('};\n\n') + return + +def write_arr_flash_only(f, name, arr, ctype, size): + f.write( ctype + " __attribute__((section(\".xheep_data_flash_only\"))) __attribute__ ((aligned (16)))" + name + "[] = {\n") + + for row in arr: + for elem in row[:-1]: + f.write('%d,' % (elem)) + f.write('%d,\n' % (row[-1])) + + f.write('};\n\n') + return + + +################################################################################ +f = open('matrices.h', 'w') +f.write('#ifndef MATRICES_H_\n') +f.write('#define MATRICES_H_\n') +f.write('// This file is automatically generated\n') + + +SIZE = 64 +RANGE = 10 + +m_a = [] +m_b = [] +m_exp = [] + +# Generate random 8 bit integers from -RANGE to RANGE for A and B +A = np.random.randint(0, RANGE, size=(SIZE, SIZE), dtype=np.int32) +B = np.random.randint(0, RANGE, size=(SIZE, SIZE), dtype=np.int32) +C = np.zeros((SIZE, SIZE), dtype=np.int32) + +# Test the function with A and B +C = np.matmul(A,B) + +write_arr_flash_only(f, 'A', A, 'int32_t', SIZE) +write_arr(f, 'B', B, 'int32_t', SIZE) +write_arr(f, 'C', C, 'int32_t', SIZE) + +f.write('#define MATRIX_SIZE %d\n' % SIZE) + + +f.write('#endif') diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c new file mode 100644 index 00000000..01f7dab7 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c @@ -0,0 +1,87 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: sw/applications/example_data_processing_from_flash/main.c +// Author: Francesco Poluzzi +// Date: 29/07/2024 + +/** + * @file main.c + * @brief Example of data processing (matrix multiplication) reading data from flash memory + * + * Simple example that read a matrix from flash memory in many step and performs + * matrix multiplication. This is useful for applications where the + * data size does not fit in the available SRAM memory, so some data needs to be + * stored as "flash_only" and read trough the spi interface. This usually requires + * filling a buffer and tiling the data processing. +*/ + +#include +#include +#include + +#include "x-heep.h" +#include "w25q128jw.h" +#include "main.h" +#include "dma_sdk.h" + +#define TILING_ROWS 2 + + /* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +int32_t buffer_data[MATRIX_SIZE*TILING_ROWS] = {0}; +int32_t output_matrix[MATRIX_SIZE*MATRIX_SIZE] = {0}; + +int main(int argc, char *argv[]) { + + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + #ifdef TARGET_SIM + PRINTF("This application is meant to run on FPGA only\n"); + return EXIT_SUCCESS; + #endif + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + // Pick the correct spi device based on simulation type + spi_host_t* spi = spi_flash; + + // Init SPI host and SPI<->Flash bridge parameters + if (w25q128jw_init(spi) != FLASH_OK){ + PRINTF("Error initializing SPI flash\n"); + return EXIT_FAILURE; + } + + for (int i = 0; i < MATRIX_SIZE; i+=TILING_ROWS) { + // read first half matrix A from flash and perform matmul + if(fill_buffer(&A[i*MATRIX_SIZE], buffer_data, MATRIX_SIZE*TILING_ROWS)!=FLASH_OK){ + PRINTF("Error reading from flash\n"); + return EXIT_FAILURE; + } + matmul(buffer_data, B, &output_matrix[i*MATRIX_SIZE], TILING_ROWS, MATRIX_SIZE, MATRIX_SIZE); + } + + for(int i = 0; i < MATRIX_SIZE*MATRIX_SIZE; i++){ + if (output_matrix[i] != C[i]){ + PRINTF("Result[%d][%d]:golden model %d : %d\n", (i/MATRIX_SIZE), (i % MATRIX_SIZE), output_matrix[i], C[i]); + return EXIT_FAILURE; + } + } + PRINTF("All tests passed!\n"); + return EXIT_SUCCESS; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.h new file mode 100644 index 00000000..0e588e78 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.h @@ -0,0 +1,42 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: sw/applications/example_data_processing_from_flash/main.h +// Author: Francesco Poluzzi +// Date: 29/07/2024 + +#ifndef MAIN_H_ +#define MAIN_H_ + +#include +#include +#include + +#include "x-heep.h" +#include "w25q128jw.h" +#include "matrices.h" + +w25q_error_codes_t fill_buffer(uint32_t *source, uint32_t *buffer, uint32_t len); +void matmul(int32_t *A, int32_t *B, int32_t *res, int rowsA, int colsA, int colsB); + +w25q_error_codes_t fill_buffer(uint32_t *source, uint32_t *buffer, uint32_t len){ + uint32_t *source_flash = heep_get_flash_address_offset(source); + w25q_error_codes_t status = w25q128jw_read_standard(source_flash, buffer, len*4); + return status; +} + +void matmul(int32_t *A, int32_t *B, int32_t *res, int rowsA, int colsA, int colsB) { + for (int i = 0; i < rowsA; i++) { + for (int j = 0; j < colsB; j++) { + int32_t sum = 0; + for (int k = 0; k < colsA; k++) { + sum += A[i*colsA + k] * B[k*colsB + j]; + } + res[i*colsB + j] = sum; + } + } +} + + +#endif // DATA_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h new file mode 100644 index 00000000..323d1a06 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h @@ -0,0 +1,206 @@ +#ifndef MATRICES_H_ +#define MATRICES_H_ +// This file is automatically generated +int32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16)))A[] = { +8,0,9,3,0,0,7,3,4,4,4,0,5,1,9,3,9,1,0,4,1,1,9,4,6,9,8,1,3,3,2,6,5,6,8,7,4,3,3,1,1,9,8,9,6,3,1,6,4,3,6,1,9,0,6,7,5,0,6,5,1,5,6,2, +3,1,8,2,9,8,1,3,0,2,4,6,6,5,7,1,5,5,5,8,6,5,4,9,2,6,7,1,7,2,5,0,9,9,7,6,2,1,6,5,4,9,5,3,1,5,6,9,3,4,4,1,1,7,2,5,8,0,6,4,3,1,8,2, +3,8,8,0,7,5,1,9,1,2,2,2,0,6,4,6,2,4,7,6,0,9,9,8,5,1,9,5,9,8,2,2,7,7,7,5,9,0,3,4,5,3,9,0,2,2,0,7,2,3,1,1,5,5,3,6,4,4,3,7,5,6,0,4, +9,4,4,2,0,4,3,5,7,5,7,5,3,6,5,4,5,7,4,2,4,0,2,8,6,8,4,0,1,3,8,5,4,8,5,1,6,0,7,6,3,1,1,6,2,5,4,9,4,9,5,1,3,7,0,1,0,2,6,3,8,0,1,6, +3,7,8,9,5,1,7,5,5,8,9,7,2,1,2,1,0,3,5,5,3,0,3,0,8,3,3,5,6,3,7,2,2,6,6,1,7,1,7,6,7,1,7,2,0,6,5,1,7,6,6,4,6,3,7,2,1,0,5,9,1,1,1,1, +4,5,6,7,5,3,5,0,2,9,1,7,1,5,6,6,8,8,1,4,5,8,5,2,5,8,8,5,9,5,2,5,6,4,1,2,9,7,1,1,0,6,9,1,2,2,6,3,7,6,6,1,2,0,1,1,8,9,7,0,4,9,0,3, +5,9,0,0,6,3,8,2,4,5,2,9,1,4,4,8,9,3,5,7,1,6,8,8,7,9,3,7,7,4,8,4,9,6,3,1,5,0,6,7,9,6,9,6,4,9,0,6,0,2,1,4,9,4,7,6,0,1,8,2,8,4,2,9, +5,0,0,9,3,7,3,3,8,4,2,0,1,9,5,5,0,0,4,9,8,7,1,3,3,4,3,0,0,3,3,0,2,5,1,8,6,0,2,0,4,2,3,2,9,5,5,2,8,9,4,2,9,7,7,8,8,3,8,9,3,9,1,9, +6,8,4,2,5,3,3,5,1,0,0,8,1,3,9,9,5,5,9,0,5,9,8,2,4,1,4,3,0,6,7,9,9,2,1,8,1,5,1,9,6,3,9,5,0,1,3,6,4,7,5,0,4,6,3,1,4,9,2,1,8,2,8,5, +9,8,5,1,8,0,0,0,1,5,2,6,2,3,2,6,6,7,3,6,6,3,5,9,8,8,1,7,4,4,1,2,0,2,4,3,0,0,5,5,3,8,6,1,4,6,4,8,5,9,7,9,8,1,0,9,8,1,9,6,4,4,0,2, +1,6,0,4,7,8,1,6,8,8,9,4,7,8,1,3,5,4,1,2,8,3,6,4,2,0,1,9,3,9,6,9,2,2,3,3,2,7,1,0,2,8,9,9,9,8,7,4,2,9,4,8,2,0,9,0,3,2,5,6,4,9,3,1, +0,9,9,8,5,4,5,4,1,9,3,3,0,1,6,3,8,6,6,6,3,8,5,7,8,9,4,1,8,2,6,0,5,3,6,7,1,9,8,7,9,0,5,5,3,7,0,1,2,9,4,3,8,3,2,6,1,0,5,5,6,0,4,8, +8,6,2,6,1,4,4,2,0,3,9,8,9,3,1,8,2,9,5,9,9,4,6,0,9,9,9,4,8,7,7,4,4,1,7,9,9,7,3,2,1,6,5,6,5,4,7,9,0,1,0,5,6,9,1,5,1,1,7,5,8,6,7,6, +7,6,5,8,6,2,3,1,2,8,3,9,5,9,3,9,8,8,2,4,7,0,7,4,1,1,9,8,9,7,4,9,3,4,8,3,6,1,1,7,4,9,7,6,8,3,9,1,2,8,2,1,1,6,0,1,2,1,2,2,2,1,0,1, +3,2,7,7,9,2,1,4,0,0,4,4,4,1,4,3,2,1,1,6,4,0,4,6,2,4,9,1,1,3,6,9,0,0,0,0,4,4,6,7,5,9,0,4,1,7,7,0,5,9,4,5,4,1,9,1,3,0,8,4,9,1,8,3, +9,9,3,9,1,9,4,5,3,6,0,5,8,4,3,9,0,2,7,6,1,9,7,4,0,0,9,4,1,6,3,6,7,9,3,9,4,6,6,1,1,7,0,8,0,3,1,0,5,9,3,9,4,7,7,1,1,7,7,1,1,0,2,1, +0,8,7,7,8,0,9,0,4,3,9,1,3,8,3,8,4,2,1,2,2,9,0,2,4,6,1,3,1,8,9,0,1,7,9,0,1,7,2,3,7,7,7,0,0,1,4,4,8,4,8,7,8,9,9,8,9,3,1,6,5,4,5,2, +6,1,9,3,1,9,0,6,0,0,1,5,3,0,0,4,7,7,2,4,8,8,9,3,8,8,9,4,5,3,8,4,1,2,7,5,4,4,9,3,7,5,2,9,4,5,0,3,2,3,7,2,2,8,7,1,4,4,9,2,1,7,7,6, +6,3,0,2,7,7,2,8,8,7,1,6,8,1,5,6,7,7,7,4,9,8,4,8,7,6,0,8,0,9,8,0,8,8,1,4,7,8,7,3,3,9,8,6,5,7,8,9,0,8,6,6,7,4,8,3,6,0,2,8,3,9,3,1, +5,9,0,5,3,9,5,4,6,8,4,9,9,6,8,2,5,8,0,1,3,8,5,9,8,3,1,4,9,0,9,8,1,6,6,9,9,5,0,4,9,4,2,5,3,0,2,9,8,1,6,3,7,3,8,2,9,9,9,6,0,7,4,5, +7,0,7,7,1,7,7,3,2,5,4,5,7,5,7,2,8,7,2,0,2,8,3,9,7,5,1,0,5,8,7,2,1,9,2,3,3,7,7,1,4,3,2,2,8,3,0,7,4,6,1,5,0,3,6,5,0,9,4,2,3,1,5,0, +9,4,2,7,3,2,5,8,5,1,7,2,1,9,1,6,7,3,7,0,2,7,9,4,3,1,9,6,1,3,2,5,9,9,1,9,0,5,4,2,3,3,3,3,1,7,2,2,9,9,8,4,1,1,1,1,6,6,5,4,0,3,1,2, +1,9,3,6,6,3,4,9,3,4,2,2,4,3,5,4,0,6,5,1,1,1,2,7,9,4,0,0,3,7,1,8,9,0,7,7,1,3,7,7,5,7,9,7,0,0,8,1,9,0,3,9,3,9,0,8,4,5,4,5,6,0,9,4, +5,6,4,1,1,8,9,4,3,2,5,9,5,4,5,6,9,4,1,7,1,3,0,0,5,9,5,2,3,2,5,5,7,2,2,9,3,1,2,8,5,0,1,0,8,9,2,9,3,4,6,9,5,4,7,4,7,9,6,1,0,8,2,8, +5,3,4,4,8,1,5,5,2,4,2,1,1,5,6,3,2,4,9,1,1,5,3,1,3,3,8,0,4,8,8,4,7,0,1,1,6,2,1,0,8,2,0,4,4,4,5,4,0,7,7,8,5,5,0,0,0,1,8,8,7,4,7,9, +1,7,2,6,1,6,7,6,2,9,6,2,5,7,7,8,1,5,7,3,3,4,9,8,7,6,5,5,2,8,7,8,7,1,6,0,5,2,2,4,2,3,3,2,0,0,3,4,5,2,2,9,2,9,7,7,9,5,9,0,1,5,3,0, +7,4,1,9,4,5,0,6,7,4,1,2,7,4,0,8,8,3,7,0,5,3,2,2,4,2,7,0,0,5,0,4,6,9,6,2,2,4,5,3,4,4,2,8,7,3,9,4,5,8,5,2,9,4,1,3,2,9,2,2,4,3,9,8, +6,7,8,8,8,8,9,1,1,5,0,5,5,4,2,0,3,0,4,2,1,0,2,6,2,8,1,4,1,6,8,0,0,5,1,3,8,0,2,3,6,6,3,3,4,8,9,2,8,3,1,3,7,2,1,4,9,9,4,4,3,1,2,1, +0,9,9,6,9,3,9,7,5,3,9,3,0,2,9,6,2,2,5,6,8,2,9,6,8,3,6,7,4,4,3,8,6,1,2,6,6,0,9,0,0,9,3,9,9,8,4,8,6,8,0,6,1,3,0,8,4,3,5,3,0,6,2,2, +1,7,1,4,3,5,6,3,7,2,3,1,6,3,5,2,9,3,7,0,6,9,6,5,3,9,6,0,2,3,1,0,6,2,5,8,2,3,0,0,0,4,3,9,4,6,3,5,2,0,3,8,8,2,8,2,5,6,9,7,3,2,9,9, +5,5,4,0,2,4,0,4,5,2,7,6,6,8,5,3,5,5,2,7,3,8,7,5,5,3,6,0,8,6,3,1,7,4,7,1,0,4,3,0,7,9,5,0,6,0,7,3,3,8,2,5,1,4,4,1,6,4,2,5,5,6,8,0, +8,5,9,6,7,9,8,2,9,1,5,1,0,5,9,6,1,9,8,7,6,9,1,0,1,2,8,4,7,4,5,6,9,1,5,8,7,2,4,3,8,3,8,9,0,6,3,1,6,5,7,0,3,1,3,8,5,7,0,8,8,2,7,3, +7,2,8,3,9,8,9,1,6,5,0,4,5,7,3,9,9,0,9,9,2,6,4,3,3,3,3,9,5,5,7,4,2,4,7,2,3,5,5,9,8,6,3,1,5,7,6,8,9,4,1,8,8,5,4,9,0,7,5,4,5,3,6,9, +0,4,8,3,0,9,2,7,1,2,8,5,6,2,8,5,2,0,4,8,2,5,8,2,0,5,7,8,8,0,8,9,3,7,9,5,4,9,4,2,6,9,7,1,5,4,6,3,2,6,3,9,8,4,1,0,1,6,2,0,5,3,7,6, +6,4,6,1,0,7,3,4,6,2,7,1,3,9,0,5,5,4,7,0,0,3,4,8,2,6,6,9,9,0,2,6,5,9,9,7,7,0,6,2,2,7,8,3,8,6,0,4,7,7,0,9,2,2,1,5,1,8,2,3,7,7,1,9, +0,4,2,8,9,7,3,4,1,5,3,3,0,6,4,1,1,8,1,4,9,6,4,0,8,0,2,7,2,2,1,2,8,3,2,3,7,5,9,1,7,8,5,5,6,2,0,0,1,4,3,5,2,8,4,2,7,7,0,5,7,3,4,0, +1,7,4,5,1,3,9,1,8,2,3,7,0,2,9,3,5,3,3,9,2,6,0,5,7,4,9,7,9,6,9,6,4,1,5,3,7,3,0,2,3,9,7,7,8,2,5,8,4,0,8,3,3,0,4,3,0,5,7,3,7,3,9,7, +4,5,5,0,8,1,5,7,8,1,2,5,8,3,0,6,2,9,6,4,5,5,6,6,0,3,8,0,2,0,9,9,1,7,9,4,8,8,7,5,8,1,5,0,0,4,7,1,2,0,2,0,6,7,8,0,1,3,4,0,8,6,9,5, +6,6,9,6,5,1,2,7,1,6,5,5,5,7,2,8,3,5,6,0,8,7,6,9,3,8,8,8,5,3,4,8,5,6,9,2,7,5,7,3,1,7,2,2,9,6,1,9,2,4,4,3,9,2,5,1,6,7,7,2,9,8,6,0, +9,4,4,3,0,3,4,7,1,0,8,4,8,3,1,4,2,5,9,0,0,1,8,5,1,9,3,0,8,9,9,7,4,2,0,3,7,5,8,8,9,1,6,8,3,2,1,6,7,1,6,9,5,9,9,3,5,2,3,4,7,2,1,1, +4,8,0,1,3,6,6,2,5,2,7,2,5,5,7,0,6,4,6,4,8,0,6,4,0,3,6,7,9,7,4,6,8,9,8,7,8,5,0,5,4,5,4,2,8,6,7,8,2,2,0,8,6,4,3,9,7,1,2,3,5,2,5,2, +8,7,0,9,4,4,0,7,5,9,1,8,7,6,9,3,5,6,8,7,8,8,6,9,4,8,6,1,2,8,5,1,1,3,3,3,6,2,8,0,7,3,1,3,2,4,1,1,3,5,6,1,0,9,7,7,7,9,3,4,3,3,6,7, +3,2,8,4,1,0,4,9,4,2,9,5,7,0,9,0,7,8,1,1,8,9,9,3,4,0,7,9,1,4,7,7,9,6,1,8,1,4,1,2,1,6,8,5,8,9,5,1,2,4,3,2,4,6,9,0,6,7,0,8,5,5,2,4, +2,8,7,9,4,3,4,7,0,1,6,9,2,4,9,0,4,2,4,7,6,2,7,7,6,1,5,7,0,2,4,8,4,9,0,1,4,0,1,5,4,9,1,6,8,6,7,9,6,7,6,5,2,0,1,7,1,0,8,0,1,2,5,2, +0,6,8,8,3,3,5,7,1,1,7,5,2,6,2,0,4,2,7,0,7,9,6,9,1,8,4,3,5,7,1,9,3,3,0,5,6,2,0,5,1,6,8,0,1,2,0,6,7,7,9,6,5,6,2,6,9,4,2,7,4,9,6,8, +3,3,9,1,5,2,9,1,4,4,8,9,3,8,1,4,7,9,0,2,4,8,4,5,6,0,7,4,8,9,6,9,9,3,4,9,6,2,2,6,4,0,5,2,5,3,2,3,4,1,3,4,1,9,5,4,9,3,0,3,4,1,2,8, +4,2,0,9,7,5,7,2,9,0,8,6,0,1,5,6,8,3,4,7,5,9,2,0,8,7,6,6,7,1,3,5,3,7,6,2,1,8,2,0,4,1,6,9,3,0,5,7,1,1,6,8,3,4,1,2,7,6,5,6,6,1,1,2, +6,3,5,8,4,9,2,0,9,7,5,4,3,5,7,0,5,7,7,4,4,0,5,3,4,6,0,0,2,2,7,7,0,5,7,2,6,5,3,5,9,9,4,1,6,7,7,3,4,8,6,6,1,1,7,1,3,4,4,4,4,2,1,1, +7,1,2,0,5,9,2,1,3,9,3,7,4,9,5,1,6,5,7,2,0,5,2,4,8,0,5,2,6,6,7,9,8,7,7,8,5,2,4,6,9,3,4,8,8,1,3,4,5,2,2,7,3,9,2,8,8,8,8,8,1,4,1,4, +8,6,3,2,5,1,1,0,9,9,9,8,3,9,5,4,6,2,0,0,4,6,7,1,0,0,0,2,5,2,5,4,9,1,1,5,6,7,6,0,6,4,3,6,5,2,8,7,3,4,0,7,5,4,6,8,8,9,9,6,2,3,2,9, +0,4,9,6,2,5,0,6,0,6,2,0,5,9,7,9,9,7,9,7,3,0,9,7,9,2,5,0,7,5,7,6,7,7,9,9,1,7,1,6,1,3,9,3,6,4,4,9,8,9,6,4,8,5,8,1,5,9,2,5,4,7,2,7, +1,1,3,6,0,1,9,3,5,0,5,0,0,3,0,3,7,7,5,7,5,8,0,4,9,8,8,2,3,7,1,9,8,3,2,1,4,7,8,4,3,7,6,0,2,7,6,2,4,6,2,4,9,2,5,0,0,0,7,5,3,5,7,1, +7,5,9,1,5,8,8,6,5,1,8,4,3,2,1,9,7,8,1,2,3,5,6,0,6,1,0,3,7,9,1,3,0,2,0,5,4,7,3,9,3,4,6,6,6,8,2,0,4,8,3,1,1,2,0,6,9,9,9,8,3,4,7,7, +4,9,4,5,0,9,6,5,5,2,5,5,5,5,1,9,4,9,8,1,5,2,9,8,1,9,9,0,0,7,4,8,7,1,8,8,7,3,3,2,2,4,5,0,1,2,3,6,9,0,0,2,1,5,5,7,7,0,7,6,5,5,7,6, +9,1,9,3,8,2,2,9,7,9,4,9,5,2,6,5,5,3,7,2,8,8,7,7,9,2,1,4,0,2,2,8,8,5,9,9,0,5,2,1,5,5,3,3,7,0,7,3,5,9,8,2,6,0,3,7,8,8,4,6,6,3,3,3, +0,8,6,6,5,9,4,8,7,8,4,8,3,8,7,9,4,4,5,5,6,0,9,4,9,2,8,7,0,1,2,5,3,6,1,9,2,7,4,6,4,7,9,5,6,0,4,1,1,2,6,5,2,1,1,9,6,2,0,8,0,4,7,5, +8,5,6,2,3,3,9,4,4,1,9,2,7,0,6,8,1,5,6,7,3,9,9,4,5,6,9,6,7,9,0,2,8,5,1,3,9,2,8,3,5,3,9,2,5,6,3,7,0,2,4,8,2,8,4,2,2,1,8,9,2,1,7,4, +3,8,3,6,2,1,1,6,1,1,7,9,3,4,5,4,8,7,2,3,9,8,8,1,8,0,8,5,8,1,1,2,2,3,9,5,6,1,0,3,1,5,2,1,6,4,4,7,0,4,9,8,7,6,6,9,6,3,0,6,7,6,3,5, +2,1,9,4,2,4,3,9,1,9,0,9,9,2,2,1,5,2,2,9,2,4,6,2,3,3,4,0,0,8,8,4,6,2,2,5,6,7,5,6,1,3,9,7,0,1,2,2,5,9,2,1,3,1,8,8,1,3,6,9,6,0,9,2, +5,4,8,8,6,8,9,1,7,6,2,0,7,8,6,1,0,6,9,2,7,6,8,1,3,6,2,1,5,1,0,4,9,1,5,2,4,4,4,5,6,4,4,6,8,5,6,7,8,5,3,1,3,3,6,9,6,0,0,8,1,8,8,6, +9,0,5,0,9,6,4,8,3,9,9,8,2,8,0,0,9,5,2,1,2,0,1,5,2,1,9,6,3,8,7,0,1,0,9,1,0,1,6,0,8,7,4,5,6,4,5,6,5,9,5,8,9,4,2,0,8,2,6,5,4,5,4,5, +8,7,5,6,8,4,8,2,4,6,5,0,2,1,1,0,8,3,0,0,6,7,6,5,5,7,0,9,4,2,1,0,8,1,5,0,4,5,5,1,4,6,6,5,5,2,2,7,9,8,6,6,4,3,9,5,7,6,5,8,5,7,7,3, +2,4,8,3,7,6,5,0,3,8,0,4,8,7,6,3,6,0,3,2,8,7,4,6,2,1,6,3,5,7,5,1,5,3,8,9,9,3,0,7,2,6,7,5,5,7,3,3,9,7,6,3,6,4,3,2,5,3,5,0,1,2,7,3, +6,0,1,2,3,9,7,8,4,6,3,8,3,0,5,2,9,1,9,6,9,6,2,1,0,6,0,1,2,5,6,4,9,8,9,4,1,2,6,6,4,7,1,2,7,3,7,9,9,2,6,0,4,4,2,5,0,0,4,6,2,4,8,0, +}; + +const int32_t B[] = { +1,1,9,1,9,6,7,6,2,8,2,8,5,6,3,0,2,4,0,1,7,5,9,1,7,4,7,3,2,2,8,0,3,1,3,7,1,9,2,5,6,5,2,3,7,1,6,3,3,2,1,4,2,4,8,9,4,0,8,3,6,4,0,9, +6,1,6,9,1,4,3,4,2,3,4,8,0,0,1,2,7,7,9,6,1,5,8,7,6,7,1,8,0,2,7,1,4,5,7,4,2,7,6,0,0,1,7,9,0,4,3,8,8,9,4,3,4,7,6,3,4,0,8,9,5,1,1,7, +3,3,4,7,0,4,1,5,2,1,2,5,6,6,1,4,4,2,8,7,5,4,0,5,8,1,7,2,3,4,7,7,6,3,1,5,6,2,8,5,7,8,7,7,9,3,5,9,9,1,1,1,6,8,5,5,9,7,9,5,8,9,0,9, +2,9,2,2,4,4,6,7,4,7,4,2,4,2,7,2,2,2,9,6,7,2,1,5,0,9,5,2,8,6,8,6,2,7,8,2,0,1,0,2,9,0,3,9,9,6,9,2,1,7,1,1,4,6,7,9,8,8,5,3,1,1,8,5, +2,2,8,2,0,6,7,3,0,1,2,0,5,2,6,9,3,5,2,0,9,7,6,7,2,5,2,3,0,6,0,4,5,1,6,4,7,8,0,1,0,7,1,6,6,5,4,7,2,3,0,3,8,0,7,4,5,0,3,8,6,3,5,0, +9,1,3,8,5,9,4,9,0,2,9,7,1,1,0,8,4,7,8,5,3,2,3,0,9,8,3,7,5,8,8,5,9,5,6,5,2,7,3,3,7,2,2,7,0,0,4,9,8,8,0,6,0,9,3,9,6,5,7,0,8,2,2,3, +4,3,2,5,2,0,4,6,7,1,5,1,6,4,1,0,4,6,1,1,3,8,8,9,1,1,9,9,7,5,0,8,5,5,9,0,4,1,7,5,2,2,7,8,5,1,1,0,0,2,0,1,7,9,2,0,3,7,7,8,6,9,4,0, +6,0,4,1,4,2,0,2,5,4,0,6,9,9,1,1,8,7,5,0,3,3,8,6,1,1,3,1,9,2,4,6,2,5,6,6,8,4,6,1,3,0,7,1,3,3,0,3,3,2,7,4,6,0,6,7,7,7,0,4,9,4,9,4, +1,9,5,5,4,5,7,7,2,4,9,4,6,0,3,5,2,6,8,0,3,0,5,5,1,6,9,2,6,9,7,3,8,0,6,1,0,0,4,4,2,3,3,7,8,1,7,4,7,0,9,2,1,4,2,7,0,3,0,7,7,7,4,0, +5,0,9,9,7,4,0,5,7,3,7,5,2,4,4,9,5,4,5,7,5,1,2,1,3,8,8,5,1,6,6,3,9,8,1,1,9,4,7,9,8,8,4,5,0,9,5,3,0,3,5,7,4,2,5,5,2,9,9,7,7,9,2,3, +4,9,9,2,5,3,1,7,6,2,5,2,5,9,3,1,1,9,0,3,1,1,2,5,0,7,6,0,4,0,0,5,5,9,8,4,1,0,9,8,9,7,1,5,8,5,7,1,1,3,7,1,3,4,7,8,7,8,8,5,2,7,5,5, +0,9,7,2,6,8,5,7,0,3,6,9,1,2,5,7,7,2,9,6,6,9,7,1,0,6,6,4,3,3,7,1,8,0,7,2,8,9,2,1,0,1,7,9,5,7,6,8,5,4,0,1,7,9,8,9,0,5,4,9,8,5,5,9, +9,9,3,4,5,3,7,5,7,3,3,2,1,5,7,5,0,8,4,5,8,9,4,3,9,8,2,6,3,9,3,1,3,6,5,3,9,0,8,4,5,5,5,9,4,0,9,6,0,4,4,6,2,5,8,2,0,9,0,0,0,0,7,9, +4,9,3,6,2,7,0,5,9,6,9,4,8,6,2,1,9,0,2,2,6,9,5,0,5,8,7,6,3,8,6,9,8,9,8,2,8,2,9,4,2,7,2,6,6,9,0,1,9,8,9,0,0,5,3,5,8,7,9,1,4,9,8,1, +3,5,1,8,4,8,7,4,0,4,9,8,0,8,6,7,0,7,9,1,6,6,4,8,2,0,8,9,7,8,9,0,1,4,2,0,9,4,9,5,3,0,4,0,6,8,2,0,3,9,7,4,8,3,4,9,4,6,9,6,2,9,9,6, +5,2,1,9,2,2,6,4,4,3,4,4,6,0,2,9,0,8,4,6,3,4,1,6,6,5,4,4,5,0,0,3,4,4,1,1,4,9,8,0,1,6,2,6,1,3,7,3,4,1,5,9,0,1,9,2,7,3,6,7,1,4,7,7, +7,7,9,0,8,0,2,4,2,3,7,5,7,4,2,0,8,8,3,7,1,4,7,2,7,9,4,3,0,8,1,6,9,8,6,0,3,4,7,8,8,6,7,1,7,9,9,9,6,0,3,9,4,8,8,3,8,9,5,0,4,4,4,7, +7,8,3,4,5,8,1,6,7,5,2,0,9,5,9,7,1,8,6,4,4,9,3,8,6,2,8,3,0,7,6,5,9,6,5,8,0,9,8,7,4,4,1,1,8,7,8,7,2,2,8,8,3,1,9,2,2,5,8,6,3,3,7,8, +1,3,6,6,2,8,8,1,2,5,2,4,8,3,8,5,0,8,4,9,9,3,4,4,3,6,6,7,3,3,8,5,0,9,6,9,0,2,5,8,9,3,1,0,8,8,4,4,3,5,9,8,6,1,2,0,9,4,2,9,4,0,0,1, +8,1,7,6,0,2,2,7,6,0,1,7,6,9,0,9,7,8,4,9,6,2,4,3,3,8,8,8,5,6,3,2,2,7,1,7,8,6,6,1,4,0,8,3,5,0,0,3,5,2,3,4,2,4,9,2,1,0,4,3,3,2,0,5, +3,8,0,3,8,6,8,3,8,8,7,2,5,4,6,5,5,8,2,8,8,1,4,0,8,9,3,2,0,9,7,2,9,4,6,2,5,0,2,5,9,1,7,7,9,9,4,5,3,7,6,3,3,9,4,8,5,4,6,4,0,8,8,2, +0,0,8,9,8,3,3,9,7,2,6,9,2,9,4,6,8,3,8,7,7,6,4,7,8,5,8,6,1,3,0,2,2,9,4,8,0,1,3,6,4,2,9,2,1,4,7,0,3,8,5,6,6,1,6,2,0,0,2,4,1,4,4,4, +6,8,7,2,1,9,3,3,8,5,8,2,7,5,9,8,5,6,5,9,8,6,3,2,7,1,1,2,7,6,7,1,1,6,8,5,0,8,4,4,3,6,8,1,7,6,0,9,2,6,0,2,2,8,6,2,6,9,7,3,3,3,5,4, +6,0,5,0,9,4,5,1,9,8,1,4,5,7,2,2,9,0,3,7,3,2,9,2,6,5,3,7,2,6,1,3,1,5,7,1,4,6,0,6,4,9,1,5,0,1,8,0,5,9,8,5,2,1,0,7,3,2,5,8,1,7,5,3, +0,5,8,3,4,8,3,3,6,1,2,9,6,8,3,6,6,9,8,1,5,2,0,9,6,7,1,7,6,3,0,9,0,3,5,6,2,4,2,8,2,7,5,7,6,5,2,2,0,2,8,9,3,6,7,6,1,5,2,9,0,1,7,5, +9,0,0,5,5,8,3,0,9,7,6,8,5,7,2,4,9,8,2,2,8,3,1,6,5,1,8,6,2,0,8,5,5,8,0,3,1,8,0,0,6,8,4,1,4,1,5,0,0,9,0,0,2,2,3,3,1,8,6,6,3,7,1,3, +6,6,0,9,4,8,7,5,0,3,1,4,0,1,1,2,8,7,4,4,8,3,1,1,6,3,7,9,2,0,8,9,6,5,8,7,0,8,8,6,3,4,9,1,5,0,9,8,8,2,0,4,2,5,7,0,7,5,1,6,5,8,6,9, +9,6,7,5,2,9,9,1,7,1,0,4,4,9,5,8,9,3,2,8,4,0,7,3,5,8,2,6,2,1,7,0,5,0,1,9,3,2,7,7,4,1,6,4,9,6,3,5,6,8,2,5,3,9,1,5,3,2,7,1,9,1,2,8, +1,0,7,9,9,1,7,7,0,5,6,8,6,8,7,4,9,6,3,7,9,3,2,5,2,4,6,7,8,9,7,5,6,9,7,4,3,7,0,1,7,1,1,7,8,4,9,8,7,1,0,2,6,8,4,9,1,9,1,3,9,7,4,5, +1,9,7,9,0,0,4,3,2,4,4,8,0,6,1,8,8,2,0,9,0,7,0,5,4,8,9,8,7,7,8,5,9,2,6,2,2,9,6,7,1,1,1,7,7,4,3,0,8,5,5,0,1,1,0,9,3,8,3,0,9,3,8,7, +4,7,5,5,2,4,5,1,3,4,6,7,7,4,3,0,7,7,8,4,0,3,4,9,0,4,6,6,4,3,9,5,5,5,2,6,2,1,8,0,8,5,0,8,2,5,7,2,6,4,3,4,7,4,3,5,0,0,1,3,0,6,7,4, +1,7,8,7,4,6,1,9,2,1,3,1,4,5,8,6,8,0,2,8,8,7,6,5,5,4,3,7,0,0,3,6,7,8,2,4,0,0,7,0,8,0,8,7,1,2,1,5,4,0,6,9,4,6,0,4,0,6,6,4,6,2,3,8, +3,2,5,5,6,6,0,8,2,5,8,5,8,9,8,6,6,2,5,0,4,4,5,9,6,3,9,5,7,6,1,6,2,6,5,8,2,2,4,1,0,6,2,1,9,7,9,5,9,7,8,3,1,2,1,0,7,5,4,4,6,4,5,8, +1,4,1,3,8,8,1,0,5,0,2,4,8,3,4,0,7,0,0,9,6,6,0,3,8,3,2,8,2,3,5,5,4,9,5,3,7,9,8,6,6,3,4,6,7,7,3,1,1,5,4,2,0,9,5,1,4,5,4,0,8,2,4,8, +5,4,4,9,9,1,0,6,9,8,4,6,0,3,8,9,4,9,5,6,2,7,0,5,7,8,0,3,7,0,1,3,1,4,7,4,7,6,3,4,7,2,4,8,9,2,4,1,7,1,9,9,5,5,4,0,5,4,5,8,6,8,1,2, +9,0,0,2,7,4,2,1,3,1,7,3,6,2,5,9,3,8,5,5,8,8,2,9,3,5,2,6,9,3,0,4,3,7,8,3,7,2,6,5,8,2,9,7,1,1,9,0,8,5,8,0,1,3,1,5,9,8,1,9,1,9,2,9, +6,7,5,6,2,5,7,6,0,9,5,7,4,3,0,6,1,8,7,9,5,7,2,8,1,5,4,3,4,7,4,7,5,0,0,4,2,8,0,2,9,9,5,1,7,3,0,7,3,3,3,0,9,7,6,8,5,6,0,2,1,5,3,5, +7,7,8,2,6,6,6,8,2,9,8,3,7,5,7,9,2,1,4,8,0,4,7,6,1,7,1,0,8,3,5,7,9,1,0,9,5,9,6,6,7,1,8,1,5,6,9,6,0,1,2,9,9,7,8,2,5,8,6,1,5,2,9,3, +1,7,5,1,6,1,4,2,8,5,1,7,0,3,0,4,1,3,2,8,0,3,6,1,8,9,4,1,7,1,2,0,3,8,7,8,1,6,9,6,5,7,6,3,3,3,9,8,2,1,0,6,6,2,4,2,5,0,8,2,6,4,6,3, +2,6,1,2,4,1,3,3,9,5,8,6,2,1,4,7,7,3,1,6,4,3,2,5,8,9,9,6,5,0,0,3,1,1,4,2,7,6,4,8,9,8,1,5,6,7,0,3,3,6,4,8,8,8,8,9,3,8,3,5,5,4,4,5, +2,3,0,1,6,0,0,1,6,3,0,9,6,8,9,5,1,4,0,7,0,5,5,2,2,8,5,1,8,2,9,9,1,9,4,5,9,6,6,5,9,2,7,6,4,4,5,2,9,5,4,6,8,4,0,7,6,1,5,3,0,9,5,1, +2,5,4,4,4,8,2,8,8,6,6,9,6,4,1,7,7,8,1,6,8,7,9,4,2,4,1,4,2,0,5,8,8,9,6,9,7,6,1,0,9,7,1,5,2,0,7,7,3,4,5,1,0,7,3,1,5,4,4,9,6,1,0,8, +2,6,8,2,6,9,8,4,3,6,5,9,8,0,0,6,7,1,8,4,0,1,8,1,2,8,2,2,2,8,1,6,1,5,9,8,9,5,6,3,2,1,4,2,9,3,2,0,9,6,8,8,3,3,7,6,7,0,0,4,8,4,0,6, +9,8,0,2,7,2,8,4,0,6,1,8,3,9,8,4,0,0,6,3,0,5,9,8,0,6,8,5,1,9,7,5,4,8,5,5,1,4,3,2,4,5,5,0,5,5,3,8,0,2,5,2,1,3,1,6,1,6,8,2,8,4,1,3, +1,0,1,5,5,2,9,9,4,1,0,0,3,6,4,0,8,5,0,6,2,9,4,5,6,2,8,8,5,5,6,0,7,4,6,3,6,9,6,1,4,3,5,4,0,3,2,6,6,5,8,1,5,7,3,0,4,5,4,8,0,0,5,4, +5,7,1,4,4,4,2,7,3,2,7,7,8,6,5,1,1,0,3,1,4,6,7,3,7,1,6,3,7,5,6,6,8,4,9,1,2,7,3,0,2,8,8,3,9,3,7,2,8,5,0,9,4,5,1,3,4,6,6,8,6,9,7,7, +1,4,8,6,7,9,7,5,6,7,4,2,0,5,4,8,2,2,4,3,4,2,3,7,2,0,4,9,6,9,1,2,6,3,2,0,4,9,9,4,9,7,7,8,4,3,4,7,8,4,9,1,9,3,1,3,4,2,5,6,2,2,8,6, +3,5,9,4,5,9,7,1,6,7,7,3,1,9,3,2,8,5,7,7,8,1,7,7,0,0,2,3,7,3,6,8,6,3,7,6,6,3,6,0,1,9,9,3,0,9,2,2,3,0,2,6,3,3,2,8,5,6,2,6,9,6,7,0, +6,5,6,4,9,5,8,1,4,2,1,7,0,7,2,9,7,7,3,8,3,2,3,7,0,0,2,7,6,7,0,6,6,8,4,9,8,5,6,3,4,4,7,0,6,6,8,2,0,4,8,2,4,2,6,0,9,7,0,9,5,2,4,1, +4,5,1,2,4,3,7,7,9,5,0,7,3,2,0,8,4,1,6,5,9,8,8,1,2,3,4,0,2,4,0,3,2,6,1,0,9,2,2,3,4,0,7,3,3,0,4,7,7,1,2,9,7,8,5,5,6,3,4,1,8,9,3,5, +1,2,9,2,1,6,5,1,5,7,5,0,2,6,5,7,6,6,8,9,1,8,3,3,6,8,2,3,0,7,8,0,9,9,8,9,7,6,1,8,8,3,7,5,5,7,6,5,5,9,0,8,6,3,1,9,5,6,2,3,4,9,2,7, +5,1,9,8,5,2,6,7,8,7,1,2,1,1,6,8,0,0,1,0,4,3,1,8,3,4,1,8,4,7,3,3,0,3,6,7,7,5,6,3,0,7,6,7,9,3,9,4,1,9,1,2,1,8,8,9,6,6,1,0,8,9,8,6, +9,4,9,5,4,3,6,1,2,9,8,6,9,1,4,4,6,0,3,6,4,6,5,0,4,2,0,1,6,8,2,6,4,6,5,5,6,8,6,8,8,2,9,9,2,9,7,4,9,3,1,3,2,1,2,2,5,8,2,2,4,2,7,0, +5,1,3,4,8,7,2,7,3,2,1,4,0,0,4,8,5,6,6,7,9,0,7,6,0,8,1,2,3,0,5,9,1,3,6,1,8,2,7,1,7,5,9,5,1,9,5,9,1,8,5,0,8,2,9,0,8,1,6,9,1,5,1,8, +4,6,2,3,5,2,7,1,6,9,9,5,2,6,1,3,6,3,3,3,7,6,5,1,4,6,2,3,0,6,0,7,4,6,0,1,9,1,5,3,3,7,3,9,0,2,8,8,8,1,1,9,0,9,7,5,3,8,8,6,7,4,0,9, +7,8,8,4,4,9,3,1,1,5,2,7,5,6,2,2,9,3,0,8,1,7,1,8,5,5,3,0,9,9,6,4,6,0,4,2,3,6,2,8,4,8,4,9,9,6,1,0,0,0,6,1,9,7,7,2,8,4,7,8,4,4,6,2, +2,4,9,4,4,3,2,9,1,4,5,2,2,4,1,9,0,0,8,0,1,5,8,5,9,0,8,3,7,8,3,3,2,1,9,5,6,0,7,6,2,1,8,4,4,4,3,2,9,3,2,8,4,1,6,3,6,2,1,4,3,0,0,5, +9,4,8,3,1,9,6,4,0,9,7,7,6,3,9,4,0,3,2,2,1,9,0,6,5,2,0,7,8,3,3,4,6,0,6,0,0,5,7,8,3,4,6,5,8,2,7,8,9,7,9,0,8,1,9,8,5,7,4,4,9,8,5,7, +3,3,3,1,4,2,9,1,7,3,7,7,9,2,7,3,1,8,6,3,6,2,0,2,0,7,6,9,6,1,9,6,2,3,7,0,1,6,7,0,0,5,8,1,0,2,2,5,8,3,3,4,1,6,8,9,3,8,0,9,2,1,6,6, +0,7,1,3,6,0,7,0,3,9,4,1,5,2,6,3,7,6,1,3,8,4,6,3,3,4,6,6,0,6,5,6,3,6,9,4,4,0,0,8,0,5,3,7,4,0,9,4,2,2,9,1,8,7,5,3,8,6,1,9,9,8,9,0, +4,8,3,0,7,6,1,6,3,7,6,5,0,1,3,4,7,3,7,0,7,8,2,8,4,0,3,3,3,2,6,3,9,1,2,6,5,6,1,7,2,8,8,5,8,0,1,4,3,8,4,4,5,6,3,4,2,9,1,7,4,0,4,5, +8,4,8,6,5,5,1,2,2,9,9,2,4,7,0,1,1,8,6,2,9,1,7,0,8,9,3,2,6,9,1,4,6,6,2,8,1,6,7,3,0,7,7,4,3,9,3,5,6,5,6,5,8,9,5,3,1,0,9,5,4,6,7,6, +7,8,3,7,7,2,5,3,4,1,7,3,8,0,0,5,2,3,6,4,5,2,0,3,3,3,1,2,6,1,1,1,4,7,6,0,4,9,1,2,8,5,0,3,3,2,5,0,1,4,5,9,0,3,6,8,2,2,4,1,2,3,7,3, +9,5,2,1,0,7,2,1,3,5,2,3,0,5,6,2,2,9,0,4,1,6,5,3,0,4,8,2,2,1,2,1,2,2,1,7,7,2,0,3,4,7,3,6,8,0,9,0,0,8,3,2,0,4,6,7,9,6,0,1,7,1,7,6, +}; + +const int32_t C[] = { +1223,1282,1286,1163,1319,1270,1192,1100,1142,1261,1291,1367,1260,1311,985,1232,1313,1316,1148,1320,1277,1275,1145,1199,1157,1203,1225,1211,1177,1281,1164,1239,1209,1454,1377,1145,1189,1335,1306,1108,1302,1233,1421,1194,1339,1065,1322,1063,1169,979,1109,1155,976,1341,1258,1173,1250,1486,1204,1322,1273,1303,1130,1377, +1184,1267,1312,1237,1443,1455,1188,1232,1260,1222,1312,1451,1244,1331,1078,1464,1396,1375,1279,1437,1466,1272,1208,1262,1248,1352,1314,1335,1209,1309,1263,1277,1264,1509,1546,1222,1369,1428,1334,1090,1392,1323,1378,1303,1411,1190,1443,1195,1305,1244,1177,1218,1132,1317,1370,1300,1356,1338,1210,1421,1310,1349,1236,1435, +1162,1146,1395,1317,1216,1378,1119,1124,1091,1251,1202,1479,1236,1287,1005,1364,1472,1348,1223,1445,1362,1273,1148,1252,1226,1323,1226,1294,1205,1235,1192,1299,1135,1351,1441,1303,1192,1422,1313,1142,1138,1213,1390,1262,1400,1148,1242,1149,1390,1197,1230,1127,1164,1269,1347,1231,1377,1294,1109,1386,1400,1285,1202,1375, +1085,1269,1161,1032,1288,1306,1093,1075,1208,1217,1133,1354,1087,1180,994,1148,1230,1282,1151,1255,1213,1176,1122,1190,1027,1230,1284,1184,1022,1073,1237,1162,1222,1300,1273,1038,1101,1271,1263,1053,1266,1276,1277,1185,1288,1092,1256,1066,1070,1100,1139,1110,1041,1201,1214,1307,1153,1334,1146,1282,1220,1292,1202,1281, +953,1262,1262,1113,1165,1134,1165,1034,1155,1150,1092,1340,1127,1129,991,1264,1190,1241,1146,1305,1178,1086,1038,1146,925,1348,1187,1146,1084,1170,1147,1201,1109,1331,1327,1101,1191,1195,1240,1088,1269,1097,1275,1367,1394,1097,1289,1092,1121,1008,1014,1078,1185,1328,1277,1274,1192,1304,1097,1331,1288,1287,1139,1227, +1201,1282,1518,1325,1281,1510,1265,1336,1105,1327,1407,1443,1225,1295,1066,1483,1340,1349,1354,1403,1371,1315,1151,1265,1189,1335,1343,1363,1137,1399,1248,1254,1465,1378,1333,1240,1131,1468,1371,1139,1253,1175,1496,1213,1473,1246,1402,1272,1330,1226,1126,1186,1212,1376,1462,1329,1229,1447,1227,1339,1347,1301,1240,1524, +1377,1419,1524,1328,1441,1503,1332,1263,1372,1402,1486,1771,1459,1449,1219,1424,1629,1493,1295,1539,1427,1451,1453,1399,1276,1583,1497,1480,1279,1354,1389,1403,1376,1571,1552,1346,1348,1654,1440,1173,1324,1504,1554,1499,1542,1332,1499,1277,1431,1402,1203,1382,1206,1560,1479,1448,1313,1516,1372,1582,1508,1404,1374,1553, +1180,1190,1170,1150,1253,1280,1261,1120,1132,1291,1259,1295,1148,1178,936,1279,1199,1307,1136,1266,1352,1219,1137,1104,1051,1323,1299,1210,1202,1416,1149,1190,1192,1345,1331,1059,1264,1186,1238,1078,1212,1136,1433,1338,1238,1081,1314,980,1253,1209,1241,996,1074,1264,1301,1235,1360,1275,1076,1355,1130,1254,1272,1195, +1159,1328,1348,1187,1256,1466,1220,1187,1064,1249,1357,1457,1216,1173,1179,1494,1289,1263,1350,1375,1310,1373,1248,1356,1142,1296,1226,1265,1158,1135,1179,1185,1210,1338,1376,1222,1213,1348,1378,1129,1272,1097,1444,1236,1363,1248,1324,1170,1316,1302,1266,1319,1195,1216,1356,1352,1313,1320,1173,1359,1298,1234,1253,1485, +1134,1192,1510,1136,1287,1364,1271,1096,1336,1308,1148,1414,1194,1245,1032,1431,1381,1276,1130,1384,1336,1264,1240,1175,1239,1336,1183,1249,1064,1289,1208,1102,1247,1302,1428,1224,1265,1470,1235,1161,1156,1305,1444,1343,1369,1177,1340,1132,1237,1177,1092,1239,1110,1324,1379,1318,1259,1278,1188,1466,1312,1262,1205,1355, +1266,1520,1489,1292,1362,1379,1379,1383,1309,1375,1416,1341,1262,1346,1139,1468,1367,1283,1245,1376,1341,1328,1405,1194,1162,1568,1256,1316,1109,1523,1281,1251,1550,1493,1500,1225,1303,1342,1463,1098,1279,1224,1440,1471,1384,1199,1433,1338,1395,1243,1313,1311,1093,1536,1311,1466,1223,1480,1327,1313,1491,1332,1396,1461, +1324,1267,1330,1251,1403,1288,1188,1214,1312,1302,1313,1591,1341,1331,1203,1456,1421,1408,1342,1529,1301,1337,1204,1372,1206,1499,1416,1278,1280,1291,1305,1313,1258,1588,1452,1262,1314,1473,1316,1285,1467,1271,1521,1386,1488,1250,1570,1182,1258,1285,1140,1369,1305,1405,1438,1359,1400,1532,1314,1458,1338,1451,1351,1364, +1508,1591,1551,1501,1560,1630,1454,1467,1378,1516,1488,1608,1383,1444,1297,1613,1483,1759,1421,1635,1655,1449,1270,1550,1260,1637,1451,1499,1405,1380,1486,1452,1522,1566,1612,1445,1283,1683,1534,1209,1565,1462,1665,1582,1626,1309,1625,1376,1302,1344,1358,1280,1260,1595,1679,1500,1399,1654,1363,1613,1365,1399,1545,1702, +1128,1402,1315,1329,1340,1389,1269,1399,1237,1236,1196,1382,1177,1206,1166,1486,1421,1321,1176,1538,1402,1373,1244,1194,1180,1494,1352,1365,1053,1302,1324,1224,1425,1421,1437,1106,1273,1479,1411,1069,1432,1156,1353,1414,1474,1224,1352,1368,1351,1155,1216,1164,1160,1468,1376,1301,1283,1407,1340,1365,1333,1314,1222,1562, +990,1242,1037,945,1056,1066,1122,1041,1072,1106,1025,1176,971,1006,867,1205,1076,1045,1000,1134,1225,1119,1020,1013,914,1099,1048,1067,931,982,1033,1069,1108,1191,1107,972,1094,1217,1063,856,1183,1130,1222,1157,1123,796,1215,1122,1048,969,815,1089,996,1210,1176,1192,1055,1217,1003,1157,1077,1052,1133,1251, +1284,1200,1269,1326,1294,1339,1278,1318,1181,1223,1209,1465,1143,1136,1127,1486,1193,1233,1248,1465,1402,1356,1180,1231,1176,1432,1200,1408,1160,1184,1267,1200,1191,1474,1389,1208,1165,1362,1425,1053,1281,1076,1472,1331,1252,1040,1517,1310,1238,1248,1084,1152,967,1341,1425,1250,1309,1399,1241,1257,1382,1239,1175,1577, +1157,1371,1479,1324,1290,1274,1173,1187,1301,1333,1326,1392,1165,1215,985,1438,1376,1284,1211,1396,1195,1319,1162,1383,1117,1438,1185,1208,1183,1294,1112,1369,1307,1449,1440,1203,1413,1294,1443,1230,1321,1264,1402,1575,1427,1266,1471,1020,1234,1245,1201,1196,1241,1327,1444,1219,1381,1343,1251,1407,1293,1369,1284,1303, +1316,1298,1260,1190,1373,1338,1219,1183,1240,1283,1256,1493,1236,1335,1122,1382,1292,1488,1302,1486,1338,1254,1162,1173,1297,1483,1244,1220,1166,1161,1344,1272,1290,1480,1411,1317,1103,1441,1318,1080,1426,1259,1527,1254,1328,1124,1486,1371,1274,1181,1027,1319,1105,1419,1442,1367,1249,1373,1263,1297,1258,1317,1227,1527, +1421,1598,1719,1432,1649,1684,1592,1420,1513,1671,1607,1690,1512,1581,1246,1737,1578,1567,1514,1660,1608,1495,1644,1490,1460,1731,1507,1492,1354,1732,1465,1436,1612,1657,1650,1527,1527,1676,1606,1398,1527,1522,1674,1585,1600,1498,1731,1449,1478,1458,1463,1573,1379,1600,1567,1585,1439,1563,1439,1575,1620,1505,1612,1670, +1491,1497,1680,1447,1639,1595,1469,1385,1371,1551,1666,1664,1403,1545,1403,1621,1512,1657,1560,1631,1536,1573,1433,1514,1314,1649,1409,1603,1415,1605,1462,1469,1523,1675,1690,1356,1478,1533,1601,1331,1565,1380,1688,1687,1424,1429,1693,1375,1481,1428,1447,1426,1364,1620,1623,1724,1355,1714,1367,1620,1474,1547,1523,1614, +1090,1249,1258,1115,1331,1239,1173,1167,1179,1179,1203,1371,1159,1269,1009,1150,1245,1181,1104,1338,1191,1301,1036,1221,1125,1263,1207,1256,1169,1232,1197,1194,1278,1346,1321,997,1116,1309,1316,1143,1253,1186,1246,1267,1269,1089,1401,1067,1059,1099,1098,1109,1089,1309,1330,1325,1136,1422,1227,1181,1224,1284,1296,1325, +1083,1217,1287,1048,1226,1301,1124,1133,1146,1134,1156,1229,1271,1223,1073,1232,1203,1169,1079,1252,1233,1235,1179,1147,1137,1240,1198,1207,1135,1142,1101,1184,1170,1434,1480,1202,1022,1193,1354,1134,1161,1055,1393,1101,1390,1119,1408,1067,1225,1142,1141,1134,982,1215,1252,1163,1391,1336,1110,1216,1293,1274,1213,1374, +1176,1248,1367,1209,1350,1327,1126,1169,1186,1257,1147,1409,1134,1158,1140,1539,1249,1262,1208,1267,1171,1228,1130,1483,1033,1346,1135,1305,1283,1225,1075,1250,1112,1364,1485,1199,1257,1356,1297,1102,1262,1223,1307,1367,1397,1109,1360,1064,1102,1259,1421,1132,1150,1122,1323,1293,1342,1352,1120,1478,1299,1183,1290,1328, +1358,1196,1378,1279,1255,1332,1182,1268,1170,1229,1412,1412,1192,1322,1065,1309,1291,1437,1206,1262,1288,1387,1202,1326,1237,1347,1386,1400,1304,1272,1176,1260,1337,1353,1438,1130,1291,1371,1493,1071,1218,1283,1566,1423,1335,1169,1460,1183,1396,1247,1090,1229,1152,1443,1453,1404,1296,1502,1227,1393,1356,1435,1306,1545, +970,1102,1135,1132,1034,1115,1110,1029,968,1150,1057,1154,1067,1083,1050,1148,1048,1194,1057,1091,1223,1172,1002,1175,842,1109,1236,1167,1003,1080,1207,1133,1084,1245,1215,1080,1015,1208,1115,949,1090,1113,1203,1106,1225,993,1243,1012,1082,1110,1004,989,1072,1076,1100,1213,1163,1220,937,1160,1132,1206,1271,1157, +1280,1299,1484,1423,1264,1417,1198,1259,1318,1303,1342,1413,1185,1310,1112,1504,1318,1388,1303,1392,1330,1217,1124,1375,1184,1439,1286,1431,1277,1300,1269,1324,1198,1410,1436,1153,1171,1297,1529,1139,1252,1276,1397,1376,1339,1280,1301,1146,1227,1303,1277,1239,1122,1313,1444,1336,1289,1461,1322,1437,1257,1302,1310,1431, +1213,1324,1265,1154,1335,1331,1249,1177,1102,1299,1174,1296,1159,1095,1117,1293,1148,1228,1118,1345,1221,1292,1112,1155,1161,1335,1152,1185,1161,1244,1133,1151,1287,1381,1380,1096,1145,1420,1294,1142,1364,1169,1359,1304,1370,1133,1458,1201,1186,1127,1257,1200,1028,1197,1323,1221,1332,1368,1115,1191,1290,1125,1327,1335, +1100,1107,1206,1076,1070,1217,1152,1037,976,1124,1102,1303,1049,1040,882,1175,1105,1061,1042,1170,1089,1200,1062,1149,1001,1083,1126,1249,1103,1233,1170,1129,1187,1130,1274,933,1092,1276,1166,982,1200,1136,1238,1307,1227,953,1190,1037,1182,1145,936,850,1108,1180,1121,1178,1162,1225,1059,1234,1170,1117,1057,1164, +1304,1421,1468,1398,1297,1510,1405,1379,1285,1250,1266,1486,1317,1492,1127,1487,1396,1510,1326,1485,1468,1341,1380,1525,1189,1391,1401,1442,1377,1416,1318,1342,1377,1510,1619,1288,1212,1407,1511,1086,1297,1355,1607,1403,1533,1261,1387,1344,1291,1234,1317,1152,1280,1513,1394,1379,1461,1464,1440,1650,1456,1457,1417,1467, +1311,1229,1205,1189,1294,1243,1263,1098,1123,1304,1394,1277,1192,1149,1133,1228,1157,1342,1180,1163,1268,1249,1113,1244,1099,1237,1215,1302,1102,1304,1141,1175,1185,1392,1483,1056,1062,1223,1203,1080,1165,1221,1384,1235,1295,1041,1492,1081,1176,1246,1169,1099,897,1234,1279,1242,1253,1482,1052,1325,1231,1235,1262,1267, +1040,1219,1342,1241,1334,1251,1081,1293,1204,1209,1230,1364,1124,1250,975,1353,1284,1270,1159,1251,1291,1236,1125,1121,1154,1273,1190,1220,1133,1240,1114,1134,1208,1417,1376,1149,1219,1342,1313,1052,1175,1109,1288,1249,1294,1029,1356,1157,1294,1130,1236,1131,1045,1275,1329,1190,1158,1222,1145,1239,1212,1243,1217,1354, +1330,1514,1426,1478,1427,1534,1396,1449,1113,1412,1455,1612,1408,1417,1252,1604,1356,1498,1443,1472,1434,1509,1309,1542,1292,1482,1586,1417,1344,1534,1440,1396,1500,1590,1601,1427,1239,1447,1447,1338,1503,1249,1509,1459,1763,1201,1585,1278,1501,1317,1409,1322,1357,1424,1436,1494,1504,1462,1386,1541,1526,1580,1334,1504, +1483,1510,1662,1516,1472,1567,1511,1383,1427,1441,1486,1693,1423,1445,1277,1653,1566,1564,1252,1712,1527,1504,1368,1474,1343,1638,1479,1562,1473,1475,1400,1462,1536,1550,1565,1394,1529,1659,1619,1351,1574,1540,1647,1672,1703,1358,1640,1358,1459,1364,1329,1423,1398,1645,1623,1495,1576,1619,1410,1576,1638,1504,1511,1513, +1378,1291,1411,1401,1335,1462,1228,1371,1250,1265,1322,1481,1251,1293,1165,1519,1344,1376,1263,1528,1354,1316,1168,1275,1161,1352,1151,1340,1317,1165,1286,1229,1292,1526,1369,1343,1357,1465,1506,1065,1534,1125,1546,1396,1442,1091,1466,1272,1352,1308,1147,1242,1180,1487,1382,1336,1331,1464,1227,1231,1398,1345,1305,1532, +1346,1268,1352,1280,1401,1465,1207,1261,1254,1325,1211,1445,1266,1284,1084,1275,1388,1362,1081,1393,1339,1344,1202,1257,1253,1346,1235,1335,1205,1225,1189,1267,1311,1467,1462,1328,1183,1386,1372,1146,1313,1354,1377,1324,1560,1051,1474,1183,1329,1275,1320,1132,1053,1471,1323,1273,1426,1453,1205,1349,1508,1382,1197,1463, +1022,1187,1170,1044,1151,1246,1027,1219,1050,1128,1098,1206,1071,1097,1007,1357,1094,1118,1119,1173,1158,1171,1093,1157,1052,1307,1048,1041,1028,1172,1076,1129,1159,1224,1297,1159,1100,1159,1144,1040,1137,1017,1259,1165,1290,1100,1200,1175,1063,1165,1072,1022,1080,1204,1242,1138,1170,1136,1153,1163,1132,1100,1126,1205, +1228,1387,1427,1403,1300,1425,1408,1294,1135,1292,1385,1536,1215,1375,1090,1372,1493,1488,1375,1443,1291,1323,1196,1449,1011,1387,1405,1524,1237,1315,1375,1284,1439,1430,1453,1275,1203,1455,1334,1082,1336,1212,1446,1398,1447,1109,1415,1167,1347,1258,1260,1182,1166,1460,1312,1474,1164,1448,1142,1484,1380,1336,1312,1462, +1229,1355,1264,1183,1314,1315,1133,1150,1185,1272,1267,1278,1256,1081,1103,1341,1182,1357,1212,1377,1320,1300,1159,1211,1155,1350,1139,1159,1123,1117,1120,1224,1267,1341,1296,1181,1190,1433,1408,1056,1392,1231,1416,1354,1320,1066,1387,1219,1231,1083,1171,1302,1194,1261,1386,1159,1144,1254,1142,1345,1164,1230,1272,1376, +1402,1490,1593,1472,1540,1586,1420,1415,1467,1578,1512,1550,1450,1479,1264,1497,1579,1482,1403,1634,1640,1530,1355,1386,1494,1515,1378,1446,1330,1336,1452,1408,1570,1617,1621,1422,1320,1645,1575,1282,1514,1496,1689,1515,1551,1392,1592,1417,1496,1390,1331,1436,1293,1555,1537,1461,1428,1662,1461,1603,1505,1478,1485,1641, +1190,1351,1391,1151,1359,1261,1272,1151,1193,1410,1220,1442,1176,1321,1145,1331,1298,1288,1138,1432,1265,1303,1234,1344,1097,1368,1299,1257,1225,1254,1342,1328,1216,1474,1431,1321,1194,1382,1412,1126,1384,1312,1382,1311,1391,1184,1442,1234,1173,1217,1092,1163,1187,1294,1353,1395,1298,1525,1167,1290,1331,1287,1237,1428, +1304,1416,1446,1406,1444,1463,1304,1344,1205,1344,1408,1391,1263,1330,1190,1426,1445,1377,1141,1490,1381,1376,1240,1404,1244,1378,1310,1436,1337,1454,1351,1288,1410,1408,1562,1208,1295,1477,1469,1192,1434,1246,1467,1463,1576,1277,1378,1198,1375,1277,1300,1163,1179,1544,1309,1334,1374,1525,1258,1383,1395,1343,1357,1443, +1337,1425,1424,1300,1416,1506,1314,1263,1283,1442,1345,1599,1210,1381,1185,1491,1360,1514,1366,1549,1449,1436,1297,1274,1278,1592,1432,1358,1241,1418,1492,1221,1363,1523,1521,1200,1309,1466,1375,1285,1432,1284,1492,1419,1474,1272,1567,1251,1258,1427,1298,1269,1276,1309,1573,1506,1367,1432,1366,1467,1307,1432,1391,1526, +1245,1479,1359,1192,1393,1455,1247,1338,1192,1281,1363,1339,1314,1433,1229,1360,1377,1332,1284,1331,1385,1395,1346,1348,1263,1295,1340,1301,1159,1368,1222,1257,1361,1454,1507,1271,1256,1206,1537,1251,1334,1178,1573,1343,1532,1225,1547,1291,1358,1286,1343,1219,1201,1442,1395,1281,1329,1515,1276,1401,1372,1362,1373,1679, +1088,1321,1295,1136,1190,1421,1235,1158,1223,1093,1118,1345,1176,1361,1049,1237,1373,1226,1196,1435,1316,1245,1186,1244,1044,1246,1207,1342,1137,1222,1302,1160,1238,1386,1398,1125,1219,1352,1315,976,1279,1157,1435,1272,1340,1212,1151,1148,1147,1207,1109,1078,1104,1456,1245,1357,1238,1354,1232,1349,1244,1180,1291,1399, +1233,1346,1483,1244,1296,1440,1206,1207,1228,1387,1335,1338,1222,1302,1034,1380,1488,1306,1266,1492,1447,1316,1269,1265,1181,1368,1261,1244,1149,1343,1204,1310,1313,1503,1547,1292,1255,1242,1249,1197,1355,1234,1505,1377,1462,1245,1408,1104,1243,1398,1216,1132,1221,1395,1361,1429,1450,1494,1145,1375,1395,1375,1295,1414, +1150,1376,1431,1299,1328,1327,1091,1375,1134,1150,1289,1330,1179,1324,1130,1429,1436,1311,1203,1401,1274,1414,1187,1409,1205,1395,1449,1332,1164,1307,1128,1333,1378,1352,1505,1192,1250,1254,1451,1217,1289,1257,1433,1468,1507,1226,1471,1181,1337,1189,1240,1139,1172,1376,1394,1321,1324,1470,1213,1393,1332,1401,1269,1547, +1086,1274,1427,1184,1336,1347,1301,1288,1076,1234,1239,1313,1176,1249,1188,1370,1234,1309,1243,1253,1244,1162,1137,1358,1024,1365,1262,1301,1150,1258,1228,1221,1250,1336,1448,1214,1060,1271,1290,1135,1225,1045,1454,1293,1480,1147,1399,1131,1121,1131,1116,1150,1134,1318,1381,1327,1183,1343,1102,1294,1311,1241,1247,1276, +1055,1338,1289,1170,1280,1362,1196,1278,1246,1310,1316,1358,1177,1180,1127,1391,1160,1306,1197,1344,1291,1294,1137,1177,1097,1365,1251,1240,1111,1305,1330,1218,1345,1410,1325,1109,1232,1329,1290,1099,1453,1200,1285,1355,1391,1092,1356,1205,1247,1158,1168,1232,1166,1421,1269,1371,1216,1398,1251,1336,1261,1328,1173,1321, +1241,1362,1541,1375,1528,1481,1285,1364,1179,1334,1358,1569,1284,1388,1337,1545,1414,1401,1245,1493,1384,1470,1260,1417,1267,1581,1456,1544,1325,1443,1378,1432,1360,1517,1612,1293,1353,1448,1561,1323,1417,1354,1493,1485,1468,1348,1504,1294,1413,1278,1469,1253,1298,1438,1467,1442,1423,1520,1282,1510,1463,1438,1355,1512, +1191,1405,1548,1192,1355,1385,1281,1306,1116,1400,1443,1404,1205,1296,1223,1375,1174,1249,1177,1294,1233,1342,1279,1290,1032,1370,1345,1204,1249,1404,1243,1196,1357,1300,1416,1119,1227,1290,1448,1139,1231,1347,1457,1401,1401,1252,1517,1270,1319,1150,1263,1046,1187,1352,1436,1425,1350,1436,1271,1350,1371,1359,1370,1384, +1533,1515,1630,1488,1528,1655,1407,1376,1435,1595,1587,1596,1514,1517,1354,1704,1603,1606,1510,1715,1590,1563,1342,1497,1435,1593,1392,1554,1467,1607,1335,1566,1479,1775,1667,1446,1608,1589,1735,1394,1572,1454,1692,1573,1659,1501,1695,1421,1608,1406,1575,1572,1313,1565,1659,1484,1697,1825,1410,1592,1599,1564,1547,1710, +1030,1264,1235,1155,1239,1140,1107,1169,1228,1181,1199,1289,1264,1173,908,1223,1267,1189,1040,1262,1244,1091,1075,1137,1063,1274,1222,1202,1090,1111,969,1306,1205,1427,1291,1148,953,1258,1254,1058,1239,1108,1343,1147,1290,1008,1357,1026,1152,999,1101,1209,994,1239,1195,1079,1115,1298,1073,1232,1165,1155,1254,1254, +1243,1402,1384,1183,1246,1257,1266,1330,1115,1206,1321,1437,1353,1240,1078,1420,1196,1383,1183,1344,1188,1398,1211,1321,1227,1379,1400,1246,1291,1312,1190,1233,1403,1285,1511,1135,1150,1454,1366,1224,1258,1221,1410,1342,1498,1066,1384,1252,1288,1102,1202,1247,1224,1436,1536,1461,1352,1494,1232,1360,1440,1282,1332,1466, +1376,1432,1337,1363,1390,1476,1213,1241,1248,1363,1401,1387,1244,1207,1079,1454,1381,1566,1314,1472,1399,1322,1191,1356,1247,1391,1336,1360,1269,1270,1294,1360,1366,1462,1550,1256,1130,1431,1423,1110,1321,1340,1438,1383,1399,1126,1480,1170,1290,1251,1342,1232,1060,1371,1438,1266,1461,1509,1254,1567,1297,1286,1327,1459, +1238,1391,1654,1282,1535,1583,1349,1371,1349,1438,1396,1503,1400,1483,1352,1670,1451,1452,1393,1511,1507,1553,1343,1431,1373,1456,1367,1364,1333,1462,1290,1251,1432,1511,1557,1338,1462,1445,1472,1429,1484,1300,1658,1546,1579,1316,1561,1295,1411,1270,1516,1399,1360,1430,1484,1458,1469,1569,1336,1635,1471,1468,1405,1548, +1328,1454,1420,1339,1301,1584,1286,1280,1242,1267,1371,1399,1361,1255,1125,1574,1424,1452,1350,1505,1338,1342,1278,1317,1284,1571,1323,1374,1275,1421,1342,1274,1397,1487,1589,1303,1386,1468,1493,1298,1385,1243,1476,1502,1498,1285,1414,1261,1274,1307,1370,1280,1183,1533,1502,1422,1490,1479,1370,1480,1419,1377,1417,1481, +1222,1364,1443,1416,1382,1408,1431,1338,1335,1312,1306,1510,1331,1404,1159,1485,1364,1526,1255,1513,1490,1320,1246,1408,1261,1466,1481,1469,1303,1305,1353,1331,1239,1519,1619,1349,1219,1522,1492,1206,1306,1366,1531,1346,1561,1139,1528,1252,1285,1321,1207,1237,1181,1438,1533,1434,1404,1478,1258,1462,1425,1431,1400,1589, +1207,1377,1473,1278,1359,1422,1204,1284,1197,1383,1316,1329,1130,1287,1145,1371,1422,1446,1296,1427,1422,1393,1162,1300,1248,1385,1149,1205,1164,1347,1224,1188,1328,1362,1530,1244,1269,1378,1281,1228,1304,1222,1561,1470,1516,1302,1417,1272,1254,1233,1184,1200,1226,1510,1500,1344,1353,1468,1197,1424,1285,1343,1358,1503, +1191,1379,1246,1083,1210,1174,1160,1093,1102,1200,1219,1429,1167,1147,923,1368,1318,1166,1231,1362,1215,1256,1084,1156,1002,1320,1218,1141,1110,1254,1116,1175,1212,1297,1225,1082,1283,1247,1229,1081,1218,1143,1336,1235,1273,986,1269,1137,1107,975,1089,1161,1112,1296,1385,1268,1172,1429,1053,1191,1338,1190,1197,1337, +1259,1436,1359,1390,1411,1479,1330,1340,1282,1402,1434,1360,1272,1425,1205,1464,1312,1423,1284,1440,1498,1374,1303,1352,1285,1402,1470,1302,1314,1571,1313,1321,1376,1566,1517,1295,1295,1339,1354,1200,1421,1357,1432,1424,1544,1293,1445,1228,1226,1258,1330,1254,1275,1477,1365,1285,1438,1490,1414,1492,1384,1388,1358,1277, +1203,1315,1492,1177,1365,1245,1219,1234,1241,1305,1174,1385,1160,1270,1017,1348,1315,1297,1118,1263,1216,1289,1330,1083,1083,1391,1298,1197,1140,1290,1254,1276,1399,1398,1534,1247,1368,1413,1429,1207,1287,1267,1412,1361,1376,1170,1480,1240,1385,1103,1117,1211,1131,1291,1320,1385,1357,1369,1198,1306,1478,1417,1300,1326, +1277,1318,1539,1185,1440,1354,1365,1235,1312,1446,1350,1412,1227,1379,1083,1407,1381,1347,1233,1348,1337,1269,1350,1304,1212,1405,1226,1215,1164,1413,1163,1254,1348,1431,1470,1297,1250,1341,1255,1221,1268,1348,1484,1347,1474,1210,1514,1269,1228,1253,1159,1259,1213,1468,1432,1361,1359,1421,1314,1402,1464,1348,1241,1340, +1276,1309,1326,1354,1357,1323,1325,1275,1202,1251,1403,1463,1174,1212,1064,1536,1341,1326,1305,1491,1351,1375,1168,1253,1217,1436,1278,1363,1195,1441,1184,1246,1358,1420,1478,1120,1412,1381,1337,1141,1416,1238,1449,1368,1412,1217,1425,1182,1378,1282,1199,1218,1140,1381,1329,1357,1345,1478,1152,1357,1294,1417,1230,1416, +1071,1204,1308,1204,1446,1269,1175,1132,1209,1188,1315,1368,1169,1283,1042,1331,1380,1409,1113,1452,1307,1186,1166,1205,1120,1335,1265,1279,1207,1236,1194,1144,1336,1483,1401,1154,1251,1352,1293,1073,1423,1138,1343,1257,1280,1237,1323,1077,1118,1105,1228,1177,1158,1301,1205,1194,1234,1343,1162,1376,1295,1242,1234,1213, +}; + +#define MATRIX_SIZE 64 +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c index ea842d8a..6ed19c0c 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c @@ -5,57 +5,218 @@ #include #include - #include "dma.h" #include "core_v_mini_mcu.h" #include "x-heep.h" #include "csr.h" #include "rv_plic.h" -#define TEST_SINGULAR_MODE +// TEST DEFINES AND CONFIGURATION + +#define TEST_SINGLE_MODE +#define TEST_ADDRESS_MODE #define TEST_PENDING_TRANSACTION #define TEST_WINDOW -#define TEST_ADDRESS_MODE #define TEST_ADDRESS_MODE_EXTERNAL_DEVICE -#define TEST_DATA_SIZE 16 -#define TEST_DATA_LARGE 1024 -#define TRANSACTIONS_N 3 // Only possible to perform transaction at a time, others should be blocked -#define TEST_WINDOW_SIZE_DU 1024 // if put at <=71 the isr is too slow to react to the interrupt +#define TEST_DATA_SIZE 16 +#define TEST_DATA_LARGE 1024 +#define TRANSACTIONS_N 3 // Only possible to perform one transaction at a time, others should be blocked +#define TEST_WINDOW_SIZE_DU 1024 // if put at <=71 the isr is too slow to react to the interrupt - - -#if TEST_DATA_LARGE < 2* TEST_DATA_SIZE - #errors("TEST_DATA_LARGE must be at least 2*TEST_DATA_SIZE") +#if TEST_DATA_LARGE < 2 * TEST_DATA_SIZE +#errors("TEST_DATA_LARGE must be at least 2*TEST_DATA_SIZE") #endif /* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 #if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else - #define PRINTF(...) +#define PRINTF(...) #endif +// UTILITIES + +#define type2name(dma_type) \ + dma_type == DMA_DATA_TYPE_BYTE ? "8-bit" : dma_type == DMA_DATA_TYPE_HALF_WORD ? "16-bit" \ + : dma_type == DMA_DATA_TYPE_WORD ? "32-bit" \ + : "TYPE NOT VALID" + +dma_data_type_t C_type_2_dma_type(int C_type) +{ + switch (C_type) + { + case 1: + return DMA_DATA_TYPE_BYTE; + case 2: + return DMA_DATA_TYPE_HALF_WORD; + case 4: + return DMA_DATA_TYPE_WORD; + default: + return DMA_DATA_TYPE_WORD; + } +} + +#define WAIT_DMA \ + while (!dma_is_ready(0)) \ + { \ + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); \ + if (dma_is_ready(0) == 0) \ + { \ + wait_for_interrupt(); \ + } \ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); \ + } + +#define RUN_DMA \ + trans.flags = 0x0; \ + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); \ + PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); \ + res = dma_load_transaction(&trans); \ + PRINTF("load: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); \ + res = dma_launch(&trans); \ + PRINTF("laun: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); + +// TEST MACROS + +#define PRINT_TEST(signed, data_size, dma_src_type, dma_dst_type) \ + PRINTF("TEST:\n\r"); \ + PRINTF("Data size: %d\n\r", data_size); \ + PRINTF("Signed: %d\n\r", signed); \ + PRINTF("Source type size: %s\n\r", type2name(dma_src_type)); \ + PRINTF("Destination type size: %s\n\r", type2name(dma_dst_type)); + +#define DEFINE_DATA(data_size, C_src_type, C_dst_type, signed) \ + C_src_type src[data_size] __attribute__((aligned(4))); \ + C_dst_type dst[data_size] __attribute__((aligned(4))); \ + if (data_size <= TEST_DATA_SIZE) \ + for (int i = 0; i < data_size; i++) \ + if (signed && (i % 2) == 0) \ + src[i] = (C_src_type)(-test_data_4B[i]); \ + else \ + src[i] = (C_src_type)test_data_4B[i]; + +#define CHECK_RESULTS(data_size) \ + for (int i = 0; i < data_size; i++) \ + { \ + if (src[i] != dst[i]) \ + { \ + PRINTF("[%d] Expected: %x Got : %x\n\r", i, src[i], dst[i]); \ + errors++; \ + } \ + } \ + if (errors != 0) \ + { \ + PRINTF("DMA failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); \ + return EXIT_FAILURE; \ + } + +#define INIT_TEST(signed, data_size, dma_src_type, dma_dst_type) \ + tgt_src.ptr = (uint8_t *)src; \ + tgt_src.inc_du = 1; \ + tgt_src.inc_d2_du = 0; \ + tgt_src.size_du = data_size; \ + tgt_src.trig = DMA_TRIG_MEMORY; \ + tgt_src.type = dma_src_type; \ + tgt_src.env = NULL; \ + tgt_dst.ptr = (uint8_t *)dst; \ + tgt_dst.inc_du = 1; \ + tgt_dst.inc_d2_du = 0; \ + tgt_dst.size_du = data_size; \ + tgt_dst.trig = DMA_TRIG_MEMORY; \ + tgt_dst.type = dma_dst_type; \ + tgt_dst.env = NULL; \ + trans.src = &tgt_src; \ + trans.dst = &tgt_dst; \ + trans.src_addr = &tgt_addr; \ + trans.src_type = dma_src_type; \ + trans.dst_type = dma_dst_type; \ + trans.mode = DMA_TRANS_MODE_SINGLE; \ + trans.win_du = 0; \ + trans.sign_ext = signed; \ + trans.end = DMA_TRANS_END_INTR; \ + trans.dim = DMA_DIM_CONF_1D; \ + +#define TEST(C_src_type, C_dst_type, test_size, sign_extend) \ + PRINT_TEST(sign_extend, test_size, C_type_2_dma_type(sizeof(C_src_type)), C_type_2_dma_type(sizeof(C_dst_type))) \ + DEFINE_DATA(test_size, C_src_type, C_dst_type, sign_extend) \ + INIT_TEST(sign_extend, test_size, C_type_2_dma_type(sizeof(C_src_type)), C_type_2_dma_type(sizeof(C_dst_type))) \ + RUN_DMA \ + WAIT_DMA \ + CHECK_RESULTS(test_size) \ + PRINTF("\n\r") + +#define TEST_SINGLE \ + { \ + TEST(uint8_t, uint8_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(uint8_t, uint16_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(uint8_t, uint32_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(int8_t, int8_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } \ + { \ + TEST(int8_t, int16_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } \ + { \ + TEST(int8_t, int32_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } \ + { \ + TEST(uint16_t, uint16_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(uint16_t, uint32_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(int16_t, int16_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } \ + { \ + TEST(int16_t, int32_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } \ + { \ + TEST(uint32_t, uint32_t, TEST_DATA_SIZE, 0); \ + errors += errors; \ + } \ + { \ + TEST(int32_t, int32_t, TEST_DATA_SIZE, 1); \ + errors += errors; \ + } + +// GLOBAL VARIABLES int32_t errors = 0; int8_t cycles = 0; -void dma_intr_handler_trans_done() +// INTERRUPT HANDLERS +void dma_intr_handler_trans_done(uint8_t channel) { cycles++; } - #ifdef TEST_WINDOW int32_t window_intr_flag; -void dma_intr_handler_window_done(void) { +void dma_intr_handler_window_done(uint8_t channel) { window_intr_flag ++; } @@ -66,94 +227,64 @@ uint8_t dma_window_ratio_warning_threshold() #endif // TEST_WINDOW +dma_trans_t trans; int main(int argc, char *argv[]) { - static uint32_t test_data_4B[TEST_DATA_SIZE] __attribute__ ((aligned (4))) = { - 0x76543210, 0xfedcba98, 0x579a6f90, 0x657d5bee, 0x758ee41f, 0x01234567, 0xfedbca98, 0x89abcdef, 0x679852fe, 0xff8252bb, 0x763b4521, 0x6875adaa, 0x09ac65bb, 0x666ba334, 0x55446677, 0x65ffba98}; - static uint32_t copied_data_4B[TEST_DATA_LARGE] __attribute__ ((aligned (4))) = { 0 }; - static uint32_t test_data_large[TEST_DATA_LARGE] __attribute__ ((aligned (4))) = { 0 }; - // this array will contain the even address of copied_data_4B - uint32_t* test_addr_4B_PTR = &test_data_large[0]; + static uint32_t test_data_4B[TEST_DATA_SIZE] __attribute__((aligned(4))) = { + 0x76543210, 0xfedcba98, 0x579a6f90, 0x657d5bee, 0x758ee41f, 0x01234567, 0xfedbca98, 0x89abcdef, 0x679852fe, 0xff8252bb, 0x763b4521, 0x6875adaa, 0x09ac65bb, 0x666ba334, 0x55446677, 0x65ffba98}; + static uint32_t copied_data_4B[TEST_DATA_LARGE] __attribute__((aligned(4))) = {0}; + static uint32_t test_data_large[TEST_DATA_LARGE] __attribute__((aligned(4))) = {0}; + + // this array will contain the even address of copied_data_4B + uint32_t *test_addr_4B_PTR = &test_data_large[0]; // The DMA is initialized (i.e. Any current transaction is cleaned.) dma_init(NULL); - dma_config_flags_t res; - - dma_target_t tgt_src = { - .ptr = test_data_4B, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, - .trig = DMA_TRIG_MEMORY, - .type = DMA_DATA_TYPE_WORD, - }; - dma_target_t tgt_dst = { - .ptr = copied_data_4B, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, - .trig = DMA_TRIG_MEMORY, - }; - + dma_target_t tgt_src; + dma_target_t tgt_dst; dma_target_t tgt_addr = { - .ptr = test_addr_4B_PTR, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, - .trig = DMA_TRIG_MEMORY, - }; - - dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - .src_addr = &tgt_addr, - .mode = DMA_TRANS_MODE_SINGLE, - .win_du = 0, - .end = DMA_TRANS_END_INTR, - }; - // Create a target pointing at the buffer to be copied. Whole WORDs, no skippings, in memory, no environment. - -#ifdef TEST_SINGULAR_MODE + .ptr = (uint8_t *)test_addr_4B_PTR, + .inc_du = 1, + .size_du = TEST_DATA_SIZE, + .trig = DMA_TRIG_MEMORY, + }; + +#ifdef TEST_SINGLE_MODE PRINTF("\n\n\r===================================\n\n\r"); PRINTF(" TESTING SINGLE MODE "); PRINTF("\n\n\r===================================\n\n\r"); - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_load_transaction(&trans); - PRINTF("load: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_launch(&trans); - PRINTF("laun: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - - while( ! dma_is_ready()) { - // disable_interrupts - // this does not prevent waking up the core as this is controlled by the MIP register - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if ( dma_is_ready() == 0 ) { - wait_for_interrupt(); - //from here we wake up even if we did not jump to the ISR - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } - PRINTF(">> Finished transaction. \n\r"); + TEST_SINGLE - for(uint32_t i = 0; i < trans.size_b; i++ ) { - if ( ((uint8_t*)copied_data_4B)[i] != ((uint8_t*)test_data_4B)[i] ) { - PRINTF("ERROR [%d]: %04x != %04x\n\r", i, ((uint8_t*)copied_data_4B)[i], ((uint8_t*)test_data_4B)[i]); - errors++; - } - } +#endif // TEST_SINGLE_MODE - if (errors == 0) { - PRINTF("DMA single mode success.\n\r"); - } else { - PRINTF("DMA single mode failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b ); - return EXIT_FAILURE; - } + // Initialize the DMA for the next tests + tgt_src.ptr = (uint8_t *)test_data_4B; + tgt_src.inc_du = 1; + tgt_src.size_du = TEST_DATA_SIZE; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE_WORD; -#endif // TEST_SINGULAR_MODE + tgt_dst.ptr = (uint8_t *)copied_data_4B; + tgt_dst.inc_du = 1; + tgt_dst.size_du = TEST_DATA_LARGE; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.src_addr = &tgt_addr; + trans.src_type = DMA_DATA_TYPE_WORD; + trans.dst_type = DMA_DATA_TYPE_WORD; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.win_du = 0; + trans.sign_ext = 0; + trans.end = DMA_TRANS_END_INTR; #ifdef TEST_ADDRESS_MODE @@ -162,66 +293,55 @@ int main(int argc, char *argv[]) PRINTF("\n\n\r===================================\n\n\r"); // Prepare the data - for (int i = 0; i < TEST_DATA_SIZE; i++) { - test_addr_4B_PTR[i] = &copied_data_4B[i*2]; + for (int i = 0; i < TEST_DATA_SIZE; i++) + { + test_addr_4B_PTR[i] = (uint32_t)&copied_data_4B[i * 2]; } trans.mode = DMA_TRANS_MODE_ADDRESS; - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_load_transaction(&trans); - PRINTF("load: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_launch(&trans); - PRINTF("laun: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - - while( ! dma_is_ready()) { - // disable_interrupts - // this does not prevent waking up the core as this is controlled by the MIP register - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if ( dma_is_ready() == 0 ) { - wait_for_interrupt(); - //from here we wake up even if we did not jump to the ISR - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } + RUN_DMA + WAIT_DMA PRINTF(">> Finished transaction. \n\r"); - for(uint32_t i = 0; i < trans.size_b >> 2; i++ ) { - if ( copied_data_4B[i*2] != test_data_4B[i] ) { - PRINTF("ERROR [%d]: %04x != %04x\n\r", i, copied_data_4B[i*2], test_data_4B[i]); + for (uint32_t i = 0; i < trans.size_b >> 2; i++) + { + if (copied_data_4B[i * 2] != test_data_4B[i]) + { + PRINTF("ERROR [%d]: %04x != %04x\n\r", i, copied_data_4B[i * 2], test_data_4B[i]); errors++; } } - if (errors == 0) { + if (errors == 0) + { PRINTF("DMA address mode success.\n\r"); - } else { - PRINTF("DMA address mode failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b ); + } + else + { + PRINTF("DMA address mode failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); return EXIT_FAILURE; } trans.mode = DMA_TRANS_MODE_SINGLE; - #endif // TEST_ADDRESS_MODE #if defined(TARGET_SIM) || defined(TARGET_SYSTEMC) #ifdef TEST_ADDRESS_MODE_EXTERNAL_DEVICE -#pragma message ( "this application should not be ran in a system integrating x-heep as in the external \ - slave can be plugged something else than a slow memory as in our testbench" ) - - uint32_t* ext_test_addr_4B_PTR = EXT_SLAVE_START_ADDRESS; - uint32_t* ext_copied_data_4B; +#pragma message("this application should not be ran in a system integrating x-heep as in the external \ + slave can be plugged something else than a slow memory as in our testbench") - ext_copied_data_4B = &ext_test_addr_4B_PTR[TEST_DATA_SIZE+1]; + uint32_t *ext_test_addr_4B_PTR = (uint32_t *)EXT_SLAVE_START_ADDRESS; + uint32_t *ext_copied_data_4B; + ext_copied_data_4B = &ext_test_addr_4B_PTR[TEST_DATA_SIZE + 1]; - tgt_addr.ptr = ext_test_addr_4B_PTR; + tgt_addr.ptr = (uint8_t *) ext_test_addr_4B_PTR; trans.src_addr = &tgt_addr; PRINTF("\n\n\r=====================================\n\n\r"); @@ -229,53 +349,44 @@ int main(int argc, char *argv[]) PRINTF("\n\n\r=====================================\n\n\r"); // Prepare the data - for (int i = 0; i < TEST_DATA_SIZE; i++) { - ext_test_addr_4B_PTR[i] = &ext_copied_data_4B[i*2]; + for (int i = 0; i < TEST_DATA_SIZE; i++) + { + ext_test_addr_4B_PTR[i] = (uint32_t) &ext_copied_data_4B[i * 2]; } trans.mode = DMA_TRANS_MODE_ADDRESS; - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_load_transaction(&trans); - PRINTF("load: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - res = dma_launch(&trans); - PRINTF("laun: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - - while( ! dma_is_ready()) { - // disable_interrupts - // this does not prevent waking up the core as this is controlled by the MIP register - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if ( dma_is_ready() == 0 ) { - wait_for_interrupt(); - //from here we wake up even if we did not jump to the ISR - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - } + RUN_DMA + WAIT_DMA PRINTF(">> Finished transaction. \n\r"); - for(uint32_t i = 0; i < trans.size_b >> 2; i++ ) { - if ( ext_copied_data_4B[i*2] != test_data_4B[i] ) { + for (uint32_t i = 0; i < trans.size_b >> 2; i++) + { + if (ext_copied_data_4B[i * 2] != test_data_4B[i]) + { PRINTF("ERROR [%d]: %04x != %04x\n\r", i, ext_copied_data_4B[i], test_data_4B[i]); errors++; } } - if (errors == 0) { + if (errors == 0) + { PRINTF("DMA address mode in external memory success.\n\r"); - } else { - PRINTF("DMA address mode in external memory failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b ); + } + else + { + PRINTF("DMA address mode in external memory failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); return EXIT_FAILURE; } trans.mode = DMA_TRANS_MODE_SINGLE; -#endif //TEST_ADDRESS_MODE_EXTERNAL_DEVICE +#endif // TEST_ADDRESS_MODE_EXTERNAL_DEVICE #else - #pragma message( "TEST_ADDRESS_MODE_EXTERNAL_DEVICE is not executed on target different than TARGET_SIM" ) +#pragma message("TEST_ADDRESS_MODE_EXTERNAL_DEVICE is not executed on target different than TARGET_SIM") #endif #ifdef TEST_PENDING_TRANSACTION @@ -283,61 +394,70 @@ int main(int argc, char *argv[]) PRINTF(" TESTING MULTIPLE TRANSACTIONS "); PRINTF("\n\n\r===================================\n\n\r"); - for (uint32_t i = 0; i < TEST_DATA_LARGE; i++) { + for (uint32_t i = 0; i < TEST_DATA_LARGE; i++) + { test_data_large[i] = i; } - - tgt_src.ptr = test_data_large; + tgt_src.ptr = (uint8_t *)test_data_large; tgt_src.size_du = TEST_DATA_LARGE; + tgt_dst.size_du = TEST_DATA_LARGE; // trans.end = DMA_TRANS_END_INTR_WAIT; // This option makes no sense, because the launch is blocking the program until the trans finishes. trans.end = DMA_TRANS_END_INTR; // trans.end = DMA_TRANS_END_POLLING; - - res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); - PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); cycles = 0; uint8_t consecutive_trans = 0; - for( uint8_t i = 0; i < TRANSACTIONS_N; i++ ){ - res = dma_load_transaction(&trans); + for (uint8_t i = 0; i < TRANSACTIONS_N; i++) + { + res = dma_load_transaction(&trans); res |= dma_launch(&trans); - if( res == DMA_CONFIG_OK ) consecutive_trans++; + if (res == DMA_CONFIG_OK) + consecutive_trans++; } - if( trans.end == DMA_TRANS_END_POLLING ){ - while( cycles < consecutive_trans ){ - while( ! dma_is_ready() ); + if (trans.end == DMA_TRANS_END_POLLING) + { + while (cycles < consecutive_trans) + { + while (!dma_is_ready(0)); cycles++; } - } else { - while( cycles < consecutive_trans ){ + } + else + { + while (cycles < consecutive_trans) + { wait_for_interrupt(); } } PRINTF(">> Finished %d transactions. That is %s.\n\r", consecutive_trans, consecutive_trans > 1 ? "bad" : "good"); - - - for(int i=0; i + * + * Info: Example application of matrix manipulation by exploiting the 2D DMA. + * In this code, there are some optional features: + * - Verification of several matrix operations carried out by the 2D DMA + * - Performance comparison between the DMA and the CPU, obtained by performing similar matrix operations + * and monitoring the performance counter. + */ + +#include +#include +#include "dma.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "csr.h" +#include "rv_plic.h" +#include "test_data.h" + +/* + * This code contains four different tests that can be run by defining the corresponding TEST_ID_* macro. + * - Extract a NxM matrix, perform optional padding and copy it to a AxB matrix, using HALs + * - Extract a NxM matrix and copy its transposed version to AxB matrix, using HALs + * - Extract a 1xN matrix (array), perform optional padding and copy it to an array, using HALs + * - Extract a NxM matrix, perform optional padding and copy it to a AxB matrix, using direct register operations + */ + +#define TEST_ID_0 +#define TEST_ID_1 +#define TEST_ID_2 +#define TEST_ID_3 + +/* Enable performance analysis */ +#define EN_PERF 1 + +/* Enable verification */ +#define EN_VERIF 1 + +/* Parameters */ + +/* Size of the extracted matrix (including strides on the input, excluding strides on the outputs) */ +#define SIZE_EXTR_D1 10 +#define SIZE_EXTR_D2 10 + +/* Set strides of the input ad output matrix */ +#define STRIDE_IN_D1 1 +#define STRIDE_IN_D2 1 +#define STRIDE_OUT_D1 1 +#define STRIDE_OUT_D2 1 + +/* Set the padding parameters */ +#define TOP_PAD 1 +#define BOTTOM_PAD 1 +#define LEFT_PAD 1 +#define RIGHT_PAD 1 + +/* Macros for dimensions computation */ +#define OUT_D1_PAD ( SIZE_EXTR_D1 + LEFT_PAD + RIGHT_PAD ) +#define OUT_D2_PAD ( SIZE_EXTR_D2 + TOP_PAD + BOTTOM_PAD ) +#define OUT_D1_PAD_STRIDE ( (OUT_D1_PAD * STRIDE_OUT_D1) - (STRIDE_OUT_D1 - 1) ) +#define OUT_D2_PAD_STRIDE ( (OUT_D2_PAD * STRIDE_OUT_D2) - (STRIDE_OUT_D2 - 1) ) +#define OUT_DIM_1D ( OUT_D1_PAD_STRIDE ) +#define OUT_DIM_2D ( OUT_D1_PAD_STRIDE * OUT_D2_PAD_STRIDE ) + +/* Mask for the direct register operations example */ +#define DMA_CSR_REG_MIE_MASK (( 1 << 19 ) | (1 << 11 )) + +/* Transposition example def */ +#define TRANSPOSITION_EN 1 + +/* Pointer increments computation */ +#define SRC_INC_D1 STRIDE_IN_D1 +#define DST_INC_D1 STRIDE_OUT_D1 +#define SRC_INC_D2 (STRIDE_IN_D2 * SIZE_IN_D1 - (SIZE_EXTR_D1 - 1 + (STRIDE_IN_D1 - 1) * (SIZE_EXTR_D1 - 1))) +#define DST_INC_D2 ((STRIDE_OUT_D2 - 1) * OUT_DIM_1D + 1) +#define SRC_INC_TRSP_D1 SRC_INC_D1 +#define SRC_INC_TRSP_D2 (STRIDE_IN_D2 * SIZE_IN_D1) + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +dma_input_data_type copied_data_2D_DMA[OUT_DIM_2D]; +dma_input_data_type copied_data_1D_DMA[OUT_DIM_1D]; +dma_input_data_type copied_data_2D_CPU[OUT_DIM_2D]; +dma_input_data_type copied_data_1D_CPU[OUT_DIM_2D]; + +dma_config_flags_t res_valid, res_load, res_launch; + +dma *peri = dma_peri(0); + +dma_target_t tgt_src; +dma_target_t tgt_dst; +dma_trans_t trans; + +uint32_t dst_ptr = 0, src_ptr = 0; +uint32_t cycles_dma, cycles_cpu; +uint32_t size_dst_trans_d1; +uint32_t dst_stride_d1; +uint32_t dst_stride_d2; +uint32_t size_src_trans_d1; +uint32_t src_stride_d1; +uint32_t src_stride_d2; +uint32_t i_in; +uint32_t j_in; +uint32_t i_in_last; +uint16_t left_pad_cnt = 0; +uint16_t top_pad_cnt = 0; +uint8_t stride_1d_cnt = 0; +uint8_t stride_2d_cnt = 0; +char passed = 1; + +int main() +{ + #ifdef TEST_ID_0 + + /* Testing copy and padding of a NxM matrix using HALs */ + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + tgt_src.ptr = (uint8_t *) test_data; + tgt_src.inc_du = SRC_INC_D1; + tgt_src.inc_d2_du = SRC_INC_D2; + tgt_src.size_du = SIZE_EXTR_D1; + tgt_src.size_d2_du = SIZE_EXTR_D2; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE; + + tgt_dst.ptr = (uint8_t *) copied_data_2D_DMA; + tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d2_du = DST_INC_D2; + tgt_dst.size_du = OUT_D1_PAD_STRIDE; + tgt_dst.size_d2_du = OUT_D2_PAD_STRIDE; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.dim = DMA_DIM_CONF_2D; + trans.pad_top_du = TOP_PAD, + trans.pad_bottom_du = BOTTOM_PAD, + trans.pad_left_du = LEFT_PAD, + trans.pad_right_du = RIGHT_PAD, + trans.win_du = 0, + trans.end = DMA_TRANS_END_INTR; + + dma_init(NULL); + + #if EN_PERF + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res_load = dma_load_transaction(&trans); + res_launch = dma_launch(&trans); + + #else + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + PRINTF("tran: %u \t%s\n\r", res_valid, res_valid == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_load = dma_load_transaction(&trans); + PRINTF("load: %u \t%s\n\r", res_load, res_load == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_launch = dma_launch(&trans); + PRINTF("laun: %u \t%s\n\r", res_launch, res_launch == DMA_CONFIG_OK ? "Ok!" : "Error!"); + #endif + + while( ! dma_is_ready(0)) { + #if !EN_PERF + /* Disable_interrupts */ + /* This does not prevent waking up the core as this is controlled by the MIP register */ + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if ( dma_is_ready(0) == 0 ) { + wait_for_interrupt(); + /* From here the core wakes up even if we did not jump to the ISR */ + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + #endif + } + + #if EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + + /* Reset the performance counter to evaluate the CPU performance */ + CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + #endif + + #if EN_VERIF + + /* Run the same computation on the CPU */ + for (int i=0; i < OUT_D2_PAD_STRIDE; i++) + { + stride_1d_cnt = 0; + j_in = 0; + + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = i * OUT_D1_PAD_STRIDE + j; + src_ptr = (i_in - top_pad_cnt ) * STRIDE_IN_D2 * SIZE_IN_D1 + (j_in - left_pad_cnt) * STRIDE_IN_D1; + if (i_in < TOP_PAD || i_in >= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + PRINTF("\n\r"); + + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int i = 0; i < OUT_D2_PAD_STRIDE; i++) { + for (int j = 0; j < OUT_D1_PAD_STRIDE; j++) { + if (copied_data_2D_DMA[i * OUT_D1_PAD_STRIDE + j] != copied_data_2D_CPU[i * OUT_D1_PAD_STRIDE + j]) { + passed = 0; + } + } + } + + if (passed) { + PRINTF("Success test 0\n\n\r"); + } + else + { + PRINTF("Fail test 0\n\r"); + return EXIT_FAILURE; + } + #endif + + #endif + + /* Reset for second test */ + passed = 1; + i_in = 0; + j_in = 0; + left_pad_cnt = 0; + top_pad_cnt = 0; + stride_1d_cnt = 0; + stride_2d_cnt = 0; + + for (int i = 0; i < OUT_DIM_2D; i++) { + copied_data_2D_DMA[i] = 0; + copied_data_2D_CPU[i] = 0; + } + + #ifdef TEST_ID_1 + + /* Testing transposition and copy of a NxM matrix using HALs */ + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + tgt_src.ptr = (uint8_t *) test_data; + tgt_src.inc_du = SRC_INC_TRSP_D1; + tgt_src.inc_d2_du = SRC_INC_TRSP_D2; + tgt_src.size_du = SIZE_EXTR_D1; + tgt_src.size_d2_du = SIZE_EXTR_D2; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE; + + tgt_dst.ptr = (uint8_t *) copied_data_2D_DMA; + tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d2_du = DST_INC_D2; + tgt_dst.trig = DMA_TRIG_MEMORY; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.dim = DMA_DIM_CONF_2D; + trans.pad_top_du = TOP_PAD; + trans.pad_bottom_du = BOTTOM_PAD; + trans.pad_left_du = LEFT_PAD; + trans.pad_right_du = RIGHT_PAD; + trans.dim_inv = TRANSPOSITION_EN; + trans.win_du = 0, + trans.end = DMA_TRANS_END_INTR; + + dma_init(NULL); + + #if EN_PERF + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res_load = dma_load_transaction(&trans); + res_launch = dma_launch(&trans); + + #else + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + PRINTF("tran: %u \t%s\n\r", res_valid, res_valid == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_load = dma_load_transaction(&trans); + PRINTF("load: %u \t%s\n\r", res_load, res_load == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_launch = dma_launch(&trans); + PRINTF("laun: %u \t%s\n\r", res_launch, res_launch == DMA_CONFIG_OK ? "Ok!" : "Error!"); + #endif + + while( ! dma_is_ready(0)) { + #if !EN_PERF + /* Disable_interrupts */ + /* This does not prevent waking up the core as this is controlled by the MIP register */ + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if ( dma_is_ready(0) == 0 ) { + wait_for_interrupt(); + /* From here the core wakes up even if we did not jump to the ISR */ + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + #endif + } + + #if EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + + /* Reset the performance counter to evaluate the CPU performance */ + CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + #endif + + #if EN_VERIF + + /* Run the same computation on the CPU */ + for (int i=0; i < OUT_D2_PAD_STRIDE; i++) + { + stride_1d_cnt = 0; + j_in = 0; + + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = i * OUT_D1_PAD_STRIDE + j; + src_ptr = (j_in - left_pad_cnt) * STRIDE_IN_D2 * SIZE_IN_D1 + (i_in - top_pad_cnt ) * STRIDE_IN_D1; + if (i_in < TOP_PAD || i_in >= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + PRINTF("\n\r"); + + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int i = 0; i < OUT_D2_PAD_STRIDE; i++) { + for (int j = 0; j < OUT_D1_PAD_STRIDE; j++) { + if (copied_data_2D_DMA[i * OUT_D1_PAD_STRIDE + j] != copied_data_2D_CPU[i * OUT_D1_PAD_STRIDE + j]) { + passed = 0; + } + } + } + + if (passed) { + PRINTF("Success test 1\n\n\r"); + } + else + { + PRINTF("Fail test 1\n\r"); + return EXIT_FAILURE; + } + #endif + + #endif + + /* Reset for third test */ + passed = 1; + i_in = 0; + j_in = 0; + left_pad_cnt = 0; + top_pad_cnt = 0; + stride_1d_cnt = 0; + stride_2d_cnt = 0; + + #ifdef TEST_ID_2 + + /* Testing copy and padding of a 1xN matrix (an array) */ + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + tgt_src.ptr = (uint8_t *) test_data; + tgt_src.inc_du = SRC_INC_D1; + tgt_src.size_du = SIZE_EXTR_D1; + tgt_src.inc_d2_du = 0; + tgt_src.size_d2_du = 0; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE; + + tgt_dst.ptr = (uint8_t *) copied_data_1D_DMA; + tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d2_du = 0; + tgt_dst.trig = DMA_TRIG_MEMORY; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.dim = DMA_DIM_CONF_1D; + trans.pad_top_du = 0; + trans.pad_bottom_du = 0; + trans.pad_left_du = LEFT_PAD; + trans.pad_right_du = RIGHT_PAD; + trans.dim_inv = 0; + trans.win_du = 0; + trans.end = DMA_TRANS_END_INTR; + + dma_init(NULL); + + #if EN_PERF + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res_load = dma_load_transaction(&trans); + res_launch = dma_launch(&trans); + + #else + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + PRINTF("tran: %u \t%s\n\r", res_valid, res_valid == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_load = dma_load_transaction(&trans); + PRINTF("load: %u \t%s\n\r", res_load, res_load == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_launch = dma_launch(&trans); + PRINTF("laun: %u \t%s\n\r", res_launch, res_launch == DMA_CONFIG_OK ? "Ok!" : "Error!"); + #endif + + while( ! dma_is_ready(0)) { + #if !EN_PERF + /* Disable_interrupts */ + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if ( dma_is_ready(0) == 0 ) { + wait_for_interrupt(); + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + #endif + } + + #if EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + + /* Reset the performance counter to evaluate the CPU performance */ + CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + #endif + + #if EN_VERIF + + /* Run the same computation on the CPU */ + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = j; + src_ptr = (j_in - left_pad_cnt) * STRIDE_IN_D1; + + if (j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0) + { + copied_data_1D_CPU[dst_ptr] = 0; + } + else + { + copied_data_1D_CPU[dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && stride_1d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + } + + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + PRINTF("\n\r"); + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int i = 0; i < OUT_D1_PAD_STRIDE; i++) { + if (copied_data_1D_DMA[i] != copied_data_1D_CPU[i]) { + passed = 0; + } + } + + if (passed) { + PRINTF("Success test 2\n\n\r"); + } + else + { + PRINTF("Fail test 2\n\r"); + return EXIT_FAILURE; + } + #endif + + #endif + + /* Reset for fourth test */ + passed = 1; + i_in = 0; + j_in = 0; + left_pad_cnt = 0; + top_pad_cnt = 0; + stride_1d_cnt = 0; + stride_2d_cnt = 0; + for (int i = 0; i < OUT_DIM_2D; i++) { + copied_data_2D_DMA[i] = 0; + copied_data_2D_CPU[i] = 0; + } + + #ifdef TEST_ID_3 + + /* Testing copy and padding of a NxM matrix using direct register operations. + * This strategy allows for maximum performance but doesn't perform any checks on the data integrity. + */ + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + /* The DMA is initialized (i.e. Any current transaction is cleaned.) */ + dma_init(NULL); + + /* Enable the DMA interrupt logic */ + write_register( 0x1, + DMA_INTERRUPT_EN_REG_OFFSET, + 0xffff, + DMA_INTERRUPT_EN_TRANSACTION_DONE_BIT, + peri ); + + /* Enable global interrupts */ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + /* Enable fast interrupts */ + CSR_SET_BITS(CSR_REG_MIE, DMA_CSR_REG_MIE_MASK); + + /* Pointer set up */ + peri->SRC_PTR = (uint32_t) (test_data); + peri->DST_PTR = (uint32_t) (copied_data_2D_DMA); + + /* Dimensionality configuration */ + write_register( 0x1, + DMA_DIM_CONFIG_REG_OFFSET, + 0xffff, + DMA_DIM_CONFIG_DMA_DIM_BIT, + peri ); + + /* Operation mode configuration */ + write_register( DMA_TRANS_MODE_SINGLE, + DMA_MODE_REG_OFFSET, + DMA_MODE_MODE_MASK, + DMA_MODE_MODE_OFFSET, + peri ); + + /* Data type configuration */ + write_register( DMA_DATA_TYPE, + DMA_DST_DATA_TYPE_REG_OFFSET, + DMA_DST_DATA_TYPE_DATA_TYPE_MASK, + DMA_DST_DATA_TYPE_DATA_TYPE_OFFSET, + peri ); + write_register( DMA_DATA_TYPE, + DMA_SRC_DATA_TYPE_REG_OFFSET, + DMA_SRC_DATA_TYPE_DATA_TYPE_MASK, + DMA_SRC_DATA_TYPE_DATA_TYPE_OFFSET, + peri ); + + /* Set the source strides */ + write_register( SRC_INC_D1 * DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE), + DMA_SRC_PTR_INC_D1_REG_OFFSET, + DMA_SRC_PTR_INC_D1_INC_MASK, + DMA_SRC_PTR_INC_D1_INC_OFFSET, + peri ); + + write_register( SRC_INC_D2 * DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE), + DMA_SRC_PTR_INC_D2_REG_OFFSET, + DMA_SRC_PTR_INC_D2_INC_MASK, + DMA_SRC_PTR_INC_D2_INC_OFFSET, + peri ); + + write_register( DST_INC_D1 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_DST_PTR_INC_D1_REG_OFFSET, + DMA_DST_PTR_INC_D1_INC_MASK, + DMA_DST_PTR_INC_D1_INC_OFFSET, + peri ); + + write_register( DST_INC_D2 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_DST_PTR_INC_D2_REG_OFFSET, + DMA_DST_PTR_INC_D2_INC_MASK, + DMA_DST_PTR_INC_D2_INC_OFFSET, + peri ); + + /* Padding configuration */ + write_register( TOP_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_TOP_REG_OFFSET, + DMA_PAD_TOP_PAD_MASK, + DMA_PAD_TOP_PAD_OFFSET, + peri ); + + write_register( RIGHT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_RIGHT_REG_OFFSET, + DMA_PAD_RIGHT_PAD_MASK, + DMA_PAD_RIGHT_PAD_OFFSET, + peri ); + + write_register( LEFT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_LEFT_REG_OFFSET, + DMA_PAD_LEFT_PAD_MASK, + DMA_PAD_LEFT_PAD_OFFSET, + peri ); + + write_register( BOTTOM_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_BOTTOM_REG_OFFSET, + DMA_PAD_BOTTOM_PAD_MASK, + DMA_PAD_BOTTOM_PAD_OFFSET, + peri ); + + /* Set the sizes */ + + write_register( SIZE_EXTR_D2 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_SIZE_D2_REG_OFFSET, + DMA_SIZE_D2_SIZE_MASK, + DMA_SIZE_D2_SIZE_OFFSET, + peri ); + + write_register( SIZE_EXTR_D1 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_SIZE_D1_REG_OFFSET, + DMA_SIZE_D1_SIZE_MASK, + DMA_SIZE_D1_SIZE_OFFSET, + peri ); + + while( ! dma_is_ready(0)) { + #if !EN_PERF + /* Disable_interrupts */ + /* This does not prevent waking up the core as this is controlled by the MIP register */ + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if ( dma_is_ready(0) == 0 ) { + wait_for_interrupt(); + /* From here the core wakes up even if we did not jump to the ISR */ + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + #endif + } + + #if EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + + /* Reset the performance counter to evaluate the CPU performance */ + CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + #endif + + #if EN_VERIF + + /* Run the same computation on the CPU */ + for (int i=0; i < OUT_D2_PAD_STRIDE; i++) + { + stride_1d_cnt = 0; + j_in = 0; + + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = i * OUT_D1_PAD_STRIDE + j; + src_ptr = (i_in - top_pad_cnt ) * STRIDE_IN_D2 * SIZE_IN_D1 + (j_in - left_pad_cnt) * STRIDE_IN_D1; + if (i_in < TOP_PAD || i_in >= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + PRINTF("\n\r"); + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int i = 0; i < OUT_D2_PAD_STRIDE; i++) { + for (int j = 0; j < OUT_D1_PAD_STRIDE; j++) { + if (copied_data_2D_DMA[i * OUT_D1_PAD_STRIDE + j] != copied_data_2D_CPU[i * OUT_D1_PAD_STRIDE + j]) { + passed = 0; + } + } + } + + if (passed) { + PRINTF("Success test 3\n\n\r"); + } + else + { + PRINTF("Fail test 3\n\r"); + return EXIT_FAILURE; + } + #endif + + #endif + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h new file mode 100644 index 00000000..d1232223 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h @@ -0,0 +1,40 @@ +#ifndef __TEST_DATA_H__ +#define __TEST_DATA_H__ + +#define SIZE_IN_D1 25 +#define SIZE_IN_D2 25 +#define DMA_DATA_TYPE DMA_DATA_TYPE_WORD + +/* Change the input datatype depending on the DMA_DATA_TYPE + * The test data has been generated using byte as datatype, so it's possible to use both uint8_t, uint16_t and uint32_t + */ +typedef uint32_t dma_input_data_type; + +dma_input_data_type test_data[SIZE_IN_D1 * SIZE_IN_D2] = { + 93 ,178 ,28 ,23 ,5 ,231 ,211 ,236 ,45 ,196 ,55 ,124 ,113 ,188 ,36 ,43 ,147 ,111 ,254 ,126 ,145 ,83 ,77 ,7 ,126, + 92 ,179 ,157 ,41 ,64 ,7 ,105 ,93 ,176 ,196 ,171 ,42 ,251 ,175 ,120 ,63 ,134 ,56 ,233 ,0 ,189 ,133 ,71 ,226 ,9, + 252 ,214 ,243 ,177 ,205 ,75 ,100 ,165 ,160 ,42 ,112 ,71 ,238 ,208 ,62 ,1 ,113 ,87 ,116 ,212 ,107 ,165 ,214 ,239 ,151, + 215 ,3 ,80 ,243 ,0 ,18 ,30 ,149 ,237 ,35 ,81 ,149 ,227 ,23 ,240 ,13 ,117 ,122 ,158 ,253 ,120 ,175 ,203 ,30 ,204, + 45 ,18 ,176 ,241 ,38 ,232 ,189 ,208 ,50 ,120 ,4 ,47 ,136 ,141 ,154 ,207 ,180 ,160 ,46 ,191 ,48 ,29 ,122 ,30 ,45, + 56 ,8 ,137 ,197 ,185 ,210 ,103 ,123 ,116 ,25 ,57 ,126 ,41 ,213 ,165 ,17 ,111 ,151 ,39 ,115 ,21 ,59 ,220 ,165 ,142, + 175 ,169 ,150 ,41 ,68 ,241 ,228 ,121 ,125 ,163 ,16 ,244 ,157 ,8 ,205 ,148 ,194 ,115 ,7 ,59 ,164 ,127 ,88 ,184 ,215, + 13 ,6 ,102 ,204 ,29 ,15 ,182 ,125 ,141 ,251 ,172 ,13 ,159 ,196 ,93 ,200 ,211 ,42 ,10 ,154 ,105 ,82 ,109 ,175 ,117, + 115 ,109 ,201 ,196 ,242 ,139 ,178 ,191 ,190 ,181 ,140 ,197 ,233 ,34 ,69 ,20 ,193 ,35 ,243 ,11 ,41 ,131 ,196 ,8 ,133, + 70 ,234 ,210 ,171 ,107 ,57 ,133 ,162 ,114 ,168 ,118 ,250 ,12 ,30 ,223 ,95 ,246 ,122 ,73 ,220 ,247 ,6 ,102 ,214 ,108, + 48 ,55 ,22 ,243 ,241 ,45 ,147 ,32 ,105 ,25 ,185 ,22 ,41 ,2 ,5 ,82 ,221 ,237 ,223 ,162 ,77 ,95 ,62 ,198 ,97, + 206 ,210 ,61 ,7 ,163 ,142 ,20 ,215 ,35 ,92 ,232 ,88 ,52 ,207 ,137 ,234 ,123 ,251 ,214 ,221 ,23 ,19 ,51 ,245 ,188, + 251 ,139 ,176 ,240 ,126 ,29 ,247 ,228 ,248 ,164 ,14 ,198 ,143 ,15 ,178 ,72 ,238 ,220 ,145 ,7 ,253 ,233 ,245 ,32 ,95, + 142 ,30 ,227 ,66 ,67 ,177 ,47 ,2 ,87 ,155 ,74 ,255 ,1 ,69 ,157 ,181 ,73 ,57 ,60 ,39 ,64 ,93 ,146 ,4 ,220, + 129 ,219 ,109 ,159 ,65 ,112 ,162 ,145 ,241 ,59 ,55 ,21 ,12 ,196 ,239 ,239 ,31 ,58 ,148 ,215 ,241 ,109 ,72 ,108 ,61, + 178 ,205 ,116 ,33 ,240 ,137 ,150 ,150 ,148 ,80 ,211 ,87 ,46 ,160 ,64 ,9 ,179 ,221 ,91 ,113 ,87 ,132 ,141 ,70 ,95, + 104 ,62 ,121 ,12 ,149 ,108 ,197 ,154 ,51 ,247 ,78 ,121 ,186 ,124 ,140 ,138 ,155 ,117 ,221 ,55 ,233 ,1 ,61 ,190 ,220, + 123 ,200 ,239 ,89 ,200 ,167 ,191 ,121 ,24 ,249 ,145 ,189 ,15 ,249 ,235 ,165 ,243 ,239 ,102 ,41 ,62 ,159 ,45 ,248 ,28, + 128 ,200 ,95 ,240 ,148 ,118 ,168 ,156 ,62 ,88 ,102 ,14 ,197 ,252 ,135 ,54 ,170 ,249 ,133 ,250 ,172 ,67 ,60 ,35 ,246, + 7 ,9 ,7 ,181 ,49 ,60 ,239 ,70 ,33 ,29 ,132 ,112 ,37 ,28 ,34 ,233 ,37 ,178 ,40 ,20 ,189 ,43 ,45 ,65 ,194, + 104 ,43 ,31 ,59 ,49 ,157 ,15 ,198 ,205 ,47 ,201 ,88 ,49 ,199 ,55 ,223 ,43 ,13 ,118 ,225 ,175 ,94 ,222 ,236 ,10, + 157 ,75 ,239 ,221 ,34 ,14 ,26 ,232 ,18 ,240 ,198 ,3 ,23 ,226 ,110 ,118 ,172 ,0 ,17 ,210 ,136 ,226 ,223 ,162 ,169, + 4 ,35 ,179 ,115 ,9 ,54 ,89 ,178 ,2 ,108 ,123 ,178 ,61 ,107 ,228 ,73 ,70 ,46 ,236 ,102 ,179 ,182 ,49 ,130 ,229, + 72 ,159 ,179 ,125 ,24 ,152 ,13 ,104 ,186 ,2 ,174 ,204 ,191 ,241 ,158 ,84 ,96 ,184 ,19 ,171 ,135 ,101 ,27 ,218 ,217, + 211 ,180 ,172 ,64 ,213 ,56 ,76 ,16 ,82 ,205 ,105 ,165 ,185 ,61 ,19 ,158 ,252 ,192 ,135 ,110 ,246 ,84 ,2 ,18 ,72}; + +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c index a4fa35a7..e73f84af 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c @@ -20,7 +20,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -29,7 +29,7 @@ int32_t errors = 0; -void dma_intr_handler_trans_done() +void dma_intr_handler_trans_done(uint8_t channel) { PRINTF("D"); } @@ -82,11 +82,11 @@ int main(int argc, char *argv[]) res = dma_launch(&trans); PRINTF("laun: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); - while( ! dma_is_ready() ){ + while( ! dma_is_ready(0) ){ // disable_interrupts // this does not prevent waking up the core as this is controlled by the MIP register CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if ( dma_is_ready() == 0 ) { + if ( dma_is_ready(0) == 0 ) { wait_for_interrupt(); //from here we wake up even if we did not jump to the ISR } diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c new file mode 100644 index 00000000..2e7f2bc8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c @@ -0,0 +1,1261 @@ +/* + * Copyright EPFL contributors. + * Licensed under the Apache License, Version 2.0, see LICENSE for details. + * SPDX-License-Identifier: Apache-2.0 + * + * Author: Tommaso Terzano + * + * Info: Example application of matrix manipulation by exploiting the multichannel feature of the DMA subsystem. + * This code is capable of testing the following features: + * - Verification of matrix operations carried out by the DMA subsystem + * - Performance comparison between the DMA multichannel and the CPU, obtained by performing similar matrix operations + * and monitoring the performance counter. + * The performance of the DMA is compared against sequential CPU loops for each operation performed by a single channel. + * A typical case in which the DMA could be used to improve the performance is a series of matrix operations, + * like extracting 3 matrices from a larger one. + * By exploiting the DMA, these three separate calls can be performed in parallel. + */ + +#include +#include +#include "dma.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "csr.h" +#include "rv_plic.h" +#include "test_data.h" +#include "w25q128jw.h" + +/* + * The following code is designed to test the DMA subsystem multichannel feature. In order to do so, several + * tests are available, which are run using some or all of the DMA channels available. + * + * DISCLAIMER: + * When using the default memory configuration (64kB), pay attention to the dimensions of the output matrices. + * When executing TEST_ID_4 on QuestaSim, make sure to enable the SPI FLASH. + * + * Enable one or more of the following tests by defining the correct TEST_ID_* macro: + * + * 0: Extract a NxM matrix, perform optional padding and copy the result to two separate + * AxB matrices using N channels at the same time and using direct register writes. + * Additionally, each DMA channel is set with a window of M size. For each window interrupt, + * the correct window flag is set. + * + * 1: Extract a NxM matrix, perform optional padding and copy the result to two separate + * AxB matrices using N channels at the same time and using HALs. For each transaction interrupt, + * the correct transaction flag is set. + * + * 2: Each DMA channel performs, alternatively, one of the following operations: + * - Extract a NxM matrix, perform optional padding and copy the result + * - Extract a NxM matrix, perform optional padding, transpose it and copy the result + * + * 3: Extract a NxM matrix, perform optional padding and copy the result to a location using one channel (with HALs), + * while at the same time read a buffer from SPI and copy it to another location using another channel (with HALs). + * This test can only be performed on FPGA boards or using QuestaSim, by setting the correct macro (SIM_QUESTASIM). + * When executing on QuestaSim, make sure to compile in the correct way: + * - Include LINKER=flash_load in "make app ..." + * - Add boot_sel and execute_from_flash: + * 'make run PLUSARGS="c firmware=../../../sw/build/main.hex boot_sel=1 execute_from_flash=0" ' + * + */ + +#define TEST_ID_0 +#define TEST_ID_1 +#define TEST_ID_2 +#define TEST_ID_3 + +/* Enable performance analysis */ +#define EN_PERF 1 + +/* Enable verification */ +#define EN_VERIF 1 + +/* Parameters */ + +/* Size of the extracted matrix (including strides on the input, excluding strides on the outputs) */ +#define SIZE_EXTR_D1 10 +#define SIZE_EXTR_D2 10 + +/* Set strides of the input ad output matrix */ +#define STRIDE_IN_D1 1 +#define STRIDE_IN_D2 1 +#define STRIDE_OUT_D1 1 +#define STRIDE_OUT_D2 1 + +/* Set the padding parameters */ +#define TOP_PAD 0 +#define BOTTOM_PAD 0 +#define LEFT_PAD 0 +#define RIGHT_PAD 0 + +/* Macros for dimensions computation */ +#define OUT_D1_PAD ( SIZE_EXTR_D1 + LEFT_PAD + RIGHT_PAD ) +#define OUT_D2_PAD ( SIZE_EXTR_D2 + TOP_PAD + BOTTOM_PAD ) +#define OUT_D1_PAD_STRIDE ( (OUT_D1_PAD * STRIDE_OUT_D1) - (STRIDE_OUT_D1 - 1) ) +#define OUT_D2_PAD_STRIDE ( (OUT_D2_PAD * STRIDE_OUT_D2) - (STRIDE_OUT_D2 - 1) ) +#define OUT_DIM_1D ( OUT_D1_PAD_STRIDE ) +#define OUT_DIM_2D ( OUT_D1_PAD_STRIDE * OUT_D2_PAD_STRIDE ) + +/* + * Window size for the DMA. Since it has to be > 71 for the ISR to have the time to react, + * the OUT_DIM_2D has to be big enough. DMA_WINDOW_SIZE is by default set to 80 for good measure. + */ + +#define DMA_WINDOW_SIZE 80 + +#if defined(TEST_ID_0) && ((OUT_DIM_2D < DMA_WINDOW_SIZE) || (DMA_WINDOW_SIZE < 72)) + #error "In order to correctly execute TEST_ID_0, the matrix output dimension has to be bigger than 72 and bigger than the window dimension.\nCheck these parameters and recompile.\n" +#endif + +/* Defines for DMA channels */ +#define DMA_CH0_IDX 0 +#define DMA_CH1_IDX 1 +#define DMA_CH2_IDX 2 +#define DMA_CH3_IDX 3 + +/* Assigning a pointer to a define writes the pointed array in the flash */ +#define TEST_DATA_FLASH_PTR test_data_flash + +/* Mask for direct register operations example */ +#define DMA_CSR_REG_MIE_MASK (( 1 << 19 ) | (1 << 11 )) + +/* Transposition example def */ +#define TRANSPOSITION_EN 1 + +/* Pointer increments computation */ +#define SRC_INC_D1 STRIDE_IN_D1 +#define DST_INC_D1 STRIDE_OUT_D1 +#define SRC_INC_D2 (STRIDE_IN_D2 * SIZE_IN_D1 - (SIZE_EXTR_D1 - 1 + (STRIDE_IN_D1 - 1) * (SIZE_EXTR_D1 - 1))) +#define DST_INC_D2 ((STRIDE_OUT_D2 - 1) * OUT_DIM_1D + 1) +#define SRC_INC_TRSP_D1 SRC_INC_D1 +#define SRC_INC_TRSP_D2 (STRIDE_IN_D2 * SIZE_IN_D1) + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_IS_FPGA && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +/* FPGA SPI board selection */ +#if !TARGET_SIM + #define USE_SPI_FLASH +#endif + +/* QuestaSim macro to enable test 4, by default is disabled */ +//#define SIM_QUESTASIM + +/* Size of FLASH buffer */ +#define TEST_DATA_FLASH_SIZE 32 + +/* Memory allocation for examples */ +uint32_t copied_test_data_flash[TEST_DATA_FLASH_SIZE]; +dma_input_data_type copied_data_2D_DMA[DMA_CH_NUM][OUT_DIM_2D]; +dma_input_data_type copied_data_2D_CPU[DMA_CH_NUM][OUT_DIM_2D]; + +#if (TARGET_SIM == 0 || defined(TARGET_QUESTASIM)) +/* Data for TEST_ID_3 to be stored in the FLASH */ +uint32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16))) test_data_flash[TEST_DATA_FLASH_SIZE] = { + 105 ,82 ,221 ,172 ,77 ,62, + 81 ,185 ,33 ,213 ,249 ,117, + 69 ,212 ,99 ,137 ,9 ,233, + 107 ,105 ,166 ,141 ,53 ,207, + 53 ,21 ,221 ,102 ,84 ,108, + 43 ,99 ,123 ,71 ,30 ,179 + }; + +/* Data for TEST_ID_3 to compare the copied data from the FLASH */ +uint32_t test_data_flash_golden[TEST_DATA_FLASH_SIZE] = { + 105 ,82 ,221 ,172 ,77 ,62, + 81 ,185 ,33 ,213 ,249 ,117, + 69 ,212 ,99 ,137 ,9 ,233, + 107 ,105 ,166 ,141 ,53 ,207, + 53 ,21 ,221 ,102 ,84 ,108, + 43 ,99 ,123 ,71 ,30 ,179 + }; +#endif + +/* DMA source, destination and transaction */ +dma_target_t tgt_src; +dma_target_t tgt_src_trsp; +dma_target_t tgt_dst[DMA_CH_NUM]; +dma_trans_t trans[DMA_CH_NUM]; + +dma_config_flags_t res_valid, res_load, res_launch; + +/* CPU computation variables */ +uint32_t dst_ptr = 0, src_ptr = 0; +uint32_t cycles_dma, cycles_cpu; +uint32_t size_dst_trans_d1; +uint32_t dst_stride_d1; +uint32_t dst_stride_d2; +uint32_t size_src_trans_d1; +uint32_t src_stride_d1; +uint32_t src_stride_d2; +uint32_t i_in; +uint32_t j_in; +uint32_t i_in_last; +uint32_t j_in_last; +uint16_t left_pad_cnt = 0; +uint16_t top_pad_cnt = 0; +uint8_t stride_1d_cnt = 0; +uint8_t stride_2d_cnt = 0; +uint8_t transaction_flag[DMA_CH_NUM]; +uint8_t window_flag[DMA_CH_NUM]; +char passed = 1; +char flag = 0; + +/* Strong transaction ISR implementation */ +void dma_intr_handler_trans_done(uint8_t channel) +{ + transaction_flag[channel] = 1; + return; +} + +/* Strong window ISR implementation */ +void dma_intr_handler_window_done(uint8_t channel) +{ + window_flag[channel] = 1; + return; +} + +int main() +{ + + #ifdef TEST_ID_0 + + /* + * Testing copy and padding of a NxM matrix using direct register operations. + * This strategy allows for maximum performance but doesn't perform any checks on the data integrity. + * The data is copied using N channels to N different memory locations. + */ + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + /* The DMA channels are initialized (i.e. Any current transaction is cleaned.) */ + dma_init(NULL); + + plic_Init(); + plic_irq_set_priority( DMA_WINDOW_INTR, 1); + plic_irq_set_enabled( DMA_WINDOW_INTR, kPlicToggleEnabled); + + /* Enable global interrupts */ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + /* Enable fast interrupts */ + CSR_SET_BITS(CSR_REG_MIE, DMA_CSR_REG_MIE_MASK); + + + for (int i=0; iSRC_PTR = &test_data[0]; + dma_peri(i)->DST_PTR = copied_data_2D_DMA[i]; + + /* Dimensionality configuration */ + write_register( 0x1, + DMA_DIM_CONFIG_REG_OFFSET, + 0x1, + DMA_DIM_CONFIG_DMA_DIM_BIT, + dma_peri(i) ); + + /* Operation mode configuration */ + write_register( DMA_TRANS_MODE_SINGLE, + DMA_MODE_REG_OFFSET, + DMA_MODE_MODE_MASK, + DMA_MODE_MODE_OFFSET, + dma_peri(i) ); + + /* Data type configuration */ + write_register( DMA_DATA_TYPE, + DMA_DST_DATA_TYPE_REG_OFFSET, + DMA_DST_DATA_TYPE_DATA_TYPE_MASK, + DMA_DST_DATA_TYPE_DATA_TYPE_OFFSET, + dma_peri(i) ); + + write_register( DMA_DATA_TYPE, + DMA_SRC_DATA_TYPE_REG_OFFSET, + DMA_SRC_DATA_TYPE_DATA_TYPE_MASK, + DMA_SRC_DATA_TYPE_DATA_TYPE_OFFSET, + dma_peri(i) ); + + /* Set the source strides */ + write_register( SRC_INC_D1 * DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE), + DMA_SRC_PTR_INC_D1_REG_OFFSET, + DMA_SRC_PTR_INC_D1_INC_MASK, + DMA_SRC_PTR_INC_D1_INC_OFFSET, + dma_peri(i) ); + + write_register( SRC_INC_D2 * DMA_DATA_TYPE_2_SIZE(DMA_DATA_TYPE), + DMA_SRC_PTR_INC_D2_REG_OFFSET, + DMA_SRC_PTR_INC_D2_INC_MASK, + DMA_SRC_PTR_INC_D2_INC_OFFSET, + dma_peri(i) ); + + write_register( DST_INC_D1 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_DST_PTR_INC_D1_REG_OFFSET, + DMA_DST_PTR_INC_D1_INC_MASK, + DMA_DST_PTR_INC_D1_INC_OFFSET, + dma_peri(i) ); + + write_register( DST_INC_D2 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_DST_PTR_INC_D2_REG_OFFSET, + DMA_DST_PTR_INC_D2_INC_MASK, + DMA_DST_PTR_INC_D2_INC_OFFSET, + dma_peri(i) ); + + /* Padding configuration */ + write_register( TOP_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_TOP_REG_OFFSET, + DMA_PAD_TOP_PAD_MASK, + DMA_PAD_TOP_PAD_OFFSET, + dma_peri(i) ); + + write_register( RIGHT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_RIGHT_REG_OFFSET, + DMA_PAD_RIGHT_PAD_MASK, + DMA_PAD_RIGHT_PAD_OFFSET, + dma_peri(i) ); + + write_register( LEFT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_LEFT_REG_OFFSET, + DMA_PAD_LEFT_PAD_MASK, + DMA_PAD_LEFT_PAD_OFFSET, + dma_peri(i) ); + + write_register( BOTTOM_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + DMA_PAD_BOTTOM_REG_OFFSET, + DMA_PAD_BOTTOM_PAD_MASK, + DMA_PAD_BOTTOM_PAD_OFFSET, + dma_peri(i) ); + + /* Set the window size */ + write_register( DMA_WINDOW_SIZE, + DMA_WINDOW_SIZE_REG_OFFSET, + DMA_WINDOW_SIZE_WINDOW_SIZE_MASK, + DMA_WINDOW_SIZE_WINDOW_SIZE_OFFSET, + dma_peri(i) ); + } + + for (int i=0; i= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[c][dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[c][dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + } + + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int c=0; c= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[c][dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[c][dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + } + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int c=0; c= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[c][dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[c][dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + flag = 1; + } + else + { + for (int i=0; i < OUT_D2_PAD_STRIDE; i++) + { + stride_1d_cnt = 0; + j_in = 0; + + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = i * OUT_D1_PAD_STRIDE + j; + src_ptr = (j_in - left_pad_cnt) * STRIDE_IN_D2 * SIZE_IN_D1 + (i_in - top_pad_cnt ) * STRIDE_IN_D1; + if (i_in < TOP_PAD || i_in >= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[c][dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[c][dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + flag = 0; + } + } + + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int c=0; c 1 + + /* Testing SPI2RAM & RAM2RAM operations on 2 channels */ + + /* Reset for fourth test */ + passed = 1; + i_in = 0; + j_in = 0; + left_pad_cnt = 0; + top_pad_cnt = 0; + stride_1d_cnt = 0; + stride_2d_cnt = 0; + for (int i = 0; i < OUT_DIM_2D; i++) { + copied_data_2D_DMA[1][i] = 0; + copied_data_2D_CPU[1][i] = 0; + } + + #if EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + dma_init(NULL); + + tgt_src.ptr = (uint8_t *) test_data; + tgt_src.inc_du = SRC_INC_D1; + tgt_src.inc_d2_du = SRC_INC_D2; + tgt_src.size_du = SIZE_EXTR_D1; + tgt_src.size_d2_du = SIZE_EXTR_D2; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE; + + tgt_dst[1].ptr = (uint8_t *) copied_data_2D_DMA[1]; + tgt_dst[1].inc_du = DST_INC_D1; + tgt_dst[1].inc_d2_du = DST_INC_D2; + tgt_dst[1].trig = DMA_TRIG_MEMORY; + + trans[1].src = &tgt_src; + trans[1].dst = &tgt_dst[1]; + trans[1].mode = DMA_TRANS_MODE_SINGLE; + trans[1].dim = DMA_DIM_CONF_2D; + trans[1].pad_top_du = TOP_PAD; + trans[1].pad_bottom_du = BOTTOM_PAD; + trans[1].pad_left_du = LEFT_PAD; + trans[1].pad_right_du = RIGHT_PAD; + trans[1].win_du = 0; + trans[1].end = DMA_TRANS_END_INTR; + trans[1].channel = DMA_CH1_IDX; + + /* Initialize the SPI */ + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + /* Pick the correct spi device based on simulation type */ + spi_host_t *spi; + #ifndef USE_SPI_FLASH + spi = spi_host1; + #else + spi = spi_flash; + #endif + + /* Init SPI host and SPI<->Flash bridge parameters */ + if (w25q128jw_init(spi) != FLASH_OK) + { + PRINTF("Error initializing the flash SPI\n\r"); + return EXIT_FAILURE; + } + + /* Start the reading process from the SPI, avoiding both sanity checks and waiting for the DMA to finish */ + w25q_error_codes_t status = w25q128jw_read_standard_dma(TEST_DATA_FLASH_PTR, copied_test_data_flash, TEST_DATA_FLASH_SIZE*4, 1, 1); + if (status != FLASH_OK) + { + PRINTF("Error reading from flash\n\r"); + return EXIT_FAILURE; + } + + #if EN_PERF + + dma_validate_transaction(&trans[1], DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + dma_load_transaction(&trans[1]); + dma_launch(&trans[1]); + + #else + + res_valid = dma_validate_transaction(&trans_ch1, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + PRINTF("tran: %u \t%s\n\r", res_valid, res_valid == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_load = dma_load_transaction(&trans_ch1); + PRINTF("load: %u \t%s\n\r", res_load, res_load == DMA_CONFIG_OK ? "Ok!" : "Error!"); + res_launch = dma_launch(&trans_ch1); + PRINTF("laun: %u \t%s\n\r", res_launch, res_launch == DMA_CONFIG_OK ? "Ok!" : "Error!"); + #endif + + /* Wait for CH1 to end */ + while(!dma_is_ready(1)) { + #if !EN_PERF + /* Disable_interrupts */ + /* This does not prevent waking up the core as this is controlled by the MIP register */ + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if ( dma_is_ready(1) == 0 ) { + wait_for_interrupt(); + /* From here the core wakes up even if we did not jump to the ISR */ + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + #endif + } + + #if EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + + /* Reset the performance counter to evaluate the CPU performance */ + CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + #endif + + #if EN_VERIF + + /* Run the same computation on the CPU */ + for (int i=0; i < OUT_D2_PAD_STRIDE; i++) + { + stride_1d_cnt = 0; + j_in = 0; + + for (int j=0; j < OUT_D1_PAD_STRIDE; j++) + { + dst_ptr = i * OUT_D1_PAD_STRIDE + j; + src_ptr = (i_in - top_pad_cnt ) * STRIDE_IN_D2 * SIZE_IN_D1 + (j_in - left_pad_cnt) * STRIDE_IN_D1; + if (i_in < TOP_PAD || i_in >= SIZE_EXTR_D2 + TOP_PAD || j_in < LEFT_PAD || j_in >= SIZE_EXTR_D1 + LEFT_PAD || + stride_1d_cnt != 0 || stride_2d_cnt != 0) + { + copied_data_2D_CPU[1][dst_ptr] = 0; + } + else + { + copied_data_2D_CPU[1][dst_ptr] = test_data[src_ptr]; + } + + if (j_in < LEFT_PAD && i_in >= TOP_PAD && stride_1d_cnt == 0 && stride_2d_cnt == 0) + { + left_pad_cnt++; + } + + if (stride_1d_cnt == STRIDE_OUT_D1 - 1) + { + stride_1d_cnt = 0; + j_in++; + } + else + { + stride_1d_cnt++; + } + + } + + if (i_in < TOP_PAD && stride_2d_cnt == 0) + { + top_pad_cnt++; + } + + if (stride_2d_cnt == STRIDE_OUT_D2 - 1) + { + stride_2d_cnt = 0; + i_in++; + } + else + { + stride_2d_cnt++; + } + + left_pad_cnt = 0; + } + #endif + + #if EN_PERF + + /* Read the cycles count after the CPU run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + PRINTF("DMA cycles: %d\n\r", cycles_dma); + PRINTF("CPU cycles: %d \n\r", cycles_cpu); + + #endif + + #if EN_VERIF + + /* Verify that the DMA and the CPU outputs are the same */ + for (int i = 0; i < OUT_D2_PAD_STRIDE; i++) { + for (int j = 0; j < OUT_D1_PAD_STRIDE; j++) { + if ((copied_data_2D_DMA[1][i * OUT_D1_PAD_STRIDE + j] != copied_data_2D_CPU[1][i * OUT_D1_PAD_STRIDE + j])) + { + passed = 0; + } + } + } + + /* Verify that the SPI copy was successful */ + for (int i=0; i < TEST_DATA_FLASH_SIZE; i++) + { + if (copied_test_data_flash[i] != test_data_flash_golden[i]) + { + passed = 0; + } + } + + if (passed) { + PRINTF("Success test 3\n\r"); + } + else + { + PRINTF("Fail test 3\n\r"); + return EXIT_FAILURE; + } + #endif + + #endif + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/test_data.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/test_data.h new file mode 100644 index 00000000..c582490e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/test_data.h @@ -0,0 +1,34 @@ +#ifndef __TEST_DATA_H__ +#define __TEST_DATA_H__ + +#define SIZE_IN_D1 15 +#define SIZE_IN_D2 15 +#define DMA_DATA_TYPE DMA_DATA_TYPE_WORD + +/* + * Change the input datatype depending on the DMA_DATA_TYPE. + * The test data has been generated using byte as datatype, so it's possible to use both uint8_t, uint16_t and uint32_t. + * NOTE: To fully evaluate the performance gains of the DMA it's recommended to increase the number of memory banks and + * the size of the data to be copied up ot at least 50x50. + */ +typedef uint32_t dma_input_data_type; + +dma_input_data_type test_data[SIZE_IN_D1 * SIZE_IN_D2] = { + 236 ,19 ,35 ,109 ,59 ,58 ,216 ,210 ,72 ,169 ,123 ,74 ,132 ,27 ,208, + 43 ,93 ,216 ,145 ,94 ,235 ,80 ,25 ,146 ,127 ,115 ,9 ,45 ,61 ,60, + 78 ,218 ,28 ,230 ,140 ,236 ,152 ,242 ,98 ,173 ,20 ,206 ,176 ,157 ,219, + 225 ,182 ,118 ,22 ,153 ,196 ,7 ,9 ,87 ,99 ,173 ,11 ,103 ,173 ,49, + 122 ,185 ,128 ,93 ,243 ,29 ,172 ,32 ,207 ,64 ,184 ,40 ,165 ,87 ,157, + 182 ,196 ,160 ,93 ,182 ,91 ,20 ,82 ,156 ,45 ,109 ,132 ,168 ,234 ,85, + 121 ,39 ,188 ,109 ,190 ,127 ,192 ,124 ,149 ,90 ,247 ,68 ,26 ,82 ,57, + 189 ,249 ,91 ,193 ,23 ,210 ,167 ,79 ,175 ,31 ,212 ,131 ,102 ,43 ,4, + 192 ,184 ,234 ,9 ,81 ,4 ,221 ,12 ,181 ,76 ,64 ,131 ,59 ,26 ,83, + 86 ,140 ,176 ,18 ,120 ,115 ,153 ,50 ,41 ,83 ,110 ,157 ,173 ,145 ,81, + 9 ,120 ,250 ,3 ,27 ,119 ,64 ,195 ,48 ,245 ,160 ,78 ,177 ,246 ,59, + 156 ,114 ,97 ,7 ,11 ,224 ,75 ,154 ,223 ,221 ,90 ,77 ,254 ,181 ,198, + 193 ,254 ,161 ,177 ,201 ,3 ,182 ,18 ,36 ,23 ,67 ,46 ,116 ,229 ,166, + 90 ,158 ,248 ,194 ,224 ,218 ,245 ,34 ,60 ,126 ,68 ,248 ,143 ,232 ,226, + 58 ,202 ,172 ,209 ,229 ,89 ,246 ,184 ,215 ,7 ,163 ,204 ,43 ,116 ,33}; +; + +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_sdk/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_sdk/main.c new file mode 100644 index 00000000..22b3ce65 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_sdk/main.c @@ -0,0 +1,112 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: example_dma_sdk.c +// Author: Juan Sapriza +// Date: 13/06/2024 +// Description: Example application to test the DMA SDK. Will copy +// a constant value in a buffer and then copy the content +// of the buffer into another. Will check that both transactions +// are performed correctly. + +#include +#include // For compatibility with OH Group compiler +#include +#include "dma_sdk.h" +#include "dma.h" // For compatibility with OH Group compiler +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "csr.h" // For compatibility with OH Group compiler + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM +#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +#define SOURCE_BUFFER_SIZE_32b 5 +#define SOURCE_BUFFER_SIZE_16b 5 +#define SOURCE_BUFFER_SIZE_8b 5 +#define CONST_VALUE_32B 123 +#define CONST_NEG_VALUE_32B -123 +#define CONST_VALUE_16B 123 +#define CONST_NEG_VALUE_16B -123 +#define CONST_VALUE_8B 123 +#define CONST_NEG_VALUE_8B -123 + +static uint32_t source_32b[SOURCE_BUFFER_SIZE_32b]; +static uint32_t destin_32b[SOURCE_BUFFER_SIZE_32b]; + +static uint16_t destin_16b[SOURCE_BUFFER_SIZE_16b]; +static uint16_t source_16b[SOURCE_BUFFER_SIZE_16b]; + +static uint8_t destin_8b[SOURCE_BUFFER_SIZE_8b]; +static uint8_t source_8b[SOURCE_BUFFER_SIZE_8b]; + +static int32_t neg_source_32b[SOURCE_BUFFER_SIZE_32b]; +static int32_t neg_destin_32b[SOURCE_BUFFER_SIZE_32b]; + +static int16_t neg_destin_16b[SOURCE_BUFFER_SIZE_16b]; +static int16_t neg_source_16b[SOURCE_BUFFER_SIZE_16b]; + +static int8_t neg_destin_8b[SOURCE_BUFFER_SIZE_8b]; +static int8_t neg_source_8b[SOURCE_BUFFER_SIZE_8b]; + +static uint32_t value_32b = CONST_VALUE_32B; +static uint16_t value_16b = CONST_VALUE_16B; +static uint8_t value_8b = CONST_VALUE_8B; + +static int32_t neg_value_32b = CONST_NEG_VALUE_32B; +static int16_t neg_value_16b = CONST_NEG_VALUE_16B; +static int8_t neg_value_8b = CONST_NEG_VALUE_8B; + +uint32_t i; +uint32_t errors = 0; + +int main() +{ + dma_sdk_init(); + + dma_fill((uint32_t)source_32b, (uint32_t)&value_32b, SOURCE_BUFFER_SIZE_32b, 0, DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD, 0); + dma_copy((uint32_t)destin_32b, (uint32_t)source_32b, SOURCE_BUFFER_SIZE_32b, 0, DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD, 0); + + for (i = 0; i < SOURCE_BUFFER_SIZE_32b; i++) + { + errors += destin_32b[i] != CONST_VALUE_32B; + } + + dma_fill((uint32_t)source_16b, (uint32_t)&value_16b, SOURCE_BUFFER_SIZE_16b, 0, DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD, 0); + dma_copy((uint32_t)destin_16b, (uint32_t)source_16b, SOURCE_BUFFER_SIZE_16b, 0, DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD, 0); + + for (i = 0; i < SOURCE_BUFFER_SIZE_16b; i++) + { + errors += destin_16b[i] != CONST_VALUE_16B; + } + + dma_fill((uint32_t)source_8b, (uint32_t)&value_8b, SOURCE_BUFFER_SIZE_8b, 0, DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE, 0); + dma_copy((uint32_t)destin_8b, (uint32_t)source_8b, SOURCE_BUFFER_SIZE_8b, 0, DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE, 0); + + for (i = 0; i < SOURCE_BUFFER_SIZE_8b; i++) + { + errors += destin_8b[i] != CONST_VALUE_8B; + } + + dma_fill((uint32_t)neg_source_16b, (uint32_t)&neg_value_8b, SOURCE_BUFFER_SIZE_32b, 0, DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD, 1); + dma_copy((uint32_t)neg_destin_32b, (uint32_t)neg_source_16b, SOURCE_BUFFER_SIZE_32b, 0, DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD, 1); + + for (i = 0; i < SOURCE_BUFFER_SIZE_32b; i++) + { + errors += destin_32b[i] != CONST_VALUE_32B; + } + + PRINTF("Errors:%d\n\r", errors); + + return errors ? EXIT_FAILURE : EXIT_SUCCESS; +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_freertos_blinky/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_freertos_blinky/main.c index fbb9941f..77c0c461 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_freertos_blinky/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_freertos_blinky/main.c @@ -116,7 +116,7 @@ /* The rate at which data is sent to the queue. The 200ms value is converted to ticks using the pdMS_TO_TICKS() macro. */ -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA #define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 200 ) #else #define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 3 ) @@ -148,7 +148,7 @@ or 0 to run the more comprehensive test and demo application. */ #endif /* #if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 */ -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA #define GPIO_LD5_R 15 #define GPIO_LD5_B 16 #define GPIO_LD5_G 17 diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_intr/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_intr/main.c index acad473a..bbdb9bc5 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_intr/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_intr/main.c @@ -29,7 +29,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -41,7 +41,7 @@ #endif -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA #define GPIO_TB_OUT 8 #define GPIO_TB_IN 9 #define GPIO_INTR GPIO_INTR_9 @@ -150,6 +150,7 @@ int main(int argc, char *argv[]) // wait_for_interrupt(); CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); } + gpio_res = gpio_write(GPIO_TB_OUT, false); gpio_assign_irq_handler( GPIO_INTR, &handler_2 ); gpio_intr_flag = 0; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_toggle/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_toggle/main.c index 9f920281..426de0f1 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_toggle/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_gpio_toggle/main.c @@ -16,7 +16,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c index dc8a5c1d..2c7d9a16 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c @@ -34,7 +34,7 @@ #include "i2s_structs.h" -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA #define I2S_TEST_BATCH_SIZE 128 #define I2S_TEST_BATCHES 16 #define I2S_CLK_DIV 8 @@ -72,7 +72,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -104,7 +104,7 @@ void handler_irq_i2s(uint32_t id) { } #ifdef USE_DMA -void dma_intr_handler_trans_done(void) +void dma_intr_handler_trans_done(uint8_t channel) { dma_intr_flag = 1; } @@ -173,7 +173,7 @@ void setup() int main(int argc, char *argv[]) { bool success = true; -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA for (uint32_t i = 0; i < 0x10000; i++) asm volatile("nop"); #endif PRINTF("I2S DEMO\r\n\r"); @@ -182,7 +182,7 @@ int main(int argc, char *argv[]) { //PRINTF("Setup done!\r\n\r"); -#ifdef TARGET_PYNQ_Z2 +#ifdef TARGET_IS_FPGA for (uint32_t i = 0; i < I2S_WAIT_CYCLES; i++) asm volatile("nop"); @@ -301,22 +301,47 @@ int main(int argc, char *argv[]) { PRINTF("B%x\r\n\r", batch); int32_t* data = audio_data_0; - for (int i = 0; i < AUDIO_DATA_NUM; i+=2) { - PRINTF("0x%x 0x%x\r\n\r", data[i], data[i+1]); + int32_t data_even = 0; + int32_t data_odd = 0; + for (int i = 0; i < AUDIO_DATA_NUM; i++) { + PRINTF("0x%x\r\n\r", data[i]); if (data[i] != 0) { mic_connected = true; // the microphone testbench is connected - if (data[i] != 0x8765431) { - PRINTF("ERROR left sample %d (B%d) = 0x%08x != 0x8765431\r\n\r", i, batch, data[i]); - success = false; + } else { + if(i == 0) { + //check what is the first data to expect, left or right + //the testbench alternatively sends these 2 data, catching which one is first for each BATCH + if ( (data[0] == 0x8765431) || (data[0] == 0xfedcba9) ) { + if (data[0] == 0x8765431) { + data_even = 0x8765431; + data_odd = 0xfedcba9; + } else { + data_odd = 0x8765431; + data_even = 0xfedcba9; + } + } else { + PRINTF("ERROR sample %d (B%d) = 0x%08x != 0x8765431 or 0xfedcba9\r\n\r", i, batch, data[0]); + success = false; + } + + } else { + //check whether even or odd + if (i & 0x1) { + //odd + if (data[i] != data_odd) { + PRINTF("ERROR left sample %d (B%d) = 0x%08x != 0x%08x\r\n\r", i, batch, data[i], data_odd); + success = false; + } + } + else { + //even + if (data[i] != data_even) { + PRINTF("ERROR left sample %d (B%d) = 0x%08x != 0x%08x\r\n\r", i, batch, data[i], data_even); + success = false; + } + } } - } - if (data[i+1] != 0) { - mic_connected = true; // the microphone testbench is connected - if (data[i+1] != 0xfedcba9) { - PRINTF("ERROR left sample data[%d] = 0x%08x != 0xfedcba9\r\n\r", i+1, batch, data[i+1]); - success = false; - } - } + } } } diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c index b62fab6a..89cc242b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c @@ -32,7 +32,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -44,16 +44,16 @@ int32_t to_fifo [6] __attribute__ ((aligned (4))) = { 1, 2, 3, 4, 5, 6 }; int32_t from_fifo[4] __attribute__ ((aligned (4))) = { 0, 0, 0, 0 }; int8_t dma_intr_flag = 0; -void dma_intr_handler_trans_done() +void dma_intr_handler_trans_done(uint8_t channel) { dma_intr_flag = 1; } void protected_wait_for_dma_interrupt(void) { - while(!dma_is_ready()) { + while(!dma_is_ready(0)) { CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (!dma_is_ready()) { + if (!dma_is_ready(0)) { wait_for_interrupt(); } CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c new file mode 100644 index 00000000..7ffd56bb --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c @@ -0,0 +1,72 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + Info: Contains randomly generated input activations and the golden result of the im2col algorithm. +*/ + +#include "im2colGolden.h" + +const uint32_t input_image_nchw[48] = { + 13932, 24003, 46802, 9895, + 46807, 33972, 44507, 1507, + 14638, 51479, 39560, 22725, + 38212, 35631, 40479, 39503, + 53705, 5796, 58640, 51585, + 45069, 32035, 41983, 18828, + 22247, 54792, 20499, 6640, + 20565, 25501, 4154, 2925, + 43660, 10618, 52141, 45092, + 46500, 63085, 57079, 16974, + 52033, 46977, 35992, 6933, + 3158, 21127, 28588, 61815 +}; + +const uint32_t golden_im2col_nchw[108] = { + 0, 0, 0, 0, 33972, 1507, 0, 35631, 39503, + 0, 0, 0, 46807, 44507, 0, 38212, 40479, 0, + 0, 24003, 9895, 0, 51479, 22725, 0, 0, 0, + 13932, 46802, 0, 14638, 39560, 0, 0, 0, 0, + 0, 0, 0, 0, 32035, 18828, 0, 25501, 2925, + 0, 0, 0, 45069, 41983, 0, 20565, 4154, 0, + 0, 5796, 51585, 0, 54792, 6640, 0, 0, 0, + 53705, 58640, 0, 22247, 20499, 0, 0, 0, 0, + 0, 0, 0, 0, 63085, 16974, 0, 21127, 61815, + 0, 0, 0, 46500, 57079, 0, 3158, 28588, 0, + 0, 10618, 45092, 0, 46977, 6933, 0, 0, 0, + 43660, 52141, 0, 52033, 35992, 0, 0, 0, 0 +}; + +const uint32_t input_image_nhwc[48] = { + 4047, 16986, 10416, + 22393, 36967, 57252, + 30217, 40720, 42651, + 3810, 4754, 56157, + 44724, 26083, 1010, + 44426, 14005, 35222, + 47712, 1887, 65, + 37412, 50137, 2236, + 7582, 53150, 12696, + 24415, 40340, 26558, + 22643, 14656, 7085, + 804, 32415, 17930, + 47706, 3314, 2947, + 19673, 37744, 24015, + 55137, 1975, 54009, + 25888, 50886, 35445 +}; + +const uint32_t golden_im2col_nhwc[108] = { + 0, 0, 0, 4047, 0, 0, 0, 16986, 0, 0, 0, 10416, + 0, 0, 22393, 30217, 0, 0, 36967, 40720, 0, 0, 57252, 42651, + 0, 0, 3810, 0, 0, 0, 4754, 0, 0, 0, 56157, 0, + 0, 44724, 0, 7582, 0, 26083, 0, 53150, 0, 1010, 0, 12696, + 44426, 47712, 24415, 22643, 14005, 1887, 40340, 14656, 35222, 65, 26558, 7085, + 37412, 0, 804, 0, 50137, 0, 32415, 0, 2236, 0, 17930, 0, + 0, 47706, 0, 0, 0, 3314, 0, 0, 0, 2947, 0, 0, + 19673, 55137, 0, 0, 37744, 1975, 0, 0, 24015, 54009, 0, 0, + 25888, 0, 0, 0, 50886, 0, 0, 0, 35445, 0, 0, 0 +}; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h new file mode 100644 index 00000000..27083aad --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h @@ -0,0 +1,31 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + Info: Header file of im2colGolden, contains activations parameters and the prototypes of both input tensors and golden output. +*/ + +#ifndef IMAGE_AND_COL_H +#define IMAGE_AND_COL_H + +#include + +// Parameters +#define IW 4 +#define IH 4 +#define CH 3 +#define FW 2 +#define FH 2 +#define STRIDES 2 +#define PAD 1 +#define BATCH 1 + +extern const uint32_t input_image_nchw[48]; +extern const uint32_t golden_im2col_nchw[108]; +extern const uint32_t input_image_nhwc[48]; +extern const uint32_t golden_im2col_nhwc[108]; + +#endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c new file mode 100644 index 00000000..75d38d74 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c @@ -0,0 +1,211 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + Info: im2col_lib.c describes functions used to calculate im2col and verify it using + the golden result in im2colGolden.c. + + Notes: im2col_nchw_int32() and im2col_nhwc_int32() algorithms are inspired from the library SHL, developed by T-HEAD Semi. + For reference, check out the following link: + https://github.com/T-head-Semi/csi-nn2/blob/main/source/reference/im2col.c +*/ + +#include "im2col_lib.h" + +int output_data[OH_NCHW*OW_NCHW]; + +int im2col_nchw_int32() +{ + PRINTF("OH: %d, OW: %d\n", OH_NCHW, OW_NCHW); + + int size_transfer = 0; + int im_row = 0; + int im_col = 0; + int w_offset = 0; // the offset ALONG the IW + int h_offset = 0; // the offset ALONG the IH + int im_c = 0; // Gets the CH on which the im2col is being performed depending on the row of the output image (c) + int col_index = 0; + + // Iterate over each row of the output matrix. + for (int c = 0; c < CH_COL; ++c) { + // Calculate offsets within the kernel window. + // These are used to move the filter around the input image + + w_offset = c % FW; + h_offset = (c / FW) % FH; + im_c = c / (FH * FW); // Gets the CH on which the im2col is being performed depending on the row of the output image (c) + + // Iterate over each BATCH. + for (int b = 0; b < BATCH; ++b) { + // Iterate over each patch on the IW of the input matrix. + for (int h = 0; h < N_PATCHES_H; ++h) { + // Iterate over each patch on the heigth in the output matrix. + for (int w = 0; w < N_PATCHES_W; ++w) { + // Calculate the row and column indices in the original input image, applying the stride and offset. + im_row = h_offset + h * STRIDES - PAD; + im_col = w_offset + w * STRIDES - PAD; + + // Calculate the index in the flattened output array where this value should be stored. + col_index = ((c * BATCH + b) * N_PATCHES_H + h) * N_PATCHES_W + w; + + // If the calculated indices are outside the bounds of the input image, set the output to 0 (padding effect). + // Otherwise, fetch the value from the input image and store it in the output array. + if (im_row < 0 || im_col < 0 || im_row >= IH || im_col >= IW) { + output_data[col_index] = 0; + } else { + output_data[col_index] = input_image_nchw[get_index(CH, IH, IW, b, im_c, im_row, im_col)]; + } + } + } + } + } + + // Finished! + + PRINTF("Final output matrix:\n\n"); + + #if DEBUG + for (int i=0; i= IH || im_col >= IW) { + output_data[col_index] = 0; + } else { + output_data[col_index] = input_image_nhwc[get_index(IH, IW, CH, b, im_row, im_col, im_c)]; + } + } + } + } + } + + PRINTF("Final output matrix:\n\n"); + + #if DEBUG + for (int i=0; i + + Info: Header file of im2col_lib.c, containing the function prototypes, parameters macros and the configuration of prints and performance analysis. +*/ + +#ifndef _IM2COL_ +#define _IM2COL_ + +#include +#include +#include +#include "im2colGolden.h" +#include "dma.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "rv_plic.h" +#include "csr.h" + +// By default, printfs are activated for FPGA and for simulation. +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 +#define DEBUG 0 // Set to 1 to enable debug prints +#define TIMING 0 // Set to 1 to enable timing measurements + +// Format is defined in im2colGolden.h + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) + #define PRINTF_DEB(...) + #define PRINTF_TIM(...) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) + #if DEBUG + #define PRINTF_DEB(fmt, ...) printf(fmt, ## __VA_ARGS__) + #else + #define PRINTF_DEB(...) + #endif + #if TIMING + #define PRINTF_TIM(fmt, ...) printf(fmt, ## __VA_ARGS__) + #else + #define PRINTF_TIM(...) + #endif +#else + #define PRINTF(...) + #define PRINTF_DEB(...) + #define PRINTF_TIM(...) +#endif + +// Define the dimensions of the input tensor and the kernel + +#define N_PATCHES_H ((IH + (PAD + PAD) - FH)/ STRIDES + 1) +#define N_PATCHES_W ((IW + (PAD + PAD) - FW)/ STRIDES + 1) + +#define CH_COL (CH * FH * FW) + +#define OH_NCHW (CH * FH * FW * BATCH) +#define OW_NCHW (N_PATCHES_H) * (N_PATCHES_W) + +#define OW_NHWC (FW * FH * CH * BATCH) +#define OH_NHWC (N_PATCHES_W) * (N_PATCHES_H) + +int im2col_nchw_int32(); +int im2col_nhwc_int32(); + +int get_index(int dim1, int dim2, int dim3, int index0, int index1, int index2, int index3); + +int verify(int format); + +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c new file mode 100644 index 00000000..a22c8bf8 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c @@ -0,0 +1,81 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + Info: Example application of im2col algorithm with configurable format, verification and performance analysis. +*/ + +#include +#include +#include +#include "x-heep.h" +#include "im2col_lib.h" + +#define NCHW_FORMAT 0 +#define NHWC_FORMAT 1 + +int main() +{ + PRINTF("\nStarting test...\n\n"); + + int errors; + unsigned int cycles; + + #if TIMING + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + im2col_nchw_int32(); // Execute the im2col algorithm with NCHW format + + #if TIMING + CSR_READ(CSR_REG_MCYCLE, &cycles); + #endif + + errors = verify(NCHW_FORMAT); + + PRINTF("im2col NCHW test executed\n"); + + PRINTF_TIM("Total number of cycles: [%d]\n\n", cycles); + + if (errors != 0) + { + PRINTF("TEST FAILED: %d errors\n", errors); + return 1; + } + else + { + PRINTF("TEST PASSED!\n"); + } + + #if TIMING + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + im2col_nhwc_int32(); // Execute the im2col algorithm with NHWC format + + #if TIMING + CSR_READ(CSR_REG_MCYCLE, &cycles); + #endif + + errors = verify(NHWC_FORMAT); + + PRINTF("im2col NHWC test executed\n"); + PRINTF_TIM("Total number of cycles: [%d]\n\n", cycles); + + if (errors != 0) + { + PRINTF("TEST FAILED: %d errors\n", errors); + return 1; + } + else + { + PRINTF("TEST PASSED!\n"); + } + + return 0; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd/main.c index 80fdb655..7c35229c 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd/main.c @@ -14,7 +14,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c index 86f69972..058aadbe 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matadd_interleaved/main.c @@ -15,7 +15,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matfadd/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matfadd/main.c index ab2191bd..59dc2bef 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matfadd/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matfadd/main.c @@ -17,7 +17,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -28,11 +28,24 @@ uint32_t check_results(float * C, int N, int M); float m_c[HEIGHT*WIDTH]; -void swap(char *a, char *b) +void putlong(long i) { - char temp = *a; - *a = *b; - *b = temp; + char int_str[20]; // An array to store the digits + int len = 0; // The length of the string + do + { + // Get the last digit and store it in the array + int_str[len] = '0' + i % 10; + len++; + // Remove the last digit from i + i /= 10; + } while (i > 0); + + // Print the reversed string of digits + for (int j = len - 1; j >= 0; j--) + { + putchar(int_str[j]); + } } // A function to print a floating point number using putchar @@ -47,57 +60,68 @@ void putfloat(float x, int p) x = -x; } - // Convert the integer part of x into a string of digits - long i = (long)x; // Get the integer part - char int_str[20]; // An array to store the digits - int len = 0; // The length of the string - do - { - // Get the last digit and store it in the array - int_str[len] = '0' + i % 10; - len++; - // Remove the last digit from i - i /= 10; - } while (i > 0); + float f = x - (long)x; // Get the fractional part of x - // Reverse the string of digits - for (int j = 0; j < len / 2; j++) + // Get the p most significant digits of the fractional part as the + // integer part of f. + // Count the number of initial zeros. + int initial_zeros = 0; + // Check if the fraction will overflow to the integer part when + // rounding up (i.e. if the fraction is 0.999...) + int fraction_overflow = 1; + for (int j = 0; j < p; j++) { - // Swap the elements at both ends - swap(&int_str[j], &int_str[len - 1 - j]); + f *= 10; + if (f < 1) + { + // exclude the last digit with round up + if (!(j == p - 1 && f >= 0.5f)) + initial_zeros++; + } + if (fraction_overflow && (long)f % 10 < 9) + { + fraction_overflow = 0; + } } - // Print the string of digits - for (int j = 0; j < len; j++) + // Round up if necessary + if ((f - (long)f) >= 0.5f) { - putchar(int_str[j]); + // If the rounding causes a digit to overflow in the fractional + // part, then we need to print one less zero + if (fraction_overflow == 0) + { + f += 1; + if (f >= 10 && initial_zeros > 0) + { + initial_zeros--; + } + } + // If the overflow is in the integer part, then we need to print + // one more digit in the integer part, and none in the fractional + else + { + f = 0; + x += 1; + initial_zeros = p - 1; + } } + // Convert the integer part of x into a string of digits + putlong((long)x); + // Print a decimal point putchar('.'); - // Convert the fractional part of x into a string of digits - float f = x - (long)x; // Get the fractional part - char frac_str[20]; // An array to store the digits - len = 0; // The length of the string - while (p--) + // Print the initial zeros + while (initial_zeros--) { - // Get the first digit after the decimal point and store it in the array - f = (f - (long)f) * 10; - frac_str[len] = '0' + (long)f; - len++; - // Round up if necessary - if (fabs(f - (long)f) >= 0.5f) - { - frac_str[len - 1]++; - } + putchar('0'); } - // Print the string of digits - for (int j = 0; j < len; j++) - { - putchar(frac_str[j]); - } + // Convert the fractional part of x into a string of digits + if (f > 1) + putlong((long)f); } void __attribute__ ((noinline)) printMatrix(float * C, int N, int M) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c index aec6ca4e..69d1750b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_matmul/main.c @@ -14,7 +14,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_pdm2pcm/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_pdm2pcm/main.c index b4f9c3b3..72551c21 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_pdm2pcm/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_pdm2pcm/main.c @@ -35,7 +35,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_core/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_core/main.c deleted file mode 100644 index da7d8448..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_core/main.c +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "rv_timer.h" -#include "power_manager.h" -#include "soc_ctrl.h" -#include "rv_plic.h" -#include "rv_plic_regs.h" -#include "gpio.h" -#include "pad_control.h" -#include "pad_control_regs.h" -#include "x-heep.h" - - -#ifndef RV_PLIC_IS_INCLUDED - #error ( "This app does NOT work as the RV_PLIC peripheral is not included" ) -#endif - - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static rv_timer_t timer_0_1; -static rv_timer_t timer_2_3; -static const uint64_t kTickFreqHz = 1000 * 1000; // 1 MHz -static power_manager_t power_manager; - -#ifndef TARGET_PYNQ_Z2 - #define GPIO_TB_OUT 30 - #define GPIO_TB_IN 31 - #define GPIO_INTR GPIO_INTR_31 -#endif - -int main(int argc, char *argv[]) -{ - - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - power_manager_counters_t power_manager_cpu_counters; - //counters - uint32_t reset_off, reset_on, switch_off, switch_on, iso_off, iso_on; - - // Setup pads -#ifndef TARGET_PYNQ_Z2 - pad_control_t pad_control; - pad_control.base_addr = mmio_region_from_addr((uintptr_t)PAD_CONTROL_START_ADDRESS); - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SCL_REG_OFFSET), 1); - pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SDA_REG_OFFSET), 1); -#endif - - // Setup plic - plic_Init(); - - // Get current Frequency - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); - - // Setup rv_timer_0_1 - mmio_region_t timer_0_1_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); - rv_timer_init(timer_0_1_reg, (rv_timer_config_t){.hart_count = 2, .comparator_count = 1}, &timer_0_1); - rv_timer_tick_params_t tick_params; - rv_timer_approximate_tick_params(freq_hz, kTickFreqHz, &tick_params); - - // Setup rv_timer_2_3 - mmio_region_t timer_2_3_reg = mmio_region_from_addr(RV_TIMER_START_ADDRESS); - rv_timer_init(timer_2_3_reg, (rv_timer_config_t){.hart_count = 2, .comparator_count = 1}, &timer_2_3); - - // Init cpu_subsystem's counters - - //Turn off: first, isolate the CPU outputs, then I reset it, then I switch it off (reset and switch off order does not really matter) - iso_off = 10; - reset_off = iso_off + 5; - switch_off = reset_off + 5; - //Turn on: first, give back power by switching on, then deassert the reset, the unisolate the CPU outputs - switch_on = 10; - reset_on = switch_on + 20; //give 20 cycles to emulate the turn on time, this number depends on technology and here it is just a random number - iso_on = reset_on + 5; - - if (power_gate_counters_init(&power_manager_cpu_counters, reset_off, reset_on, switch_off, switch_on, iso_off, iso_on, 0, 0) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Power-gate and wake-up due to timer_0 - rv_timer_set_tick_params(&timer_0_1, 0, tick_params); - rv_timer_irq_enable(&timer_0_1, 0, 0, kRvTimerEnabled); - rv_timer_arm(&timer_0_1, 0, 0, 1024); - rv_timer_counter_set_enabled(&timer_0_1, 0, kRvTimerEnabled); - - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_0_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - // Power-gate and wake-up due to timer_1 - rv_timer_set_tick_params(&timer_0_1, 1, tick_params); - rv_timer_irq_enable(&timer_0_1, 1, 0, kRvTimerEnabled); - rv_timer_arm(&timer_0_1, 1, 0, 1024); - rv_timer_counter_set_enabled(&timer_0_1, 1, kRvTimerEnabled); - - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_1_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - // Power-gate and wake-up due to timer_2 - rv_timer_set_tick_params(&timer_2_3, 0, tick_params); - rv_timer_irq_enable(&timer_2_3, 0, 0, kRvTimerEnabled); - rv_timer_arm(&timer_2_3, 0, 0, 1024); - rv_timer_counter_set_enabled(&timer_2_3, 0, kRvTimerEnabled); - - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_2_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - // Power-gate and wake-up due to timer_3 - rv_timer_set_tick_params(&timer_2_3, 1, tick_params); - rv_timer_irq_enable(&timer_2_3, 1, 0, kRvTimerEnabled); - rv_timer_arm(&timer_2_3, 1, 0, 1024); - rv_timer_counter_set_enabled(&timer_2_3, 1, kRvTimerEnabled); - - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kTimer_3_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - -#ifndef TARGET_PYNQ_Z2 - // Power-gate and wake-up due to plic - bool state = false; - plic_irq_set_priority(GPIO_INTR_31, 1); - plic_irq_set_enabled(GPIO_INTR_31, kPlicToggleEnabled); - - gpio_cfg_t pin2_cfg = {.pin = GPIO_TB_IN, .mode = GpioModeIn,.en_input_sampling = true, - .en_intr = true, .intr_type = GpioIntrEdgeRising}; - gpio_config (pin2_cfg); - - gpio_cfg_t pin1_cfg = {.pin = GPIO_TB_OUT, .mode = GpioModeOutPushPull}; - gpio_config (pin1_cfg); - gpio_write(GPIO_TB_OUT, true); - - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - if (power_gate_core(&power_manager, kPlic_pm_e, &power_manager_cpu_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - uint32_t intr_num; - plic_irq_complete(&intr_num); -#endif - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; - -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_external/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_external/main.c deleted file mode 100644 index 1ffc90c4..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_external/main.c +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_external_counters; - - // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_external_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Power off external domain - if (power_gate_external(&power_manager, 0, kOff_e, &power_manager_external_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - // Check that the external domain is actually OFF - while(!external_power_domain_is_off(&power_manager, 0)); - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop"); - - // Power on external domain - if (power_gate_external(&power_manager, 0, kOn_e, &power_manager_external_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; - - return EXIT_FAILURE; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_periph/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_periph/main.c deleted file mode 100644 index fb51e1c7..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_periph/main.c +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_periph_counters; - - // Init peripheral_subsystem's counters - if (power_gate_counters_init(&power_manager_periph_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Power off peripheral_subsystem domain - if (power_gate_periph(&power_manager, kOff_e, &power_manager_periph_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - // Check that the peripheral_subsystem domain is actually OFF - while(!periph_power_domain_is_off(&power_manager)); - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop;"); - - // Power on peripheral_subsystem domain - if (power_gate_periph(&power_manager, kOn_e, &power_manager_periph_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_ram_blocks/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_ram_blocks/main.c deleted file mode 100644 index fe673403..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_gating_ram_blocks/main.c +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ - -#if MEMORY_BANKS > 2 - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_ram_blocks_counters; - - // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_ram_blocks_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Power off ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kOff_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - // Check that the ram block 2 domain is actually OFF - while(!ram_block_power_domain_is_off(&power_manager, 2)); - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop"); - - // Power on ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kOn_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; - -#else - #pragma message ( "this application can run only when MEMORY_BANKS > 2" ) - return EXIT_SUCCESS; -#endif - -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c new file mode 100644 index 00000000..4f025e1e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c @@ -0,0 +1,471 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include "csr.h" +#include "hart.h" +#include "handler.h" +#include "core_v_mini_mcu.h" +#include "rv_timer.h" +#include "power_manager.h" +#include "soc_ctrl.h" +#include "rv_plic.h" +#include "rv_plic_regs.h" +#include "gpio.h" +#include "pad_control.h" +#include "pad_control_regs.h" +#include "x-heep.h" +#include "dma.h" + +#ifndef RV_PLIC_IS_INCLUDED + #error ( "This app does NOT work as the RV_PLIC peripheral is not included" ) +#endif + + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +static rv_timer_t timer_0_1; +static rv_timer_t timer_2_3; +static const uint64_t kTickFreqHz = 1000 * 1000; // 1 MHz +static power_manager_t power_manager; + +#ifndef TARGET_IS_FPGA + #define GPIO_TB_OUT 30 + #define GPIO_TB_IN 31 + #define GPIO_INTR GPIO_INTR_31 +#endif + +#define TEST_WORD +//this data has to be big to allow the CPU to power gate +#define TEST_DATA_SIZE 500 + +// Source and destination addresses have to be aligned on a 4 bytes address +uint32_t test_data_4B[TEST_DATA_SIZE] __attribute__ ((aligned (4))) = { 0 }; +uint32_t copied_data_4B[TEST_DATA_SIZE] __attribute__ ((aligned (4))) = { 0 }; + +uint8_t gpio_intr_flag = 0; + +void gpio_handler_in() +{ + gpio_intr_flag = 1; +} + +int main(int argc, char *argv[]) +{ + + // Setup power_manager + mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); + power_manager.base_addr = power_manager_reg; + power_manager_counters_t power_manager_counters; + //counters + uint32_t reset_off, reset_on, switch_off, switch_on, iso_off, iso_on; + + // Setup pads +#ifndef TARGET_IS_FPGA + pad_control_t pad_control; + pad_control.base_addr = mmio_region_from_addr((uintptr_t)PAD_CONTROL_START_ADDRESS); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SCL_REG_OFFSET), 1); + pad_control_set_mux(&pad_control, (ptrdiff_t)(PAD_CONTROL_PAD_MUX_I2C_SDA_REG_OFFSET), 1); +#endif + + // Setup plic + plic_Init(); + + // Get current Frequency + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + // Setup rv_timer_0_1 + mmio_region_t timer_0_1_reg = mmio_region_from_addr(RV_TIMER_AO_START_ADDRESS); + rv_timer_init(timer_0_1_reg, (rv_timer_config_t){.hart_count = 2, .comparator_count = 1}, &timer_0_1); + rv_timer_tick_params_t tick_params; + rv_timer_approximate_tick_params(freq_hz, kTickFreqHz, &tick_params); + + // Setup rv_timer_2_3 + mmio_region_t timer_2_3_reg = mmio_region_from_addr(RV_TIMER_START_ADDRESS); + rv_timer_init(timer_2_3_reg, (rv_timer_config_t){.hart_count = 2, .comparator_count = 1}, &timer_2_3); + + // Init cpu_subsystem's counters + + //Turn off: first, isolate the CPU outputs, then I reset it, then I switch it off (reset and switch off order does not really matter) + iso_off = 10; + reset_off = iso_off + 5; + switch_off = reset_off + 5; + //Turn on: first, give back power by switching on, then deassert the reset, the unisolate the CPU outputs + switch_on = 10; + reset_on = switch_on + 20; //give 20 cycles to emulate the turn on time, this number depends on technology and here it is just a random number + iso_on = reset_on + 5; + + if (power_gate_counters_init(&power_manager_counters, reset_off, reset_on, switch_off, switch_on, iso_off, iso_on, 0, 0) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + + // Power-gate and wake-up due to timer_0 + rv_timer_set_tick_params(&timer_0_1, 0, tick_params); + rv_timer_irq_enable(&timer_0_1, 0, 0, kRvTimerEnabled); + rv_timer_arm(&timer_0_1, 0, 0, 1024); + rv_timer_counter_set_enabled(&timer_0_1, 0, kRvTimerEnabled); + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (power_gate_core(&power_manager, kTimer_0_pm_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + // Power-gate and wake-up due to timer_1 + rv_timer_set_tick_params(&timer_0_1, 1, tick_params); + rv_timer_irq_enable(&timer_0_1, 1, 0, kRvTimerEnabled); + rv_timer_arm(&timer_0_1, 1, 0, 1024); + rv_timer_counter_set_enabled(&timer_0_1, 1, kRvTimerEnabled); + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (power_gate_core(&power_manager, kTimer_1_pm_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + // Power-gate and wake-up due to timer_2 + rv_timer_set_tick_params(&timer_2_3, 0, tick_params); + rv_timer_irq_enable(&timer_2_3, 0, 0, kRvTimerEnabled); + rv_timer_arm(&timer_2_3, 0, 0, 1024); + rv_timer_counter_set_enabled(&timer_2_3, 0, kRvTimerEnabled); + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (power_gate_core(&power_manager, kTimer_2_pm_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + // Power-gate and wake-up due to timer_3 + rv_timer_set_tick_params(&timer_2_3, 1, tick_params); + rv_timer_irq_enable(&timer_2_3, 1, 0, kRvTimerEnabled); + rv_timer_arm(&timer_2_3, 1, 0, 1024); + rv_timer_counter_set_enabled(&timer_2_3, 1, kRvTimerEnabled); + + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (power_gate_core(&power_manager, kTimer_3_pm_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + // Power-gate and wake-up due to DMA + + //prepare data + for(int i=0; i 2 + // ------------ MEMORY SUBSYSTEM ------------ + PRINTF("Testing Memory Subsystem...\n\r"); + + // ------------ clock gating ------------ + // do not clock gate instruction and data memory (usually first 2 banks) + for(uint32_t i = 2; i < MEMORY_BANKS; ++i) + mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x1); + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop;"); + // Enabling ram-banks + for(uint32_t i = 2; i < MEMORY_BANKS; ++i) + mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_ram_map[i].clk_gate), 0x0); + + PRINTF("Memory Clock Gating Test Successefull\n\r"); + + // ------------ power gating ------------ + if (power_gate_counters_init(&power_manager_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + // Power off ram block 2 domain + if (power_gate_ram_block(&power_manager, 2, kOff_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + // Check that the ram block 2 domain is actually OFF + while(!ram_block_power_domain_is_off(&power_manager, 2)); + + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop"); + // Power on ram block 2 domain + if (power_gate_ram_block(&power_manager, 2, kOn_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + + PRINTF("Memory Power Gating Test Successefull\n\r"); + + // ------------ set retentive ------------ + if (power_gate_counters_init(&power_manager_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + // Set retention mode on for ram block 2 domain + if (power_gate_ram_block(&power_manager, 2, kRetOn_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop"); + // Set retention mode off for ram block 2 domain + if (power_gate_ram_block(&power_manager, 2, kRetOff_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + + PRINTF("Memory Set Retentive Test Successefull\n\r"); + + +#else + #pragma message ( "the memory test can only run if MEMORY_BANKS > 2" ) +#endif + +#if EXTERNAL_DOMAINS > 0 + + // ------------ External SUBSYSTEM ------------ + PRINTF("Testing External Domain Subsystems...\n\r"); + + // ------------ clock gating ------------ + for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) + mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x1); + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop;"); + // Enabling external subsystems + for(uint32_t i = 0; i < EXTERNAL_DOMAINS; ++i) + mmio_region_write32(power_manager.base_addr, (ptrdiff_t)(power_manager_external_map[i].clk_gate), 0x0); + + PRINTF("External Clock Gating Test Successefull\n\r"); + + // ------------ power gating domain 0 ------------ + if (power_gate_counters_init(&power_manager_counters, 30, 30, 30, 30, 30, 30, 0, 0) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + // Power off external domain + if (power_gate_external(&power_manager, 0, kOff_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + // Check that the external domain is actually OFF + while(!external_power_domain_is_off(&power_manager, 0)); + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop"); + // Power on external domain + if (power_gate_external(&power_manager, 0, kOn_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + + PRINTF("External Power Gating Test Successefull\n\r"); + + // ------------ set retentive domain 0------------ + if (power_gate_counters_init(&power_manager_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + // Set retention mode on for external domain block 0 + if (power_gate_external(&power_manager, 0, kRetOn_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + // Wait some time + for (int i=0; i<100; i++) asm volatile("nop"); + // Set retention mode off for external domain block 0 + if (power_gate_external(&power_manager, 0, kRetOff_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + + PRINTF("External Set Retentive Test Successefull\n\r"); +#else + #pragma message ( "the external domain test can only run if EXTERNAL_DOMAINS > 0" ) +#endif + return EXIT_SUCCESS; + +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_sdk_spi_flash/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_sdk_spi_flash/main.c new file mode 100644 index 00000000..226a2a02 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_sdk_spi_flash/main.c @@ -0,0 +1,353 @@ +/** + * @file main.c + * @brief Simple spi communication example using SDK + * + * Simple example that reads a sector (4096 Bytes) from flash, overwrites the + * specified location range with new data, erases that sector from flash, writes + * the modified sector back to the flash and finally reads the modified location + * range directly from the flash to verify the operation has succeeded. + * + * The flash device being used is the w25q128jw + * +*/ + +#include +#include +#include +#include + +#include "x-heep.h" +#include "core_v_mini_mcu.h" +#include "spi_sdk.h" + +#include "fast_intr_ctrl.h" +#include "csr.h" +#include "csr_registers.h" + +/* By default, PRINTFs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif TARGET_IS_FPGA && PRINTF_IN_FPGA + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef TARGET_IS_FPGA + #define USE_SPI_FLASH +#endif + +// =========================== VARS & DEFS ================================== + +// 1 to print the modified data at the end of program 0 to disable +#define PRINT_DATA 1 + +// Flash w25q128jw SPI commands +#define FC_WE 0x06 /** Write Enable */ +#define FC_RD 0x03 /** Read Data */ +#define FC_PP 0x02 /** Page Program */ +#define FC_SE 0x20 /** Sector Erase 4kb */ +#define FC_RSR1 0x05 /** Read Status Register 1 */ + +#define READ_WRITE_LEN 16 // Amount words to read/write +#define START_ADDRESS ((FLASH_MEM_SIZE / 2) + 256) // Flash address where read/write +#define SECT_ADDRESS (START_ADDRESS & 0xfffff000) // Start sector address +#define SECT_LEN 4096 // Length bytes of a sector +#define PAGE_LEN 256 // Length bytes of a page +#define FLASH_MAX_FREQ (133*1000*1000) // Device max spi frequency +#define FIC_FLASH_MEIE 21 // SPI Flash fast interrupt bit enable +#define CSR_INTR_EN 0x08 // CPU Global interrupt enable + +// Hold sector data +uint8_t sect_data[SECT_LEN]; + +// Data to write +uint32_t flash_original_1024B[PAGE_LEN] = { + 0x76543211, 0xfedcba99, 0x579a6f91, 0x657d5bef, 0x758ee420, 0x01234568, 0xfedbca97, 0x89abde00, + 0x76543212, 0xfedcba9a, 0x579a6f92, 0x657d5bf0, 0x758ee421, 0x01234569, 0xfedbca98, 0x89abde01, + 0x76543213, 0xfedcba9b, 0x579a6f93, 0x657d5bf1, 0x758ee422, 0x0123456a, 0xfedbca99, 0x89abde02, + 0x76543214, 0xfedcba9c, 0x579a6f94, 0x657d5bf2, 0x758ee423, 0x0123456b, 0xfedbca9a, 0x89abde03, + 0x76543215, 0xfedcba9d, 0x579a6f95, 0x657d5bf3, 0x758ee424, 0x0123456c, 0xfedbca9b, 0x89abde04, + 0x76543216, 0xfedcba9e, 0x579a6f96, 0x657d5bf4, 0x758ee425, 0x0123456d, 0xfedbca9c, 0x89abde05, + 0x76543217, 0xfedcba9f, 0x579a6f97, 0x657d5bf5, 0x758ee426, 0x0123456e, 0xfedbca9d, 0x89abde06, + 0x76543218, 0xfedcbaa0, 0x579a6f98, 0x657d5bf6, 0x758ee427, 0x0123456f, 0xfedbca9e, 0x89abde07, + 0x76543219, 0xfedcbaa1, 0x579a6f99, 0x657d5bf7, 0x758ee428, 0x01234570, 0xfedbca9f, 0x89abde08, + 0x7654321a, 0xfedcbaa2, 0x579a6f9a, 0x657d5bf8, 0x758ee429, 0x01234571, 0xfedbcaa0, 0x89abde09, + 0x7654321b, 0xfedcbaa3, 0x579a6f9b, 0x657d5bf9, 0x758ee42a, 0x01234572, 0xfedbcaa1, 0x89abde0a, + 0x7654321c, 0xfedcbaa4, 0x579a6f9c, 0x657d5bfa, 0x758ee42b, 0x01234573, 0xfedbcaa2, 0x89abde0b, + 0x7654321d, 0xfedcbaa5, 0x579a6f9d, 0x657d5bfb, 0x758ee42c, 0x01234574, 0xfedbcaa3, 0x89abde0c, + 0x7654321e, 0xfedcbaa6, 0x579a6f9e, 0x657d5bfc, 0x758ee42d, 0x01234575, 0xfedbcaa4, 0x89abde0d, + 0x7654321f, 0xfedcbaa7, 0x579a6f9f, 0x657d5bfd, 0x758ee42e, 0x01234576, 0xfedbcaa5, 0x89abde0e, + 0x76543220, 0xfedcbaa8, 0x579a6fa0, 0x657d5bfe, 0x758ee42f, 0x01234577, 0xfedbcaa6, 0x89abde0f, + 0x76543221, 0xfedcbaa9, 0x579a6fa1, 0x657d5bff, 0x758ee430, 0x01234578, 0xfadbcaa7, 0x89abde10, + 0x76543222, 0xfedcbaaa, 0x579a6fa2, 0x657d5c00, 0x758ee431, 0x01234579, 0xfadbcaa8, 0x89abde11, + 0x76543223, 0xfedcbaab, 0x579a6fa3, 0x657d5c01, 0x758ee432, 0x0123457a, 0xfadbcaa9, 0x89abde12, + 0x76543224, 0xfedcbaac, 0x579a6fa4, 0x657d5c02, 0x758ee433, 0x0123457b, 0xfadbcaaa, 0x89abde13, + 0x76543225, 0xfedcbaad, 0x579a6fa5, 0x657d5c03, 0x758ee434, 0x0123457c, 0xfadbcaab, 0x89abde14, + 0x76543226, 0xfedcbaae, 0x579a6fa6, 0x657d5c04, 0x758ee435, 0x0123457d, 0xfadbcaac, 0x89abde15, + 0x76543227, 0xfedcbaaf, 0x579a6fa7, 0x657d5c05, 0x758ee436, 0x0123457e, 0xfadbcaad, 0x89abde16, + 0x76543228, 0xfedcbab0, 0x579a6fa8, 0x657d5c06, 0x758ee437, 0x0123457f, 0xfadbcaae, 0x89abde17, + 0x76543220, 0xfedcbaa8, 0x579a6fa0, 0x657d5bfe, 0x758ee42f, 0x01234577, 0xfedbcaa6, 0x89abde0f, + 0x76543221, 0xfedcbaa9, 0x579a6fa1, 0x657d5bff, 0x758ee430, 0x01234578, 0xfadbcaa7, 0x89abde10, + 0x76543222, 0xfedcbaaa, 0x579a6fa2, 0x657d5c00, 0x758ee431, 0x01234579, 0xfadbcaa8, 0x89abde11, + 0x76543223, 0xfedcbaab, 0x579a6fa3, 0x657d5c01, 0x758ee432, 0x0123457a, 0xfadbcaa9, 0x89abde12, + 0x76543224, 0xfedcbaac, 0x579a6fa4, 0x657d5c02, 0x758ee433, 0x0123457b, 0xfadbcaaa, 0x89abde13, + 0x76543225, 0xfedcbaad, 0x579a6fa5, 0x657d5c03, 0x758ee434, 0x0123457c, 0xfadbcaab, 0x89abde14, + 0x76543226, 0xfedcbaae, 0x579a6fa6, 0x657d5c04, 0x758ee435, 0x0123457d, 0xfadbcaac, 0x89abde15, + 0x76543227, 0xfedcbaaf, 0x579a6fa7, 0x657d5c05, 0x758ee436, 0x0123457e, 0xfadbcaad, 0x89abde16, + 0x76543228, 0xfedcbab0, 0x579a6fa8, 0x657d5c06, 0x758ee437, 0x0123457f, 0xfadbcaae, 0x89abde17 +}; + +// ====================== PROTOTYPES ====================== + +bool flash_read(spi_t* spi, uint32_t addr, uint32_t* dest_buff, uint32_t len); +bool flash_read_non_blocking(spi_t* spi, uint32_t addr, uint32_t* dest_buff, uint32_t len); +bool flash_write_enable(spi_t* spi); +bool flash_erase_sector(spi_t* spi, uint32_t addr); +bool flash_write_sector(spi_t* spi, uint32_t addr, uint32_t* src_buff); +void flash_wait(spi_t* spi); + +void done_cb(const uint32_t* txbuff, uint32_t txlen, uint32_t* rxbuff, uint32_t rxlen); +void rxwm_cb(const uint32_t* txbuff, uint32_t txlen, uint32_t* rxbuff, uint32_t rxlen); + +// ========================= MAIN ========================= + +int main(int argc, char *argv[]) { + // Create our slave (flash device) with its specifications + spi_slave_t slave = SPI_SLAVE(0, FLASH_MAX_FREQ); + + // Initialize the spi device that is CONNECTED to the flash with our slave + #ifdef USE_SPI_FLASH + spi_t spi = spi_init(SPI_IDX_FLASH, slave); + #else + spi_t spi = spi_init(SPI_IDX_HOST, slave); + #endif + + // Check if initialization succeeded + if (!spi.init) { + PRINTF("\nFailed to initialize spi\n"); + return EXIT_FAILURE; + } + + PRINTF("\nSPI initialized\n"); + + // Enable global interrupt for machine-level interrupts + CSR_SET_BITS(CSR_REG_MSTATUS, CSR_INTR_EN); + // Set mie.MEIE bit to one to enable machine-level fast spi_flash interrupt + const uint32_t mask = 1 << FIC_FLASH_MEIE; + CSR_SET_BITS(CSR_REG_MIE, mask); + + // Buffer to hold data for final comparison + uint32_t rxbuffer[READ_WRITE_LEN] = {0}; + + // Read whole sector containing the desired START_ADDRESS + if (!flash_read_non_blocking(&spi, SECT_ADDRESS, sect_data, SECT_LEN)) + return EXIT_FAILURE; + + // No need to erase if on simulation + #ifdef USE_SPI_FLASH + // Erase that sector + if (!flash_erase_sector(&spi, START_ADDRESS)) return EXIT_FAILURE; + #endif + + // Copy the data to overwrite + memcpy(§_data[START_ADDRESS - SECT_ADDRESS], flash_original_1024B, READ_WRITE_LEN * 4); + // Write the whole sector with the new data back to flash + if (!flash_write_sector(&spi, START_ADDRESS, sect_data)) return EXIT_FAILURE; + // Read the modified part + if (!flash_read(&spi, START_ADDRESS, rxbuffer, 4*READ_WRITE_LEN)) return EXIT_FAILURE; + + // Compare the modified part with the data used to modify + if (memcmp(rxbuffer, flash_original_1024B, 4*READ_WRITE_LEN)) + PRINTF("\nMISMATCH\n\n"); + else PRINTF("\nSUCCESS\n\n"); + + // If wanted display the data + #if PRINT_DATA + PRINTF(" address original on flash\n"); + PRINTF("-------------------------------\n"); + for (int i = 0; i < READ_WRITE_LEN; i++) + { + PRINTF("0x%08X: %08X %08X\n", START_ADDRESS+4*i, flash_original_1024B[i], rxbuffer[i]); + } + #endif + + PRINTF("\n==================================================\n\n"); + + + return EXIT_SUCCESS; +} + +// ========================= FUNCTIONS ========================= + +bool flash_read(spi_t* spi, uint32_t addr, uint32_t* dest_buff, uint32_t len) { + // Transaction segments + spi_segment_t segments[2] = { SPI_SEG_TX(4), SPI_SEG_RX(len) }; + + // TX SPI command to send to flash for read + // Flash uses Big Endian, CPU Little Endian, hence swap bytes + uint32_t read_byte_cmd = ((bitfield_byteswap32(addr & 0x00ffffff)) | FC_RD); + + PRINTF("Blocking Reading %4i Bytes at 0x%08X\n", len, addr); + + // Start transaction + spi_codes_e error = spi_execute(spi, segments, 2, &read_byte_cmd, dest_buff); + if (error) { + PRINTF("FAILED! Error Code: %i\n", error); + return false; + } + return true; +} + +bool flash_read_non_blocking(spi_t* spi, uint32_t addr, uint32_t* dest_buff, uint32_t len) { + // Transaction segments + spi_segment_t segments[2] = { SPI_SEG_TX(4), SPI_SEG_RX(len) }; + + // TX SPI command to send to flash for read + // Flash uses Big Endian, CPU Little Endian, hence swap bytes + uint32_t read_byte_cmd = ((bitfield_byteswap32(addr & 0x00ffffff)) | FC_RD); + + PRINTF("\nNon-Blocking Reading %4i Bytes at 0x%08X\n", len, addr); + PRINTF("Counter set to 0.\n"); + + uint32_t counter = 0; + spi_callbacks_t callbacks = { + .done_cb = &done_cb, + .error_cb = NULL,//&done_cb, + .rxwm_cb = &rxwm_cb, + .txwm_cb = NULL + }; + + // Save previous watermark to reset it after transaction completes + uint8_t watermark; + spi_get_rxwm(spi, &watermark); + spi_set_rxwm(spi, 12); // Arbitrarily chosen watermark + + // Start transaction + spi_codes_e error = spi_execute_nb(spi, segments, 2, &read_byte_cmd, dest_buff, callbacks); + if (error) { + PRINTF("FAILED! Error Code: %i\n", error); + return false; + } + + while(spi_get_state(spi) == SPI_STATE_BUSY) counter++; + // Check if the communication ended because of an error + if (spi_get_state(spi) == SPI_STATE_ERROR) { + PRINTF("FAILED! Hardware ERROR !\n"); + return false; + } + + // Reset the watermark to its previous value + spi_set_rxwm(spi, watermark); + + PRINTF("Counter reached %4i. => Non Blocking\n\n", counter); + + return true; +} + +bool flash_erase_sector(spi_t* spi, uint32_t addr) { + // Sector start address + const uint32_t sect_start = addr & 0xfffff000; + // Sector erase command + // Flash uses Big Endian, CPU Little Endian, hence swap bytes + const uint32_t cmd = ((bitfield_byteswap32(sect_start & 0x00ffffff)) | FC_SE); + + PRINTF("Blocking Erasing 4096 Bytes at 0x%08X\n", sect_start); + + // Enable write before erase + if (!flash_write_enable(spi)) return false; + + // Start TX Only transaction + spi_codes_e error = spi_transmit(spi, &cmd, 4); + if (error) { + PRINTF("FAILED! Error Code: %i\n", error); + return false; + } + + // Wait flash finished processing + flash_wait(spi); + + return true; +} + +bool flash_write_sector(spi_t* spi, uint32_t addr, uint32_t* src_buff) { + // Sector start address + uint32_t sect = addr & 0xfffff000; + // Current page (256 bytes) address (can't write more than one page at a time...) + uint32_t curr_addr = sect; + + for (int i = 0; i < SECT_LEN / PAGE_LEN; i++) + { + // Our TX Buffer + uint32_t wbuff[PAGE_LEN/4 + 1] = {0}; + // Our segments for the SPI transaction + spi_segment_t segments[2] = { SPI_SEG_TX(4), SPI_SEG_TX(PAGE_LEN) }; + + // Flash uses Big Endian, CPU Little Endian, hence swap bytes + wbuff[0] = ((bitfield_byteswap32(curr_addr & 0x00ffffff)) | FC_PP); + memcpy(&wbuff[1], &src_buff[i * (PAGE_LEN/4)], PAGE_LEN); + + if (!flash_write_enable(spi)) return false; + + // Start transaction + // Note that since segments are only TX we could have used spi_transmit + // instead of spi_execute, but both work perfectly fine + spi_codes_e error = spi_execute(spi, segments, 2, wbuff, NULL); + if (error) { + PRINTF("FAILED! Error Code: %i\n", error); + return false; + } + curr_addr += PAGE_LEN; + + PRINTF("\rBlocking Written %4i/4096 Bytes at 0x%08X", (i+1) * PAGE_LEN, sect); + + // Wait flash finished processing + flash_wait(spi); + } + + PRINTF("\n"); + + return true; +} + +bool flash_write_enable(spi_t* spi) { + // SPI Flash command + const uint32_t cmd = FC_WE; + // Start TX Only transaction + spi_codes_e error = spi_transmit(spi, &cmd, 1); + if (error) { + PRINTF("FAILED! Error Code: %i\n", error); + return false; + } + return true; +} + +void flash_wait(spi_t* spi) { + // Response buffer + uint32_t resp; + // SPI Flash command + uint32_t cmd = FC_RSR1; + // Here we have to use segments and execute since our transaction is composed + // of a TX Only part and thereafter a RX Only + spi_segment_t segments[2] = {SPI_SEG_TX(1), SPI_SEG_RX(2)}; + // Flash busy flag + bool busy = true; + while (busy) + { + spi_execute(spi, segments, 2, &cmd, &resp); + busy = resp & 0x01; + } +} + +void done_cb(const uint32_t* txbuff, uint32_t txlen, uint32_t* rxbuff, uint32_t rxlen) { + PRINTF("\x1b[33mTXN DONE CALLBACK with txlen: %i, rxlen: %i\x1b[m\n", txlen, rxlen); +} + +void rxwm_cb(const uint32_t* txbuff, uint32_t txlen, uint32_t* rxbuff, uint32_t rxlen) { + PRINTF("\x1b[36mTXN RXWM CALLBACK with txlen: %i, rxlen: %i\x1b[m\n", txlen, rxlen); +} + +// ========================= THE END ========================= \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks/main.c deleted file mode 100644 index cde898ad..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks/main.c +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ -#if MEMORY_BANKS > 2 - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_ram_blocks_counters; - - // Init ram block 2's counters - if (power_gate_counters_init(&power_manager_ram_blocks_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Set retention mode on for ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kRetOn_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop"); - - // Set retention mode off for ram block 2 domain - if (power_gate_ram_block(&power_manager, 2, kRetOff_e, &power_manager_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; - -#else - #pragma message ( "this application can run only when MEMORY_BANKS > 2" ) - return EXIT_SUCCESS; -#endif - -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks_external/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks_external/main.c deleted file mode 100644 index 7b455591..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_set_retentive_ram_blocks_external/main.c +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "core_v_mini_mcu.h" -#include "power_manager.h" -#include "x-heep.h" - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -static power_manager_t power_manager; - -int main(int argc, char *argv[]) -{ - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - - power_manager_counters_t power_manager_external_ram_blocks_counters; - - // Init external ram block 0's counters - if (power_gate_counters_init(&power_manager_external_ram_blocks_counters, 0, 0, 0, 0, 0, 0, 30, 30) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - // Set retention mode on for external ram block 0 - if (power_gate_external(&power_manager, 0, kRetOn_e, &power_manager_external_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - // Wait some time - for (int i=0; i<100; i++) asm volatile("nop"); - - // Set retention mode off for external ram block 0 - if (power_gate_external(&power_manager, 0, kRetOff_e, &power_manager_external_ram_blocks_counters) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail.\n\r"); - return EXIT_FAILURE; - } - - /* write something to stdout */ - PRINTF("Success.\n\r"); - return EXIT_SUCCESS; -} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c index 71de642f..53fb896b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_simple_accelerator/main.c @@ -10,7 +10,7 @@ #define TEST_DATA_SIZE 16 -#define PRINTF_IN_SIM 1 +#define PRINTF_IN_SIM 0 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma_power_gate/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma_power_gate/main.c deleted file mode 100644 index 0f1a444a..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_spi_host_dma_power_gate/main.c +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include - -#include "core_v_mini_mcu.h" -#include "csr.h" -#include "hart.h" -#include "handler.h" -#include "soc_ctrl.h" -#include "spi_host.h" -#include "dma.h" -#include "fast_intr_ctrl.h" -#include "power_manager.h" -#include "x-heep.h" - -#ifdef TARGET_PYNQ_Z2 - #define USE_SPI_FLASH -#endif - -/* By default, printfs are activated for FPGA and disabled for simulation. */ -#define PRINTF_IN_FPGA 1 -#define PRINTF_IN_SIM 0 - -#if TARGET_SIM && PRINTF_IN_SIM - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA - #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else - #define PRINTF(...) -#endif - -// Type of data frome the SPI. For types different than words the SPI data is requested in separate transactions -// word(0), half-word(1), byte(2,3) -#define SPI_DATA_TYPE DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD - -// Number of elements to copy -#define COPY_DATA_NUM 16 - -#define FLASH_CLK_MAX_HZ (133*1000*1000) // In Hz (133 MHz for the flash w25q128jvsim used in the EPFL Programmer) - -#define REVERT_24b_ADDR(addr) ((((uint32_t)(addr) & 0xff0000) >> 16) | ((uint32_t)(addr) & 0xff00) | (((uint32_t)(addr) & 0xff) << 16)) - -volatile int8_t dma_intr_flag; -int8_t core_sleep_flag; -spi_host_t spi_host; - -static power_manager_t power_manager; - -void dma_intr_handler_trans_done(void) -{ - PRINTF("Non-weak implementation of a DMA interrupt\n\r"); - dma_intr_flag = 1; -} - -// Reserve memory array -uint32_t flash_data[COPY_DATA_NUM] __attribute__ ((aligned (4))) = {0x76543210,0xfedcba98,0x579a6f90,0x657d5bee,0x758ee41f,0x01234567,0xfedbca98,0x89abcdef,0x679852fe,0xff8252bb,0x763b4521,0x6875adaa,0x09ac65bb,0x666ba334,0x44556677,0x0000ba98}; -uint32_t copy_data[COPY_DATA_NUM] __attribute__ ((aligned (4))) = { 0 }; - -#if SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD - #define DATA_TYPE uint32_t -#elif SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD - #define DATA_TYPE uint16_t -#else - #define DATA_TYPE uint8_t -#endif - -#define COPY_DATA_TYPE (COPY_DATA_NUM/(sizeof(uint32_t)/sizeof(DATA_TYPE))) - -int main(int argc, char *argv[]) -{ - - soc_ctrl_t soc_ctrl; - soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); - uint32_t read_byte_cmd; - uint32_t* flash_data_lma = flash_data; - //set MS 8 bits to 0 as the flash only uses 24b - flash_data_lma = (uint32_t*) ((uint32_t)(flash_data_lma) & 0x00FFFFFF); - - - if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) - { -#ifdef USE_SPI_FLASH - PRINTF("This application cannot work with the memory mapped SPI FLASH module - do not use the FLASH_EXEC linker script for this application\n"); - return EXIT_SUCCESS; -#else - /* - if we are using in SIMULATION the SPIMMIO from Yosys, then the flash_original data is different - as the compilation is done differently, so we will store there the first WORDs of code mapped at the beginning of the FLASH - */ - uint32_t* ptr_flash = (uint32_t*)FLASH_MEM_START_ADDRESS; - for(int i =0; i < COPY_DATA_NUM ; i++){ - flash_data[i] = ptr_flash[i]; - } -#endif - } - - #ifndef USE_SPI_FLASH - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_HOST_START_ADDRESS); - #else - spi_host.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); - #endif - - // Setup power_manager - mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); - power_manager.base_addr = power_manager_reg; - power_manager_counters_t power_manager_cpu_counters; - // Init cpu_subsystem's counters - if (power_gate_counters_init(&power_manager_cpu_counters, 300, 300, 300, 300, 300, 300, 0, 0) != kPowerManagerOk_e) - { - PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); - return EXIT_FAILURE; - } - - uint32_t core_clk = soc_ctrl_get_frequency(&soc_ctrl); - - // Enable interrupt on processor side - // Enable global interrupt for machine-level interrupts - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - - // Set mie.MEIE bit to one to enable machine-level fast dma interrupt - const uint32_t mask = 1 << 19; - CSR_SET_BITS(CSR_REG_MIE, mask); - - #ifdef USE_SPI_FLASH - // Select SPI host as SPI output - soc_ctrl_select_spi_host(&soc_ctrl); - #endif - - // Enable SPI host device - spi_set_enable(&spi_host, true); - // Enable SPI output - spi_output_enable(&spi_host, true); - - // SPI and SPI_FLASH are the same IP so same register map - uint32_t *fifo_ptr_rx = spi_host.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; - - core_sleep_flag = 0; - - // -- DMA CONFIGURATION -- - - dma_init(NULL); - - #ifndef USE_SPI_FLASH - uint8_t slot = DMA_TRIG_SLOT_SPI_RX ; // The DMA will wait for the SPI RX FIFO valid signal - #else - uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX ; // The DMA will wait for the SPI FLASH RX FIFO valid signal - #endif - - static dma_target_t tgt_src = { - .size_du = COPY_DATA_NUM, - .inc_du = 0, - .type = SPI_DATA_TYPE, - }; - tgt_src.ptr = fifo_ptr_rx; - tgt_src.trig = slot; - - static dma_target_t tgt_dst = { - .ptr = copy_data, - .inc_du = 1, - .type = SPI_DATA_TYPE, - .trig = DMA_TRIG_MEMORY, - }; - - static dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - .end = DMA_TRANS_END_INTR, - }; - - dma_config_flags_t res; - - res = dma_validate_transaction(&trans ,DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); - PRINTF("trans: %u \n\r", res ); - res = dma_load_transaction(&trans); - PRINTF(" load: %u \n\r", res ); - - - - // Configure SPI clock - // SPI clk freq = 1/2 core clk freq when clk_div = 0 - // SPI_CLK = CORE_CLK/(2 + 2 * CLK_DIV) <= CLK_MAX => CLK_DIV > (CORE_CLK/CLK_MAX - 2)/2 - uint16_t clk_div = 0; - if(FLASH_CLK_MAX_HZ < core_clk/2){ - clk_div = (core_clk/(FLASH_CLK_MAX_HZ) - 2)/2; // The value is truncated - if (core_clk/(2 + 2 * clk_div) > FLASH_CLK_MAX_HZ) clk_div += 1; // Adjust if the truncation was not 0 - } - // SPI Configuration - // Configure chip 0 (flash memory) - const uint32_t chip_cfg = spi_create_configopts((spi_configopts_t){ - .clkdiv = clk_div, - .csnidle = 0xF, - .csntrail = 0xF, - .csnlead = 0xF, - .fullcyc = false, - .cpha = 0, - .cpol = 0 - }); - spi_set_configopts(&spi_host, 0, chip_cfg); - spi_set_csid(&spi_host, 0); - - // Reset - const uint32_t reset_cmd = 0xFFFFFFFF; - spi_write_word(&spi_host, reset_cmd); - const uint32_t cmd_reset = spi_create_command((spi_command_t){ - .len = 3, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_reset); - spi_wait_for_ready(&spi_host); - - // Power up flash - const uint32_t powerup_byte_cmd = 0xab; - spi_write_word(&spi_host, powerup_byte_cmd); - const uint32_t cmd_powerup = spi_create_command((spi_command_t){ - .len = 0, - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - spi_set_command(&spi_host, cmd_powerup); - spi_wait_for_ready(&spi_host); - - // Load command FIFO with read command (1 Byte at single speed) - const uint32_t cmd_read = spi_create_command((spi_command_t){ - .len = 3, - .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly - }); - - dma_intr_flag = 0; - dma_launch(&trans); - PRINTF("Launched\n\r"); - - #if SPI_DATA_TYPE == DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD - if(get_spi_flash_mode(&soc_ctrl) != SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO) - read_byte_cmd = ((REVERT_24b_ADDR(flash_data_lma) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - else - // we read the data from the FLASH address 0x0, which corresponds to FLASH_MEM_START_ADDRESS - read_byte_cmd = ((REVERT_24b_ADDR(0x0) << 8) | 0x03); // The address bytes sent through the SPI to the Flash are in reverse order - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ // Single transaction - .len = COPY_DATA_NUM*sizeof(DATA_TYPE) - 1, // In bytes - 1 - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - spi_write_word(&spi_host, read_byte_cmd); // Fill TX FIFO with TX data (read command + 3B address) - spi_wait_for_ready(&spi_host); // Wait for readiness to process commands - spi_set_command(&spi_host, cmd_read); // Send read command to the external device through SPI - spi_wait_for_ready(&spi_host); - spi_set_command(&spi_host, cmd_read_rx); // Receive data in RX - spi_wait_for_ready(&spi_host); - #else - const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ // Multiple transactions of the data type - .len = (sizeof(DATA_TYPE) - 1), - .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly - }); - DATA_TYPE* flash_ptr = (DATA_TYPE *)flash_data_lma; - for (int i = 0; i +#include +#include + +#include "x-heep.h" +#include "w25q128jw.h" +#include "csr.h" +#include "core_v_mini_mcu.h" +#include "power_manager.h" + +/* By default, PRINTFs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#if defined(TARGET_PYNQ_Z2) || defined(TARGET_ZCU104) || defined(TARGET_NEXYS_A7_100T) + #define USE_SPI_FLASH +#endif + +#define FLASH_ONLY_WORDS 32 +#define FLASH_ONLY_BYTES (FLASH_ONLY_WORDS*4) + +uint32_t on_chip_buffer[FLASH_ONLY_WORDS]; + +int32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16))) flash_only_buffer[FLASH_ONLY_WORDS] = { + 0xABCDEF00, + 0xABCDEF01, + 0xABCDEF02, + 0xABCDEF03, + 0xABCDEF04, + 0xABCDEF05, + 0xABCDEF06, + 0xABCDEF07, + 0xABCDEF08, + 0xABCDEF09, + 0xABCDEF0A, + 0xABCDEF0B, + 0xABCDEF0C, + 0xABCDEF0D, + 0xABCDEF0E, + 0xABCDEF0F, + 0xABCDEF10, + 0xABCDEF11, + 0xABCDEF12, + 0xABCDEF13, + 0xABCDEF14, + 0xABCDEF15, + 0xABCDEF16, + 0xABCDEF17, + 0xABCDEF18, + 0xABCDEF19, + 0xABCDEF1A, + 0xABCDEF1B, + 0xABCDEF1C, + 0xABCDEF1D, + 0xABCDEF1E, + 0xABCDEF1F, +}; + +int32_t __attribute__ ((aligned (16))) flash_only_buffer_golden_value[FLASH_ONLY_WORDS] = { + 0xABCDEF00, + 0xABCDEF01, + 0xABCDEF02, + 0xABCDEF03, + 0xABCDEF04, + 0xABCDEF05, + 0xABCDEF06, + 0xABCDEF07, + 0xABCDEF08, + 0xABCDEF09, + 0xABCDEF0A, + 0xABCDEF0B, + 0xABCDEF0C, + 0xABCDEF0D, + 0xABCDEF0E, + 0xABCDEF0F, + 0xABCDEF10, + 0xABCDEF11, + 0xABCDEF12, + 0xABCDEF13, + 0xABCDEF14, + 0xABCDEF15, + 0xABCDEF16, + 0xABCDEF17, + 0xABCDEF18, + 0xABCDEF19, + 0xABCDEF1A, + 0xABCDEF1B, + 0xABCDEF1C, + 0xABCDEF1D, + 0xABCDEF1E, + 0xABCDEF1F, +}; + + +int main(int argc, char *argv[]) +{ + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + if ( get_spi_flash_mode(&soc_ctrl) == SOC_CTRL_SPI_FLASH_MODE_SPIMEMIO ) { + PRINTF("This application cannot work with the memory mapped SPI FLASH" + "module - do not use the FLASH_EXEC linker script for this application\n"); + return EXIT_SUCCESS; + } + + // Pick the correct spi device based on simulation type + spi_host_t* spi; + #ifndef USE_SPI_FLASH + spi = spi_host1; + #else + spi = spi_flash; + #endif + + // Setup power_manager + power_manager_t power_manager; + mmio_region_t power_manager_reg = mmio_region_from_addr(POWER_MANAGER_START_ADDRESS); + power_manager.base_addr = power_manager_reg; + power_manager_counters_t power_manager_counters; + //counters + uint32_t reset_off, reset_on, switch_off, switch_on, iso_off, iso_on; + + //Turn off: first, isolate the CPU outputs, then I reset it, then I switch it off (reset and switch off order does not really matter) + iso_off = 10; + reset_off = iso_off + 5; + switch_off = reset_off + 5; + //Turn on: first, give back power by switching on, then deassert the reset, the unisolate the CPU outputs + switch_on = 10; + reset_on = switch_on + 20; //give 20 cycles to emulate the turn on time, this number depends on technology and here it is just a random number + iso_on = reset_on + 5; + + if (power_gate_counters_init(&power_manager_counters, reset_off, reset_on, switch_off, switch_on, iso_off, iso_on, 0, 0) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail. Check the reset and powergate counters value\n\r"); + return EXIT_FAILURE; + } + + // Define status variable + int32_t errors = 0; + + // Init SPI host and SPI<->Flash bridge parameters + if (w25q128jw_init(spi) != FLASH_OK) return EXIT_FAILURE; + + uint32_t *test_buffer_flash = heep_get_flash_address_offset(flash_only_buffer); + // Read from flash memory at the same address + w25q_error_codes_t status = w25q128jw_read_standard_dma_async(test_buffer_flash, on_chip_buffer, FLASH_ONLY_BYTES); + if (status != FLASH_OK) exit(EXIT_FAILURE); + + //wait for the DMA to finish in DEEP SLEEP mode + while (!dma_is_ready(0)) + { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (dma_is_ready(0) == 0) + { + PRINTF("Going to sleep...\r\n"); + if (power_gate_core(&power_manager, kDma_pm_e, &power_manager_counters) != kPowerManagerOk_e) + { + PRINTF("Error: power manager fail.\n\r"); + return EXIT_FAILURE; + } + PRINTF("Woken up...\r\n"); + + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } + + + PRINTF("Check results...\r\n"); + + // Check if what we read is correct (i.e. on_chip_buffer == flash_only_buffer_golden_value) + for(int i = 0; i < FLASH_ONLY_WORDS; i++) { + if (on_chip_buffer[i] != flash_only_buffer_golden_value[i]) { + errors++; + PRINTF("Error: on_chip_buffer[%d] = 0x%08x, flash_only_buffer_golden_value[%d] = 0x%08x\n", i, on_chip_buffer[i], i, flash_only_buffer_golden_value[i]); + } + } + + if(errors==0) PRINTF("TEST RUN SUCCEFFULLY\r\n"); + + return errors; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_timer_sdk/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_timer_sdk/main.c new file mode 100644 index 00000000..cb5bb5ae --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_timer_sdk/main.c @@ -0,0 +1,126 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: example_timer_sdk.c +// Author: Juan Sapriza, Francesco Poluzzi +// Date: 23/07/2024 +// Description: Example application to test the Timer SDK. Will count the time to execute a few short tasks. + +#include +#include +#include +#include "core_v_mini_mcu.h" +#include "timer_sdk.h" +#include "x-heep.h" +#include "soc_ctrl.h" + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +/* Error tolerances for the tests. */ +#define CYCLE_TOLERANCE 2 // cycles tolerance for simple timer reads +#define INTERRUPT_TOLERANCE 70 // cycles tolerance for timer interrupt +#define TIMER_WAIT_TOLERANCE 20 // milliseconds tolerance for timer wait + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +void __attribute__((aligned(4), interrupt)) handler_irq_timer(void) { + timer_arm_stop(); + timer_irq_clear(); + return; +} + +int main(){ + uint32_t i = 0; + uint32_t timer_cycles; + uint32_t nop_cycles[4]; + + // Get current Frequency + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + timer_cycles_init(); // Init the timer SDK for clock cycles + timer_start(); // Start counting the time + nop_cycles[0] = timer_stop(); // Stop counting the time + PRINTF("0 NOPs:\t%d cc\n\r", nop_cycles[0] ); + + timer_start(); + asm volatile ("nop"); + nop_cycles[1] = timer_stop(); + PRINTF("1 NOP:\t%d cc\n\r", nop_cycles[1] ); + + timer_start(); + asm volatile ("nop"); + asm volatile ("nop"); + nop_cycles[2] = timer_stop(); + PRINTF("2 NOPs:\t%d cc\n\r", nop_cycles[2] ); + + timer_start(); + asm volatile ("nop"); + asm volatile ("nop"); + asm volatile ("nop"); + nop_cycles[3] = timer_stop(); + PRINTF("3 NOPs:\t%d cc\n\r", nop_cycles[3] ); + + if( abs(nop_cycles[1] - nop_cycles[0])>CYCLE_TOLERANCE || abs(nop_cycles[2] - nop_cycles[1])>CYCLE_TOLERANCE || abs(nop_cycles[3] - nop_cycles[2])>CYCLE_TOLERANCE){ + PRINTF("Clock count failed\n\r"); + return EXIT_FAILURE; + } + + enable_timer_interrupt(); // Enable the timer machine-level interrupt + + timer_cycles_init(); + timer_irq_enable(); + timer_arm_start(1000); + asm volatile ("wfi"); // Wait for interrupt + timer_cycles = timer_stop(); + if(abs(timer_cycles-1000) < INTERRUPT_TOLERANCE){ + PRINTF("Timer threshold interrupt working\n" ); + } else { + PRINTF("Timer threshold interrupt failed\n\r"); + return EXIT_FAILURE; + } + + timer_cycles_init(); // Init the timer SDK for microseconds + timer_start(); + for(i = 0; i < 1000; i++){ + asm volatile ("nop"); + } + timer_cycles = timer_stop(); + PRINTF("Microseconds for 1000 NOPs:\t%d μs\n\r", (uint32_t)get_time_from_cycles(timer_cycles) ); + + #ifdef TARGET_IS_FPGA + PRINTF("Wait 5 second\n\r"); + timer_wait_us(5000000); // Wait for 5 seconds + timer_cycles = timer_stop(); + PRINTF("Done\n\r"); + + if(abs(timer_cycles-(5*freq_hz)) > TIMER_WAIT_TOLERANCE){ + PRINTF("Timer wait failed\n\r"); + return EXIT_FAILURE; + } + #endif + #ifdef TARGET_SIM // Reduced time for simulation for faster testing + PRINTF("Wait 0.001 second\n\r"); + timer_wait_us(1000); // Wait for 1 millisecond + timer_cycles = timer_stop(); + PRINTF("Done\n\r"); + + if(abs(timer_cycles-(0.001*freq_hz)) > TIMER_WAIT_TOLERANCE){ + PRINTF("Timer wait failed\n\r"); + return EXIT_FAILURE; + } + #endif + + PRINTF("All tests passed\n\r"); + return EXIT_SUCCESS; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/hello_world/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/hello_world/main.c index e6133973..bbe2f071 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/hello_world/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/hello_world/main.c @@ -25,4 +25,3 @@ int main(int argc, char *argv[]) printf("hello world!\n"); return EXIT_SUCCESS; } - diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c index 3228651d..181a3dd9 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/minver/chipsupport.c @@ -31,7 +31,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA +#elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) diff --git a/hw/vendor/esl_epfl_x_heep/sw/cmake/riscv.cmake b/hw/vendor/esl_epfl_x_heep/sw/cmake/riscv.cmake index 5c9d070d..972710f5 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/cmake/riscv.cmake +++ b/hw/vendor/esl_epfl_x_heep/sw/cmake/riscv.cmake @@ -43,7 +43,7 @@ get_filename_component(RISCV_TOOLCHAIN_BIN_EXT ${RISCV_GCC_COMPILER} EXT) #message( "RISC-V GCC Path: ${RISCV_TOOLCHAIN_BIN_PATH}" ) -STRING(REGEX REPLACE "\-gcc" "-" GCC_CROSS_COMPILE ${RISCV_GCC_COMPILER}) +STRING(REGEX REPLACE "\-gcc$" "-" GCC_CROSS_COMPILE ${RISCV_GCC_COMPILER}) if ($ENV{COMPILER} MATCHES "clang") STRING(REGEX REPLACE "clang" "" CLANG_CROSS_COMPILE ${RISCV_CLANG_COMPILER}) endif() diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c index 5c7763f5..04908d8e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c @@ -24,6 +24,10 @@ * @brief Source file of the W25Q-family flash memory driver. */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + /****************************************************************************/ /** **/ /* MODULES USED */ @@ -46,6 +50,8 @@ /* To get TX and RX FIFO depth */ #include "spi_host_regs.h" +/* To get SPI functions */ +#include "spi_host.h" /* To get the target of the compilation (sim or pynq) */ #include "x-heep.h" @@ -72,7 +78,7 @@ /** * @bref If the target is the FPGA, use the SPI FLASH. */ -#ifdef TARGET_PYNQ_Z2 +#ifndef TARGET_SIM #define USE_SPI_FLASH #endif @@ -210,7 +216,7 @@ static int32_t MIN(int32_t a, int32_t b) { /** * @brief SPI structure. */ -spi_host_t __attribute__((section(".xheep_init_data_crt0"))) spi; //this variable is also used by the crt0, thus keep it in this section +spi_host_t* __attribute__((section(".xheep_init_data_crt0"))) spi; //this variable is also used by the crt0, thus keep it in this section /** * @brief Static vector used in the erase_and_write function. @@ -231,11 +237,11 @@ uint8_t sector_data[FLASH_SECTOR_SIZE]; void w25q128jw_init_crt0() { //make sure spi variable is into the xheep_init_data_crt0 section - spi.base_addr = mmio_region_from_addr((uintptr_t)SPI_FLASH_START_ADDRESS); + spi = spi_flash; return; } -w25q_error_codes_t w25q128jw_init(spi_host_t spi_host) { +w25q_error_codes_t w25q128jw_init(spi_host_t* spi_host) { /* * Check if memory mapped SPI is enabled. Current version of the bsp * does not support memory mapped SPI. @@ -253,24 +259,24 @@ w25q_error_codes_t w25q128jw_init(spi_host_t spi_host) { #endif // USE_SPI_FLASH // Enable SPI host device - spi_set_enable(&spi, true); + spi_set_enable(spi, true); // Enable SPI output - spi_output_enable(&spi, true); + spi_output_enable(spi, true); // Configure SPI<->Flash connection on CSID 0 configure_spi(); // Set CSID - spi_set_csid(&spi, 0); + spi_set_csid(spi, 0); // Power up flash flash_power_up(); // Set QE bit (only FPGA, simulation do not support status registers at all) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM if (set_QE_bit() == FLASH_ERROR) return FLASH_ERROR; // Error occurred while setting QE bit - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM return FLASH_OK; // Success } @@ -287,7 +293,7 @@ w25q_error_codes_t w25q128jw_read(uint32_t addr, void *data, uint32_t length) { if (status != FLASH_OK) return status; } else { // Wait DMA to be free - while(!dma_is_ready()); + while(!dma_is_ready(0)); status = w25q128jw_read_quad_dma(addr, data, length); if (status != FLASH_OK) return status; } @@ -306,7 +312,7 @@ w25q_error_codes_t w25q128jw_write(uint32_t addr, void *data, uint32_t length, u status = erase_and_write(addr, data, length); } else { // Wait DMA to be free - while(!dma_is_ready()); + while(!dma_is_ready(0)); status = w25q128jw_write_quad_dma(addr, data, length); } @@ -320,29 +326,29 @@ w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t l // Address + Read command uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); // Load command to TX FIFO - spi_write_word(&spi, read_byte_cmd); - spi_wait_for_ready(&spi); + spi_write_word(spi, read_byte_cmd); + spi_wait_for_ready(spi); // Set up segment parameters -> send command and address const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ .len = 3, // 4 Bytes .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); // Load segment parameters to COMMAND register - spi_set_command(&spi, cmd_read_1); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_1); + spi_wait_for_ready(spi); // Set up segment parameters -> read length bytes const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ .len = length-1, // len bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirRxOnly // Read only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_RX_ONLY // Read only }); - spi_set_command(&spi, cmd_read_2); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_2); + spi_wait_for_ready(spi); /* * Set RX watermark to length. The watermark is in words. @@ -359,20 +365,20 @@ w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t l uint32_t *data_32bit = (uint32_t *)data; while (flag) { if (length >= SPI_HOST_PARAM_RX_DEPTH) { - spi_set_rx_watermark(&spi, SPI_HOST_PARAM_RX_DEPTH>>2); + spi_set_rx_watermark(spi, SPI_HOST_PARAM_RX_DEPTH>>2); length -= SPI_HOST_PARAM_RX_DEPTH; to_read += SPI_HOST_PARAM_RX_DEPTH; } else { - spi_set_rx_watermark(&spi, (length%4==0 ? length>>2 : (length>>2)+1)); + spi_set_rx_watermark(spi, (length%4==0 ? length>>2 : (length>>2)+1)); to_read += length; flag = 0; } // Wait till SPI RX FIFO is full (or I read all the data) - spi_wait_for_rx_watermark(&spi); + spi_wait_for_rx_watermark(spi); // Read data from SPI RX FIFO for (int i = i_start; i < to_read>>2; i++) { - spi_read_word(&spi, &data_32bit[i]); // Writes a full word + spi_read_word(spi, &data_32bit[i]); // Writes a full word } // Update the starting index i_start += SPI_HOST_PARAM_RX_DEPTH>>2; @@ -380,7 +386,7 @@ w25q_error_codes_t w25q128jw_read_standard(uint32_t addr, void* data, uint32_t l // Take into account the extra bytes (if any) if (length_original % 4 != 0) { uint32_t last_word = 0; - spi_read_word(&spi, &last_word); + spi_read_word(spi, &last_word); memcpy(&data_32bit[length_original>>2], &last_word, length%4); } @@ -410,9 +416,9 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, if (status != FLASH_OK) return FLASH_ERROR; // Erase the sector (no need to do so in simulation) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM w25q128jw_4k_erase(sector_start_addr); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM // Calculate the length of data to write in this sector uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); @@ -435,19 +441,19 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, } +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_dma, uint8_t no_sanity_checks) { -w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length) { // Sanity checks - if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + if (!no_sanity_checks) if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; /* * SET UP DMA */ // SPI and SPI_FLASH are the same IP so same register map - uint32_t *fifo_ptr_rx = spi.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; + uint32_t *fifo_ptr_rx = (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); // Init DMA, the integrated DMA is used (peri == NULL) - dma_init(NULL); + if(!no_wait_dma) dma_init(NULL); // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal #ifndef USE_SPI_FLASH @@ -484,6 +490,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 }; // Validate, load and launch DMA transaction + dma_config_flags_t res; res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); res = dma_load_transaction(&trans); @@ -492,42 +499,139 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 // Address + Read command uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); // Load command to TX FIFO - spi_write_word(&spi, read_byte_cmd); - spi_wait_for_ready(&spi); + spi_write_word(spi, read_byte_cmd); + spi_wait_for_ready(spi); // Set up segment parameters -> send command and address const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ .len = 3, // 4 Bytes .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); // Load segment parameters to COMMAND register - spi_set_command(&spi, cmd_read_1); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_1); + spi_wait_for_ready(spi); // Set up segment parameters -> read length bytes const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ .len = length-1, // len bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirRxOnly // Read only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_RX_ONLY // Read only }); - spi_set_command(&spi, cmd_read_2); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_2); + spi_wait_for_ready(spi); // Wait for DMA to finish transaction - while(!dma_is_ready()); + if(!no_wait_dma) while(!dma_is_ready(0)); // Take into account the extra bytes (if any) if (length % 4 != 0) { uint32_t last_word = 0; - spi_read_word(&spi, &last_word); + + spi_read_word((spi_host_t *)spi, &last_word); + #ifdef __cplusplus + memcpy(static_cast(data) + length - (length % 4), &last_word, length % 4); + #else memcpy(&data[length - length%4], &last_word, length%4); + #endif } return FLASH_OK; } +w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, uint32_t length) { + + // Sanity checks + if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; + + // Take into account the extra bytes (if any) + if (length % 4 != 0) { + //only multiple of 4 bytes are supported in this function + return FLASH_ERROR; + } + + /* + * SET UP DMA + */ + // SPI and SPI_FLASH are the same IP so same register map + uint32_t *fifo_ptr_rx = (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); + + // Init DMA, the integrated DMA is used (peri == NULL) + dma_init(NULL); + + // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal + #ifndef USE_SPI_FLASH + uint8_t slot = DMA_TRIG_SLOT_SPI_RX; + #else + uint8_t slot = DMA_TRIG_SLOT_SPI_FLASH_RX; + #endif + + // Set up DMA source target + static dma_target_t tgt_src = { + .inc_du = 0, // Target is peripheral, no increment + .type = DMA_DATA_TYPE_WORD, // Data type is word + }; + // Size is in data units (words in this case) + tgt_src.size_du = length>>2; + // Target is SPI RX FIFO + tgt_src.ptr = (uint8_t*)fifo_ptr_rx; + // Trigger to control the data flow + tgt_src.trig = slot; + + // Set up DMA destination target + static dma_target_t tgt_dst = { + .inc_du = 1, // Increment by 1 data unit (word) + .type = DMA_DATA_TYPE_WORD, // Data type is byte + .trig = DMA_TRIG_MEMORY, // Read-write operation to memory + }; + tgt_dst.ptr = (uint8_t*)data; // Target is the data buffer + + // Set up DMA transaction + static dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .end = DMA_TRANS_END_INTR, //so that you can wait for interrupt + }; + // Validate, load and launch DMA transaction + dma_config_flags_t res; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + res = dma_load_transaction(&trans); + res = dma_launch(&trans); + + // Address + Read command + uint32_t read_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_RD); + // Load command to TX FIFO + spi_write_word(spi, read_byte_cmd); + spi_wait_for_ready(spi); + + // Set up segment parameters -> send command and address + const uint32_t cmd_read_1 = spi_create_command((spi_command_t){ + .len = 3, // 4 Bytes + .csaat = true, // Command not finished + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only + }); + // Load segment parameters to COMMAND register + spi_set_command(spi, cmd_read_1); + spi_wait_for_ready(spi); + + // Set up segment parameters -> read length bytes + const uint32_t cmd_read_2 = spi_create_command((spi_command_t){ + .len = length-1, // len bytes + .csaat = false, // End command + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_RX_ONLY // Read only + }); + spi_set_command(spi, cmd_read_2); + spi_wait_for_ready(spi); + + // Wait for DMA to finish transaction outside this function, the DMA generates also an interrupt + // However, you need to enable the interrupt in the INT controllers, and CPU + + return FLASH_OK; +} + w25q_error_codes_t w25q128jw_write_standard_dma(uint32_t addr, void *data, uint32_t length) { // Call the wrapper with quad = 0, dma = 1 @@ -547,13 +651,13 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard_dma(uint32_t addr, void* d uint32_t sector_start_addr = current_addr & 0xfffff000; // Read the full sector and save it into RAM - status = w25q128jw_read_standard_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE); + status = w25q128jw_read_standard_dma(sector_start_addr, sector_data, FLASH_SECTOR_SIZE, 0, 0); if (status != FLASH_OK) return FLASH_ERROR; // Erase the sector (no need to do so in simulation) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM w25q128jw_4k_erase(sector_start_addr); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM // Calculate the length of data to write in this sector uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); @@ -582,54 +686,54 @@ w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void *data, uint32_t lengt // Send quad read command at standard speed uint32_t cmd_read_quadIO = FC_RDQIO; - spi_write_word(&spi, cmd_read_quadIO); + spi_write_word(spi, cmd_read_quadIO); const uint32_t cmd_read = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_read); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read); + spi_wait_for_ready(spi); /* * Send address at quad speed. * Last byte is Fxh (here FFh) required by W25Q128JW */ uint32_t read_byte_cmd = (REVERT_24b_ADDR(addr) | (0xFF << 24)); - spi_write_word(&spi, read_byte_cmd); + spi_write_word(spi, read_byte_cmd); const uint32_t cmd_address = spi_create_command((spi_command_t){ .len = 3, // 3 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_address); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_address); + spi_wait_for_ready(spi); // Quad read requires dummy clocks const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM .len = DUMMY_CLOCKS_FAST_READ_QUAD_IO-1, #else .len = DUMMY_CLOCKS_SIM-1, #endif .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirDummy // Dummy + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_DUMMY // Dummy }); - spi_set_command(&spi, dummy_clocks_cmd); - spi_wait_for_ready(&spi); + spi_set_command(spi, dummy_clocks_cmd); + spi_wait_for_ready(spi); // Read back the requested data at quad speed const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ .len = length-1, // 32 Byte .csaat = false, // End command - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirRxOnly // Read only + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_RX_ONLY // Read only }); - spi_set_command(&spi, cmd_read_rx); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_rx); + spi_wait_for_ready(spi); /* COMMAND FINISHED */ @@ -648,20 +752,20 @@ w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void *data, uint32_t lengt uint32_t *data_32bit = (uint32_t *)data; while (flag) { if (length >= SPI_HOST_PARAM_RX_DEPTH) { - spi_set_rx_watermark(&spi, SPI_HOST_PARAM_RX_DEPTH>>2); + spi_set_rx_watermark(spi, SPI_HOST_PARAM_RX_DEPTH>>2); length -= SPI_HOST_PARAM_RX_DEPTH; to_read += SPI_HOST_PARAM_RX_DEPTH; } else { - spi_set_rx_watermark(&spi, (length%4==0 ? length>>2 : (length>>2)+1)); + spi_set_rx_watermark(spi, (length%4==0 ? length>>2 : (length>>2)+1)); to_read += length; flag = 0; } // Wait till SPI RX FIFO is full (or I read all the data) - spi_wait_for_rx_watermark(&spi); + spi_wait_for_rx_watermark(spi); // Read data from SPI RX FIFO for (int i = i_start; i < to_read>>2; i++) { - spi_read_word(&spi, &data_32bit[i]); // Writes a full word + spi_read_word(spi, &data_32bit[i]); // Writes a full word } // Update the starting index i_start += SPI_HOST_PARAM_RX_DEPTH>>2; @@ -669,7 +773,7 @@ w25q_error_codes_t w25q128jw_read_quad(uint32_t addr, void *data, uint32_t lengt // Take into account the extra bytes (if any) if (length_original%4 != 0) { uint32_t last_word = 0; - spi_read_word(&spi, &last_word); + spi_read_word(spi, &last_word); memcpy(&data_32bit[length_original>>2], &last_word, length%4); } @@ -699,9 +803,9 @@ w25q_error_codes_t w25q128jw_erase_and_write_quad(uint32_t addr, void *data, uin if (status != FLASH_OK) return FLASH_ERROR; // Erase the sector (no need to do so in simulation) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM w25q128jw_4k_erase(sector_start_addr); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM // Calculate the length of data to write in this sector uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); @@ -730,54 +834,54 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l // Send quad read command at standard speed uint32_t cmd_read_quadIO = FC_RDQIO; - spi_write_word(&spi, cmd_read_quadIO); + spi_write_word(spi, cmd_read_quadIO); const uint32_t cmd_read = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_read); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read); + spi_wait_for_ready(spi); /* * Send address at quad speed. * Last byte is Fxh (here FFh) required by W25Q128JW */ uint32_t read_byte_cmd = (REVERT_24b_ADDR(addr) | (0xFF << 24)); - spi_write_word(&spi, read_byte_cmd); + spi_write_word(spi, read_byte_cmd); const uint32_t cmd_address = spi_create_command((spi_command_t){ .len = 3, // 3 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_address); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_address); + spi_wait_for_ready(spi); // Quad read requires dummy clocks const uint32_t dummy_clocks_cmd = spi_create_command((spi_command_t){ - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM .len = DUMMY_CLOCKS_FAST_READ_QUAD_IO-1, // W25Q128JW flash needs 4 dummy cycles #else .len = DUMMY_CLOCKS_SIM-1, // SPI flash simulation model needs 8 dummy cycles #endif .csaat = true, // Command not finished - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirDummy // Dummy + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_DUMMY // Dummy }); - spi_set_command(&spi, dummy_clocks_cmd); - spi_wait_for_ready(&spi); + spi_set_command(spi, dummy_clocks_cmd); + spi_wait_for_ready(spi); // Read back the requested data at quad speed const uint32_t cmd_read_rx = spi_create_command((spi_command_t){ .len = length-1, // length bytes .csaat = false, // End command - .speed = kSpiSpeedQuad, // Quad speed - .direction = kSpiDirRxOnly // Read only + .speed = SPI_SPEED_QUAD, // Quad speed + .direction = SPI_DIR_RX_ONLY // Read only }); - spi_set_command(&spi, cmd_read_rx); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_read_rx); + spi_wait_for_ready(spi); /* COMMAND FINISHED */ @@ -785,7 +889,7 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l * SET UP DMA */ // SPI and SPI_FLASH are the same IP so same register map - uint32_t *fifo_ptr_rx = spi.base_addr.base + SPI_HOST_RXDATA_REG_OFFSET; + uint32_t *fifo_ptr_rx = (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); // Init DMA, the integrated DMA is used (peri == NULL) dma_init(NULL); @@ -831,13 +935,20 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l res = dma_launch(&trans); // Wait for DMA to finish transaction - while(!dma_is_ready()); + while(!dma_is_ready(0)); // Take into account the extra bytes (if any) if (length % 4 != 0) { uint32_t last_word = 0; - spi_read_word(&spi, &last_word); + + spi_read_word((spi_host_t *)spi, &last_word); + + #ifdef __cplusplus + memcpy(static_cast(data) + length - (length % 4), &last_word, length % 4); + #else memcpy(&data[length - length%4], &last_word, length%4); + #endif + } return FLASH_OK; @@ -845,14 +956,14 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l w25q_error_codes_t w25q128jw_write_quad_dma(uint32_t addr, void *data, uint32_t length) { // Call the wrapper with quad = 1, dma = 1 - return page_write_wrapper(addr, data, length, 1, 1); + return page_write_wrapper(addr, (uint8_t *)data, length, 1, 1); } w25q_error_codes_t w25q128jw_erase_and_write_quad_dma(uint32_t addr, void *data, uint32_t length) { uint32_t remaining_length = length; uint32_t current_addr = addr; - uint8_t *current_data = data; + uint8_t *current_data = (uint8_t *)data; w25q_error_codes_t status; @@ -865,9 +976,9 @@ w25q_error_codes_t w25q128jw_erase_and_write_quad_dma(uint32_t addr, void *data, if (status != FLASH_OK) return FLASH_ERROR; // Erase the sector (no need to do so in simulation) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM w25q128jw_4k_erase(sector_start_addr); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM // Calculate the length of data to write in this sector uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); @@ -901,16 +1012,16 @@ w25q_error_codes_t w25q128jw_4k_erase(uint32_t addr) { // Build and send erase command uint32_t erase_4k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_SE); - spi_write_word(&spi, erase_4k_cmd); - spi_wait_for_ready(&spi); + spi_write_word(spi, erase_4k_cmd); + spi_wait_for_ready(spi); const uint32_t cmd_erase = spi_create_command((spi_command_t){ .len = 3, // 4 Bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_erase); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_erase); + spi_wait_for_ready(spi); // Wait for the erase operation to be finished flash_wait(); @@ -928,16 +1039,16 @@ w25q_error_codes_t w25q128jw_32k_erase(uint32_t addr) { // Build and send erase command uint32_t erase_32k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_BE32); - spi_write_word(&spi, erase_32k_cmd); - spi_wait_for_ready(&spi); + spi_write_word(spi, erase_32k_cmd); + spi_wait_for_ready(spi); const uint32_t cmd_erase = spi_create_command((spi_command_t){ .len = 3, // 4 Bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_erase); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_erase); + spi_wait_for_ready(spi); // Wait for the erase operation to be finished flash_wait(); @@ -955,16 +1066,16 @@ w25q_error_codes_t w25q128jw_64k_erase(uint32_t addr) { // Build and send erase command uint32_t erase_64k_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | FC_BE64); - spi_write_word(&spi, erase_64k_cmd); - spi_wait_for_ready(&spi); + spi_write_word(spi, erase_64k_cmd); + spi_wait_for_ready(spi); const uint32_t cmd_erase = spi_create_command((spi_command_t){ .len = 3, // 4 Bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_erase); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_erase); + spi_wait_for_ready(spi); // Wait for the erase operation to be finished flash_wait(); @@ -978,16 +1089,16 @@ void w25q128jw_chip_erase(void) { flash_write_enable(); // Build and send erase command - spi_write_word(&spi, FC_CE); - spi_wait_for_ready(&spi); + spi_write_word(spi, FC_CE); + spi_wait_for_ready(spi); const uint32_t cmd_erase = spi_create_command((spi_command_t){ .len = 0, // 1 Bytes .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_erase); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_erase); + spi_wait_for_ready(spi); // Wait for the erase operation to be finished flash_wait(); @@ -1014,15 +1125,15 @@ void w25q128jw_reset_force(void) { void w25q128jw_power_down(void) { // Build and send power down command - spi_write_word(&spi, FC_PD); + spi_write_word(spi, FC_PD); const uint32_t cmd_power_down = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_power_down); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_power_down); + spi_wait_for_ready(spi); } @@ -1033,50 +1144,50 @@ void w25q128jw_power_down(void) { /****************************************************************************/ static void flash_power_up(void) { - spi_write_word(&spi, FC_RPD); - spi_wait_for_ready(&spi); + spi_write_word(spi, FC_RPD); + spi_wait_for_ready(spi); const uint32_t cmd_powerup = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_powerup); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_powerup); + spi_wait_for_ready(spi); } static w25q_error_codes_t set_QE_bit(void) { - spi_set_rx_watermark(&spi,1); + spi_set_rx_watermark(spi,1); // Read Status Register 2 const uint32_t reg2_read_cmd = FC_RSR2; - spi_write_word(&spi, reg2_read_cmd); + spi_write_word(spi, reg2_read_cmd); const uint32_t reg2_read_1 = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, reg2_read_1); - spi_wait_for_ready(&spi); + spi_set_command(spi, reg2_read_1); + spi_wait_for_ready(spi); const uint32_t reg2_read_2 = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Standard speed - .direction = kSpiDirRxOnly // Read only + .speed = SPI_SPEED_STANDARD, // Standard speed + .direction = SPI_DIR_RX_ONLY // Read only }); - spi_set_command(&spi, reg2_read_2); - spi_wait_for_ready(&spi); - spi_wait_for_rx_watermark(&spi); + spi_set_command(spi, reg2_read_2); + spi_wait_for_ready(spi); + spi_wait_for_rx_watermark(spi); /* * the partial word will be zero-padded and inserted into the RX FIFO once the segment is completed * The actual register is 8 bit, but the SPI host gives a full word */ uint32_t reg2_data; - spi_read_word(&spi, ®2_data); + spi_read_word(spi, ®2_data); // Set bit in position 1 (QE bit), leaving the others unchanged reg2_data |= 0x2; @@ -1086,42 +1197,42 @@ static w25q_error_codes_t set_QE_bit(void) { // Write Status Register 2 (set QE bit) const uint32_t reg2_write_cmd = FC_WSR2; - spi_write_word(&spi, reg2_write_cmd); + spi_write_word(spi, reg2_write_cmd); const uint32_t reg2_write_1 = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = true, // Command not finished - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, reg2_write_1); - spi_wait_for_ready(&spi); + spi_set_command(spi, reg2_write_1); + spi_wait_for_ready(spi); // Load data to TX FIFO - spi_write_word(&spi, reg2_data); + spi_write_word(spi, reg2_data); // Create command segment const uint32_t reg2_write_2 = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Standard speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Standard speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, reg2_write_2); - spi_wait_for_ready(&spi); + spi_set_command(spi, reg2_write_2); + spi_wait_for_ready(spi); // Wait flash to complete write routine flash_wait(); // Read back Status Register 2 - spi_write_word(&spi, reg2_read_cmd); - spi_set_command(&spi, reg2_read_1); - spi_wait_for_ready(&spi); - spi_set_command(&spi, reg2_read_2); - spi_wait_for_ready(&spi); - spi_wait_for_rx_watermark(&spi); + spi_write_word(spi, reg2_read_cmd); + spi_set_command(spi, reg2_read_1); + spi_wait_for_ready(spi); + spi_set_command(spi, reg2_read_2); + spi_wait_for_ready(spi); + spi_wait_for_rx_watermark(spi); uint32_t reg2_data_check = 0x00; - spi_read_word(&spi, ®2_data_check); + spi_read_word(spi, ®2_data_check); // Check if the QE bit is set if ((reg2_data_check & 0x2) == 0) return FLASH_ERROR; @@ -1147,60 +1258,60 @@ static void configure_spi(void) { .cpha = 0, .cpol = 0 }); - spi_set_configopts(&spi, 0, chip_cfg); + spi_set_configopts(spi, 0, chip_cfg); } static void flash_wait(void) { - spi_set_rx_watermark(&spi,1); + spi_set_rx_watermark(spi,1); bool flash_busy = true; uint8_t flash_resp[4] = {0xff,0xff,0xff,0xff}; while(flash_busy){ uint32_t flash_cmd = FC_RSR1; // [CMD] Read status register 1 - spi_write_word(&spi, flash_cmd); // Push TX buffer + spi_write_word(spi, flash_cmd); // Push TX buffer uint32_t spi_status_cmd = spi_create_command((spi_command_t){ .len = 0, .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly + .speed = SPI_SPEED_STANDARD, + .direction = SPI_DIR_TX_ONLY }); uint32_t spi_status_read_cmd = spi_create_command((spi_command_t){ .len = 0, .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirRxOnly + .speed = SPI_SPEED_STANDARD, + .direction = SPI_DIR_RX_ONLY }); - spi_set_command(&spi, spi_status_cmd); - spi_wait_for_ready(&spi); - spi_set_command(&spi, spi_status_read_cmd); - spi_wait_for_ready(&spi); - spi_wait_for_rx_watermark(&spi); - spi_read_word(&spi, (uint32_t *)flash_resp); + spi_set_command(spi, spi_status_cmd); + spi_wait_for_ready(spi); + spi_set_command(spi, spi_status_read_cmd); + spi_wait_for_ready(spi); + spi_wait_for_rx_watermark(spi); + spi_read_word(spi, (uint32_t *)flash_resp); if ((flash_resp[0] & 0x01) == 0) flash_busy = false; } } static void flash_reset(void) { - spi_write_word(&spi, FC_ERESET); - spi_write_word(&spi, FC_RESET); - spi_wait_for_ready(&spi); + spi_write_word(spi, FC_ERESET); + spi_write_word(spi, FC_RESET); + spi_wait_for_ready(spi); const uint32_t cmd_reset_enable = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_reset_enable); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_reset_enable); + spi_wait_for_ready(spi); const uint32_t cmd_reset = spi_create_command((spi_command_t){ .len = 0, // 1 Byte .csaat = false, // End command - .speed = kSpiSpeedStandard, // Single speed - .direction = kSpiDirTxOnly // Write only + .speed = SPI_SPEED_STANDARD, // Single speed + .direction = SPI_DIR_TX_ONLY // Write only }); - spi_set_command(&spi, cmd_reset); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_reset); + spi_wait_for_ready(spi); } w25q_error_codes_t erase_and_write(uint32_t addr, uint8_t *data, uint32_t length) { @@ -1220,9 +1331,9 @@ w25q_error_codes_t erase_and_write(uint32_t addr, uint8_t *data, uint32_t length if (status != FLASH_OK) return FLASH_ERROR; // Erase the sector (no need to do so in simulation) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM w25q128jw_4k_erase(sector_start_addr); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM // Calculate the length of data to write in this sector uint32_t write_length = MIN(FLASH_SECTOR_SIZE - (current_addr - sector_start_addr), remaining_length); @@ -1299,15 +1410,15 @@ static w25q_error_codes_t page_write(uint32_t addr, uint8_t *data, uint32_t leng * The command is picked based on the quad flag. */ const uint32_t write_byte_cmd = ((REVERT_24b_ADDR(addr & 0x00ffffff) << 8) | (quad ? FC_PPQ : FC_PP)); - spi_write_word(&spi, write_byte_cmd); + spi_write_word(spi, write_byte_cmd); const uint32_t cmd_write = spi_create_command((spi_command_t){ .len = 3, .csaat = true, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly + .speed = SPI_SPEED_STANDARD, + .direction = SPI_DIR_TX_ONLY }); - spi_set_command(&spi, cmd_write); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_write); + spi_wait_for_ready(spi); /* * Place data in TX FIFO @@ -1319,14 +1430,14 @@ static w25q_error_codes_t page_write(uint32_t addr, uint8_t *data, uint32_t leng } else { uint32_t *data_32bit = (uint32_t *)data; for (int i = 0; i < length>>2; i++) { - spi_wait_for_tx_not_full(&spi); - spi_write_word(&spi, data_32bit[i]); + spi_wait_for_tx_not_full(spi); + spi_write_word(spi, data_32bit[i]); } if (length % 4 != 0) { uint32_t last_word = 0; memcpy(&last_word, &data[length - length % 4], length % 4); - spi_wait_for_tx_not_full(&spi); - spi_write_word(&spi, last_word); + spi_wait_for_tx_not_full(spi); + spi_write_word(spi, last_word); } } @@ -1337,21 +1448,21 @@ static w25q_error_codes_t page_write(uint32_t addr, uint8_t *data, uint32_t leng const uint32_t cmd_write_2 = spi_create_command((spi_command_t){ .len = length-1, .csaat = false, - .speed = quad ? kSpiSpeedQuad : kSpiSpeedStandard, - .direction = kSpiDirTxOnly + .speed = quad ? SPI_SPEED_QUAD : SPI_SPEED_STANDARD, + .direction = SPI_DIR_TX_ONLY }); - spi_set_command(&spi, cmd_write_2); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_write_2); + spi_wait_for_ready(spi); // Wait for flash to be ready again (FPGA only) - #ifdef TARGET_PYNQ_Z2 + #ifndef TARGET_SIM flash_wait(); - #endif // TARGET_PYNQ_Z2 + #endif // TARGET_SIM } static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { // SPI and SPI_FLASH are the same IP so same register map - uint32_t *fifo_ptr_tx = spi.base_addr.base + SPI_HOST_TXDATA_REG_OFFSET; + uint32_t *fifo_ptr_tx = (uint32_t *)((uintptr_t)spi + SPI_HOST_TXDATA_REG_OFFSET); // Init DMA, the integrated DMA is used (peri == NULL) dma_init(NULL); @@ -1402,28 +1513,28 @@ static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { if (res != DMA_CONFIG_OK) return FLASH_ERROR_DMA; // Wait for DMA to finish transaction - while(!dma_is_ready()); + while(!dma_is_ready(0)); // Take into account the extra bytes (if any) if (length % 4 != 0) { uint32_t last_word = 0; memcpy(&last_word, &data[length - length % 4], length % 4); - spi_wait_for_tx_not_full(&spi); - spi_write_word(&spi, last_word); + spi_wait_for_tx_not_full(spi); + spi_write_word(spi, last_word); } return FLASH_OK; } static void flash_write_enable(void) { - spi_write_word(&spi, FC_WE); + spi_write_word(spi, FC_WE); const uint32_t cmd_write_en = spi_create_command((spi_command_t){ .len = 0, .csaat = false, - .speed = kSpiSpeedStandard, - .direction = kSpiDirTxOnly + .speed = SPI_SPEED_STANDARD, + .direction = SPI_DIR_TX_ONLY }); - spi_set_command(&spi, cmd_write_en); - spi_wait_for_ready(&spi); + spi_set_command(spi, cmd_write_en); + spi_wait_for_ready(spi); } static w25q_error_codes_t w25q128jw_sanity_checks(uint32_t addr, uint8_t *data, uint32_t length) { @@ -1441,7 +1552,9 @@ static w25q_error_codes_t w25q128jw_sanity_checks(uint32_t addr, uint8_t *data, return FLASH_OK; // Success } - +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus /****************************************************************************/ /** **/ /* EOF */ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h index c6f29e9c..1bc8b5e4 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h @@ -49,6 +49,7 @@ */ #define FLASH_CLK_MAX_HZ (133*1000*1000) + /** * @defgroup flash_commands Flash commands * @{ @@ -191,7 +192,7 @@ void w25q128jw_init_crt0(); * * @return FLASH_OK if the flash is correctly initialized, @ref error_codes otherwise. */ -w25q_error_codes_t w25q128jw_init(spi_host_t spi_host); +w25q_error_codes_t w25q128jw_init(spi_host_t* spi_host); /** * @brief Read from flash. @@ -266,8 +267,17 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, * @param length number of bytes to read. * @return FLASH_OK if the read is successful, @ref error_codes otherwise. */ -w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void* data, uint32_t length); +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_dma, uint8_t no_sanity_checks); +/** + * @brief Read from flash at standard speed using DMA but wait for DMA in the application + * + * @param addr 24-bit flash address to read from. + * @param data pointer to the data buffer. + * @param length number of bytes to read, must be multiple of 4 + * @return FLASH_OK if the read is successful, @ref error_codes otherwise. +*/ +w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, uint32_t length); /** * @brief Write to flash at standard speed using DMA. Use this function only to write to unitialized data diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/assert.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/assert.h index 0b701dc8..2619af76 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/assert.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/assert.h @@ -21,11 +21,26 @@ // defined for C. #ifndef __cplusplus #define static_assert _Static_assert -#endif // __cplusplus +#endif + // `assert()` should not be used. When building with Clang, using this function // in device code will emit a compile-time error. + + +#ifndef __cplusplus #define assert(do_not_use) \ static_assert(false, "do not use assert(); use CHECK() instead") +#else + #include + #define assert(expression) \ + do { \ + if (!(expression)) { \ + printf("Assertion failed: %s, file %s, line %d\n", \ + #expression, __FILE__, __LINE__); \ + while(1); \ + } \ + } while (0) +#endif // __cplusplus*/ #endif // OPENTITAN_SW_DEVICE_LIB_BASE_FREESTANDING_ASSERT_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdalign.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdalign.h index 10126c9e..d0cc3f2a 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdalign.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdalign.h @@ -13,10 +13,16 @@ * S4p6. This header is specified in detail in S7.15 of the same. */ + + +#ifndef __cplusplus #define alignas _Alignas #define __alignas_is_defined 1 #define alignof _Alignof #define __alignof_is_defined 1 +#endif // __cplusplus + + #endif // OPENTITAN_SW_DEVICE_LIB_BASE_FREESTANDING_STDALIGN_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdbool.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdbool.h index f9a9fa0b..2b04a3af 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdbool.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/freestanding/stdbool.h @@ -12,11 +12,15 @@ * This header implements the stdbool.h standard header, as required by C11 * S4p6. This header is specified in detail in S7.18 of the same. */ +#ifndef __cplusplus +#define _Bool char #define bool _Bool #define true 1 #define false 0 #define __bool_true_false_are_defined 1 +#endif + #endif // OPENTITAN_SW_DEVICE_LIB_BASE_FREESTANDING_STDBOOL_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c index 180cdd90..e0234bf1 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c @@ -2,6 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + #include "memory.h" extern uint32_t read_32(const void *); @@ -18,7 +22,7 @@ extern void write_32(uint32_t, void *); // built for host-side software. #if !defined(HOST_BUILD) -void *memcpy(void *restrict dest, const void *restrict src, size_t len) { +void *memcpy(void *__restrict dest, const void *__restrict src, size_t len) { uint8_t *dest8 = (uint8_t *)dest; uint8_t *src8 = (uint8_t *)src; for (size_t i = 0; i < len; ++i) { @@ -84,3 +88,9 @@ void *memrchr(const void *ptr, int value, size_t len) { } return NULL; } + + + +#ifdef __cplusplus +} +#endif // __cplusplus diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h index 4a9f213b..3ff64ff7 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h @@ -107,7 +107,7 @@ inline void write_32(uint32_t value, void *ptr) { * @param len the number of bytes to copy. * @return the value of `dest`. */ -void *memcpy(void *restrict dest, const void *restrict src, size_t len); +void *memcpy(void *__restrict dest, const void *__restrict src, size_t len); /** * Set a region of memory to a particular byte value. diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c index 58309170..dff7f78a 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c @@ -2,6 +2,11 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + #include "mmio.h" #include @@ -158,3 +163,8 @@ extern void mmio_region_nonatomic_set_bit32(mmio_region_t base, extern void mmio_region_write_only_set_bit32(mmio_region_t base, ptrdiff_t offset, uint32_t bit_index); + + +#ifdef __cplusplus +} +#endif // __cplusplus diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl similarity index 83% rename from hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S rename to hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl index 82776471..72d2b2e6 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl @@ -1,164 +1,153 @@ -/* Copyright (c) 2017 SiFive Inc. All rights reserved. - * Copyright (c) 2019 ETH Zürich and University of Bologna - * Copyright (c) 2022 EPFL - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the FreeBSD License. This program is distributed in the hope that - * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, - * including the implied warranties of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. A copy of this license is available at - * http://www.opensource.org/licenses. - */ - -#include "x-heep.h" -#include "core_v_mini_mcu.h" -#include "soc_ctrl_regs.h" - -#define RAMSIZE_COPIEDBY_BOOTROM 2048 - -/* Entry point for bare metal programs */ -.section .text.start -.global _start -.type _start, @function - -_start: -/* initialize global pointer */ -.option push -.option norelax -1: auipc gp, %pcrel_hi(__global_pointer$) - addi gp, gp, %pcrel_lo(1b) -.option pop - -/* initialize stack pointer */ - la sp, _sp - -/* set the frequency */ - li a0, SOC_CTRL_START_ADDRESS - li a2, REFERENCE_CLOCK_Hz - sw a2, SOC_CTRL_SYSTEM_FREQUENCY_HZ_REG_OFFSET(a0) - -#ifdef EXTERNAL_CRTO - #include "external_crt0.S" -#endif - -#ifdef FLASH_LOAD - - call w25q128jw_init_crt0 - - // This assumes ram base address is 0x00000000 and the section .text stars from ram0 (in the first RAMSIZE_COPIEDBY_BOOTROM Byte) - li s1, RAMSIZE_COPIEDBY_BOOTROM - li s2, FLASH_MEM_START_ADDRESS - - // copy the remaining (if any) text and data sections // - // Setup the in/out pointers and copy size knowing 1KiB as already been copied - mv a0, s2 // src ptr (flash) - add a0, a0, s1 - - la a1, _etext - // Skip if everything has already been copied, and copy the data section - blt a1, s1, _load_data_section - - // copy size in bytes, i.e. _etext - RAMSIZE_COPIEDBY_BOOTROM - sub a2, a1, s1 - - // dst ptr (ram) - mv a1, s1 - - // copy the remaining data --> w25q128jw_read_standard(a0 is src addr, a1 is dest ptr data, a2 is length) - - // this sub is redundat as we could have simply set a0 to RAMSIZE_COPIEDBY_BOOTROM+0x0, - // but like this is more readable as we set the FLASH address as memory mapped to FLASH_MEM_START_ADDRESS, and then remove the offset - // as required bz the w25q128jw_read_standard function - sub a0,a0,s2 - call w25q128jw_read_standard - -_load_data_section: - // src ptr - la a0, _lma_data_start - // dst ptr - la a1, __data_start - // copy size in bytes - la a2, _lma_data_end - sub a2, a2, a0 - - bltz a2, _load_data_interleaved_section // dont do anything if you do not have data - - sub a0,a0,s2 - call w25q128jw_read_standard - - -_load_data_interleaved_section: - #ifdef HAS_MEMORY_BANKS_IL - // src ptr - la a0, _lma_data_interleaved_start - // dst ptr - la a1, __data_interleaved_start - // copy size in bytes - la a2, _lma_data_interleaved_end - sub a2, a2, a0 - - bltz a2, _init_bss // dont do anything if you do not have interleaved data - - sub a0,a0,s2 - call w25q128jw_read_standard - #endif - -#endif - -/* clear the bss segment */ -_init_bss: - la a0, __bss_start - la a2, __bss_end - sub a2, a2, a0 - li a1, 0 - call memset - -#ifdef FLASH_EXEC -/* copy initialized data sections from flash to ram (to be verified, copied from picosoc)*/ - la a0, _sidata - la a1, _sdata - la a2, _edata - bge a1, a2, end_init_data - loop_init_data: - lw a3, 0(a0) - sw a3, 0(a1) - addi a0, a0, 4 - addi a1, a1, 4 - blt a1, a2, loop_init_data - end_init_data: -#endif - -/* set vector table address and vectored mode */ - la a0, __vector_start - ori a0, a0, 0x1 - csrw mtvec, a0 - -/* new-style constructors and destructors */ - la a0, __libc_fini_array - call atexit - call __libc_init_array - -/* call main */ - lw a0, 0(sp) /* a0 = argc */ - addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ - li a2, 0 /* a2 = envp = NULL */ - call main - tail exit - -.size _start, .-_start - -.global _init -.type _init, @function -.global _fini -.type _fini, @function -_init: - call init -_fini: - /* These don't have to do anything since we use init_array/fini_array. Prevent - missing symbol error */ - ret -.size _init, .-_init -.size _fini, .-_fini - - - +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + * Copyright (c) 2019 ETH Zürich and University of Bologna + * Copyright (c) 2022 EPFL + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the FreeBSD License. This program is distributed in the hope that + * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + * including the implied warranties of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. A copy of this license is available at + * http://www.opensource.org/licenses. + */ + +#include "x-heep.h" +#include "core_v_mini_mcu.h" +#include "soc_ctrl_regs.h" + +#define RAMSIZE_COPIEDBY_BOOTROM 2048 + +/* Entry point for bare metal programs */ +.section .text.start +.global _start +.type _start, @function + +_start: +/* initialize global pointer */ +.option push +.option norelax +1: auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) +.option pop + +/* initialize stack pointer */ + la sp, _sp + +/* set the frequency */ + li a0, SOC_CTRL_START_ADDRESS + li a2, REFERENCE_CLOCK_Hz + sw a2, SOC_CTRL_SYSTEM_FREQUENCY_HZ_REG_OFFSET(a0) + +#ifdef EXTERNAL_CRTO + #include "external_crt0.S" +#endif + +#ifdef FLASH_LOAD + + call w25q128jw_init_crt0 + + // This assumes ram base address is 0x00000000 and the section .text stars from ram0 (in the first RAMSIZE_COPIEDBY_BOOTROM Byte) + li s1, RAMSIZE_COPIEDBY_BOOTROM + li s2, FLASH_MEM_START_ADDRESS + + // copy the remaining (if any) text and data sections // + // Setup the in/out pointers and copy size knowing 1KiB as already been copied + mv a0, s2 // src ptr (flash) + add a0, a0, s1 + + la a1, _etext + // Skip if everything has already been copied, and copy the data section + blt a1, s1, _load_data_section + + // copy size in bytes, i.e. _etext - RAMSIZE_COPIEDBY_BOOTROM + sub a2, a1, s1 + + // dst ptr (ram) + mv a1, s1 + + // copy the remaining data --> w25q128jw_read_standard(a0 is src addr, a1 is dest ptr data, a2 is length) + + // this sub is redundat as we could have simply set a0 to RAMSIZE_COPIEDBY_BOOTROM+0x0, + // but like this is more readable as we set the FLASH address as memory mapped to FLASH_MEM_START_ADDRESS, and then remove the offset + // as required bz the w25q128jw_read_standard function + sub a0,a0,s2 + call w25q128jw_read_standard + +% for i, section in enumerate(xheep.iter_linker_sections()): +% if section.name != "code": +_load_${section.name}_section: + // src ptr + la a0, _lma_${section.name}_start + // dst ptr + la a1, __${section.name}_start + // copy size in bytes + la a2, _lma_${section.name}_end + sub a2, a2, a0 + + bltz a2, _load_${section.name}_section_end // dont do anything if you do not have something in ${section.name} + + sub a0,a0,s2 + call w25q128jw_read_standard +_load_${section.name}_section_end: + +% endif +% endfor + +#endif + +/* clear the bss segment */ +_init_bss: + la a0, __bss_start + la a2, __bss_end + sub a2, a2, a0 + li a1, 0 + call memset + +#ifdef FLASH_EXEC +/* copy initialized data sections from flash to ram (to be verified, copied from picosoc)*/ + la a0, _sidata + la a1, _sdata + la a2, _edata + bge a1, a2, end_init_data + loop_init_data: + lw a3, 0(a0) + sw a3, 0(a1) + addi a0, a0, 4 + addi a1, a1, 4 + blt a1, a2, loop_init_data + end_init_data: +#endif + +/* set vector table address and vectored mode */ + la a0, __vector_start + ori a0, a0, 0x1 + csrw mtvec, a0 + +/* new-style constructors and destructors */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +/* call main */ + lw a0, 0(sp) /* a0 = argc */ + addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ + li a2, 0 /* a2 = envp = NULL */ + call main + tail exit + +.size _start, .-_start + +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: + call init +_fini: + /* These don't have to do anything since we use init_array/fini_array. Prevent + missing symbol error */ + ret +.size _init, .-_init +.size _fini, .-_fini + + + diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors.S index f6a805c6..8e573eef 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors.S +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors.S @@ -126,39 +126,13 @@ new vector table (which is at mtvec) */ .section .text.vecs /* exception handling */ +.globl __no_irq_handler __no_irq_handler: la a0, no_exception_handler_msg jal ra, puts j __no_irq_handler - -sw_irq_handler: - csrr t0, mcause - slli t0, t0, 1 /* shift off the high bit */ - srli t0, t0, 1 - li t1, 2 - beq t0, t1, handle_illegal_insn - li t1, 11 - beq t0, t1, handle_ecall - li t1, 3 - beq t0, t1, handle_ebreak - j handle_unknown - -handle_ecall: - la a0, ecall_msg - jal ra, puts - j end_handler - -handle_ebreak: - la a0, ebreak_msg - jal ra, puts - j end_handler - -handle_illegal_insn: - la a0, illegal_insn_msg - jal ra, puts - j end_handler - +.globl handle_unknown handle_unknown: la a0, unknown_msg jal ra, puts diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors_freertos.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors_freertos.S index 3596dc18..c4586b30 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors_freertos.S +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/vectors_freertos.S @@ -132,33 +132,6 @@ __no_irq_handler: jal ra, puts j __no_irq_handler -sw_irq_handler: - csrr t0, mcause - slli t0, t0, 1 /* shift off the high bit */ - srli t0, t0, 1 - li t1, 2 - beq t0, t1, handle_illegal_insn - li t1, 11 - beq t0, t1, handle_ecall - li t1, 3 - beq t0, t1, handle_ebreak - j handle_unknown - -handle_ecall: - la a0, ecall_msg - jal ra, puts - j end_handler - -handle_ebreak: - la a0, ebreak_msg - jal ra, puts - j end_handler - -handle_illegal_insn: - la a0, illegal_insn_msg - jal ra, puts - j end_handler - handle_unknown: la a0, unknown_msg jal ra, puts diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c index d0b977d2..52097770 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c @@ -31,6 +31,11 @@ /** **/ /****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + #include "dma.h" /* To manage addresses. */ @@ -57,11 +62,6 @@ */ #define DMA_CSR_REG_MIE_MASK (( 1 << 19 ) | (1 << 11 ) ) // @ToDo Add definitions for this 19 and 11 -/** - * Size of a register of 32 bits. - */ -#define DMA_REGISTER_SIZE_BYTES sizeof(int) - /** * Mask to determine if an address is multiple of 4 (Word aligned). */ @@ -165,36 +165,49 @@ static inline uint8_t get_misalignment_b( uint8_t *p_ptr, * @retval 1 There is an outbound. * @retval 0 There is NOT an outbound. */ -static inline uint8_t is_region_outbound( uint8_t *p_start, +static inline uint8_t is_region_outbound_1D( uint8_t *p_start, uint8_t *p_end, uint32_t p_type, uint32_t p_size_du, uint32_t p_inc_du ); /** - * @brief Writes a given value into the specified register. Its operation - * mimics that of bitfield_field32_write(), but does not require the use of - * a field structure, that is not always provided in the _regs.h file. - * @param p_val The value to be written. - * @param p_offset The register's offset from the peripheral's base address - * where the target register is located. - * @param p_mask The variable's mask to only modify its bits inside the whole - * register. - * @param p_sel The selection index (i.e. From which bit inside the register - * the value is to be written). + * @brief Determines whether a given region will fit before the end of an + * environment with a 2D transaction. + * @param p_start Pointer to the beginning of the region. + * @param p_end Pointer to the last byte of the environment. + * @param p_type The data type to be transferred. + * @param p_size_du The number of data units to be transferred. Must be + * non-zero. + * @param p_inc_du The size in data units of each increment. + * @retval 1 There is an outbound. + * @retval 0 There is NOT an outbound. */ -static inline void write_register( uint32_t p_val, - uint32_t p_offset, - uint32_t p_mask, - uint8_t p_sel ); +static inline uint8_t is_region_outbound_2D( uint8_t *p_start, + uint8_t *p_end, + uint32_t p_type, + uint32_t p_size_d1_du, + uint32_t p_size_d2_du, + uint32_t p_inc_d1_du, + uint32_t p_inc_d2_du ); +/** + * @brief Analyzes a target to determine the size of its D1 increment (in bytes). + * @param p_tgt A pointer to the target to analyze. + * @param channel The channel to use as target. + * @return The number of bytes of the increment. + */ +static inline uint32_t get_increment_b_1D( dma_target_t * p_tgt, + uint8_t channel ); /** - * @brief Analyzes a target to determine the size of its increment (in bytes). + * @brief Analyzes a target to determine the size of its D2 increment (in bytes). * @param p_tgt A pointer to the target to analyze. + * @param channel The channel to use as target. * @return The number of bytes of the increment. */ -static inline uint32_t get_increment_b( dma_target_t * p_tgt ); +static inline uint32_t get_increment_b_2D( dma_target_t * p_tgt, + uint8_t channel ); /****************************************************************************/ @@ -210,10 +223,10 @@ static inline uint32_t get_increment_b( dma_target_t * p_tgt ); /****************************************************************************/ /** - * Control Block (CB) of the DMA peripheral. + * Control Block (CB) of a single DMA channel. * Has variables and constant necessary/useful for its control. */ -static struct +typedef struct { /** * Pointer to the transaction to be performed. @@ -232,7 +245,14 @@ static struct */ dma *peri; -}dma_cb; +}dma_ch_cb; + +/* Allocate the channel's memory space */ +static dma_ch_cb dma_subsys_per[DMA_CH_NUM]; + +/* High priority interrupts counters */ +uint16_t dma_hp_tr_intr_counter = 0; +uint16_t dma_hp_win_intr_counter = 0; /****************************************************************************/ @@ -243,45 +263,130 @@ static struct void handler_irq_dma(uint32_t id) { - /* - * Call the weak implementation provided in this module, + /* + * Find out which channel raised the interrupt and call + * either the weak implementation provided in this module, * or the non-weak implementation. */ - dma_intr_handler_window_done(); + + for (int i = 0; i < DMA_CH_NUM; i++) + { + if (dma_subsys_per[i].peri->WINDOW_IFR == 1) + { + dma_intr_handler_window_done(i); + + #ifdef DMA_HP_INTR_INDEX + /* + * If the channel that raised the interrupt is among the high priority channels, + * return to break the loop. + */ + #ifdef DMA_NUM_HP_INTR + if (i <= DMA_HP_INTR_INDEX && dma_hp_win_intr_counter < DMA_NUM_HP_INTR) + { + dma_hp_win_intr_counter++; + return; + } else if (i > DMA_HP_INTR_INDEX) + { + dma_hp_win_intr_counter = 0; + } + + #else + + if (i <= DMA_HP_INTR_INDEX) + { + return; + } + #endif + + #endif + } + } + return; } void fic_irq_dma(void) { - /* The flag is raised so the waiting loop can be broken.*/ - dma_cb.intrFlag = 1; - - /* - * Call the weak implementation provided in this module, + /* + * Find out which channel raised the interrupt and call + * either the weak implementation provided in this module, * or the non-weak implementation. */ - dma_intr_handler_trans_done(); + + for (int i = 0; i < DMA_CH_NUM; i++) + { + if (dma_subsys_per[i].peri->TRANSACTION_IFR == 1) + { + dma_subsys_per[i].intrFlag = 1; + dma_intr_handler_trans_done(i); + + #ifdef DMA_HP_INTR_INDEX + /* + * If the channel that raised the interrupt is among the high priority channels, + * return to break the loop. + */ + #ifdef DMA_NUM_HP_INTR + if (i <= DMA_HP_INTR_INDEX && dma_hp_tr_intr_counter < DMA_NUM_HP_INTR) + { + dma_hp_tr_intr_counter++; + return; + } + else if (i > DMA_HP_INTR_INDEX) + { + dma_hp_tr_intr_counter = 0; + } + + #else + + if (i <= DMA_HP_INTR_INDEX) + { + return; + } + #endif + + #endif + } + } + return; } -void dma_init( dma *peri ) +void dma_init( dma *dma_peri ) { /* * If a DMA peripheral was provided, use that one, otherwise use the * integrated one. */ - dma_cb.peri = peri ? peri : dma_peri; - - /* Clear the loaded transaction */ - dma_cb.trans = NULL; - /* Clear all values in the DMA registers. */ - dma_cb.peri->SRC_PTR = 0; - dma_cb.peri->DST_PTR = 0; - dma_cb.peri->SIZE = 0; - dma_cb.peri->PTR_INC = 0; - dma_cb.peri->SLOT = 0; - dma_cb.peri->DATA_TYPE = 0; - dma_cb.peri->MODE = 0; - dma_cb.peri->WINDOW_SIZE = 0; - dma_cb.peri->INTERRUPT_EN = 0; + + for (int i = 0; i < DMA_CH_NUM; i++) + { + dma_subsys_per[i].peri = dma_peri ? dma_peri : dma_peri(i); + + /* Clear the loaded transaction */ + dma_subsys_per[i].trans = NULL; + + /* Clear all values in the DMA registers. */ + dma_subsys_per[i].peri->SRC_PTR = 0; + dma_subsys_per[i].peri->DST_PTR = 0; + dma_subsys_per[i].peri->ADDR_PTR = 0; + dma_subsys_per[i].peri->SIZE_D1 = 0; + dma_subsys_per[i].peri->SIZE_D2 = 0; + dma_subsys_per[i].peri->SRC_PTR_INC_D1 = 0; + dma_subsys_per[i].peri->SRC_PTR_INC_D2 = 0; + dma_subsys_per[i].peri->DST_PTR_INC_D1 = 0; + dma_subsys_per[i].peri->DST_PTR_INC_D2 = 0; + dma_subsys_per[i].peri->DIM_CONFIG = 0; + dma_subsys_per[i].peri->DIM_INV = 0; + dma_subsys_per[i].peri->SLOT = 0; + dma_subsys_per[i].peri->SRC_DATA_TYPE = 0; + dma_subsys_per[i].peri->DST_DATA_TYPE = 0; + dma_subsys_per[i].peri->SIGN_EXT = 0; + dma_subsys_per[i].peri->MODE = 0; + dma_subsys_per[i].peri->WINDOW_SIZE = 0; + dma_subsys_per[i].peri->PAD_TOP = 0; + dma_subsys_per[i].peri->PAD_BOTTOM = 0; + dma_subsys_per[i].peri->PAD_LEFT = 0; + dma_subsys_per[i].peri->PAD_RIGHT = 0; + dma_subsys_per[i].peri->INTERRUPT_EN = 0; + } } dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, @@ -308,6 +413,14 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, /* The checks request should be a valid request. */ DMA_STATIC_ASSERT( p_check < DMA_PERFORM_CHECKS__size, "Check request not valid"); + /* The padding should be a valid number */ + DMA_STATIC_ASSERT( ((p_trans->pad_top_du >= 0 && p_trans->pad_top_du < 64) && + (p_trans->pad_bottom_du >= 0 && p_trans->pad_bottom_du < 64) && + (p_trans->pad_left_du >= 0 && p_trans->pad_left_du < 64) && + (p_trans->pad_right_du >= 0 && p_trans->pad_right_du < 64)), + "Padding not valid"); + /* The dimensionality should be valid*/ + DMA_STATIC_ASSERT( p_trans->dim < DMA_DIM_CONF__size, "Dimensionality not valid"); /* * CHECK IF TARGETS HAVE ERRORS @@ -335,6 +448,43 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, return p_trans->flags; } + /* + * CHECK IF THERE ARE INCREMENTS INCONSISTENCIES + */ + + /* + * A transaction is considered 2D if the source and/or the destination has a 2D increment. + * e.g. It's possible to copy a 1x9 matrix to a 3x3 matrix or to copy a 3x3 matrix to a 1x9 one. + */ + + if (p_check) + { + // If the transaction is 2D, check that the D2 increment of the targets are non zero. + // If the transaction is 1D, check that the D2 increment of the targets are zero. + if((p_trans->dim == DMA_DIM_CONF_2D && (p_trans->src->inc_d2_du == 0 || p_trans->dst->inc_d2_du == 0)) || + (p_trans->dim == DMA_DIM_CONF_1D && (p_trans->src->inc_d2_du != 0 || p_trans->dst->inc_d2_du != 0))) + { + p_trans->flags |= DMA_CONFIG_INCOMPATIBLE; + p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; + return p_trans->flags; + } + } + + /* + * CHECK IF THERE ARE PADDING INCONSISTENCIES + */ + + if (p_check) + { + // If the transaction is 1D, check that the top and bottom paddings are set to zero. + if((p_trans->dim == DMA_DIM_CONF_1D && (p_trans->pad_top_du != 0 || p_trans->pad_bottom_du != 0))) + { + p_trans->flags |= DMA_CONFIG_INCOMPATIBLE; + p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; + return p_trans->flags; + } + } + /* * CHECK IF THERE ARE TRIGGER INCONSISTENCIES */ @@ -387,12 +537,16 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, /* The flags are cleaned in case the structure was used before.*/ p_trans->flags = DMA_CONFIG_OK; + /* The copy size of the source (in data units -of the source-) is transformed to bytes, to be used as default size.*/ uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE(p_trans->src->type); p_trans->size_b = p_trans->src->size_du * dataSize_b; - /* By default, the source defines the data type.*/ - p_trans->type = p_trans->src->type; + p_trans->size_d2_b = p_trans->src->size_d2_du * dataSize_b; + + p_trans->src_type = p_trans->src->type; + p_trans->dst_type = p_trans->dst->type; + /* * By default, the transaction increment is set to 0 and, if required, * it will be changed to 1 (in which case both src and dst will have an @@ -416,12 +570,12 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, if( p_trans->src->trig == DMA_TRIG_MEMORY ) { - misalignment = get_misalignment_b( p_trans->src->ptr, p_trans->type ); + misalignment = get_misalignment_b( p_trans->src->ptr, p_trans->src_type ); } if( p_trans->dst->trig == DMA_TRIG_MEMORY ) { - dstMisalignment = get_misalignment_b( p_trans->dst->ptr, p_trans->type ); + dstMisalignment = get_misalignment_b( p_trans->dst->ptr, p_trans->dst_type ); } p_trans->flags |= ( misalignment ? DMA_CONFIG_SRC : DMA_CONFIG_OK ); @@ -507,27 +661,28 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * If realignment is allowed and there are no discontinuities, * a more granular data type is used according to the detected * misalignment in order to overcome it. - */ - p_trans->type += misalignment; - /* + */ + p_trans->dst_type = p_trans->dst_type + misalignment; + + /* * Source and destination increment should now be of the size * of the data. * As increments are given in bytes, in both cases should be the * size of a data unit. */ - p_trans->inc_b = DMA_DATA_TYPE_2_SIZE( p_trans->type ); + p_trans->inc_b = DMA_DATA_TYPE_2_SIZE( p_trans->dst_type ); /* The copy size does not change, as it is already stored in bytes.*/ } /* - * CHECK IF SOURCE HAS SIZE 0 + * CHECK IF SOURCE HAS ZERO SIZE(s) */ /* * No further operations are done to prevent corrupting information * that could be useful for debugging purposes. */ - if( p_trans->src->size_du == 0 ) + if(p_trans->src->size_du == 0 || (p_trans->dim == DMA_DIM_CONF_2D && p_trans->src->size_d2_du == 0)) { p_trans->flags |= DMA_CONFIG_SRC; p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; @@ -563,20 +718,23 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * that could be useful for debugging purposes. */ uint8_t isEnv = (p_trans->dst->env != NULL); - uint8_t isOutb = is_region_outbound( - p_trans->dst->ptr, - p_trans->dst->env->end, - p_trans->type, - p_trans->src->size_du, - p_trans->dst->inc_du ); - if( isEnv && isOutb ) - { - p_trans->flags |= DMA_CONFIG_DST; - p_trans->flags |= DMA_CONFIG_OUTBOUNDS; - p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; - return p_trans->flags; - } + if(isEnv) { + uint8_t isOutb = is_region_outbound_1D( + p_trans->dst->ptr, + p_trans->dst->env->end, + p_trans->dst_type, + p_trans->src->size_du, + p_trans->dst->inc_du ); + if( isOutb ) + { + p_trans->flags |= DMA_CONFIG_DST; + p_trans->flags |= DMA_CONFIG_OUTBOUNDS; + p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; + + return p_trans->flags; + } + } // @ToDo: It should also be checked that the destination is behind the // source if there will be overlap. // @ToDo: Consider if (when a destination target has no environment) @@ -622,8 +780,9 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, return p_trans->flags; } -dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans ) +dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans) { + uint8_t channel = p_trans->channel; /* * CHECK FOR CRITICAL ERRORS */ @@ -635,7 +794,7 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans ) */ if( p_trans->flags & DMA_CONFIG_CRITICAL_ERROR ) { - dma_cb.trans = NULL; + dma_subsys_per[channel].trans = NULL; return DMA_CONFIG_CRITICAL_ERROR; } @@ -650,61 +809,138 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans ) * until it has ended. * Transactions can still be validated in the meantime. */ - if( !dma_is_ready() ) + if( !dma_is_ready(channel) ) { return DMA_CONFIG_TRANS_OVERRIDE; } /* Save the current transaction */ - dma_cb.trans = p_trans; + dma_subsys_per[channel].trans = p_trans; /* * ENABLE/DISABLE INTERRUPTS */ /* - * If the selected en event is polling, interrupts are disabled. + * If the selected end event is polling, interrupts are disabled. * Otherwise the mie.MEIE bit is set to one to enable machine-level * fast DMA interrupt. */ - dma_cb.peri->INTERRUPT_EN = INTR_EN_NONE; + dma_subsys_per[channel].peri->INTERRUPT_EN = INTR_EN_NONE; CSR_CLEAR_BITS(CSR_REG_MIE, DMA_CSR_REG_MIE_MASK ); - if( dma_cb.trans->end != DMA_TRANS_END_POLLING ) + if( dma_subsys_per[channel].trans->end != DMA_TRANS_END_POLLING ) { - /* Enable global interrupt for machine-level interrupts. */ + /* Enable global interrupt. */ CSR_SET_BITS(CSR_REG_MSTATUS, 0x8 ); - /* @ToDo: What does this do? */ + /* Enable machine-level fast interrupt. */ CSR_SET_BITS(CSR_REG_MIE, DMA_CSR_REG_MIE_MASK ); - dma_cb.peri->INTERRUPT_EN |= INTR_EN_TRANS_DONE; + /* Enable the transaction interrupt for the channel by setting the corresponding bit in Transaction IFR */ + write_register( + 0x1, + DMA_INTERRUPT_EN_REG_OFFSET, + 0xffff, + DMA_INTERRUPT_EN_TRANSACTION_DONE_BIT, + dma_subsys_per[channel].peri + ); /* Only if a window is used should the window interrupt be set. */ if( p_trans->win_du > 0 ) { - dma_cb.peri->INTERRUPT_EN |= INTR_EN_WINDOW_DONE; + write_register( + 0x1, + DMA_INTERRUPT_EN_REG_OFFSET, + 0xffff, + DMA_INTERRUPT_EN_WINDOW_DONE_BIT, + dma_subsys_per[channel].peri + ); } } + /* + * SET THE PADDING + */ + + /* + * In the case of a 1D transaction with padding enabled, the DMA has to be configured to treat + * the transaction as a 2D one with a second dimension of 1 du and a second dimension increment of 1 du. + */ + + if (p_trans->dim == DMA_DIM_CONF_1D && (p_trans->pad_left_du != 0 || p_trans->pad_right_du != 0)) + { + p_trans->dim = DMA_DIM_CONF_2D; + p_trans->size_d2_b = DMA_DATA_TYPE_2_SIZE( p_trans->dst_type ); + p_trans->src->inc_d2_du = DMA_DATA_TYPE_2_SIZE( p_trans->dst_type ); + + write_register( dma_subsys_per[channel].trans->pad_left_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_LEFT_REG_OFFSET, + DMA_PAD_LEFT_PAD_MASK, + DMA_PAD_LEFT_PAD_OFFSET, + dma_subsys_per[channel].peri); + + write_register( dma_subsys_per[channel].trans->pad_right_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_RIGHT_REG_OFFSET, + DMA_PAD_RIGHT_PAD_MASK, + DMA_PAD_RIGHT_PAD_OFFSET, + dma_subsys_per[channel].peri); + } + else if (p_trans->dim == DMA_DIM_CONF_2D) + { + write_register( dma_subsys_per[channel].trans->pad_top_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_TOP_REG_OFFSET, + DMA_PAD_TOP_PAD_MASK, + DMA_PAD_TOP_PAD_OFFSET, + dma_subsys_per[channel].peri); + + write_register( dma_subsys_per[channel].trans->pad_bottom_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_BOTTOM_REG_OFFSET, + DMA_PAD_BOTTOM_PAD_MASK, + DMA_PAD_BOTTOM_PAD_OFFSET, + dma_subsys_per[channel].peri); + + write_register( dma_subsys_per[channel].trans->pad_left_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_LEFT_REG_OFFSET, + DMA_PAD_LEFT_PAD_MASK, + DMA_PAD_LEFT_PAD_OFFSET, + dma_subsys_per[channel].peri); + + write_register( dma_subsys_per[channel].trans->pad_right_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + DMA_PAD_RIGHT_REG_OFFSET, + DMA_PAD_RIGHT_PAD_MASK, + DMA_PAD_RIGHT_PAD_OFFSET, + dma_subsys_per[channel].peri); + } + /* * SET THE POINTERS */ - dma_cb.peri->SRC_PTR = (uint32_t)dma_cb.trans->src->ptr; + dma_subsys_per[channel].peri->SRC_PTR = (uint32_t)dma_subsys_per[channel].trans->src->ptr; - if(dma_cb.trans->mode != DMA_TRANS_MODE_ADDRESS) + if(dma_subsys_per[channel].trans->mode != DMA_TRANS_MODE_ADDRESS) { /* Write to the destination pointers only if we are not in address mode, otherwise the destination address is read in a separate port in parallel with the data from the address port */ - dma_cb.peri->DST_PTR = (uint32_t)dma_cb.trans->dst->ptr; + dma_subsys_per[channel].peri->DST_PTR = (uint32_t)dma_subsys_per[channel].trans->dst->ptr; } else { - dma_cb.peri->ADDR_PTR = (uint32_t)dma_cb.trans->src_addr->ptr; + dma_subsys_per[channel].peri->ADDR_PTR = (uint32_t)dma_subsys_per[channel].trans->src_addr->ptr; } + /* + * SET THE TRANSPOSITION MODE + */ + + write_register(dma_subsys_per[channel].trans->dim_inv, + DMA_DIM_INV_REG_OFFSET, + 0x1 << DMA_DIM_INV_SEL_BIT, + DMA_DIM_INV_SEL_BIT, + dma_subsys_per[channel].peri); + /* * SET THE INCREMENTS */ @@ -717,66 +953,124 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans ) * In that case, a increment of 0 is necessary. * In case of DMA Address mode transaction, the dst pointer is ignored * as the values read from the second port are instead used. + * In case of a 2D DMA transaction, the second dimension increment is set. */ - write_register( get_increment_b( dma_cb.trans->src ), - DMA_PTR_INC_REG_OFFSET, - DMA_PTR_INC_SRC_PTR_INC_MASK, - DMA_PTR_INC_SRC_PTR_INC_OFFSET ); + write_register( get_increment_b_1D( dma_subsys_per[channel].trans->src, channel), + DMA_SRC_PTR_INC_D1_REG_OFFSET, + DMA_SRC_PTR_INC_D1_INC_MASK, + DMA_SRC_PTR_INC_D1_INC_OFFSET, + dma_subsys_per[channel].peri); - - - if(dma_cb.trans->mode != DMA_TRANS_MODE_ADDRESS) + if(dma_subsys_per[channel].trans->dim == DMA_DIM_CONF_2D) { - write_register( get_increment_b( dma_cb.trans->dst ), - DMA_PTR_INC_REG_OFFSET, - DMA_PTR_INC_DST_PTR_INC_MASK, - DMA_PTR_INC_DST_PTR_INC_OFFSET ); + write_register( get_increment_b_2D( dma_subsys_per[channel].trans->src, channel), + DMA_SRC_PTR_INC_D2_REG_OFFSET, + DMA_SRC_PTR_INC_D2_INC_MASK, + DMA_SRC_PTR_INC_D2_INC_OFFSET, + dma_subsys_per[channel].peri ); } + if(dma_subsys_per[channel].trans->mode != DMA_TRANS_MODE_ADDRESS) + { + write_register( get_increment_b_1D( dma_subsys_per[channel].trans->dst, channel), + DMA_DST_PTR_INC_D1_REG_OFFSET, + DMA_DST_PTR_INC_D1_INC_MASK, + DMA_DST_PTR_INC_D1_INC_OFFSET, + dma_subsys_per[channel].peri ); + + if(dma_subsys_per[channel].trans->dim == DMA_DIM_CONF_2D) + { + write_register( get_increment_b_2D( dma_subsys_per[channel].trans->dst, channel), + DMA_DST_PTR_INC_D2_REG_OFFSET, + DMA_DST_PTR_INC_D2_INC_MASK, + DMA_DST_PTR_INC_D2_INC_OFFSET, + dma_subsys_per[channel].peri ); + } + } /* * SET THE OPERATION MODE AND WINDOW SIZE */ - dma_cb.peri->MODE = dma_cb.trans->mode; + dma_subsys_per[channel].peri->MODE = dma_subsys_per[channel].trans->mode; /* The window size is set to the transaction size if it was set to 0 in order to disable the functionality (it will never be triggered). */ - dma_cb.peri->WINDOW_SIZE = dma_cb.trans->win_du - ? dma_cb.trans->win_du - : dma_cb.trans->size_b; + dma_subsys_per[channel].peri->WINDOW_SIZE = dma_subsys_per[channel].trans->win_du + ? dma_subsys_per[channel].trans->win_du + : dma_subsys_per[channel].trans->size_b; + + /* + * SET THE DIMENSIONALITY + */ + write_register( dma_subsys_per[channel].trans->dim, + DMA_DIM_CONFIG_REG_OFFSET, + 0x1, + DMA_DIM_CONFIG_DMA_DIM_BIT, + dma_subsys_per[channel].peri ); + + /* + * SET THE SIGN EXTENSION BIT + */ + write_register( dma_subsys_per[channel].trans->sign_ext, + DMA_SIGN_EXT_REG_OFFSET, + 0x1 << DMA_SIGN_EXT_SIGNED_BIT, + DMA_SIGN_EXT_SIGNED_BIT, + dma_subsys_per[channel].peri ); + + + /* + * SET THE SIGN EXTENSION BIT + */ + write_register( dma_subsys_per[channel].trans->sign_ext, + DMA_SIGN_EXT_REG_OFFSET, + 0x1 << DMA_SIGN_EXT_SIGNED_BIT, + DMA_SIGN_EXT_SIGNED_BIT, + dma_subsys_per[channel].peri ); + /* * SET TRIGGER SLOTS AND DATA TYPE */ - write_register( dma_cb.trans->src->trig, + write_register( dma_subsys_per[channel].trans->src->trig, DMA_SLOT_REG_OFFSET, DMA_SLOT_RX_TRIGGER_SLOT_MASK, - DMA_SLOT_RX_TRIGGER_SLOT_OFFSET ); + DMA_SLOT_RX_TRIGGER_SLOT_OFFSET, + dma_subsys_per[channel].peri ); - write_register( dma_cb.trans->dst->trig, + write_register( dma_subsys_per[channel].trans->dst->trig, DMA_SLOT_REG_OFFSET, DMA_SLOT_TX_TRIGGER_SLOT_MASK, - DMA_SLOT_TX_TRIGGER_SLOT_OFFSET ); - - write_register( dma_cb.trans->type, - DMA_DATA_TYPE_REG_OFFSET, - DMA_DATA_TYPE_DATA_TYPE_MASK, - DMA_SELECTION_OFFSET_START ); + DMA_SLOT_TX_TRIGGER_SLOT_OFFSET, + dma_subsys_per[channel].peri ); + + write_register( dma_subsys_per[channel].trans->dst_type, + DMA_DST_DATA_TYPE_REG_OFFSET, + DMA_DST_DATA_TYPE_DATA_TYPE_MASK, + DMA_SELECTION_OFFSET_START, + dma_subsys_per[channel].peri ); + + write_register( dma_subsys_per[channel].trans->src_type, + DMA_SRC_DATA_TYPE_REG_OFFSET, + DMA_SRC_DATA_TYPE_DATA_TYPE_MASK, + DMA_SELECTION_OFFSET_START, + dma_subsys_per[channel].peri ); return DMA_CONFIG_OK; } -dma_config_flags_t dma_launch( dma_trans_t *p_trans ) +dma_config_flags_t dma_launch( dma_trans_t *p_trans) { + uint8_t channel = p_trans->channel; + /* * Make sure that the loaded transaction is the intended transaction. * If the loaded trans was NULL'd, then this the transaction is never * launched. */ if( ( p_trans == NULL ) - || ( dma_cb.trans != p_trans ) ) // @ToDo: Check per-element. + || ( dma_subsys_per[channel].trans != p_trans ) ) // @ToDo: Check per-element. { return DMA_CONFIG_CRITICAL_ERROR; } @@ -792,7 +1086,7 @@ dma_config_flags_t dma_launch( dma_trans_t *p_trans ) * until it has ended. * Transactions can still be validated in the meantime. */ - if( !dma_is_ready() ) + if( !dma_is_ready(channel) ) { return DMA_CONFIG_TRANS_OVERRIDE; } @@ -801,58 +1095,74 @@ dma_config_flags_t dma_launch( dma_trans_t *p_trans ) * This has to be done prior to writing the register because otherwise * the interrupt could arrive before it is lowered. */ - dma_cb.intrFlag = 0; + dma_subsys_per[channel].intrFlag = 0; - /* Load the size and start the transaction. */ - dma_cb.peri->SIZE = dma_cb.trans->size_b; + /* Load the size(s) and start the transaction. */ + if(dma_subsys_per[channel].trans->dim == DMA_DIM_CONF_2D) + { + write_register( dma_subsys_per[channel].trans->size_d2_b, + DMA_SIZE_D2_REG_OFFSET, + DMA_SIZE_D2_SIZE_MASK, + DMA_SIZE_D2_SIZE_OFFSET, + dma_subsys_per[channel].peri + ); + } + + write_register( dma_subsys_per[channel].trans->size_b, + DMA_SIZE_D1_REG_OFFSET, + DMA_SIZE_D1_SIZE_MASK, + DMA_SIZE_D1_SIZE_OFFSET, + dma_subsys_per[channel].peri + ); /* * If the end event was set to wait for the interrupt, the dma_launch * will not return until the interrupt arrives. */ + + while( p_trans->end == DMA_TRANS_END_INTR_WAIT - && ( dma_cb.intrFlag != 0 ) ) { // @ToDo: add a label for this 0 - wait_for_interrupt(); + && ( dma_subsys_per[channel].intrFlag != 0x0 ) ) { + wait_for_interrupt(); } return DMA_CONFIG_OK; } - -__attribute__((optimize("O0"))) uint32_t dma_is_ready(void) +__attribute__((optimize("O0"))) uint32_t dma_is_ready(uint8_t channel) { /* The transaction READY bit is read from the status register*/ - uint32_t ret = ( dma_cb.peri->STATUS & (1<STATUS & (1<DONE ); + * return ( 1 && dma_subsys_per[channel].peri->DONE ); * 2) Consider only the LSB == 1 to be a valid 1 using a BITWISE AND. - * return ( 1 & dma_cb.peri->DONE ); + * return ( 1 & dma_subsys_per[channel].peri->DONE ); * This would be fixed if the DONE register was a 1 bit field. */ -uint32_t dma_get_window_count() +uint32_t dma_get_window_count(uint8_t channel) { - return dma_cb.peri->WINDOW_COUNT; + return dma_subsys_per[channel].peri->WINDOW_COUNT; } -void dma_stop_circular() +void dma_stop_circular(uint8_t channel) { /* * The DMA finishes the current transaction before and does not start * a new one. */ - dma_cb.peri->MODE = DMA_TRANS_MODE_SINGLE; + dma_subsys_per[channel].peri->MODE = DMA_TRANS_MODE_SINGLE; } -__attribute__((weak, optimize("O0"))) void dma_intr_handler_trans_done() +__attribute__((weak, optimize("O0"))) void dma_intr_handler_trans_done(uint8_t channel) { /* * The DMA transaction has finished! @@ -863,7 +1173,7 @@ __attribute__((weak, optimize("O0"))) void dma_intr_handler_trans_done() */ } -__attribute__((weak, optimize("O0"))) void dma_intr_handler_window_done() +__attribute__((weak, optimize("O0"))) void dma_intr_handler_window_done(uint8_t channel) { /* * The DMA has copied another window. @@ -901,14 +1211,19 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) */ /* Increment can be 0 when a trigger is used. */ - DMA_STATIC_ASSERT( p_tgt->inc_du >= 0 , "Increment not valid"); + DMA_STATIC_ASSERT( p_tgt->inc_du >= 0 && p_tgt->inc_du < 64 , "Increment not valid"); + /* Increment on D2 has to be 0 for 1D operations */ + DMA_STATIC_ASSERT( p_tgt->inc_d2_du >= 0 && p_tgt->inc_d2_du < 4194304 , "Increment d2 not valid"); /* The size could be 0 if the target is only going to be used as a destination. */ - DMA_STATIC_ASSERT( p_tgt->size_du >= 0 , "Size not valid"); + DMA_STATIC_ASSERT( p_tgt->size_du >= 0 && p_tgt->size_du < 65536 , "Size not valid"); + /* The size can be 0 or 1 if the target is involved in a 1D padded transaction */ + DMA_STATIC_ASSERT( p_tgt->size_d2_du >= 0 && p_tgt->size_du < 65536 , "Size d2 not valid"); /* The data type must be a valid type */ - DMA_STATIC_ASSERT( p_tgt->type < DMA_DATA_TYPE__size , "Type not valid"); + DMA_STATIC_ASSERT( p_tgt->type < DMA_DATA_TYPE__size , "Source type not valid"); /* The trigger must be among the valid trigger values. */ DMA_STATIC_ASSERT( p_tgt->trig < DMA_TRIG__size , "Trigger not valid"); + /* * INTEGRITY CHECKS @@ -923,7 +1238,6 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) { /* Check if the environment was properly formed.*/ flags |= validate_environment( p_tgt->env ); - /* * Check if the target selected size goes beyond the boundaries of * the environment. @@ -931,7 +1245,7 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) */ if( p_tgt->size_du != 0 ) { - uint8_t isOutb = is_region_outbound( p_tgt->ptr, + uint8_t isOutb = is_region_outbound_1D( p_tgt->ptr, p_tgt->env->end, p_tgt->type, p_tgt->size_du, @@ -941,6 +1255,21 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) flags |= DMA_CONFIG_OUTBOUNDS; } } + /* Do the same but for 2D case */ + if( p_tgt->size_d2_du != 0 ) + { + uint8_t isOutb = is_region_outbound_2D( p_tgt->ptr, + p_tgt->env->end, + p_tgt->type, + p_tgt->size_du, + p_tgt->size_d2_du, + p_tgt->inc_du, + p_tgt->inc_d2_du); + if( isOutb ) + { + flags |= DMA_CONFIG_OUTBOUNDS; + } + } /* Check if the target starts before the environment starts. */ uint8_t beforeEnv = ( p_tgt->ptr < p_tgt->env->start ); @@ -1071,7 +1400,7 @@ static inline uint8_t get_misalignment_b( uint8_t *p_ptr, return misalignment; } -static inline uint8_t is_region_outbound( uint8_t *p_start, +static inline uint8_t is_region_outbound_1D( uint8_t *p_start, uint8_t *p_end, uint32_t p_type, uint32_t p_size_du, @@ -1093,37 +1422,34 @@ static inline uint8_t is_region_outbound( uint8_t *p_start, */ uint32_t affectedUnits = ( p_size_du - 1 ) * p_inc_du + 1; uint32_t rangeSize = DMA_DATA_TYPE_2_SIZE(p_type) * affectedUnits; - uint32_t lasByteInsideRange = (uint32_t)p_start + rangeSize -1; - return ( p_end < lasByteInsideRange ); + uint32_t lastByteInsideRange = (uint32_t)p_start + rangeSize -1; + return ( p_end < lastByteInsideRange ); // Size is be guaranteed to be non-zero before calling this function. } -/* @ToDo: Consider changing the "mask" parameter for a bitfield definition -(see dma_regs.h) */ -static inline void write_register( uint32_t p_val, - uint32_t p_offset, - uint32_t p_mask, - uint8_t p_sel ) +static inline uint8_t is_region_outbound_2D( uint8_t *p_start, + uint8_t *p_end, + uint32_t p_type, + uint32_t p_size_d1_du, + uint32_t p_size_d2_du, + uint32_t p_inc_d1_du, + uint32_t p_inc_d2_du ) { - /* - * The index is computed to avoid needing to access the structure - * as a structure. - */ - uint8_t index = p_offset / DMA_REGISTER_SIZE_BYTES; - /* - * An intermediate variable "value" is used to prevent writing twice into - * the register. - */ - uint32_t value = (( uint32_t * ) dma_cb.peri ) [ index ]; - value &= ~( p_mask << p_sel ); - value |= (p_val & p_mask) << p_sel; - (( uint32_t * ) dma_cb.peri ) [ index ] = value; + /* + * If the environment ends before the last affected byte, then there is + * outbound writing and the function returns 1. + */ -// @ToDo: mmio_region_write32(dma->base_addr, (ptrdiff_t)(DMA_SLOT_REG_OFFSET), (tx_slot_mask << DMA_SLOT_TX_TRIGGER_SLOT_OFFSET) + rx_slot_mask) + uint32_t affectedUnits = (( p_size_d1_du - 1 ) * p_inc_d1_du + 1) * (p_size_d2_du) + p_inc_d2_du * (p_size_d2_du - 1); + uint32_t rangeSize = DMA_DATA_TYPE_2_SIZE(p_type) * affectedUnits; + uint32_t lastByteInsideRange = (uint32_t)p_start + rangeSize -1; + return ( p_end < lastByteInsideRange ); + // Size is be guaranteed to be non-zero before calling this function. } -static inline uint32_t get_increment_b( dma_target_t * p_tgt ) +static inline uint32_t get_increment_b_1D( dma_target_t * p_tgt, + uint8_t channel) { uint32_t inc_b = 0; /* If the target uses a trigger, the increment remains 0. */ @@ -1133,7 +1459,7 @@ static inline uint32_t get_increment_b( dma_target_t * p_tgt ) * If the transaction increment has been overriden (due to * misalignments), then that value is used (it's always set to 1). */ - inc_b = dma_cb.trans->inc_b; + inc_b = dma_subsys_per[channel].trans->inc_b; /* * Otherwise, the target-specific increment is used transformed into @@ -1141,15 +1467,46 @@ static inline uint32_t get_increment_b( dma_target_t * p_tgt ) */ if( inc_b == 0 ) { - uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE( dma_cb.trans->type ); + uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); inc_b = ( p_tgt->inc_du * dataSize_b ); } } return inc_b; } +static inline uint32_t get_increment_b_2D( dma_target_t * p_tgt, + uint8_t channel ) +{ + uint32_t inc_b = 0; + /* If the target uses a trigger, the increment remains 0. */ + if( p_tgt->trig == DMA_TRIG_MEMORY ) + { + /* + * If the transaction increment has been overriden (due to + * misalignments), then that value is used (it's always set to 1). + */ + inc_b = dma_subsys_per[channel].trans->inc_b; + + /* + * Otherwise, the target-specific increment is used transformed into + * bytes). + */ + if( inc_b == 0 ) + { + uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); + inc_b = ( p_tgt->inc_d2_du * dataSize_b ); + } + } + return inc_b; +} + + +#ifdef __cplusplus +} +#endif // __cplusplus + /****************************************************************************/ /** **/ /* EOF */ /** **/ -/****************************************************************************/ +/****************************************************************************/ \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h index 85ee6475..ad87434a 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h @@ -68,6 +68,36 @@ #define DMA_SPI_FLASH_TX_SLOT 0x08 #define DMA_I2S_RX_SLOT 0x10 +#define DMA_INT_TR_START 0x0 + +/* + * For multichannel configurations, a priority mechanism can be set up to allow the interrupt handler + * to prioritize a set of channels. + * + * In order to enable this feature, the user must define DMA_HP_INTR_INDEX. + * + * When an interrupt is raised, the handler will loop through the channels. If the channel that + * raised the interrupt is part of the high priority channels (index <= DMA_HP_INTR_INDEX), + * it will call the actual handler and exit the loop. + * It this way, low index channels will always be serviced first. + * + * However, this feature could cause low priority channels to never be serviced if the high priority + * interrupts are raised at a faster frequency. + * In order to avoid this, the user can define DMA_NUM_HP_INTR (uint16_t). + * This macro puts a limit to the number of consecutive interrupts raised by high priority channels + * that can trigger a "return". + * If N = DMA_NUM_HP_INTR interrupts are raised by high priority channels, the N+1 interrupt will be + * serviced and then no "return" will be triggered, thus allowing the handler's loop to continue and + * low priority channels to be serviced, if necessary. + * + * The priority mechanism is applied to both transaction done and window done interrupts, if enabled. + * Separate counters are used for each type of interrupt. + */ + +//#define DMA_HP_INTR_INDEX 0 +//#define DMA_NUM_HP_INTR 5 + + #ifdef __cplusplus extern "C" { #endif @@ -77,6 +107,8 @@ extern "C" { */ #define DMA_DATA_TYPE_2_SIZE(type) (0b00000100 >> (type) ) +#define DMA_SELECTION_OFFSET_START 0 + /****************************************************************************/ /** **/ /** TYPEDEFS AND STRUCTURES **/ @@ -118,11 +150,11 @@ typedef enum */ typedef enum { - DMA_DATA_TYPE_WORD = DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD,/*!< + DMA_DATA_TYPE_WORD = DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD,/*!< Word = 4 bytes = 32 bits */ - DMA_DATA_TYPE_HALF_WORD = DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD,/*!< + DMA_DATA_TYPE_HALF_WORD = DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD,/*!< Half Word = 2 bytes = 16 bits */ - DMA_DATA_TYPE_BYTE = DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD,/*!< + DMA_DATA_TYPE_BYTE = DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD,/*!< Byte = 1 byte = 8 bits */ /* DMA_DATA_TYPE_BYTE_alt = DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD_2, * BYTE and BYTE_alt are interchangeable in hw, but we advice against @@ -134,6 +166,19 @@ typedef enum DMA_DATA_TYPE__undef, /*!< DMA will not be used. */ } dma_data_type_t; +typedef enum +{ + DMA_DIM_CONF_1D = 0, /* The DMA will copy data along D1 only. */ + DMA_DIM_CONF_2D = 1, /* The DMA will copy data along D1 and D2. */ + DMA_DIM_CONF__size, /* Not used, only for sanity checks. */ + /* + Padding is enabled with the 2D mode. This means that to pad a 1D + data structure, i.e. an array, the DMA would have to be set in 2D + mode with the D2 dimension set to 1. + This case is handled by the DMA HAL, so it's transparent to the user. + */ +} dma_dim_t; + /** * It is possible to choose the level of safety with which the DMA operation * should be configured. @@ -279,11 +324,15 @@ typedef struct if the target is a peripheral. */ uint8_t* ptr; /*!< Pointer to the start address from/to where data will be copied/pasted. */ - uint16_t inc_du; /*!< How much the pointer will increase + uint8_t inc_du; /*!< How much the pointer will increase every time a read/write operation is done. It is a multiple of the data units. Can be left blank if the target is a peripheral. */ - uint32_t size_du; /*!< The size (in data units) of the data to + uint32_t inc_d2_du; /*!< How much the D2 pointer will increase + every time the DMA finishes to read a #D1 of data units. */ + uint16_t size_du; /*!< The size (in data units) of the data to be copied. Can be left blank if the target will only be used as destination.*/ + uint16_t size_d2_du; /*!< The size (in data units) of the data + to be copied along D2.*/ dma_data_type_t type; /*!< The type of data to be transferred. Can be left blank if the target will only be used as destination. */ dma_trigger_slot_mask_t trig; /*!< If the target is a peripheral, a @@ -296,6 +345,7 @@ typedef struct * It also includes control parameters to override the targets' specific ones * if needed. */ + typedef struct { dma_target_t* src; /*!< Target from where the data will be @@ -306,11 +356,23 @@ typedef struct copied. - only valid in address mode */ uint16_t inc_b; /*!< A common increment in case both targets need to use one same increment. */ - uint32_t size_b; /*!< The size of the transfer, in bytes (in + uint32_t size_b; /*!< The size of the transfer along D1, in bytes (in + contrast, the size stored in the targets is in data units). */ + uint32_t size_d2_b; /*!< The size of the transfer along D2, in bytes (in contrast, the size stored in the targets is in data units). */ - dma_data_type_t type; /*!< The data type to use. One is chosen among + dma_dim_t dim; /*!< Sets the dimensionality of the + DMA, either 1D or 2D. */ + uint8_t pad_top_du; /*!< Padding at the top of the 2D transfer. */ + uint8_t pad_bottom_du; /*!< Padding at the bottom of the 2D transfer. */ + uint8_t pad_left_du; /*!< Padding at the left of the 2D transfer. */ + uint8_t pad_right_du; /*!< Padding at the right of the 2D transfer. */ + dma_data_type_t src_type; /*!< Source data type to use. One is chosen among the targets. */ + dma_data_type_t dst_type; /*!< Destination data type to use. One is chosen among + the targets. */ + uint8_t sign_ext; /*!< Whether to sign extend the data. */ dma_trans_mode_t mode; /*!< The copy mode to use. */ + uint8_t dim_inv; /*!< If the D1 and D2 dimensions are inverted, i.e. perform transposition. */ uint32_t win_du; /*!< The amount of data units every which the WINDOW_DONE flag is raised and its corresponding interrupt triggered. It can be set to 0 to disable this functionality. */ @@ -318,6 +380,7 @@ typedef struct is launched. */ dma_config_flags_t flags; /*!< A mask with possible issues aroused from the creation of the transaction. */ + uint8_t channel; /*!< The channel to use. */ } dma_trans_t; /****************************************************************************/ @@ -335,22 +398,62 @@ typedef struct /** * @brief Attends the plic interrupt. */ -void handler_irq_dma( uint32_t id ); +__attribute__((optimize("O0"))) void handler_irq_dma( uint32_t id ); /** * @brief This is a non-weak implementation of the function declared in * fast_intr_ctrl.c */ -void fic_irq_dma(void); +__attribute__((optimize("O0"))) void fic_irq_dma(void); + +/** + * @brief Writes a given value into the specified register. Its operation + * mimics that of bitfield_field32_write(), but does not require the use of + * a field structure, that is not always provided in the _regs.h file. + * @param p_val The value to be written. + * @param p_offset The register's offset from the peripheral's base address + * where the target register is located. + * @param p_mask The variable's mask to only modify its bits inside the whole + * register. + * @param p_sel The selection index (i.e. From which bit inside the register + * the value is to be written). + * @param p_peri The peripheral where the register is located. + */ +/* @ToDo: Consider changing the "mask" parameter for a bitfield definition +(see dma_regs.h) */ +inline void write_register( uint32_t p_val, + uint32_t p_offset, + uint32_t p_mask, + uint8_t p_sel, + dma* p_dma) +{ + /* + * The index is computed to avoid needing to access the structure + * as a structure. + */ + uint8_t index = p_offset / sizeof(uint32_t); + /* + * An intermediate variable "value" is used to prevent writing twice into + * the register. + */ + uint32_t value = (( uint32_t * ) p_dma ) [ index ]; + value &= ~( p_mask << p_sel ); + value |= (p_val & p_mask) << p_sel; + (( uint32_t * ) p_dma ) [ index ] = value; + +// @ToDo: mmio_region_write32(dma->base_addr, (ptrdiff_t)(DMA_SLOT_REG_OFFSET), (tx_slot_mask << DMA_SLOT_TX_TRIGGER_SLOT_OFFSET) + rx_slot_mask) + +} + /** *@brief Takes all DMA configurations to a state where no accidental * transaction can be performed. * It can be called anytime to reset the DMA control block. - * @param peri Pointer to a register address following the dma structure. By + * @param dma_peri Pointer to a register address following the dma structure. By * default (peri == NULL), the integrated DMA will be used. */ -void dma_init( dma *peri ); +void dma_init( dma *dma_peri); /** * @brief Creates a transaction that can be loaded into the DMA. @@ -381,7 +484,7 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * the result from inside target structure as an error could have appeared * before the creation of the structure. */ -dma_config_flags_t dma_load_transaction( dma_trans_t* p_trans ); +dma_config_flags_t dma_load_transaction( dma_trans_t* p_trans); /** * @brief Launches the loaded transaction. @@ -393,7 +496,7 @@ dma_config_flags_t dma_load_transaction( dma_trans_t* p_trans ); * loaded is not the desired one). * @retval DMA_CONFIG_OK == 0 otherwise. */ -dma_config_flags_t dma_launch( dma_trans_t* p_trans ); +dma_config_flags_t dma_launch( dma_trans_t* p_trans); /** * @brief Read from the done register of the DMA. Additionally decreases the @@ -402,41 +505,45 @@ dma_config_flags_t dma_launch( dma_trans_t* p_trans ); * running or a new transaction was launched. * Be careful when calling this function if interrupts were chosen as the end * event. + * @param channel The channel to read from. * @return Whether the DMA is working or not. It starts returning 0 as soon as * the dma_launch function has returned. * @retval 0 - DMA is working. * @retval 1 - DMA has finished the transmission. DMA is idle. */ -uint32_t dma_is_ready(void); +uint32_t dma_is_ready(uint8_t channel); /** * @brief Get the number of windows that have already been written. Resets on * the start of each transaction. + * @param channel The channel to read from. * @return The number of windows that have been written from this transaction. */ -uint32_t dma_get_window_count(void); +uint32_t dma_get_window_count(uint8_t channel); /** * @brief Prevent the DMA from relaunching the transaction automatically after * finishing the current one. It does not affect the currently running - * transaction. It has no effect if the DMA is operating in SINGULAR + * transaction. It has no effect if the DMA is operating in SINGLE * transaction mode. + * @param channel The channel to stop. */ -void dma_stop_circular(void); +void dma_stop_circular(uint8_t channel); /** * @brief DMA interrupt handler. * `dma.c` provides a weak definition of this symbol, which can be overridden * at link-time by providing an additional non-weak definition. +* @param channel The channel that triggered the interrupt. */ -void dma_intr_handler_trans_done(void); +void dma_intr_handler_trans_done(uint8_t channel); /** * @brief DMA interrupt handler. * `dma.c` provides a weak definition of this symbol, which can be overridden * at link-time by providing an additional non-weak definition. */ -void dma_intr_handler_window_done(void); +void dma_intr_handler_window_done(uint8_t channel); /** * @brief This weak implementation allows the user to override the threshold diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h index ce6169c1..408b23ae 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h @@ -25,27 +25,56 @@ extern "C" { // Addess data pointer (word aligned) #define DMA_ADDR_PTR_REG_OFFSET 0x8 -// Number of bytes to copy - Once a value is written, the copy starts -#define DMA_SIZE_REG_OFFSET 0xc +// Number of bytes to copy from, defined with respect to the first dimension +// - Once a value is written, the copy starts +#define DMA_SIZE_D1_REG_OFFSET 0xc +#define DMA_SIZE_D1_SIZE_MASK 0xffff +#define DMA_SIZE_D1_SIZE_OFFSET 0 +#define DMA_SIZE_D1_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = DMA_SIZE_D1_SIZE_MASK, .index = DMA_SIZE_D1_SIZE_OFFSET }) + +// Number of bytes to copy from, defined with respect to the second dimension +#define DMA_SIZE_D2_REG_OFFSET 0x10 +#define DMA_SIZE_D2_SIZE_MASK 0xffff +#define DMA_SIZE_D2_SIZE_OFFSET 0 +#define DMA_SIZE_D2_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = DMA_SIZE_D2_SIZE_MASK, .index = DMA_SIZE_D2_SIZE_OFFSET }) // Status bits are set to one if a given event occurred -#define DMA_STATUS_REG_OFFSET 0x10 +#define DMA_STATUS_REG_OFFSET 0x14 #define DMA_STATUS_READY_BIT 0 #define DMA_STATUS_WINDOW_DONE_BIT 1 -// Increment number of src/dst pointer every time a word is copied -#define DMA_PTR_INC_REG_OFFSET 0x14 -#define DMA_PTR_INC_SRC_PTR_INC_MASK 0xff -#define DMA_PTR_INC_SRC_PTR_INC_OFFSET 0 -#define DMA_PTR_INC_SRC_PTR_INC_FIELD \ - ((bitfield_field32_t) { .mask = DMA_PTR_INC_SRC_PTR_INC_MASK, .index = DMA_PTR_INC_SRC_PTR_INC_OFFSET }) -#define DMA_PTR_INC_DST_PTR_INC_MASK 0xff -#define DMA_PTR_INC_DST_PTR_INC_OFFSET 8 -#define DMA_PTR_INC_DST_PTR_INC_FIELD \ - ((bitfield_field32_t) { .mask = DMA_PTR_INC_DST_PTR_INC_MASK, .index = DMA_PTR_INC_DST_PTR_INC_OFFSET }) +// Increment the D1 source pointer every time a word is copied +#define DMA_SRC_PTR_INC_D1_REG_OFFSET 0x18 +#define DMA_SRC_PTR_INC_D1_INC_MASK 0x3f +#define DMA_SRC_PTR_INC_D1_INC_OFFSET 0 +#define DMA_SRC_PTR_INC_D1_INC_FIELD \ + ((bitfield_field32_t) { .mask = DMA_SRC_PTR_INC_D1_INC_MASK, .index = DMA_SRC_PTR_INC_D1_INC_OFFSET }) + +// Increment the D2 source pointer every time a word is copied +#define DMA_SRC_PTR_INC_D2_REG_OFFSET 0x1c +#define DMA_SRC_PTR_INC_D2_INC_MASK 0x7fffff +#define DMA_SRC_PTR_INC_D2_INC_OFFSET 0 +#define DMA_SRC_PTR_INC_D2_INC_FIELD \ + ((bitfield_field32_t) { .mask = DMA_SRC_PTR_INC_D2_INC_MASK, .index = DMA_SRC_PTR_INC_D2_INC_OFFSET }) + +// Increment the D1 destination pointer every time a word is copied +#define DMA_DST_PTR_INC_D1_REG_OFFSET 0x20 +#define DMA_DST_PTR_INC_D1_INC_MASK 0x3f +#define DMA_DST_PTR_INC_D1_INC_OFFSET 0 +#define DMA_DST_PTR_INC_D1_INC_FIELD \ + ((bitfield_field32_t) { .mask = DMA_DST_PTR_INC_D1_INC_MASK, .index = DMA_DST_PTR_INC_D1_INC_OFFSET }) + +// Increment the D2 destination pointer every time a word is copied +#define DMA_DST_PTR_INC_D2_REG_OFFSET 0x24 +#define DMA_DST_PTR_INC_D2_INC_MASK 0x7fffff +#define DMA_DST_PTR_INC_D2_INC_OFFSET 0 +#define DMA_DST_PTR_INC_D2_INC_FIELD \ + ((bitfield_field32_t) { .mask = DMA_DST_PTR_INC_D2_INC_MASK, .index = DMA_DST_PTR_INC_D2_INC_OFFSET }) // The DMA will wait for the signal -#define DMA_SLOT_REG_OFFSET 0x18 +#define DMA_SLOT_REG_OFFSET 0x28 #define DMA_SLOT_RX_TRIGGER_SLOT_MASK 0xffff #define DMA_SLOT_RX_TRIGGER_SLOT_OFFSET 0 #define DMA_SLOT_RX_TRIGGER_SLOT_FIELD \ @@ -55,19 +84,35 @@ extern "C" { #define DMA_SLOT_TX_TRIGGER_SLOT_FIELD \ ((bitfield_field32_t) { .mask = DMA_SLOT_TX_TRIGGER_SLOT_MASK, .index = DMA_SLOT_TX_TRIGGER_SLOT_OFFSET }) -// Width/type of the data to transfer -#define DMA_DATA_TYPE_REG_OFFSET 0x1c -#define DMA_DATA_TYPE_DATA_TYPE_MASK 0x3 -#define DMA_DATA_TYPE_DATA_TYPE_OFFSET 0 -#define DMA_DATA_TYPE_DATA_TYPE_FIELD \ - ((bitfield_field32_t) { .mask = DMA_DATA_TYPE_DATA_TYPE_MASK, .index = DMA_DATA_TYPE_DATA_TYPE_OFFSET }) -#define DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD 0x0 -#define DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD 0x1 -#define DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD 0x2 -#define DMA_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD_2 0x3 +// Width/type of the source data to transfer +#define DMA_SRC_DATA_TYPE_REG_OFFSET 0x2c +#define DMA_SRC_DATA_TYPE_DATA_TYPE_MASK 0x3 +#define DMA_SRC_DATA_TYPE_DATA_TYPE_OFFSET 0 +#define DMA_SRC_DATA_TYPE_DATA_TYPE_FIELD \ + ((bitfield_field32_t) { .mask = DMA_SRC_DATA_TYPE_DATA_TYPE_MASK, .index = DMA_SRC_DATA_TYPE_DATA_TYPE_OFFSET }) +#define DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD 0x0 +#define DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD 0x1 +#define DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD 0x2 +#define DMA_SRC_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD_2 0x3 + +// Width/type of the destination data to transfer +#define DMA_DST_DATA_TYPE_REG_OFFSET 0x30 +#define DMA_DST_DATA_TYPE_DATA_TYPE_MASK 0x3 +#define DMA_DST_DATA_TYPE_DATA_TYPE_OFFSET 0 +#define DMA_DST_DATA_TYPE_DATA_TYPE_FIELD \ + ((bitfield_field32_t) { .mask = DMA_DST_DATA_TYPE_DATA_TYPE_MASK, .index = DMA_DST_DATA_TYPE_DATA_TYPE_OFFSET }) +#define DMA_DST_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD 0x0 +#define DMA_DST_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD 0x1 +#define DMA_DST_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD 0x2 +#define DMA_DST_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD_2 0x3 + +// Is the data to be sign extended? (Checked only if the dst data type is +// wider than the src data type) +#define DMA_SIGN_EXT_REG_OFFSET 0x34 +#define DMA_SIGN_EXT_SIGNED_BIT 0 // Set the operational mode of the DMA -#define DMA_MODE_REG_OFFSET 0x20 +#define DMA_MODE_REG_OFFSET 0x38 #define DMA_MODE_MODE_MASK 0x3 #define DMA_MODE_MODE_OFFSET 0 #define DMA_MODE_MODE_FIELD \ @@ -76,17 +121,69 @@ extern "C" { #define DMA_MODE_MODE_VALUE_CIRCULAR_MODE 0x1 #define DMA_MODE_MODE_VALUE_ADDRESS_MODE 0x2 +// Set the dimensionality of the DMA +#define DMA_DIM_CONFIG_REG_OFFSET 0x3c +#define DMA_DIM_CONFIG_DMA_DIM_BIT 0 + +// DMA dimensionality inversion selector +#define DMA_DIM_INV_REG_OFFSET 0x40 +#define DMA_DIM_INV_SEL_BIT 0 + +// Set the top padding +#define DMA_PAD_TOP_REG_OFFSET 0x44 +#define DMA_PAD_TOP_PAD_MASK 0x3f +#define DMA_PAD_TOP_PAD_OFFSET 0 +#define DMA_PAD_TOP_PAD_FIELD \ + ((bitfield_field32_t) { .mask = DMA_PAD_TOP_PAD_MASK, .index = DMA_PAD_TOP_PAD_OFFSET }) + +// Set the bottom padding +#define DMA_PAD_BOTTOM_REG_OFFSET 0x48 +#define DMA_PAD_BOTTOM_PAD_MASK 0x3f +#define DMA_PAD_BOTTOM_PAD_OFFSET 0 +#define DMA_PAD_BOTTOM_PAD_FIELD \ + ((bitfield_field32_t) { .mask = DMA_PAD_BOTTOM_PAD_MASK, .index = DMA_PAD_BOTTOM_PAD_OFFSET }) + +// Set the right padding +#define DMA_PAD_RIGHT_REG_OFFSET 0x4c +#define DMA_PAD_RIGHT_PAD_MASK 0x3f +#define DMA_PAD_RIGHT_PAD_OFFSET 0 +#define DMA_PAD_RIGHT_PAD_FIELD \ + ((bitfield_field32_t) { .mask = DMA_PAD_RIGHT_PAD_MASK, .index = DMA_PAD_RIGHT_PAD_OFFSET }) + +// Set the left padding +#define DMA_PAD_LEFT_REG_OFFSET 0x50 +#define DMA_PAD_LEFT_PAD_MASK 0x3f +#define DMA_PAD_LEFT_PAD_OFFSET 0 +#define DMA_PAD_LEFT_PAD_FIELD \ + ((bitfield_field32_t) { .mask = DMA_PAD_LEFT_PAD_MASK, .index = DMA_PAD_LEFT_PAD_OFFSET }) + // Will trigger a every "WINDOW_SIZE" writes -#define DMA_WINDOW_SIZE_REG_OFFSET 0x24 +#define DMA_WINDOW_SIZE_REG_OFFSET 0x54 +#define DMA_WINDOW_SIZE_WINDOW_SIZE_MASK 0x1fff +#define DMA_WINDOW_SIZE_WINDOW_SIZE_OFFSET 0 +#define DMA_WINDOW_SIZE_WINDOW_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = DMA_WINDOW_SIZE_WINDOW_SIZE_MASK, .index = DMA_WINDOW_SIZE_WINDOW_SIZE_OFFSET }) // Number of times the end of the window was reached since the beginning. -#define DMA_WINDOW_COUNT_REG_OFFSET 0x28 +#define DMA_WINDOW_COUNT_REG_OFFSET 0x58 +#define DMA_WINDOW_COUNT_WINDOW_COUNT_MASK 0xff +#define DMA_WINDOW_COUNT_WINDOW_COUNT_OFFSET 0 +#define DMA_WINDOW_COUNT_WINDOW_COUNT_FIELD \ + ((bitfield_field32_t) { .mask = DMA_WINDOW_COUNT_WINDOW_COUNT_MASK, .index = DMA_WINDOW_COUNT_WINDOW_COUNT_OFFSET }) // Interrupt Enable Register -#define DMA_INTERRUPT_EN_REG_OFFSET 0x2c +#define DMA_INTERRUPT_EN_REG_OFFSET 0x5c #define DMA_INTERRUPT_EN_TRANSACTION_DONE_BIT 0 #define DMA_INTERRUPT_EN_WINDOW_DONE_BIT 1 +// Interrupt Flag Register for transactions +#define DMA_TRANSACTION_IFR_REG_OFFSET 0x60 +#define DMA_TRANSACTION_IFR_FLAG_BIT 0 + +// Interrupt Flag Register for windows +#define DMA_WINDOW_IFR_REG_OFFSET 0x64 +#define DMA_WINDOW_IFR_FLAG_BIT 0 + #ifdef __cplusplus } // extern "C" #endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c index 27c000a0..0493864e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.c @@ -29,6 +29,9 @@ /* MODULES USED */ /** **/ /****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif #include "fast_intr_ctrl.h" #include "core_v_mini_mcu.h" @@ -418,6 +421,9 @@ void handler_irq_fast_gpio_7(void) // call the weak fic handler fic_irq_gpio_7(); } +#ifdef __cplusplus +} +#endif /****************************************************************************/ /** **/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h index 87997551..46c0ada2 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/fast_intr_ctrl/fast_intr_ctrl.h @@ -32,7 +32,9 @@ /** MODULES USED **/ /** **/ /****************************************************************************/ - +#ifdef __cplusplus +extern "C" { +#endif #include #include #include "mmio.h" @@ -242,7 +244,9 @@ void fic_irq_gpio_7(void); /** INLINE FUNCTIONS **/ /** **/ /****************************************************************************/ - +#ifdef __cplusplus +} +#endif /****************************************************************************/ /** **/ /** EOF **/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c index f5cb004f..7f28db54 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/gpio/gpio.c @@ -23,7 +23,9 @@ * @version 1 * @brief GPIO driver */ - +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus /****************************************************************************/ /** **/ /* MODULES USED */ @@ -572,4 +574,9 @@ __attribute__((optimize("O0"))) static void gpio_handler_irq_dummy( uint32_t dum /** **/ /* EOF */ /** **/ -/****************************************************************************/ \ No newline at end of file +/****************************************************************************/ + + +#ifdef __cplusplus +} +#endif // __cplusplus \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl index 7f0d939e..52215d27 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/data/power_manager.h.tpl @@ -105,16 +105,16 @@ typedef struct power_manager_ram_map_t { uint32_t monitor_power_gate; } power_manager_ram_map_t; -static power_manager_ram_map_t power_manager_ram_map[${ram_numbanks}] = { -% for bank in range(ram_numbanks): +static power_manager_ram_map_t power_manager_ram_map[${xheep.ram_numbanks()}] = { +% for bank in xheep.iter_ram_banks(): (power_manager_ram_map_t) { - .clk_gate = POWER_MANAGER_RAM_${bank}_CLK_GATE_REG_OFFSET, - .power_gate_ack = POWER_MANAGER_POWER_GATE_RAM_BLOCK_${bank}_ACK_REG_OFFSET, - .switch_off = POWER_MANAGER_RAM_${bank}_SWITCH_REG_OFFSET, - .wait_ack_switch = POWER_MANAGER_RAM_${bank}_WAIT_ACK_SWITCH_ON_REG_OFFSET, - .iso = POWER_MANAGER_RAM_${bank}_ISO_REG_OFFSET, - .retentive = POWER_MANAGER_RAM_${bank}_RETENTIVE_REG_OFFSET, - .monitor_power_gate = POWER_MANAGER_MONITOR_POWER_GATE_RAM_BLOCK_${bank}_REG_OFFSET + .clk_gate = POWER_MANAGER_RAM_${bank.name()}_CLK_GATE_REG_OFFSET, + .power_gate_ack = POWER_MANAGER_POWER_GATE_RAM_BLOCK_${bank.name()}_ACK_REG_OFFSET, + .switch_off = POWER_MANAGER_RAM_${bank.name()}_SWITCH_REG_OFFSET, + .wait_ack_switch = POWER_MANAGER_RAM_${bank.name()}_WAIT_ACK_SWITCH_ON_REG_OFFSET, + .iso = POWER_MANAGER_RAM_${bank.name()}_ISO_REG_OFFSET, + .retentive = POWER_MANAGER_RAM_${bank.name()}_RETENTIVE_REG_OFFSET, + .monitor_power_gate = POWER_MANAGER_MONITOR_POWER_GATE_RAM_BLOCK_${bank.name()}_REG_OFFSET }, % endfor }; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager.c index 4a9c37a8..06677121 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager.c @@ -15,174 +15,7 @@ #include "x-heep.h" - -void __attribute__ ((noinline)) power_gate_core_asm() -{ - asm volatile ( - - // write POWER_GATE_CORE[0] = 1 - "lui a0, %[base_address_20bit]\n" - "li a1, 1\n" - "sw a1, %[power_manager_power_gate_core_reg_offset](a0)\n" - - // write WAKEUP_STATE[0] = 1 - "sw a1, %[power_manager_wakeup_state_reg_offset](a0)\n" : : \ - \ - [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ - [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ - [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET) : "a0", "a1" \ - ); - - asm volatile ( - - // write registers - "la a0, __power_manager_start\n" - "sw x1, 0(a0)\n" - "sw x2, 4(a0)\n" - "sw x3, 8(a0)\n" - "sw x4, 12(a0)\n" - "sw x5, 16(a0)\n" - "sw x6, 20(a0)\n" - "sw x7, 24(a0)\n" - "sw x8, 28(a0)\n" - "sw x9, 32(a0)\n" - "sw x10, 36(a0)\n" - "sw x11, 40(a0)\n" - "sw x12, 44(a0)\n" - "sw x13, 48(a0)\n" - "sw x14, 52(a0)\n" - "sw x15, 56(a0)\n" - "sw x16, 60(a0)\n" - "sw x17, 64(a0)\n" - "sw x18, 68(a0)\n" - "sw x19, 72(a0)\n" - "sw x20, 76(a0)\n" - "sw x21, 80(a0)\n" - "sw x22, 88(a0)\n" - "sw x23, 92(a0)\n" - "sw x24, 96(a0)\n" - "sw x25, 100(a0)\n" - "sw x26, 104(a0)\n" - "sw x27, 108(a0)\n" - "sw x28, 112(a0)\n" - "sw x29, 116(a0)\n" - "sw x30, 120(a0)\n" - "sw x31, 124(a0)\n" - //csr - "csrr a1, mstatus\n" - "sw a1, 128(a0)\n" - "csrr a1, mie\n" - "sw a1, 132(a0)\n" - "csrr a1, mtvec\n" - "sw a1, 136(a0)\n" - "csrr a1, mscratch\n" - "sw a1, 140(a0)\n" - "csrr a1, mepc\n" - "sw a1, 144(a0)\n" - "csrr a1, mcause\n" - "sw a1, 148(a0)\n" - "csrr a1, mtval\n" - "sw a1, 152(a0)\n" - "csrr a1, mcycle\n" - "sw a1, 156(a0)\n" - "csrr a1, minstret\n" - "sw a1, 160(a0)\n" : : : "a0", "a1" \ - ); - - asm volatile ( - - // write RESTORE_ADDRESS[31:0] = PC - "lui a0, %[base_address_20bit]\n" - "la a1, wakeup\n" - "sw a1, %[power_manager_restore_address_reg_offset](a0)\n" - - // wait for interrupt - "wfi\n" - - // ---------------------------- - // power-gate - // ---------------------------- - - // ---------------------------- - // wake-up - // ---------------------------- - - // write POWER_GATE_CORE[0] = 0 - "wakeup:" - "lui a0, %[base_address_20bit]\n" - "sw x0, %[power_manager_power_gate_core_reg_offset](a0)\n" - - // write WAKEUP_STATE[0] = 0 - "sw x0, %[power_manager_wakeup_state_reg_offset](a0)\n" - - // write RESTORE_ADDRESS[31:0] = 0 - "sw x0, %[power_manager_restore_address_reg_offset](a0)\n" : : \ - \ - [base_address_20bit] "i" (POWER_MANAGER_START_ADDRESS >> 12), \ - [power_manager_power_gate_core_reg_offset] "i" (POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET), \ - [power_manager_wakeup_state_reg_offset] "i" (POWER_MANAGER_WAKEUP_STATE_REG_OFFSET), \ - [power_manager_restore_address_reg_offset] "i" (POWER_MANAGER_RESTORE_ADDRESS_REG_OFFSET) : "a0", "a1" \ - ); - - asm volatile ( - - // write CORE_REG_Xn[31:0] = Xn - "la a0, __power_manager_start\n" - //one of the following load is gonna overwrite a0, but a0 was already stored before to the right value - "lw x1, 0(a0)\n" - "lw x2, 4(a0)\n" - "lw x3, 8(a0)\n" - "lw x4, 12(a0)\n" - "lw x5, 16(a0)\n" - "lw x6, 20(a0)\n" - "lw x7, 24(a0)\n" - "lw x8, 28(a0)\n" - "lw x9, 32(a0)\n" - "lw x10, 36(a0)\n" - "lw x11, 40(a0)\n" - "lw x12, 44(a0)\n" - "lw x13, 48(a0)\n" - "lw x14, 52(a0)\n" - "lw x15, 56(a0)\n" - "lw x16, 60(a0)\n" - "lw x17, 64(a0)\n" - "lw x18, 68(a0)\n" - "lw x19, 72(a0)\n" - "lw x20, 76(a0)\n" - "lw x21, 80(a0)\n" - "lw x22, 88(a0)\n" - "lw x23, 92(a0)\n" - "lw x24, 96(a0)\n" - "lw x25, 100(a0)\n" - "lw x26, 104(a0)\n" - "lw x27, 108(a0)\n" - "lw x28, 112(a0)\n" - "lw x29, 116(a0)\n" - "lw x30, 120(a0)\n" - "lw x31, 124(a0)\n" - //csr - "lw a1, 128(a0)\n" - "csrw mstatus, a1\n" - "lw a1, 132(a0)\n" - "csrw mie, a1\n" - "lw a1, 136(a0)\n" - "csrw mtvec, a1\n" - "lw a1, 140(a0)\n" - "csrw mscratch, a1\n" - "lw a1, 144(a0)\n" - "csrw mepc, a1\n" - "lw a1, 148(a0)\n" - "csrw mcause, a1\n" - "lw a1, 152(a0)\n" - "csrw mtval, a1\n" - "lw a1, 156(a0)\n" - "csrw mcycle, a1\n" - "lw a1, 160(a0)\n" - "csrw minstret, a1\n": : : "a0", "a1" \ - ); - - return; -} +extern void power_manager_cpu_store(); power_manager_result_t __attribute__ ((noinline)) power_gate_core(const power_manager_t *power_manager, power_manager_sel_intr_t sel_intr, power_manager_counters_t* cpu_counter) { @@ -201,14 +34,11 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_core(const power_ma mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_INTR_STATE_REG_OFFSET), 0x0); // enable wait for SWITCH ACK - #ifdef TARGET_PYNQ_Z2 - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, 0x0); - #else - reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, 0x1); - #endif + reg = bitfield_bit32_write(reg, POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_BIT, 0x1); + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_CPU_WAIT_ACK_SWITCH_ON_COUNTER_REG_OFFSET), reg); - power_gate_core_asm(); + power_manager_cpu_store(); // clean up states mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_EN_WAIT_FOR_INTR_REG_OFFSET), 0x0); @@ -231,11 +61,7 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_periph(const power_ { uint32_t reg = 0; - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_WAIT_ACK_SWITCH_ON_REG_OFFSET), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_WAIT_ACK_SWITCH_ON_REG_OFFSET), 0x1); - #endif + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(POWER_MANAGER_PERIPH_WAIT_ACK_SWITCH_ON_REG_OFFSET), 0x1); if (sel_state == kOn_e) { @@ -265,11 +91,7 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_ram_block(const pow if (sel_state == kOn_e) { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); - #endif + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); for (int i=0; iswitch_on; i++) asm volatile ("nop\n;"); mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].switch_off), 0x0); for (int i=0; iiso_off; i++) asm volatile ("nop\n;"); @@ -277,11 +99,7 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_ram_block(const pow } else if (sel_state == kOff_e) { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); - #endif + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].wait_ack_switch), 0x1); for (int i=0; iiso_on; i++) asm volatile ("nop\n;"); mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_ram_map[sel_block].iso), 0x1); for (int i=0; iswitch_off; i++) asm volatile ("nop\n;"); @@ -309,11 +127,7 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_external(const powe if (sel_state == kOn_e) { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); - #endif + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); for (int i=0; iswitch_on; i++) asm volatile ("nop\n;"); mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].switch_off), 0x0); for (int i=0; iiso_off; i++) asm volatile ("nop\n;"); @@ -323,11 +137,7 @@ power_manager_result_t __attribute__ ((noinline)) power_gate_external(const powe } else if (sel_state == kOff_e) { - #ifdef TARGET_PYNQ_Z2 - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x0); - #else - mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); - #endif + mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].wait_ack_switch), 0x1); for (int i=0; iiso_on; i++) asm volatile ("nop\n;"); mmio_region_write32(power_manager->base_addr, (ptrdiff_t)(power_manager_external_map[sel_external].iso), 0x1); for (int i=0; iswitch_off; i++) asm volatile ("nop\n;"); diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_restore.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_restore.S new file mode 100644 index 00000000..00c9f9f3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_restore.S @@ -0,0 +1,88 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include "core_v_mini_mcu.h" +#include "power_manager_regs.h" // Generated. + +# power_manager_cpu.S +# This function re-stores the CPU context when back from (deep) sleep +.global power_manager_cpu_restore +.type power_manager_cpu_restore, @function + +#define POWER_MANAGER_START_ADDRESS_20bit (POWER_MANAGER_START_ADDRESS >> 12) + + +power_manager_cpu_restore: + + //using lui to load the upper 20 bits of the address instead of la as I want to be sure no other registers are used + lui t0, POWER_MANAGER_START_ADDRESS_20bit + sw x0, POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET(t0) + + // write WAKEUP_STATE[0] = 0 + sw x0, POWER_MANAGER_WAKEUP_STATE_REG_OFFSET(t0) + + // write RESTORE_ADDRESS[31:0] = 0 + sw x0, POWER_MANAGER_RESTORE_ADDRESS_REG_OFFSET(t0) + + // restore gp as it is gonna be used to calculate the address of __power_manager_start + lw gp, POWER_MANAGER_GLOBAL_POINTER_REG_OFFSET(t0) + + // write CORE_REG_Xn[31:0] = Xn + la t0, __power_manager_start + // restore context, this part could be optimized + + //one of the following load is gonna overwrite t0, but t0 was already stored before to the right value + lw x1, 0(t0) + lw x2, 4(t0) + lw x3, 8(t0) + lw x4, 12(t0) + lw x5, 16(t0) + lw x6, 20(t0) + lw x7, 24(t0) + lw x8, 28(t0) + lw x9, 32(t0) + lw x10, 36(t0) + lw x11, 40(t0) + lw x12, 44(t0) + lw x13, 48(t0) + lw x14, 52(t0) + lw x15, 56(t0) + lw x16, 60(t0) + lw x17, 64(t0) + lw x18, 68(t0) + lw x19, 72(t0) + lw x20, 76(t0) + lw x21, 80(t0) + lw x22, 88(t0) + lw x23, 92(t0) + lw x24, 96(t0) + lw x25, 100(t0) + lw x26, 104(t0) + lw x27, 108(t0) + lw x28, 112(t0) + lw x29, 116(t0) + lw x30, 120(t0) + lw x31, 124(t0) + //csr + lw t1, 128(t0) + csrw mstatus, t1 + lw t1, 132(t0) + csrw mie, t1 + lw t1, 136(t0) + csrw mtvec, t1 + lw t1, 140(t0) + csrw mscratch, t1 + lw t1, 144(t0) + csrw mepc, t1 + lw t1, 148(t0) + csrw mcause, t1 + lw t1, 152(t0) + csrw mtval, t1 + lw t1, 156(t0) + csrw mcycle, t1 + lw t1, 160(t0) + csrw minstret, t1 + + + ret \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_store.S b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_store.S new file mode 100644 index 00000000..92e1ca8e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/power_manager/power_manager_cpu_store.S @@ -0,0 +1,88 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#include "core_v_mini_mcu.h" +#include "power_manager_regs.h" // Generated. + +# power_manager_cpu.S +# This function stores the CPU context, goes to (deep) sleep with WFI +.global power_manager_cpu_store # make the function visible to the linker +.type power_manager_cpu_store, @function + +power_manager_cpu_store: + + // write POWER_GATE_CORE[0] = 1 + la t0, POWER_MANAGER_START_ADDRESS + li t1, 1 + sw t1, POWER_MANAGER_POWER_GATE_CORE_REG_OFFSET(t0) + + // write WAKEUP_STATE[0] = 1, this is check in the bootrom at reset time when waking up + sw t1, POWER_MANAGER_WAKEUP_STATE_REG_OFFSET(t0) + + // save the global pointer, _power_manager_start is the start of the power_manager section and saved in the gp reg + // when returning from deep sleep, the gp register is used to restore the context, thus saving it in an always on register + sw gp, POWER_MANAGER_GLOBAL_POINTER_REG_OFFSET(t0) + + // save context, this part could be optimized + la t0, __power_manager_start + sw x1, 0(t0) + sw x2, 4(t0) + sw x3, 8(t0) + sw x4, 12(t0) + sw x5, 16(t0) + sw x6, 20(t0) + sw x7, 24(t0) + sw x8, 28(t0) + sw x9, 32(t0) + sw x10, 36(t0) + sw x11, 40(t0) + sw x12, 44(t0) + sw x13, 48(t0) + sw x14, 52(t0) + sw x15, 56(t0) + sw x16, 60(t0) + sw x17, 64(t0) + sw x18, 68(t0) + sw x19, 72(t0) + sw x20, 76(t0) + sw x21, 80(t0) + sw x22, 88(t0) + sw x23, 92(t0) + sw x24, 96(t0) + sw x25, 100(t0) + sw x26, 104(t0) + sw x27, 108(t0) + sw x28, 112(t0) + sw x29, 116(t0) + sw x30, 120(t0) + sw x31, 124(t0) + //csr + csrr t1, mstatus + sw t1, 128(t0) + csrr t1, mie + sw t1, 132(t0) + csrr t1, mtvec + sw t1, 136(t0) + csrr t1, mscratch + sw t1, 140(t0) + csrr t1, mepc + sw t1, 144(t0) + csrr t1, mcause + sw t1, 148(t0) + csrr t1, mtval + sw t1, 152(t0) + csrr t1, mcycle + sw t1, 156(t0) + csrr t1, minstret + sw t1, 160(t0) + + la t0, POWER_MANAGER_START_ADDRESS + //save return address to restore + la t1, power_manager_cpu_restore + sw t1, POWER_MANAGER_RESTORE_ADDRESS_REG_OFFSET(t0) + + // wait for interrupt + wfi + + ret \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c index ffbb822d..c7fb8c7c 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_plic/rv_plic.c @@ -34,6 +34,9 @@ /* MODULES USED */ /** **/ /****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif #include "rv_plic.h" #include "rv_plic_structs.h" @@ -72,7 +75,7 @@ const uint32_t plicMaxPriority = RV_PLIC_PRIO0_PRIO0_MASK; * Pointer used to dynamically access the different interrupt handlers. */ typedef void (*handler_funct_t)(uint32_t); - +//#endif /****************************************************************************/ /** **/ /* PROTOTYPES OF LOCAL FUNCTIONS */ @@ -366,8 +369,7 @@ plic_result_t plic_software_irq_is_pending(void) } -plic_result_t plic_assign_external_irq_handler( uint32_t id, - void *handler ) +plic_result_t plic_assign_external_irq_handler( uint32_t id, void *handler ) { if( id >= EXT_IRQ_START && id <= QTY_INTR ) { @@ -377,6 +379,7 @@ plic_result_t plic_assign_external_irq_handler( uint32_t id, return kPlicBadArg; } + void plic_reset_handlers_list(void) { handlers[NULL_INTR] = &handler_irq_dummy; @@ -433,7 +436,9 @@ static uint8_t plic_irq_bit_index( uint32_t irq) { return irq % RV_PLIC_PARAM_REG_WIDTH; } - +#ifdef __cplusplus +} +#endif /****************************************************************************/ /** **/ /* EOF */ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_timer/rv_timer.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_timer/rv_timer.h index 09f30945..cba44974 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_timer/rv_timer.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/rv_timer/rv_timer.h @@ -105,6 +105,12 @@ typedef enum rv_timer_approximate_tick_params_result { * @param[out] out Tick parameters that will approximately produce the desired * counter frequency. * @return The result of the operation. + * + * The minimum value for `counter_freq` is given by: + * counter_freq_min = (255/4096) * clock_freq + * For example, if the clock frequency is 15MHz, the minimum value for `counter_freq` is about + * 1 MHz. + * The maximum value for `counter_freq` is given by the clock frequency. */ rv_timer_approximate_tick_params_result_t rv_timer_approximate_tick_params(uint64_t clock_freq, uint64_t counter_freq, diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/soc_ctrl/soc_ctrl.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/soc_ctrl/soc_ctrl.h index 9cfa45af..fe0e33c7 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/soc_ctrl/soc_ctrl.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/soc_ctrl/soc_ctrl.h @@ -21,7 +21,7 @@ extern "C" { * Initialization parameters for SOC CTRL. * */ -typedef struct soc_ctrl { +typedef struct /*soc_ctrl*/ { /** * The base address for the soc_ctrl hardware registers. */ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.c index 3312b8cd..f22c2bdb 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.c @@ -1,127 +1,491 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : spi_host.c +** version : 1 +** date : 06/03/24 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ +/***************************************************************************/ +/***************************************************************************/ +/** +* @file spi_host.c +* @date 06/03/24 +* @author Llorenç Muela +* @brief The Serial Peripheral Interface (SPI) driver to set up and use the +* SPI peripheral +*/ + +/****************************************************************************/ +/** **/ +/* MODULES USED */ +/** **/ +/****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif #include "spi_host.h" -#include "mmio.h" #include "bitfield.h" -// SPI get functions -volatile uint8_t spi_get_tx_queue_depth(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - return bitfield_field32_read(status_reg, SPI_HOST_STATUS_TXQD_FIELD); +/****************************************************************************/ +/** **/ +/* DEFINITIONS AND MACROS */ +/** **/ +/****************************************************************************/ + +#define SPI_EVENTS_INDEX 0 +#define SPI_ERRORS_INDEX 0 + +#define SPI_CONFIGOPTS_ADDR(spi, csid) ((&SPI_HW(spi)->CONFIGOPTS0) + csid*sizeof(uint32_t)) + +/****************************************************************************/ +/** **/ +/* TYPEDEFS AND STRUCTURES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +/** + * @brief Function that translates the status register to spi_event_e type. This + * has been implemented because the SPI peripheral has no other way to know which + * event was triggered other than reading the status. + * This function has been made local since only the event interrupt handler should + * need it. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param events Pointer to store the events that were triggered. + * @return spi_return_flags_e indicating problems, SPI_FLAG_OK if all went well. + */ +spi_return_flags_e spi_get_events(spi_host_t* spi, spi_event_e* events); + +/** + * @brief Function to acknoledge event interrupts once received to prevent them + * from triggering again. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return spi_return_flags_e indicating problems, SPI_FLAG_OK if all went well. + */ +spi_return_flags_e spi_acknowledge_event(spi_host_t* spi); + +/****************************************************************************/ +/** **/ +/* EXPORTED VARIABLES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* EXPORTED FUNCTIONS */ +/** **/ +/****************************************************************************/ + +spi_return_flags_e spi_get_events_enabled(spi_host_t* spi, spi_event_e* events) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + *events = bitfield_read(SPI_HW(spi)->EVENT_ENABLE, SPI_EVENT_ALL, SPI_EVENTS_INDEX); + return SPI_FLAG_OK; } -volatile spi_ch_status_t spi_get_tx_channel_status(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - spi_ch_status_t ch_status = { - .empty = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_TXEMPTY_BIT), - .full = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_TXFULL_BIT), - .stall = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_TXSTALL_BIT), - .wm = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_TXWM_BIT) - }; - return ch_status; +spi_return_flags_e spi_set_events_enabled(spi_host_t* spi, spi_event_e events, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + if (events > SPI_EVENT_ALL) return SPI_FLAG_EVENT_INVALID; + // Since spi_event_e is mapped to EVENT_ENABLE: | = set, & ~ = clear + if (enable) SPI_HW(spi)->EVENT_ENABLE |= events; + else SPI_HW(spi)->EVENT_ENABLE &= ~events; + + return SPI_FLAG_OK; } -volatile uint8_t spi_get_rx_queue_depth(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - return bitfield_field32_read(status_reg, SPI_HOST_STATUS_RXQD_FIELD); +spi_return_flags_e spi_get_errors_enabled(spi_host_t* spi, spi_error_e* errors) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + *errors = bitfield_read(SPI_HW(spi)->ERROR_ENABLE, SPI_ERROR_IRQALL, SPI_ERRORS_INDEX); + return SPI_FLAG_OK; } -volatile spi_ch_status_t spi_get_rx_channel_status(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - spi_ch_status_t ch_status = { - .empty = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_RXEMPTY_BIT), - .full = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_RXFULL_BIT), - .stall = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_RXSTALL_BIT), - .wm = bitfield_bit32_read(status_reg, SPI_HOST_STATUS_RXWM_BIT) - }; - return ch_status; +spi_return_flags_e spi_set_errors_enabled(spi_host_t* spi, spi_error_e errors, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + if (errors > SPI_ERROR_IRQALL) return SPI_FLAG_ERROR_INVALID; + // Since spi_error_e is mapped to ERROR_ENABLE: | = set, & ~ = clear + if (enable) SPI_HW(spi)->ERROR_ENABLE |= errors; + else SPI_HW(spi)->ERROR_ENABLE &= ~errors; + + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_get_errors(spi_host_t* spi, spi_error_e* errors) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + *errors = bitfield_read(SPI_HW(spi)->ERROR_STATUS, SPI_ERROR_ALL, SPI_ERRORS_INDEX); + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_acknowledge_errors(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Write a one to each bit in ERROR_STATUS to clear these bits + SPI_HW(spi)->ERROR_STATUS = bitfield_write(SPI_HW(spi)->ERROR_STATUS, + SPI_ERROR_ALL, SPI_ERRORS_INDEX, + SPI_ERROR_ALL); + // Write a one to INTR_STATE error bit to clear the error + SPI_HW(spi)->INTR_STATE = bitfield_write(SPI_HW(spi)->INTR_STATE, BIT_MASK_1, + SPI_HOST_INTR_STATE_ERROR_BIT, true); + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_enable_error_intr_test(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->INTR_TEST = bitfield_write(SPI_HW(spi)->INTR_TEST, BIT_MASK_1, + SPI_HOST_INTR_TEST_ERROR_BIT, enable); + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_enable_evt_intr_test(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->INTR_TEST = bitfield_write(SPI_HW(spi)->INTR_TEST, BIT_MASK_1, + SPI_HOST_INTR_TEST_SPI_EVENT_BIT, enable); + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_alert_test_fatal_fault_trigger(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->ALERT_TEST = bitfield_write(SPI_HW(spi)->ALERT_TEST, BIT_MASK_1, + SPI_HOST_ALERT_TEST_FATAL_FAULT_BIT, true); + return SPI_FLAG_OK; +} + +volatile uint8_t spi_get_tx_queue_depth(spi_host_t* spi) +{ + // Returning an impossible value (tx fifo is 76 words long...) + SPI_NULL_CHECK(spi, UINT8_MAX) + return spi_get_status(spi).txqd; +} + +volatile uint8_t spi_get_rx_queue_depth(spi_host_t* spi) +{ + // Returning an impossible value (rx fifo is 64 words long...) + SPI_NULL_CHECK(spi, UINT8_MAX) + return spi_get_status(spi).rxqd; +} + +volatile uint32_t spi_get_csid(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, UINT32_MAX) + return SPI_HW(spi)->CSID; +} + +spi_return_flags_e spi_sw_reset(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Assert spi reset bit + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, BIT_MASK_1, + SPI_HOST_CONTROL_SW_RST_BIT, true); + + volatile spi_status_t status = spi_get_status(spi); + // Wait for spi active and txqd & rxqd both go to 0 + while (status.active || status.txqd || status.rxqd); + // Deassert spi reset bit + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, BIT_MASK_1, + SPI_HOST_CONTROL_SW_RST_BIT, false); + return SPI_FLAG_OK; } -volatile uint32_t spi_get_csid(const spi_host_t *spi) { - return mmio_region_read32(spi->base_addr, SPI_HOST_CSID_REG_OFFSET); +spi_return_flags_e spi_set_enable(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, BIT_MASK_1, + SPI_HOST_CONTROL_SPIEN_BIT, enable); + return SPI_FLAG_OK; } -// SPI set functions +spi_return_flags_e spi_set_tx_watermark(spi_host_t* spi, uint8_t watermark) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Check that watermark is not bigger than the fifo size (makes no sense otherwise) + if (watermark > SPI_HOST_PARAM_TX_DEPTH) return SPI_FLAG_WATERMARK_EXCEEDS; -void spi_sw_reset(const spi_host_t *spi) { - volatile uint32_t ctrl_reg = mmio_region_read32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET); - ctrl_reg = bitfield_bit32_write(ctrl_reg, SPI_HOST_CONTROL_SW_RST_BIT, 1); - mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, ctrl_reg); + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, + SPI_HOST_CONTROL_TX_WATERMARK_MASK, + SPI_HOST_CONTROL_TX_WATERMARK_OFFSET, + watermark); + return SPI_FLAG_OK; } -void spi_set_enable(const spi_host_t *spi, bool enable) { - volatile uint32_t ctrl_reg = mmio_region_read32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET); - ctrl_reg = bitfield_bit32_write(ctrl_reg, SPI_HOST_CONTROL_SPIEN_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, ctrl_reg); +spi_return_flags_e spi_set_rx_watermark(spi_host_t* spi, uint8_t watermark) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Check that watermark is not bigger than the fifo size (makes no sense otherwise) + if (watermark > SPI_HOST_PARAM_RX_DEPTH) return SPI_FLAG_WATERMARK_EXCEEDS; + + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, + SPI_HOST_CONTROL_RX_WATERMARK_MASK, + SPI_HOST_CONTROL_RX_WATERMARK_OFFSET, + watermark); + return SPI_FLAG_OK; } -void spi_set_tx_watermark(const spi_host_t *spi, uint8_t watermark) { - volatile uint32_t ctrl_reg = mmio_region_read32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET); - ctrl_reg = bitfield_field32_write(ctrl_reg, SPI_HOST_CONTROL_TX_WATERMARK_FIELD, watermark); - mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, ctrl_reg); +spi_return_flags_e spi_set_configopts(spi_host_t* spi, uint32_t csid, const uint32_t conf_reg) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + if (SPI_CSID_INVALID(csid)) return SPI_FLAG_CSID_INVALID; + // Since the configopts registers always follow one after another, offset + // by csid times address delta + *SPI_CONFIGOPTS_ADDR(spi, csid) = conf_reg; + return SPI_FLAG_OK; } -void spi_set_rx_watermark(const spi_host_t *spi, uint8_t watermark) { - volatile uint32_t ctrl_reg = mmio_region_read32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET); - ctrl_reg = bitfield_field32_write(ctrl_reg, SPI_HOST_CONTROL_RX_WATERMARK_FIELD, watermark); - mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, ctrl_reg); +spi_return_flags_e spi_get_configopts(spi_host_t* spi, uint32_t csid, uint32_t* conf_reg) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + if (SPI_CSID_INVALID(csid)) return SPI_FLAG_CSID_INVALID; + // Since the configopts registers always follow one after another, offset + // by csid times address delta + *conf_reg = *SPI_CONFIGOPTS_ADDR(spi, csid); + return SPI_FLAG_OK; } -void spi_set_configopts(const spi_host_t *spi, uint32_t csid, const uint32_t conf_reg) { - mmio_region_write32(spi->base_addr, sizeof(uint32_t) * csid + SPI_HOST_CONFIGOPTS_0_REG_OFFSET, conf_reg); +spi_return_flags_e spi_set_csid(spi_host_t* spi, uint32_t csid) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + if (SPI_CSID_INVALID(csid)) return SPI_FLAG_CSID_INVALID; + + SPI_HW(spi)->CSID = csid; + return SPI_FLAG_OK; } -void spi_set_csid(const spi_host_t* spi, uint32_t csid) { - mmio_region_write32(spi->base_addr, SPI_HOST_CSID_REG_OFFSET, csid); +spi_return_flags_e spi_set_command(spi_host_t* spi, const uint32_t cmd_reg) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + + spi_return_flags_e flags = SPI_FLAG_OK; + spi_speed_e speed = bitfield_read(cmd_reg, SPI_HOST_COMMAND_SPEED_MASK, + SPI_HOST_COMMAND_SPEED_OFFSET); + spi_dir_e direction = bitfield_read(cmd_reg, SPI_HOST_COMMAND_DIRECTION_MASK, + SPI_HOST_COMMAND_DIRECTION_OFFSET); + + // Incompatible speed and direction produces an error + if (!spi_validate_cmd(direction, speed)) flags |= SPI_FLAG_SPEED_INVALID; + // Writing a command while not ready produces an error + if (spi_get_ready(spi) != SPI_TRISTATE_TRUE) flags |= SPI_FLAG_NOT_READY; + if (flags) return flags; + + SPI_HW(spi)->COMMAND = cmd_reg; + return SPI_FLAG_OK; } -void spi_set_command(const spi_host_t *spi, const uint32_t cmd_reg) { - mmio_region_write32(spi->base_addr, SPI_HOST_COMMAND_REG_OFFSET, cmd_reg); +spi_return_flags_e spi_write_word(spi_host_t* spi, uint32_t wdata) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Check we're not overflowing + if (spi_get_tx_queue_depth(spi) >= SPI_HOST_PARAM_TX_DEPTH) + return SPI_FLAG_TX_QUEUE_FULL; + SPI_HW(spi)->TXDATA = wdata; + return SPI_FLAG_OK; } -void spi_write_word(const spi_host_t *spi, uint32_t wdata) { - mmio_region_write32(spi->base_addr, SPI_HOST_TXDATA_REG_OFFSET, wdata); +spi_return_flags_e spi_write_byte(spi_host_t* spi, uint8_t bdata) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Check we're not overflowing + if (spi_get_tx_queue_depth(spi) >= SPI_HOST_PARAM_TX_DEPTH) + return SPI_FLAG_TX_QUEUE_FULL; + SPI_HW(spi)->TXDATA = bdata; + return SPI_FLAG_OK; } -void spi_read_word(const spi_host_t *spi, uint32_t* dst) { - *dst = mmio_region_read32(spi->base_addr, SPI_HOST_RXDATA_REG_OFFSET); +spi_return_flags_e spi_read_word(spi_host_t* spi, uint32_t* dst) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + // Check we're not underflowing + if (spi_get_rx_queue_depth(spi) == 0) return SPI_FLAG_RX_QUEUE_EMPTY; + *dst = SPI_HW(spi)->RXDATA; + return SPI_FLAG_OK; } -void spi_enable_evt_intr(const spi_host_t *spi, bool enable) { - volatile uint32_t intr_enable_reg = mmio_region_read32(spi->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET); - intr_enable_reg = bitfield_bit32_write(intr_enable_reg, SPI_HOST_INTR_ENABLE_SPI_EVENT_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET, intr_enable_reg); +spi_return_flags_e spi_enable_evt_intr(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->INTR_ENABLE = bitfield_write(SPI_HW(spi)->INTR_ENABLE, BIT_MASK_1, + SPI_HOST_INTR_ENABLE_SPI_EVENT_BIT, + enable); + return SPI_FLAG_OK; } -void spi_enable_error_intr(const spi_host_t *spi, bool enable) { - volatile uint32_t intr_enable_reg = mmio_region_read32(spi->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET); - intr_enable_reg = bitfield_bit32_write(intr_enable_reg, SPI_HOST_INTR_STATE_ERROR_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET, intr_enable_reg); +spi_return_flags_e spi_enable_error_intr(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->INTR_ENABLE = bitfield_write(SPI_HW(spi)->INTR_ENABLE, BIT_MASK_1, + SPI_HOST_INTR_STATE_ERROR_BIT, + enable); + return SPI_FLAG_OK; } -void spi_enable_rxwm_intr(const spi_host_t *spi, bool enable) { - volatile uint32_t intr_enable_reg = mmio_region_read32(spi->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET); - intr_enable_reg = bitfield_bit32_write(intr_enable_reg, SPI_HOST_EVENT_ENABLE_RXWM_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET, intr_enable_reg); +spi_return_flags_e spi_output_enable(spi_host_t* spi, bool enable) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + SPI_HW(spi)->CONTROL = bitfield_write(SPI_HW(spi)->CONTROL, BIT_MASK_1, + SPI_HOST_CONTROL_OUTPUT_EN_BIT, enable); + return SPI_FLAG_OK; } -void spi_enable_txempty_intr(const spi_host_t *spi, bool enable) { - volatile uint32_t intr_enable_reg = mmio_region_read32(spi->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET); - intr_enable_reg = bitfield_bit32_write(intr_enable_reg, SPI_HOST_EVENT_ENABLE_TXEMPTY_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET, intr_enable_reg); +// PLIC handles SPI Host 2 interrupts +void handler_irq_spi(uint32_t id) +{ + spi_error_e errors; + // Get errors and check if error triggered the interrupt + spi_get_errors(spi_host2, &errors); + if (errors) { + // Call either weak error handler in this module, or user implementation + spi_intr_handler_error_host2(errors); + } + else { + // If it wasn't an error it must have been an event + spi_event_e events; + // We need to acknowledge the event to avoid triggering in loop + spi_acknowledge_event(spi_host2); + spi_get_events(spi_host2, &events); + // Call either weak event handler in this module, or user implementation + spi_intr_handler_event_host2(events); + } } -void spi_output_enable(const spi_host_t *spi, bool enable){ - volatile uint32_t output_enable_reg = mmio_region_read32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET); - output_enable_reg = bitfield_bit32_write(output_enable_reg, SPI_HOST_CONTROL_OUTPUT_EN_BIT, enable); - mmio_region_write32(spi->base_addr, SPI_HOST_CONTROL_REG_OFFSET, output_enable_reg); +// FIC SPI Host 1 interrupt handler +void fic_irq_spi(void) +{ + spi_error_e errors; + // Get errors and check if error triggered the interrupt + spi_get_errors(spi_host1, &errors); + if (errors) { + // Call either weak error handler in this module, or user implementation + spi_intr_handler_error_host(errors); + } + else { + // If it wasn't an error it must have been an event + spi_event_e events; + // We need to acknowledge the event to avoid triggering in loop + spi_acknowledge_event(spi_host1); + spi_get_events(spi_host1, &events); + // Call either weak event handler in this module, or user implementation + spi_intr_handler_event_host(events); + } } -__attribute__((weak, optimize("O0"))) void handler_irq_spi(uint32_t id) +// FIC SPI Flash interrupt handler +void fic_irq_spi_flash(void) { - // Replace this function with a non-weak implementation -} \ No newline at end of file + spi_error_e errors; + // Get errors and check if error triggered the interrupt + spi_get_errors(spi_flash, &errors); + if (errors) { + // Call either weak error handler in this module, or user implementation + spi_intr_handler_error_flash(errors); + } + else { + // If it wasn't an error it must have been an event + spi_event_e events; + // We need to acknowledge the event to avoid triggering in loop + spi_acknowledge_event(spi_flash); + spi_get_events(spi_flash, &events); + // Call either weak event handler in this module, or user implementation + spi_intr_handler_event_flash(events); + } +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_event_flash(spi_event_e events) { + +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_error_flash(spi_error_e errors) { + +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_event_host(spi_event_e events) { + +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_error_host(spi_error_e errors) { + +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_event_host2(spi_event_e events) { + +} + +__attribute__((weak, optimize("O0"))) void spi_intr_handler_error_host2(spi_error_e errors) { + +} + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +spi_return_flags_e spi_get_events(spi_host_t* spi, spi_event_e* events) { + // This function is somewhat a little cheat. Since there is no hardware implementation + // telling which event triggered the interrupt, we just read the status register and + // map the statuses to their respective event. This allows to pass a pseudo-event + // variable to the event handlers. + volatile spi_status_t status = spi_get_status(spi); + // Also, we do not need any NULL check since this function is made to be called + // __ONLY__ from `handler_irq_spi`, `fic_irq_spi`, `fic_irq_spi_flash`. + // Therefore we know that spi argument will not be NULL. + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_RXFULL_BIT, status.rxfull); + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_TXEMPTY_BIT, status.txempty); + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_RXWM_BIT, status.rxwm); + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_TXWM_BIT, status.txwm); + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_READY_BIT, status.ready); + *events = bitfield_write(*events, BIT_MASK_1, + SPI_HOST_EVENT_ENABLE_IDLE_BIT, ~status.active); + return SPI_FLAG_OK; +} + +spi_return_flags_e spi_acknowledge_event(spi_host_t* spi) { + // We do not need any NULL check since this function is made to be called + // __ONLY__ from `handler_irq_spi`, `fic_irq_spi`, `fic_irq_spi_flash`. + // Therefore we know that spi argument will not be NULL. + SPI_HW(spi)->INTR_STATE = bitfield_write(SPI_HW(spi)->INTR_STATE, BIT_MASK_1, + SPI_HOST_INTR_STATE_SPI_EVENT_BIT, true); + return SPI_FLAG_OK; +} +#ifdef __cplusplus +} +#endif +/****************************************************************************/ +/** **/ +/* EOF */ +/** **/ +/****************************************************************************/ \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h index af81fe21..6eef81b9 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/spi_host/spi_host.h @@ -1,360 +1,1014 @@ -// Copyright EPFL contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : spi_host.h +** version : 1 +** date : 06/03/24 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ -// Basic device functions for opentitan SPI host +/***************************************************************************/ +/***************************************************************************/ +/** +* @file spi_host.h +* @date 06/03/24 +* @author Llorenç Muela +* @brief The Serial Peripheral Interface (SPI) driver to set up and use the +* SPI peripheral +*/ #ifndef _DRIVERS_SPI_HOST_H_ #define _DRIVERS_SPI_HOST_H_ +/****************************************************************************/ +/** **/ +/** MODULES USED **/ +/** **/ +/****************************************************************************/ + #include +#include + +#include "fast_intr_ctrl.h" +#include "rv_plic.h" + +#include "spi_host_regs.h" // Generated +#include "spi_host_structs.h" // Generated + +/****************************************************************************/ +/** **/ +/** DEFINITIONS AND MACROS **/ +/** **/ +/****************************************************************************/ + +#define SPI_CSID_INVALID(csid) csid >= SPI_HOST_PARAM_NUM_C_S + +#define spi_host1_peri ((volatile spi_host *) SPI_HOST_START_ADDRESS) +#define spi_host2_peri ((volatile spi_host *) SPI2_START_ADDRESS) +#define spi_flash_peri ((volatile spi_host *) SPI_FLASH_START_ADDRESS) + +#define spi_host1 ((spi_host_t*) spi_host1_peri) +#define spi_host2 ((spi_host_t*) spi_host2_peri) +#define spi_flash ((spi_host_t*) spi_flash_peri) + +#define SPI_HW(spi_inst) ((volatile spi_host *) spi_inst) -#include "mmio.h" -#include "spi_host_regs.h" +// Sanity check to return retval when spi is NULL. +// For development purposes. If 100% sure spi will NEVER be NULL, comment out +// the macro expansion to speed up SPI HAL. +#define SPI_NULL_CHECK(spi,retval) if (spi == NULL) return retval; #ifdef __cplusplus extern "C" { #endif -/** - * Initialization parameters for SPI. - * - */ -typedef struct spi { - /** - * The base address for the SPI hardware registers. - */ - mmio_region_t base_addr; -} spi_host_t; +/****************************************************************************/ +/** **/ +/** TYPEDEFS AND STRUCTURES **/ +/** **/ +/****************************************************************************/ /** -* SPI channel status structure +* SPI endianness */ -typedef struct spi_ch_status { - bool empty : 1; - bool full : 1; - bool wm : 1; - bool stall : 1; -} spi_ch_status_t; +typedef enum { + SPI_BYTE_ORDER_BIG_ENDIAN = 0, + SPI_BYTE_ORDER_LITTLE_ENDIAN = 1 +} spi_byte_order_e; /** * SPI speed type */ typedef enum { - kSpiSpeedStandard = 0, - kSpiSpeedDual = 1, - kSpiSpeedQuad = 2 + SPI_SPEED_STANDARD = 0, + SPI_SPEED_DUAL = 1, + SPI_SPEED_QUAD = 2 } spi_speed_e; /** * SPI directionality */ typedef enum { - kSpiDirDummy = 0, - kSpiDirRxOnly = 1, - kSpiDirTxOnly = 2, - kSpiDirBidir = 3 + SPI_DIR_DUMMY = 0, + SPI_DIR_RX_ONLY = 1, + SPI_DIR_TX_ONLY = 2, + SPI_DIR_BIDIR = 3 } spi_dir_e; +/** +* SPI events +*/ +typedef enum { + SPI_EVENT_NONE = 0, + // Triggers event when RX becomes full + SPI_EVENT_RXFULL = (1 << SPI_HOST_EVENT_ENABLE_RXFULL_BIT), + // Triggers event when TX becomes empty + SPI_EVENT_TXEMPTY = (1 << SPI_HOST_EVENT_ENABLE_TXEMPTY_BIT), + // Triggers event when RX goes above watermark + SPI_EVENT_RXWM = (1 << SPI_HOST_EVENT_ENABLE_RXWM_BIT), + // Triggers event when TX falls below watermark + SPI_EVENT_TXWM = (1 << SPI_HOST_EVENT_ENABLE_TXWM_BIT), + // Triggers event as soon as SPI Host IP is ready to receive more commands + SPI_EVENT_READY = (1 << SPI_HOST_EVENT_ENABLE_READY_BIT), + // Triggers event as soon as SPI Host IP is not processing any command + SPI_EVENT_IDLE = (1 << SPI_HOST_EVENT_ENABLE_IDLE_BIT), + // All the above mentioned events + SPI_EVENT_ALL = (1 << SPI_HOST_EVENT_ENABLE_IDLE_BIT+1) - 1 +} spi_event_e; + +/** +* SPI errors +*/ +typedef enum { + SPI_ERROR_NONE = 0, + // Triggers error interrupt whenever a command is issued while busy. + SPI_ERROR_CMDBUSY = (1 << SPI_HOST_ERROR_ENABLE_CMDBUSY_BIT), + // Triggers error interrupt whenever the TX FIFO overflows. + SPI_ERROR_OVERFLOW = (1 << SPI_HOST_ERROR_ENABLE_OVERFLOW_BIT), + // Triggers error interrupt whenever there is a read from RXDATA but the RX + // FIFO is empty. + SPI_ERROR_UNDERFLOW = (1 << SPI_HOST_ERROR_ENABLE_UNDERFLOW_BIT), + // Triggers error interrupt whenever a command is sent with invalid values for + // COMMAND.SPEED or COMMAND.DIRECTION. + SPI_ERROR_CMDINVAL = (1 << SPI_HOST_ERROR_ENABLE_CMDINVAL_BIT), + // Triggers error interrupt whenever a command is submitted, but CSID exceeds + // NumCS. + SPI_ERROR_CSIDINVAL = (1 << SPI_HOST_ERROR_ENABLE_CSIDINVAL_BIT), + // INDICATES that TLUL attempted to write to TXDATA with no bytes enabled. + // This error cannot be set (enabled or disabled). + // This error should never happen since it is the hardware that controls this. + SPI_ERROR_ACCESSINVAL = (1 << SPI_HOST_ERROR_STATUS_ACCESSINVAL_BIT), + // All the above mentioned errors that can be set. + SPI_ERROR_IRQALL = (1 << SPI_HOST_ERROR_ENABLE_CSIDINVAL_BIT+1) - 1, + // All the above mentioned errors. + SPI_ERROR_ALL = (1 << SPI_HOST_ERROR_STATUS_ACCESSINVAL_BIT+1) - 1 +} spi_error_e; + +/** +* SPI functions return flags, informs user what problem there was or if all OK +*/ +typedef enum { + // Everithing went well + SPI_FLAG_OK = 0x0000, + // The SPI variabled passed was a null pointer + SPI_FLAG_NULL_PTR = 0x0001, + // The Watermark exceeded SPI_HOST_PARAM_TX_DEPTH or SPI_HOST_PARAM_RX_DEPTH + // and was therefore not set + SPI_FLAG_WATERMARK_EXCEEDS = 0x0002, + // The CSID was out of the bounds specified inSPI_HOST_PARAM_NUM_C_S + SPI_FLAG_CSID_INVALID = 0x0004, + // The CMD FIFO is currently full so couldn't write command + SPI_FLAG_COMMAND_FULL = 0x0008, + // The specified speed is not valid so couldn't write command + SPI_FLAG_SPEED_INVALID = 0x0010, + // The TX Queue is full, thus could not write to TX register + SPI_FLAG_TX_QUEUE_FULL = 0x0020, + // The RX Queue is empty, thus could not read from RX register + SPI_FLAG_RX_QUEUE_EMPTY = 0x0040, + // The SPI is not ready + SPI_FLAG_NOT_READY = 0x0080, + // The event to enable is not a valid event + SPI_FLAG_EVENT_INVALID = 0x0100, + // The error irq to enable is not a valid error irq + SPI_FLAG_ERROR_INVALID = 0x0200 +} spi_return_flags_e; + +/** +* Extended bool to return if a function catched an error +*/ +typedef enum { + SPI_TRISTATE_ERROR = 0, + SPI_TRISTATE_TRUE = 1, + SPI_TRISTATE_FALSE = 2 +} spi_tristate_e; + +/** + * Opaque structure definition to hide the registers. + */ +typedef struct spi_s spi_host_t; + /** * SPI chip (slave) configuration structure */ -typedef struct spi_configopts { +typedef struct spi_configopts_s { + // The clock divider to use with a paricular slave uint16_t clkdiv : 16; - uint8_t csnidle : 4; + // Indicates the minimum number of sck half-cycles to hold cs_n high between + // commands + uint8_t csnidle : 4; + // Indicates the number of half sck cycles, CSNTRAIL+1, to leave between last + // edge of sck and the rising edge of cs_n uint8_t csntrail : 4; + // Indicates the number of half sck cycles, CSNLEAD+1, to leave between the + // falling edge of cs_n and the first edge of sck uint8_t csnlead : 4; + // Will be ignored by hardware bool __rsvd0 : 1; + // If 1 data is sampled a full cycle after shifting data out, instead of half cycle bool fullcyc : 1; + // If 0 data lines change on trailing edge and sample done on leading edge, + // if 1 it is the opposite bool cpha : 1; + // If 0 sck is low when idle, and emits high pulses. If 1 sck is high when idle, + // and emits of low pulses bool cpol : 1; } spi_configopts_t; /** * SPI command structure */ -typedef struct spi_command { +typedef struct spi_command_s { + // Length-1 in bytes for the command to transmit/receive uint32_t len : 24; + // Keep CS line active after command has finished (allows to instruct series + // of commands) bool csaat : 1; + // Speed of communication spi_speed_e speed : 2; + // Direction of communication spi_dir_e direction : 2; } spi_command_t; -// SPI registers access functions +/** +* SPI status structure +*/ +typedef struct spi_status_s { + union { + struct { + // TX queue depth (how many unsent words are in the FIFO) + uint8_t txqd : 8; + // RX queue depth (how many unread words are in the FIFO) + uint8_t rxqd : 8; + // CMD queue depth (how many unprocessed commands are in the FIFO) + uint8_t cmdqd : 4; + // Indicates wether rxqd is above the RX Watermark + bool rxwm : 1; + // Not used + bool __rsvd0 : 1; + // The endianness of the SPI Peripheral + bool byteorder : 1; + // Indicates if the SPI still still has more data to read but the RX FIFO is full + bool rxstall : 1; + // Indicates RX FIFO is empty + bool rxempty : 1; + // Indicates RX FIFO is full + bool rxfull : 1; + // Indicates wether txqd is below the TX Watermark + bool txwm : 1; + // Indicates if the SPI still has more data to send but the TX FIFO is empty + bool txstall : 1; + // Indicates TX FIFO is empty + bool txempty : 1; + // Indicates TX FIFO is full + bool txfull : 1; + // Indicates if the SPI peripheral is currently processing a command + bool active : 1; + // Indicates if the SPI peripheral is ready to receive more commands + bool ready : 1; + }; + uint32_t value; // This allows accessing all the bitfields as a single 32-bit integer + }; +} spi_status_t; + + +/****************************************************************************/ +/** **/ +/** EXPORTED VARIABLES **/ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/** EXPORTED FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +/** + * @brief Get enabled events for a specified SPI peripheral. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param events Pointer to store enabled event interrupts. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_get_events_enabled(spi_host_t* spi, spi_event_e* events); + +/** + * @brief Set enabled events for a specified SPI peripheral. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param events Pointer to events to enable/disable and to store the currently enabled + * event interrupts. + * @param enable Flag to enable (true) or disable (false) the specified event interrupts. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_EVENT_INVALID if events not valid. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_set_events_enabled(spi_host_t* spi, spi_event_e events, bool enable); + +/** + * @brief Get enabled error interrupts for a specified SPI peripheral. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param errors Pointer to store enabled error interrupts. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_get_errors_enabled(spi_host_t* spi, spi_error_e* errors); + +/** + * @brief Set enabled error interrupts for a specified SPI peripheral. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param errors Pointer to error interrupts to enable/disable and to store the currently + * enabled error interrupts. + * @param enable Flag to enable (true) or disable (false) the specified error interrupts. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_ERROR_INVALID if errors not valid. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_set_errors_enabled(spi_host_t* spi, spi_error_e errors, bool enable); /** - * Read the TX FIFO depth register. + * @brief Get the errors that have raised if any. * * @param spi Pointer to spi_host_t representing the target SPI. - * @return TX FIFO depth. + * @param errors Pointer to store the errors. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -volatile uint8_t spi_get_tx_queue_depth(const spi_host_t *spi); +spi_return_flags_e spi_get_errors(spi_host_t* spi, spi_error_e* errors); /** - * Read the TX channel status register. + * @brief Acknoledge the errors that have raised once solved in order to renable + * the SPI peripheral operation. * * @param spi Pointer to spi_host_t representing the target SPI. - * @return TX channel status structure. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -volatile spi_ch_status_t spi_get_tx_channel_status(const spi_host_t *spi); +spi_return_flags_e spi_acknowledge_errors(spi_host_t* spi); /** - * Read the RX FIFO depth register. + * @brief Enable or disable error interrupt test mode for a specified SPI peripheral. * * @param spi Pointer to spi_host_t representing the target SPI. - * @return RX FIFO depth. + * @param enable Flag to enable (true) or disable (false) error interrupt test mode. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -volatile uint8_t spi_get_rx_queue_depth(const spi_host_t *spi); +spi_return_flags_e spi_enable_error_intr_test(spi_host_t* spi, bool enable); /** - * Read the RX channel status register. + * @brief Enable or disable event interrupt test mode for a specified SPI peripheral. * * @param spi Pointer to spi_host_t representing the target SPI. - * @return RX channel status structure. + * @param enable Flag to enable (true) or disable (false) event interrupt test mode. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -volatile spi_ch_status_t spi_get_rx_channel_status(const spi_host_t *spi); +spi_return_flags_e spi_enable_evt_intr_test(spi_host_t* spi, bool enable); /** - * Read the Chip Select (CS) ID register. + * @brief Trigger a fatal fault test alert for a specified SPI peripheral. * * @param spi Pointer to spi_host_t representing the target SPI. - * @return Chip Select (CS) ID. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -volatile uint32_t spi_get_csid(const spi_host_t *spi); +spi_return_flags_e spi_alert_test_fatal_fault_trigger(spi_host_t* spi); /** - * Reset the SPI from software. + * @brief Read the TX FIFO depth register. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return TX FIFO depth. UINT8_MAX if spi is NULL. */ -void spi_sw_reset(const spi_host_t *spi); +volatile uint8_t spi_get_tx_queue_depth(spi_host_t* spi); /** - * Enable the SPI host. + * @brief Read the RX FIFO depth register. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return RX FIFO depth. UINT8_MAX if spi is NULL. + */ +volatile uint8_t spi_get_rx_queue_depth(spi_host_t* spi); + +/** + * @brief Read the Chip Select (CS) ID register. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return Chip Select (CS) ID. UINT32_MAX if spi is NULL. + */ +volatile uint32_t spi_get_csid(spi_host_t* spi); + +/** + * @brief Reset the SPI from software. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_sw_reset(spi_host_t* spi); + +/** + * @brief Enable the SPI host. * * @param spi Pointer to spi_host_t representing the target SPI. * @param enable SPI enable register value. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -void spi_set_enable(const spi_host_t *spi, bool enable); +spi_return_flags_e spi_set_enable(spi_host_t* spi, bool enable); /** - * Set the transmit queue watermark level (to enable interrupt triggering). + * @brief Set the transmit queue watermark level (to enable interrupt triggering). * * @param spi Pointer to spi_host_t representing the target SPI. * @param watermark Queue/fifo trigger level (minimum level). + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_WATERMARK_EXCEEDS if watermark exceeds max (currently 76). + * @return SPI_FLAG_OK if success. */ -void spi_set_tx_watermark(const spi_host_t *spi, uint8_t watermark); +spi_return_flags_e spi_set_tx_watermark(spi_host_t* spi, uint8_t watermark); /** - * Set the receive queue watermark level (to enable interrupt triggering). + * @brief Set the receive queue watermark level (to enable interrupt triggering). * * @param spi Pointer to spi_host_t representing the target SPI. * @param watermark Queue/fifo trigger level (maximum level). + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_WATERMARK_EXCEEDS if watermark exceeds max (currently 64). + * @return SPI_FLAG_OK if success. */ -void spi_set_rx_watermark(const spi_host_t *spi, uint8_t watermark); +spi_return_flags_e spi_set_rx_watermark(spi_host_t* spi, uint8_t watermark); /** - * Set the requirement of a target device (i.e., a slave). + * @brief Set the requirement of a target device (slave). * * @param spi Pointer to spi_host_t representing the target SPI. * @param csid Chip Select (CS) ID. - * @param conf_reg Slave transmission configuration. + * @param conf_reg Slave configuration. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_CSID_INVALID if csid out of range. + * @return SPI_FLAG_OK if success. */ -void spi_set_configopts(const spi_host_t *spi, uint32_t csid, uint32_t conf_reg); +spi_return_flags_e spi_set_configopts(spi_host_t* spi, uint32_t csid, const uint32_t conf_reg); /** - * Select which device to target with the next command. + * @brief Get the requirement of a target device (slave). + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param csid Chip Select (CS) ID. + * @param conf_reg Where slave configuration gets stored. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_CSID_INVALID if csid out of range. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_get_configopts(spi_host_t* spi, uint32_t csid, uint32_t* conf_reg); + +/** + * @brief Select which device to target with the next command. * * @param spi Pointer to spi_host_t representing the target SPI. * @param csid Chip Select (SC) ID. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_CSID_INVALID if csid out of range. + * @return SPI_FLAG_OK if success. */ -void spi_set_csid(const spi_host_t *spi, uint32_t csid); +spi_return_flags_e spi_set_csid(spi_host_t* spi, uint32_t csid); /** - * Set the next command (one for all attached SPI devices). + * @brief Set the next command (one for all attached SPI devices). * * @param spi Pointer to spi_host_t representing the target SPI. * @param cmd_reg Command register value (Length, speed, ...). + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_SPEED_INVALID if direction and speed incompatible. + * @return SPI_FLAG_NOT_READY if SPI Host not ready. + * @return SPI_FLAG_OK if success. */ -void spi_set_command(const spi_host_t *spi, uint32_t cmd_reg); +spi_return_flags_e spi_set_command(spi_host_t* spi, uint32_t cmd_reg); /** - * Write one word to the TX FIFO. + * @brief Write one word to the TX FIFO. * * @param spi Pointer to spi_host_t representing the target SPI. * @param wdata Data to write. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_TX_QUEUE_FULL if TX FIFO is full. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_write_word(spi_host_t* spi, uint32_t wdata); + +/** + * @brief Write a byte of data to the transmit queue of a specified SPI peripheral. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param bdata Byte of data to write. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_TX_QUEUE_FULL if TX FIFO is full. + * @return SPI_FLAG_OK if success. */ -void spi_write_word(const spi_host_t *spi, uint32_t wdata); +spi_return_flags_e spi_write_byte(spi_host_t* spi, uint8_t bdata); /** - * Read one word to the RX FIFO. + * @brief Read one word to the RX FIFO. * * @param spi Pointer to spi_host_t representing the target SPI. * @param rdata Read data. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_RX_QUEUE_EMPTY if RX FIFO is empty. + * @return SPI_FLAG_OK if success. */ -void spi_read_word(const spi_host_t *spi, uint32_t* dst); +spi_return_flags_e spi_read_word(spi_host_t* spi, uint32_t* dst); /** - * Enable SPI event interrupt + * @brief Enable SPI event interrupt * * @param spi Pointer to spi_host_t representing the target SPI. * @param enable SPI event interrupt bit value. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -void spi_enable_evt_intr(const spi_host_t *spi, bool enable); +spi_return_flags_e spi_enable_evt_intr(spi_host_t* spi, bool enable); /** - * Enable SPI error interrupt + * @brief Enable SPI error interrupt * * @param spi Pointer to spi_host_t representing the target SPI. * @param enable SPI error interrupt bit value. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +spi_return_flags_e spi_enable_error_intr(spi_host_t* spi, bool enable); + +/** + * @brief Enable SPI output + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @param enable SPI TX empty interrupt bit value. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -void spi_enable_error_intr(const spi_host_t *spi, bool enable); +spi_return_flags_e spi_output_enable(spi_host_t* spi, bool enable); + +/****************************************************************************/ +/** **/ +/** INLINE FUNCTIONS **/ +/** **/ +/****************************************************************************/ /** - * Enable SPI watermark event interrupt + * @brief Check if a given direction and speed are compatible. + * i.e. bidirectional communication only possible at standard speed * * @param spi Pointer to spi_host_t representing the target SPI. - * @param enable SPI RX watermark interrupt bit value. + * @param direction spi_dir_e direction of communication. + * @param speed spi_speed_e speed of communication. + * @return true if compatible false otherwise. */ -void spi_enable_rxwm_intr(const spi_host_t *spi, bool enable); +static inline __attribute__((always_inline)) +bool spi_validate_cmd(uint8_t direction, uint8_t speed) +{ + if (speed > SPI_SPEED_QUAD || direction > SPI_DIR_BIDIR || + (direction == SPI_DIR_BIDIR && speed != SPI_SPEED_STANDARD)) + return false; + else + return true; +} /** - * Enable SPI TX empty event interrupt + * @brief Get the state of the event interrupt flag (indicates if event has been + * triggered). * * @param spi Pointer to spi_host_t representing the target SPI. - * @param enable SPI TX empty interrupt bit value. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if flag active + * or SPI_TRISTATE_FALSE if not active. */ -void spi_enable_txempty_intr(const spi_host_t *spi, bool enable); +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_evt_intr_state(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + + if (bitfield_read(SPI_HW(spi)->INTR_STATE, BIT_MASK_1, + SPI_HOST_INTR_STATE_SPI_EVENT_BIT)) + return SPI_TRISTATE_TRUE; + else + return SPI_TRISTATE_FALSE; +} /** - * Enable SPI output + * @brief Get the state of the error interrupt flag (indicates if error has been + * triggered). * * @param spi Pointer to spi_host_t representing the target SPI. - * @param enable SPI TX empty interrupt bit value. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if flag active + * or SPI_TRISTATE_FALSE if not active. + */ +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_error_intr_state(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + + if (bitfield_read(SPI_HW(spi)->INTR_STATE, BIT_MASK_1, + SPI_HOST_INTR_STATE_ERROR_BIT)) + return SPI_TRISTATE_TRUE; + else + return SPI_TRISTATE_FALSE; +} + +/** + * @brief Check if event interrupts are enabled. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if enabled + * or SPI_TRISTATE_FALSE otherwise. + */ +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_evt_intr_enable(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + + if (bitfield_read(SPI_HW(spi)->INTR_ENABLE, BIT_MASK_1, + SPI_HOST_INTR_ENABLE_SPI_EVENT_BIT)) + return SPI_TRISTATE_TRUE; + else + return SPI_TRISTATE_FALSE; +} + +/** + * @brief Check if error interrupts are enabled. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if enabled + * or SPI_TRISTATE_FALSE otherwise. + */ +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_error_intr_enable(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + + if (bitfield_read(SPI_HW(spi)->INTR_ENABLE, BIT_MASK_1, + SPI_HOST_INTR_ENABLE_ERROR_BIT)) + return SPI_TRISTATE_TRUE; + else + return SPI_TRISTATE_FALSE; +} + +/** + * @brief Read SPI status register + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return Pointer to spi_status_t structure. NULL if spi is NULL. + */ +static inline __attribute__((always_inline)) +const volatile spi_status_t spi_get_status(spi_host_t* spi) +{ + spi_status_t status; + status.value = SPI_HW(spi)->STATUS; // Assuming SPI_HW(spi)->STATUS returns a uint32_t value representing the status + return status; +} + +/** + * @brief Read SPI active bit from status register (indicates if SPI peripheral + * is currently processing a command) + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if active + * or SPI_TRISTATE_FALSE otherwise. + */ +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_active(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + //return spi_get_status(spi)->active ? SPI_TRISTATE_TRUE : SPI_TRISTATE_FALSE; + spi_status_t spi_status; + spi_status.value = 0x00; + spi_status.value = SPI_HW(spi)->STATUS; +} + +/** + * @brief Read SPI ready bit from status register (indicates if SPI peripheral + * is ready to receive more commands) + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_TRISTATE_ERROR if null pointer, else SPI_TRISTATE_TRUE if ready + * or SPI_TRISTATE_FALSE otherwise. */ -void spi_output_enable(const spi_host_t *spi, bool enable); +static inline __attribute__((always_inline)) +spi_tristate_e spi_get_ready(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_TRISTATE_ERROR) + return spi_get_status(spi).ready ? SPI_TRISTATE_TRUE : SPI_TRISTATE_FALSE; +} +/** + * @brief Wait SPI is ready to receive commands. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_ready(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_ready(spi) == SPI_TRISTATE_FALSE); + return SPI_FLAG_OK; +} -// Inline functions +/** + * @brief Wait SPI is no longer processing commands. + * + * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. + */ +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_idle(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_active(spi) == SPI_TRISTATE_TRUE); + return SPI_FLAG_OK; +} /** - * Read SPI status register + * @brief Wait CMD FIFO not full. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) volatile uint32_t spi_get_status(const spi_host_t *spi) { - return mmio_region_read32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_cmdqd_not_full(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_status(spi).cmdqd >= SPI_HOST_PARAM_CMD_DEPTH); + return SPI_FLAG_OK; } /** - * Read SPI active bit from status register + * @brief Wait TX FIFO reach watermark. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) volatile bool spi_get_active(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - return bitfield_bit32_read(status_reg, SPI_HOST_STATUS_ACTIVE_BIT); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_tx_watermark(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (!spi_get_status(spi).txwm); + return SPI_FLAG_OK; } /** - * Read SPI ready bit from status register + * @brief Wait TX FIFO empty. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) volatile bool spi_get_ready(const spi_host_t *spi) { - volatile uint32_t status_reg = spi_get_status(spi); - return bitfield_bit32_read(status_reg, SPI_HOST_STATUS_READY_BIT); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_tx_empty(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (!spi_get_status(spi).txempty); + return SPI_FLAG_OK; } /** - * Wait SPI is ready to receive commands. + * @brief Wait TX FIFO not empty. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_ready(const spi_host_t *spi) { - while (!spi_get_ready(spi)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_tx_not_empty(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_status(spi).txempty); + return SPI_FLAG_OK; } /** - * Wait TX FIFO reach watermark. + * @brief Wait TX FIFO not full. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_tx_watermark(const spi_host_t *spi) { - while (!mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXWM_BIT)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_tx_not_full(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_status(spi).txfull); + return SPI_FLAG_OK; } /** - * Wait TX FIFO empty. + * @brief Wait RX FIFO empty. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_tx_empty(const spi_host_t *spi) { - while (!mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXEMPTY_BIT)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_rx_empty(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (!spi_get_status(spi).rxempty); + return SPI_FLAG_OK; } /** - * Wait TX FIFO not empty. + * @brief Wait RX FIFO not empty. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_tx_not_empty(const spi_host_t *spi) { - while (mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXEMPTY_BIT)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_rx_not_empty(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (spi_get_status(spi).rxempty); + return SPI_FLAG_OK; } /** - * Wait TX FIFO not full. + * @brief Wait RX FIFO full. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_tx_not_full(const spi_host_t *spi) { - while (mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_TXFULL_BIT)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_rx_full(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (!spi_get_status(spi).rxfull); + return SPI_FLAG_OK; } /** - * Wait RX FIFO reach watermark. + * @brief Wait RX FIFO reach watermark. * * @param spi Pointer to spi_host_t representing the target SPI. + * @return SPI_FLAG_NULL_PTR if spi NULL pointer. + * @return SPI_FLAG_OK if success. */ -static inline __attribute__((always_inline)) void spi_wait_for_rx_watermark(const spi_host_t *spi) { - while (!mmio_region_get_bit32(spi->base_addr, SPI_HOST_STATUS_REG_OFFSET, SPI_HOST_STATUS_RXWM_BIT)); +static inline __attribute__((always_inline)) +spi_return_flags_e spi_wait_for_rx_watermark(spi_host_t* spi) +{ + SPI_NULL_CHECK(spi, SPI_FLAG_NULL_PTR) + while (!spi_get_status(spi).rxwm); + return SPI_FLAG_OK; } /** - * Create SPI target device configuration word. + * @brief Create SPI target device configuration word. * * @param configopts Target device configuation structure. + * @return uint32 representing the configopts. */ -static inline __attribute__((always_inline)) __attribute__((const)) uint32_t spi_create_configopts(const spi_configopts_t configopts) { +static inline __attribute__((always_inline)) __attribute__((const)) +uint32_t spi_create_configopts(const spi_configopts_t configopts) +{ uint32_t conf_reg = 0; - conf_reg = bitfield_field32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CLKDIV_0_FIELD, configopts.clkdiv); - conf_reg = bitfield_field32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_FIELD, configopts.csnidle); - conf_reg = bitfield_field32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_FIELD, configopts.csntrail); - conf_reg = bitfield_field32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_FIELD, configopts.csnlead); - conf_reg = bitfield_bit32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_FULLCYC_0_BIT, configopts.fullcyc); - conf_reg = bitfield_bit32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CPHA_0_BIT, configopts.cpha); - conf_reg = bitfield_bit32_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CPOL_0_BIT, configopts.cpol); + conf_reg = bitfield_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CLKDIV_0_MASK, + SPI_HOST_CONFIGOPTS_0_CLKDIV_0_OFFSET, configopts.clkdiv); + conf_reg = bitfield_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_OFFSET, configopts.csnidle); + conf_reg = bitfield_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_OFFSET, configopts.csntrail); + conf_reg = bitfield_write(conf_reg, SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_OFFSET, configopts.csnlead); + conf_reg = bitfield_write(conf_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_FULLCYC_0_BIT, configopts.fullcyc); + conf_reg = bitfield_write(conf_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_CPHA_0_BIT, configopts.cpha); + conf_reg = bitfield_write(conf_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_CPOL_0_BIT, configopts.cpol); return conf_reg; } /** - * Create SPI command word. + * @brief Convert SPI target device configuration word to spi_configopts_t structure. + * + * @param configopts Target device configuation structure. + * @return spi_configopts_t representing the config_reg. + */ +static inline __attribute__((always_inline)) __attribute__((const)) +spi_configopts_t spi_create_configopts_structure(const uint32_t config_reg) +{ + spi_configopts_t configopts = { + .clkdiv = bitfield_read(config_reg, SPI_HOST_CONFIGOPTS_0_CLKDIV_0_MASK, + SPI_HOST_CONFIGOPTS_0_CLKDIV_0_OFFSET), + .csnidle = bitfield_read(config_reg, SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNIDLE_0_OFFSET), + .csntrail = bitfield_read(config_reg, SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNTRAIL_0_OFFSET), + .csnlead = bitfield_read(config_reg, SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_MASK, + SPI_HOST_CONFIGOPTS_0_CSNLEAD_0_OFFSET), + .fullcyc = bitfield_read(config_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_FULLCYC_0_BIT), + .cpha = bitfield_read(config_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_CPHA_0_BIT), + .cpol = bitfield_read(config_reg, BIT_MASK_1, + SPI_HOST_CONFIGOPTS_0_CPOL_0_BIT) + }; + return configopts; +} + +/** + * @brief Create SPI command word. * * @param command Command configuration structure. + * @return uint32 representing the command. */ -static inline __attribute__((always_inline)) __attribute__((const)) uint32_t spi_create_command(const spi_command_t command) { +static inline __attribute__((always_inline)) __attribute__((const)) +uint32_t spi_create_command(const spi_command_t command) +{ uint32_t cmd_reg = 0; - cmd_reg = bitfield_field32_write(cmd_reg, SPI_HOST_COMMAND_LEN_FIELD, command.len); - cmd_reg = bitfield_bit32_write(cmd_reg, SPI_HOST_COMMAND_CSAAT_BIT, command.csaat); - cmd_reg = bitfield_field32_write(cmd_reg, SPI_HOST_COMMAND_SPEED_FIELD, command.speed); - cmd_reg = bitfield_field32_write(cmd_reg, SPI_HOST_COMMAND_DIRECTION_FIELD, command.direction); + cmd_reg = bitfield_write(cmd_reg, SPI_HOST_COMMAND_LEN_MASK, + SPI_HOST_COMMAND_LEN_OFFSET, command.len); + cmd_reg = bitfield_write(cmd_reg, BIT_MASK_1, + SPI_HOST_COMMAND_CSAAT_BIT, command.csaat); + cmd_reg = bitfield_write(cmd_reg, SPI_HOST_COMMAND_SPEED_MASK, + SPI_HOST_COMMAND_SPEED_OFFSET, command.speed); + cmd_reg = bitfield_write(cmd_reg, SPI_HOST_COMMAND_DIRECTION_MASK, + SPI_HOST_COMMAND_DIRECTION_OFFSET, command.direction); return cmd_reg; } /** - * @brief Attends the plic interrupt. + * @brief Attends the plic interrupt for SPI Host 2. */ -__attribute__((weak, optimize("O0"))) void handler_irq_spi(uint32_t id); +void handler_irq_spi(uint32_t id); + +/** + * @brief Attends the fic interrupt for SPI Host. + */ +void fic_irq_spi(void); + +/** + * @brief Attends the fic interrupt for SPI Flash. + */ +void fic_irq_spi_flash(void); + +/** + * @brief weak implementation of the function that gets called when an event + * interrupt is triggered on the SPI Flash. + * Replace with your own implementation. + */ +void spi_intr_handler_event_flash(spi_event_e events); + +/** + * @brief weak implementation of the function that gets called when an error + * interrupt is triggered on the SPI Flash. + * Replace with your own implementation. + */ +void spi_intr_handler_error_flash(spi_error_e errors); + +/** + * @brief weak implementation of the function that gets called when an event + * interrupt is triggered on the SPI Host. + * Replace with your own implementation. + */ +void spi_intr_handler_event_host(spi_event_e events); + +/** + * @brief weak implementation of the function that gets called when an error + * interrupt is triggered on the SPI Host. + * Replace with your own implementation. + */ +void spi_intr_handler_error_host(spi_error_e errors); + +/** + * @brief weak implementation of the function that gets called when an event + * interrupt is triggered on the SPI Host 2. + * Replace with your own implementation. + */ +void spi_intr_handler_event_host2(spi_event_e events); + +/** + * @brief weak implementation of the function that gets called when an error + * interrupt is triggered on the SPI Host 2. + * Replace with your own implementation. + */ +void spi_intr_handler_error_host2(spi_error_e errors); #ifdef __cplusplus @@ -362,3 +1016,9 @@ __attribute__((weak, optimize("O0"))) void handler_irq_spi(uint32_t id); #endif #endif // _DRIVERS_SPI_HOST_H_ + +/****************************************************************************/ +/** **/ +/** EOF **/ +/** **/ +/****************************************************************************/ \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/uart/uart.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/uart/uart.c index 08a32fa7..fef349c4 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/uart/uart.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/uart/uart.c @@ -4,12 +4,14 @@ // Modified version for core-v-mini-mcu // original at: https://github.com/lowRISC/opentitan/blob/master/sw/ - +#ifdef __cplusplus +extern "C" { +#endif #include "uart.h" #include #include - +#include "assert.h" #include "bitfield.h" #include "mmio.h" #include "error.h" @@ -17,8 +19,12 @@ #include "uart_regs.h" // Generated. #define NCO_WIDTH 16 -_Static_assert((1UL << NCO_WIDTH) - 1 == UART_CTRL_NCO_MASK, - "Bad value for NCO_WIDTH"); + +//#ifdef __cplusplus +static_assert((1UL << NCO_WIDTH) - 1 == UART_CTRL_NCO_MASK, "Bad value for NCO_WIDTH"); +//#else +static_assert((1UL << NCO_WIDTH) - 1 == UART_CTRL_NCO_MASK, "Bad value for NCO_WIDTH"); +//#endif static void uart_reset(const uart_t *uart) { mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, 0u); @@ -147,4 +153,8 @@ size_t uart_sink(void *uart, const char *data, size_t len) { __attribute__((weak, optimize("O0"))) void handler_irq_uart(uint32_t id) { // Replace this function with a non-weak implementation -} \ No newline at end of file +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl index 2bfec7d9..710cf02e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl @@ -9,11 +9,17 @@ extern "C" { #endif // __cplusplus -#define MEMORY_BANKS ${ram_numbanks} -% if ram_numbanks_il > 0: +#define MEMORY_BANKS ${xheep.ram_numbanks()} +% if xheep.has_il_ram(): #define HAS_MEMORY_BANKS_IL % endif +% for bank in xheep.iter_ram_banks(): +#define RAM${bank.name()}_START_ADDRESS 0x${f'{bank.start_address():08X}'} +#define RAM${bank.name()}_END_ADDRESS 0x${f'{bank.end_address():08X}'} +% endfor + + #define EXTERNAL_DOMAINS ${external_domains} #define DEBUG_START_ADDRESS 0x${debug_start_address} @@ -29,9 +35,13 @@ extern "C" { #define ${name.upper()}_START_ADDRESS (AO_PERIPHERAL_START_ADDRESS + 0x${peripheral['offset']}) #define ${name.upper()}_SIZE 0x${peripheral['length']} #define ${name.upper()}_END_ADDRESS (${name.upper()}_START_ADDRESS + ${name.upper()}_SIZE) +#define ${name.upper()}_IDX ${loop.index} %endfor +#define DMA_CH_NUM ${dma_ch_count} +#define DMA_CH_SIZE 0x${dma_ch_size} + //switch-on/off peripherals #define PERIPHERAL_START_ADDRESS 0x${peripheral_start_address} #define PERIPHERAL_SIZE 0x${peripheral_size_address} @@ -41,6 +51,7 @@ extern "C" { #define ${name.upper()}_START_ADDRESS (PERIPHERAL_START_ADDRESS + 0x${peripheral['offset']}) #define ${name.upper()}_SIZE 0x${peripheral['length']} #define ${name.upper()}_END_ADDRESS (${name.upper()}_START_ADDRESS + ${name.upper()}_SIZE) +#define ${name.upper()}_IDX ${loop.index + len(ao_peripherals.items())} % if "yes" in peripheral['is_included']: #define ${name.upper()}_IS_INCLUDED diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu_memory.h.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu_memory.h.tpl new file mode 100644 index 00000000..02a99da5 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu_memory.h.tpl @@ -0,0 +1,29 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#ifndef COREV_MINI_MCU_MEMORY_H_ +#define COREV_MINI_MCU_MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include "core_v_mini_mcu.h" + +typedef struct memory_address { + unsigned int start; + unsigned int end; +} xheep_memory_address_t; + +xheep_memory_address_t xheep_memory_regions[MEMORY_BANKS] = { +% for bank in xheep.iter_ram_banks(): + {.start = RAM${bank.name()}_START_ADDRESS, .end = RAM${bank.name()}_END_ADDRESS}, +% endfor +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // COREV_MINI_MCU_MEMORY_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c index c9cd02d3..564abdcd 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.c @@ -2,6 +2,10 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + #include "handler.h" #include "csr.h" #include "stdasm.h" @@ -110,3 +114,7 @@ __attribute__((weak)) void handler_ecall(void) { while (1) { } } +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.h index 8f987be7..1aaacc3b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/handler.h @@ -5,6 +5,10 @@ #ifndef OPENTITAN_SW_DEVICE_LIB_HANDLER_H_ #define OPENTITAN_SW_DEVICE_LIB_HANDLER_H_ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + typedef enum exc_id { kInstMisa = 0, kInstAccFault = 1, @@ -126,4 +130,9 @@ void handler_lsu_fault(void); */ void handler_ecall(void); + +#ifdef __cplusplus +} +#endif // __cplusplus + #endif // OPENTITAN_SW_DEVICE_LIB_HANDLER_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h index c2e885c0..9759edfb 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h @@ -5,6 +5,11 @@ #ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_HART_H_ #define OPENTITAN_SW_DEVICE_LIB_RUNTIME_HART_H_ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + #include #include @@ -24,4 +29,9 @@ */ inline void wait_for_interrupt(void) { asm volatile("wfi"); } + +#ifdef __cplusplus +} +#endif // __cplusplus + #endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_HART_H_ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/heap.cpp b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/heap.cpp new file mode 100644 index 00000000..d4c8fd8b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/heap.cpp @@ -0,0 +1,60 @@ +/* +* Copyright 2024 Anestis Athanasiadis +* +* 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. +*/ + +//Additional heap functions required for C++ + +#include +#include + +void* operator new(size_t size) noexcept +{ + return malloc(size); +} + +void operator delete(void *p) noexcept +{ + free(p); +} + +void* operator new[](size_t size) noexcept +{ + return operator new(size); // Same as regular new +} + +void operator delete[](void *p) noexcept +{ + operator delete(p); // Same as regular delete +} + +void* operator new(size_t size, std::nothrow_t) noexcept +{ + return operator new(size); // Same as regular new +} + +void operator delete(void *p, std::nothrow_t) noexcept +{ + operator delete(p); // Same as regular delete +} + +void* operator new[](size_t size, std::nothrow_t) noexcept +{ + return operator new(size); // Same as regular new +} + +void operator delete[](void *p, std::nothrow_t) noexcept +{ + operator delete(p); // Same as regular delete +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/init.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/init.c index cfbf206a..ad29fca6 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/init.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/init.c @@ -1,7 +1,16 @@ // Copyright 2022 OpenHW Group // Solderpad Hardware License, Version 2.1, see LICENSE.md for details. // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +#ifdef __cplusplus +extern "C" { +#endif + int init() { return 0; -} \ No newline at end of file +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c index a9a7fcc2..8e516af0 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls.c @@ -17,8 +17,13 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#ifdef __cplusplus +extern "C" { +#endif + #include -#include +#include +#include #include #include #include @@ -46,6 +51,7 @@ int _link (const char *__path1, const char *__path2); _off_t _lseek (int __fildes, _off_t __offset, int __whence); ssize_t _read (int __fd, void *__buf, size_t __nbyte); void * _sbrk (ptrdiff_t __incr); +int _brk(void *addr); int _unlink (const char *__path); ssize_t _write (int __fd, const void *__buf, size_t __nbyte); int _execve (const char *__path, char * const __argv[], char * const __envp[]); @@ -259,9 +265,13 @@ ssize_t _write(int file, const void *ptr, size_t len) errno = ENOSYS; return -1; } - return uart_write(&uart,(uint8_t *)ptr,len); +} + +_ssize_t _write_r(struct _reent *ptr, int fd, const void *buf, size_t cnt) +{ + return _write(fd,buf,cnt); } extern char __heap_start[]; @@ -270,8 +280,12 @@ static char *brk = __heap_start; int _brk(void *addr) { - brk = addr; - return 0; + if (addr >= (void *)__heap_start && addr <= (void *)__heap_end) { + brk = addr; + return 0; + } else { + return -1; + } } void *_sbrk(ptrdiff_t incr) @@ -279,13 +293,27 @@ void *_sbrk(ptrdiff_t incr) char *old_brk = brk; if (__heap_start == __heap_end) { - return NULL; + return NULL; } - if ((brk += incr) < __heap_end) { + if (brk + incr < __heap_end && brk + incr >= __heap_start) { brk += incr; } else { - brk = __heap_end; + return (void *)-1; } return old_brk; } + +int raise(int sig) +{ + return _kill(_getpid(), sig); +} + +void abort(void) +{ + _exit(-1); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls_cpp.cpp b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls_cpp.cpp new file mode 100644 index 00000000..3385fcb5 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/syscalls_cpp.cpp @@ -0,0 +1,39 @@ +/* +* Copyright 2024 Anestis Athanasiadis +* +* 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. +*/ + + +// This function is required to register the call for the destructor +// of static object +extern "C" int __aeabi_atexit(void *object, void (*destructor)(void *),void *dso_handle) +{ + static_cast(object); + static_cast(destructor); + static_cast(dso_handle); + return 0; +} + +void operator delete(void *,unsigned int) +{ +} + +// Required when there is pure virtual function +extern "C" void __cxa_pure_virtual() +{ + while (true) {} +} + + +void *__dso_handle = 0; \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c new file mode 100644 index 00000000..67371531 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c @@ -0,0 +1,100 @@ +// Copyright 2024 EPFL and Politecnico di Torino. +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: dma_sdk.c +// Author: Michele Caon, Luigi Giuffrida +// Date: 19/06/2023 +// Description: Utility functions for DMA peripheral. + +#include "dma_sdk.h" +#include "dma.h" +#include "hart.h" +#include "handler.h" +#include "fast_intr_ctrl.h" +#include "core_v_mini_mcu.h" +#include "csr.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /******************************/ + /* ---- GLOBAL VARIABLES ---- */ + /******************************/ + + volatile uint8_t dma_sdk_intr_flag; + +#define DMA_REGISTER_SIZE_BYTES sizeof(int) +#define DMA_SELECTION_OFFSET_START 0 + +/* Mask for direct register operations */ +#define DMA_CSR_REG_MIE_MASK ((1 << 19) | (1 << 11)) + + /**********************************/ + /* ---- FUNCTION DEFINITIONS ---- */ + /**********************************/ + + static __attribute__((always_inline)) void dma_start(dma *peri, uint32_t size, dma_data_type_t src_type) + { + peri->SIZE_D1 = (uint32_t)((size * DMA_DATA_TYPE_2_SIZE(src_type)) & DMA_SIZE_D1_SIZE_MASK); + } + + // Initialize the DMA + void dma_sdk_init(void) + { + dma_init(NULL); + + /* Enable global interrupts */ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + /* Enable fast interrupts */ + CSR_SET_BITS(CSR_REG_MIE, DMA_CSR_REG_MIE_MASK); + + return; + } + + void dma_copy(uint32_t dst_ptr, uint32_t src_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data) + { + volatile dma *the_dma = dma_peri(channel); + DMA_COPY(dst_ptr, src_ptr, size, src_type, dst_type, signed_data, the_dma); + dma_start(the_dma, size, src_type); + DMA_WAIT(channel); + return; + } + + void dma_fill(uint32_t dst_ptr, uint32_t value_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data) + { + volatile dma *the_dma = dma_peri(channel); + DMA_FILL(dst_ptr, value_ptr, size, src_type, dst_type, signed_data, the_dma); + dma_start(the_dma, size, src_type); + DMA_WAIT(channel); + return; + } + + void __attribute__ ((noinline)) dma_copy_async(uint32_t dst_ptr, uint32_t src_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data) + { + volatile dma *the_dma = dma_peri(channel); + DMA_COPY(dst_ptr, src_ptr, size, src_type, dst_type, signed_data, the_dma); + dma_start(the_dma, size, src_type); + return; + } + + void __attribute__ ((noinline)) dma_fill_async(uint32_t dst_ptr, uint32_t value_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data) + { + volatile dma *the_dma = dma_peri(channel); + DMA_FILL(dst_ptr, value_ptr, size, src_type, dst_type, signed_data, the_dma); + dma_start(the_dma, size, src_type); + return; + } + + void __attribute__ ((noinline)) dma_wait(uint8_t channel) + { + DMA_WAIT(channel); + return; + } + +#ifdef __cplusplus +} +#endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.h new file mode 100644 index 00000000..726024e0 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.h @@ -0,0 +1,108 @@ +// Copyright 2024 EPFL and Politecnico di Torino. +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: dma_sdk.h +// Author: Michele Caon, Luigi Giuffrida +// Date: 19/06/2023 +// Description: DMA utility functions + +#ifndef DMA_SDK_H_ +#define DMA_SDK_H_ + +#include +#include // for size_t +#include "csr.h" + +#include "dma.h" +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#define INCREMENT(TYPE) ((TYPE == DMA_DATA_TYPE_BYTE) ? 1 : (TYPE == DMA_DATA_TYPE_HALF_WORD) ? 2 \ + : 4) + +#define DMA_COPY(DST, SRC, SIZE, SRC_TYPE, DST_TYPE, SIGNED, DMA_PERI) \ + DMA_PERI->INTERRUPT_EN = (uint32_t)0x1; \ + DMA_PERI->SRC_PTR = (uint32_t)SRC; \ + DMA_PERI->DST_PTR = (uint32_t)DST; \ + DMA_PERI->SRC_PTR_INC_D1 = (uint32_t)(INCREMENT(SRC_TYPE) & DMA_SRC_PTR_INC_D1_INC_MASK); \ + DMA_PERI->DST_PTR_INC_D1 = (uint32_t)(INCREMENT(DST_TYPE) & DMA_DST_PTR_INC_D1_INC_MASK); \ + DMA_PERI->MODE = (uint32_t)(DMA_TRANS_MODE_SINGLE & DMA_MODE_MODE_MASK); \ + DMA_PERI->SRC_DATA_TYPE = (uint32_t)(SRC_TYPE & DMA_SRC_DATA_TYPE_DATA_TYPE_MASK); \ + DMA_PERI->DST_DATA_TYPE = (uint32_t)(DST_TYPE & DMA_DST_DATA_TYPE_DATA_TYPE_MASK); \ + DMA_PERI->SIGN_EXT = (uint32_t)SIGNED; + +#define DMA_FILL(DST, VALUE_PTR, SIZE, SRC_TYPE, DST_TYPE, SIGNED, DMA_PERI) \ + DMA_PERI->INTERRUPT_EN = (uint32_t)0x1; \ + DMA_PERI->SRC_PTR = (uint32_t)VALUE_PTR; \ + DMA_PERI->DST_PTR = (uint32_t)DST; \ + DMA_PERI->SRC_PTR_INC_D1 = (uint32_t)0; \ + DMA_PERI->DST_PTR_INC_D1 = (uint32_t)(INCREMENT(DST_TYPE) & DMA_DST_PTR_INC_D1_INC_MASK); \ + DMA_PERI->MODE = (uint32_t)(DMA_TRANS_MODE_SINGLE & DMA_MODE_MODE_MASK); \ + DMA_PERI->SRC_DATA_TYPE = (uint32_t)(SRC_TYPE & DMA_SRC_DATA_TYPE_DATA_TYPE_MASK); \ + DMA_PERI->DST_DATA_TYPE = (uint32_t)(DST_TYPE & DMA_DST_DATA_TYPE_DATA_TYPE_MASK); \ + DMA_PERI->SIGN_EXT = (uint32_t)SIGNED; + +#define DMA_WAIT(CH) \ + while (!dma_is_ready(CH)) \ + { \ + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); \ + if (dma_is_ready(CH) == 0) \ + { \ + wait_for_interrupt(); \ + } \ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); \ + } + + /********************************/ + /* ---- EXPORTED VARIABLES ---- */ + /********************************/ + + extern volatile uint8_t dma_sdk_intr_flag; + + /** + * @brief Initializes the DMA SDK. + * + * This function initializes the DMA SDK and prepares it for use. + */ + void __attribute__((noinline)) dma_sdk_init(void); + + /** + * @brief Copies data from source to destination using DMA. + * + * @param dst_ptr Pointer to the destination memory location. + * @param src_ptr Pointer to the source memory location. + * @param size Size of the data to be copied in bytes. + * @param channel DMA channel to be used for the transfer. + * @param src_type Source variable type (byte, half-word, word). + * @param dst_type Destination variable type (byte, half-word, word). + * @param signed_data Indicates whether the data is signed or unsigned. + */ + void __attribute__((noinline)) dma_copy(uint32_t dst_ptr, uint32_t src_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data); + + /** + * @brief Fills a memory region with a specified value using DMA. + * + * @param dst_ptr Pointer to the destination memory location. + * @param value_ptr Pointer to the value to be filled. + * @param size Size of the memory region to be filled in bytes. + * @param channel DMA channel to be used for the transfer. + * @param src_type Source variable type (byte, half-word, word). + * @param dst_type Destination variable type (byte, half-word, word). + * @param signed_data Indicates whether the data is signed or unsigned. + */ + void __attribute__((noinline)) dma_fill(uint32_t dst_ptr, uint32_t value_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data); + + void __attribute__((noinline)) dma_copy_async(uint32_t dst_ptr, uint32_t src_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data); + + void __attribute__((noinline)) dma_fill_async(uint32_t dst_ptr, uint32_t value_ptr, uint32_t size, uint8_t channel, dma_data_type_t src_type, dma_data_type_t dst_type, uint8_t signed_data); + + void __attribute__((noinline)) dma_wait(uint8_t channel); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* DMA_SDK_H_ */ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.c new file mode 100644 index 00000000..8c8a6a16 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.c @@ -0,0 +1,1127 @@ +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : spi_sdk.c +** version : 1 +** date : 18/04/24 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ +/** +* @file spi_sdk.c +* @date 18/04/24 +* @author Llorenç Muela +* @brief The Serial Peripheral Interface (SPI) SDK to set up and use the +* SPI peripheral +*/ + +/****************************************************************************/ +/** **/ +/** MODULES USED **/ +/** **/ +/****************************************************************************/ + +#include "spi_sdk.h" +#include "spi_host.h" +#include "spi_host_regs.h" +#include "soc_ctrl_structs.h" +#include "bitfield.h" +#include "csr.h" + +/****************************************************************************/ +/** **/ +/** DEFINITIONS AND MACROS **/ +/** **/ +/****************************************************************************/ + +#define DATA_MODE_CPHA_OFFS 0 +#define DATA_MODE_CPOL_OFFS 1 + +#define SPI_MAX_IDX 2 +#define SPI_IDX_INVALID(idx) idx > SPI_MAX_IDX + +#define SYS_FREQ (soc_ctrl_peri->SYSTEM_FREQUENCY_HZ) +#define SPI_MIN_FREQ (SYS_FREQ / (2 * 65535 + 2)) // 65535 = 2^16 - 1 + +// Maximum length of data (in bytes) for a command segment (currently 2^24) +#define MAX_COMMAND_LENGTH SPI_HOST_COMMAND_LEN_MASK +#define BYTES_PER_WORD 4 +// Convert byte count to word count +#define LEN_WORDS(bytes) ((bytes / BYTES_PER_WORD) + (bytes % BYTES_PER_WORD ? 1 : 0)) + +// Bitmasks for speed and direction relative to spi_mode_e +#define DIR_SPD_MASK 0b11 +#define DIR_INDEX 0 +#define SPD_INDEX 2 + +#define TRIGGERING_EVENTS (SPI_EVENT_IDLE | SPI_EVENT_READY | SPI_EVENT_TXWM | SPI_EVENT_RXWM) + +// The standard watermark for all transactions (seems reasonable) +#define TXWM_DEFAULT (SPI_HOST_PARAM_TX_DEPTH / 4) // Arbirarily chosen +#define RXWM_DEFAULT (SPI_HOST_PARAM_RX_DEPTH - 12) // Arbirarily chosen + +#define NULL_CALLBACKS (spi_callbacks_t) {NULL, NULL, NULL, NULL} + +// SPI peripheral busy checks +#define SPI_BUSY(peri) (peri.state == SPI_STATE_BUSY) +#define SPI_NOT_BUSY(peri) (peri.state != SPI_STATE_BUSY) + +// Check command length validity +#define SPI_INVALID_LEN(len) (len == 0 || len > MAX_COMMAND_LENGTH) + +/** + * @brief Allows easy TX Transaction instantiation. + */ +#define SPI_TXN_TX(segment, txbuff, len) (spi_transaction_t) { \ + .segments = segment, \ + .seglen = 1, \ + .txbuffer = txbuff, \ + .txlen = len, \ + .rxbuffer = NULL, \ + .rxlen = 0 \ +} + +/** + * @brief Allows easy RX Transaction instantiation. + */ +#define SPI_TXN_RX(segment, rxbuff, len) (spi_transaction_t) { \ + .segments = segment, \ + .seglen = 1, \ + .txbuffer = NULL, \ + .txlen = 0, \ + .rxbuffer = rxbuff, \ + .rxlen = len \ +} + +/** + * @brief Allows easy BIDIR Transaction instantiation. + */ +#define SPI_TXN_BIDIR(segment, txbuff, rxbuff, len) (spi_transaction_t) { \ + .segments = segment, \ + .seglen = 1, \ + .txbuffer = txbuff, \ + .txlen = len, \ + .rxbuffer = rxbuff, \ + .rxlen = len \ +} + +/** + * @brief Allows easy generic Transaction instantiation. + */ +#define SPI_TXN(segment, seg_len, txbuff, rxbuff) (spi_transaction_t) { \ + .segments = segment, \ + .seglen = seg_len, \ + .txbuffer = txbuff, \ + .txlen = 0, \ + .rxbuffer = rxbuff, \ + .rxlen = 0 \ +} + +/****************************************************************************/ +/** **/ +/** TYPEDEFS AND STRUCTURES **/ +/** **/ +/****************************************************************************/ + +/** + * @brief Transaction Structure. Holds all information relevant to a transaction. + */ +typedef struct { + const spi_segment_t* segments; // Pointer to array/buffer of command segments + uint8_t seglen; // Size of the command segents array/buffer + const uint32_t* txbuffer; // Pointer to array/buffer of TX data + uint32_t txlen; // Size of TX array/buffer + uint32_t* rxbuffer; // Pointer to array/buffer for RX data + uint32_t rxlen; // Size of RX array/buffer +} spi_transaction_t; + +/** + * @brief Structure to hold all relative information about a particular peripheral. + * peripherals variable in this file holds an instance of this structure for every + * SPI peripheral defined in the HAL. This is in order to store relevant information + * of the peripheral current status, transaction info, and peripheral instance. + */ +typedef struct { + spi_host_t* instance; // Instance of peripheral defined in HAL + uint8_t txwm; // TX watermark for this particular peripheral + uint8_t rxwm; // RX watermark for this particular peripheral + uint32_t last_id; // ID of last used spi_t to avoid resetting slave + uint32_t timeout; // Timeout for blocking transactions in ms + spi_state_e state; // Current state of device + spi_transaction_t txn; // Current transaction being processed + uint32_t scnt; // Counter to track segment to process + uint32_t txcnt; // Counter to track TX word being processed + uint32_t rxcnt; // Counter to track RX word being processed + spi_callbacks_t callbacks; // Callback functions to call +} spi_peripheral_t; + +/****************************************************************************/ +/** **/ +/* PROTOTYPES OF LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +/** + * @brief Validates the idx and init variables of spi_t. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @return spi_codes_e information about error. SPI_CODE_OK if all went well + */ +spi_codes_e spi_check_valid(spi_t* spi); + +/** + * @brief Validates slave csid. + * + * @param slave to validate + * @return spi_codes_e information about error. SPI_CODE_OK if all went well + */ +spi_codes_e spi_validate_slave(spi_slave_t slave); + +/** + * @brief Sets the slave configuration options and the slave CSID. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @return spi_codes_e information about error. SPI_CODE_OK if all went well + */ +spi_codes_e spi_set_slave(spi_t* spi); + +/** + * @brief Validation and configuration of device prior to any transaction. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @return spi_codes_e information about error. SPI_CODE_OK if all went well + */ +spi_codes_e spi_prepare_transfer(spi_t* spi); + +/** + * @brief Computes the true frequency that will be set based on the user desired + * frequency. + * + * @param freq Frequency defined by user + * @return uint32_t True frequency after determining the SPI clk divider + */ +uint32_t spi_true_slave_freq(uint32_t freq); + +/** + * @brief Validates all the provided segments and counts the number of words for + * TX and RX buffers. + * + * @param segments An array of segments to validate + * @param segments_len The length of the array of segments + * @param tx_count Variable to store the counted TX words + * @param rx_count Variable to store the counted RX words + * @return true if all segments are valid + * @return false otherwise + */ +bool spi_validate_segments(const spi_segment_t* segments, uint32_t segments_len, + uint32_t* tx_count, uint32_t* rx_count); + +/** + * @brief Fills the TX FIFO until no more space or no more data. + * + * @param peri Pointer to the spi_peripheral_t instance with the relevant data + * @return true if any word has been written to TX fifo + * @return false otherwise + */ +bool spi_fill_tx(spi_peripheral_t* peri); + +/** + * @brief Empties the RX FIFO. + * + * @param peri Pointer to the spi_peripheral_t instance with the relevant data + * @return true if any word has been read to RX fifo + * @return false otherwise + */ +bool spi_empty_rx(spi_peripheral_t* peri); + +/** + * @brief Proceeds to initiate transaction once all tests passed. + * + * @param peri Pointer to the relevant spi_peripheral_t instance + * @param spi Pointer to the spi_t that requested transaction + * @param txn Transaction data (segments, buffers, lengths) + * @param done_cb The callback to be called once transaction is over + * @param error_cb The callback to be called if a Hardware error occurs + */ +void spi_launch(spi_peripheral_t* peri, spi_t* spi, spi_transaction_t txn, + spi_callbacks_t callbacks); + +/** + * @brief Issues a command segment and increments counter (post inc.). + * Determines value of CSAAT bit based on if it is last segment of transaction + * or not. + * + * @param peri Pointer to the relevant spi_peripheral_t instance + */ +void spi_wait_transaction_done(spi_peripheral_t* peri); + +/** + * @brief Issues a command segment and increments counter (post inc.). + * Determines value of CSAAT bit based on if it is last segment of transaction + * or not. + * + * @param peri Pointer to the relevant spi_peripheral_t instance + */ +void spi_issue_next_seg(spi_peripheral_t* peri); + +/** + * @brief Resets the entire peripheral, hardware included + * + * @param peri Pointer to the relevant spi_peripheral_t instance + */ +void spi_reset_peri(spi_peripheral_t* peri); + +/** + * @brief Resets the transaction-related variables of the spi_peripheral_t to + * their initial values + * + * @param peri Pointer to the relevant spi_peripheral_t instance + */ +void spi_reset_transaction(spi_peripheral_t* peri); + +/** + * @brief Function that gets called on each Event Interrupt. Handles all the logic + * of a transacton since all transactions use the interrupt. + * + * @param peri Pointer to the relevant spi_peripheral_t instance + * @param events Variable holding all the current events + */ +void spi_event_handler(spi_peripheral_t* peri, spi_event_e events); + +/** + * @brief Function that handles the harware errors. It is responsible of aborting + * any current transaction, resetting variables and calling the error callback if any. + * + * @param peri Pointer to the relevant spi_peripheral_t instance + * @param error Variable holding all the errors that occured + */ +void spi_error_handler(spi_peripheral_t* peri, spi_error_e error); + +/****************************************************************************/ +/** **/ +/** EXPORTED VARIABLES **/ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/* GLOBAL VARIABLES */ +/** **/ +/****************************************************************************/ + +/** + * @brief Global SDK spi_t instance counter to assign each instance a unique ID. + */ +static uint32_t global_id = 0; + +/** + * @brief Static variable representing each SPI peripheral (FLASH, HOST, HOST2) + * We can have infinitely many spi_t variables but all reference one of these + * spi_peripheral_t. Each variable here holds all the relevant information about + * the current transaction the peripheral is executing. + */ +static volatile spi_peripheral_t peripherals[] = { + (spi_peripheral_t) { + .instance = spi_flash, + .txwm = TXWM_DEFAULT, + .rxwm = RXWM_DEFAULT, + .last_id = 0, + .timeout = SPI_TIMEOUT_DEFAULT, + .state = SPI_STATE_NONE, + .txn = {0}, + .scnt = 0, + .txcnt = 0, + .rxcnt = 0, + .callbacks = {0} + }, + (spi_peripheral_t) { + .instance = spi_host1, + .txwm = TXWM_DEFAULT, + .rxwm = RXWM_DEFAULT, + .last_id = 0, + .timeout = SPI_TIMEOUT_DEFAULT, + .state = SPI_STATE_NONE, + .txn = {0}, + .scnt = 0, + .txcnt = 0, + .rxcnt = 0, + .callbacks = {0} + }, + (spi_peripheral_t) { + .instance = spi_host2, + .txwm = TXWM_DEFAULT, + .rxwm = RXWM_DEFAULT, + .last_id = 0, + .timeout = SPI_TIMEOUT_DEFAULT, + .state = SPI_STATE_NONE, + .txn = {0}, + .scnt = 0, + .txcnt = 0, + .rxcnt = 0, + .callbacks = {0} + } +}; + +/****************************************************************************/ +/** **/ +/** EXPORTED FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +spi_t spi_init(spi_idx_e idx, spi_slave_t slave) +{ + // Make sure all parameters of the slave are valid. + spi_codes_e error = spi_validate_slave(slave); + // Check that the SPI peripheral identifier is valid. + if (SPI_IDX_INVALID(idx)) error |= SPI_CODE_IDX_INVAL; + // Since watermark is set here, not a good idea to allow for initialization. + // Anyways not very elegant to initialize while being busy... right? + if (SPI_BUSY(peripherals[idx])) error |= SPI_CODE_IS_BUSY; + if (error) + return (spi_t) { + .idx = UINT32_MAX, + .id = 0, + .init = false, + .slave = (spi_slave_t) {0} + }; + // Enable SPI peripheral. We do not check return value since we know here that + // it will never return an error. + spi_set_enable(peripherals[idx].instance, true); + spi_output_enable(peripherals[idx].instance, true); + // Enable all error interrupts so that the SPI peripheral doesn't get stuck if + // there is an error. And we don't check return value since we know it's error free. + spi_set_errors_enabled(peripherals[idx].instance, SPI_ERROR_IRQALL, true); + spi_enable_error_intr(peripherals[idx].instance, true); + // Set the watermarks for the specific peripheral + spi_set_tx_watermark(peripherals[idx].instance, peripherals[idx].txwm); + spi_set_rx_watermark(peripherals[idx].instance, peripherals[idx].rxwm); + // Just set a state so user can see it has been initialized somewhen. + peripherals[idx].state = SPI_STATE_INIT; + // Set the true frequency at which the SCK will be for that particular slave + // so the user can know the real frequency. + slave.freq = spi_true_slave_freq(slave.freq); + return (spi_t) { + .idx = idx, + .id = ++global_id, // Pre-increment because id 0 defined as invalid + .init = true, + .slave = slave + }; +} + +void spi_deinit(spi_t* spi) +{ + // Set all values to something that will prevent spi variable to be used. + spi->idx = UINT32_MAX; + spi->id = 0; + spi->init = false; + spi->slave = (spi_slave_t) {0}; +} + +spi_codes_e spi_reset(spi_t* spi) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + // Reset entire peripheral + spi_reset_peri(&peripherals[spi->idx]); + + return SPI_CODE_OK; +} + +spi_codes_e spi_set_txwm(spi_t* spi, uint8_t watermark) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + // Do not change watermark if SPI is busy + if (SPI_BUSY(peripherals[spi->idx])) return SPI_CODE_IS_BUSY; + // Set the new value at hardware level + if (spi_set_tx_watermark(peripherals[spi->idx].instance, watermark)) + return SPI_CODE_WM_EXCEEDS; + // Store the watermark if previous operation succeeded + peripherals[spi->idx].txwm = watermark; + + return SPI_CODE_OK; +} + +spi_codes_e spi_get_txwm(spi_t* spi, uint8_t* watermark) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + + *watermark = peripherals[spi->idx].txwm; + + return SPI_CODE_OK; +} + +spi_codes_e spi_set_rxwm(spi_t* spi, uint8_t watermark) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + // Do not change watermark if SPI is busy + if (SPI_BUSY(peripherals[spi->idx])) return SPI_CODE_IS_BUSY; + // Set the new value at hardware level + if (spi_set_rx_watermark(peripherals[spi->idx].instance, watermark)) + return SPI_CODE_WM_EXCEEDS; + // Store the watermark if previous operation succeeded + peripherals[spi->idx].rxwm = watermark; + + return SPI_CODE_OK; +} + +spi_codes_e spi_get_rxwm(spi_t* spi, uint8_t* watermark) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + + *watermark = peripherals[spi->idx].rxwm; + + return SPI_CODE_OK; +} + +spi_codes_e spi_set_timeout(spi_t* spi, uint32_t timeout) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + + peripherals[spi->idx].timeout = timeout; + + return SPI_CODE_OK; +} + +spi_codes_e spi_get_timeout(spi_t* spi, uint32_t* timeout) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + + *timeout = peripherals[spi->idx].timeout; + + return SPI_CODE_OK; +} + +spi_codes_e spi_set_slave_freq(spi_t* spi, uint32_t freq) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + // Save current freq and change to new freq to check validity + const uint32_t old_freq = spi->slave.freq; + spi->slave.freq = freq; + error = spi_validate_slave(spi->slave); + if (error) { + // If not valid reset the frequency and return error + spi->slave.freq = old_freq; + return error; + } + // If valid set the true frequency and return OK + spi->slave.freq = spi_true_slave_freq(freq); + return SPI_CODE_OK; +} + +spi_state_e spi_get_state(spi_t* spi) +{ + spi_codes_e error = spi_check_valid(spi); + if (error) return SPI_STATE_ARG_INVAL; // The spi parameter passed is invalid + + return peripherals[spi->idx].state; +} + +spi_codes_e spi_transmit(spi_t* spi, const uint32_t* src_buffer, uint32_t len) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for TX transaction + spi_segment_t seg = SPI_SEG_TX(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_TX(&seg, src_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. No callbacks since function is blocking. + spi_launch(&peripherals[spi->idx], spi, txn, NULL_CALLBACKS); + + spi_wait_transaction_done(&peripherals[spi->idx]); + // while (SPI_BUSY(peripherals[spi->idx])) wait_for_interrupt(); + + return SPI_CODE_OK; +} + +spi_codes_e spi_receive(spi_t* spi, uint32_t* dest_buffer, uint32_t len) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for RX transaction + spi_segment_t seg = SPI_SEG_RX(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_RX(&seg, dest_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. No callbacks since function is blocking. + spi_launch(&peripherals[spi->idx], spi, txn, NULL_CALLBACKS); + + spi_wait_transaction_done(&peripherals[spi->idx]); + // while (SPI_BUSY(peripherals[spi->idx])) wait_for_interrupt(); + + return SPI_CODE_OK; +} + +spi_codes_e spi_transceive(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for BIDIR transaction + spi_segment_t seg = SPI_SEG_BIDIR(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_BIDIR(&seg, src_buffer, dest_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. No callbacks since function is blocking. + spi_launch(&peripherals[spi->idx], spi, txn, NULL_CALLBACKS); + + spi_wait_transaction_done(&peripherals[spi->idx]); + // while (SPI_BUSY(peripherals[spi->idx])) wait_for_interrupt(); + + return SPI_CODE_OK; +} + +spi_codes_e spi_execute(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + if (error) return error; + + // Create the transaction with the provided segments + spi_transaction_t txn = SPI_TXN(segments, segments_len, src_buffer, dest_buffer); + + // We check every segment for validity since they are defined by user. + // This function also counts the number of words of TX and RX the entire + // transaction is composed of. + if (!spi_validate_segments(txn.segments, txn.seglen, &txn.txlen, &txn.rxlen)) + return SPI_CODE_SEGMENT_INVAL; + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. No callbacks since function is blocking. + spi_launch(&peripherals[spi->idx], spi, txn, NULL_CALLBACKS); + + spi_wait_transaction_done(&peripherals[spi->idx]); + // while (SPI_BUSY(peripherals[spi->idx])) wait_for_interrupt(); + + return SPI_CODE_OK; +} + +spi_codes_e spi_transmit_nb(spi_t* spi, const uint32_t* src_buffer, uint32_t len, + spi_callbacks_t callbacks) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for TX transaction + spi_segment_t seg = SPI_SEG_TX(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_TX(&seg, src_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. Here user callbacks are used because non-blocking function. + spi_launch(&peripherals[spi->idx], spi, txn, callbacks); + + return SPI_CODE_OK; +} + +spi_codes_e spi_receive_nb(spi_t* spi, uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for RX transaction + spi_segment_t seg = SPI_SEG_RX(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_RX(&seg, dest_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. Here user callbacks are used because non-blocking function. + spi_launch(&peripherals[spi->idx], spi, txn, callbacks); + + return SPI_CODE_OK; +} + +spi_codes_e spi_transceive_nb(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + // Check that length doesn't exceed maximum and is not 0 + if (SPI_INVALID_LEN(len)) error |= SPI_CODE_TXN_LEN_INVAL; + if (error) return error; + + // Create command segment for BIDIR transaction + spi_segment_t seg = SPI_SEG_BIDIR(len); + // Create the transaction with the created segment + spi_transaction_t txn = SPI_TXN_BIDIR(&seg, src_buffer, dest_buffer, LEN_WORDS(len)); + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. Here user callbacks are used because non-blocking function. + spi_launch(&peripherals[spi->idx], spi, txn, callbacks); + + return SPI_CODE_OK; +} + +spi_codes_e spi_execute_nb(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer, spi_callbacks_t callbacks) +{ + // Make validity checks and set the slave at hardware level + spi_codes_e error = spi_prepare_transfer(spi); + if (error) return error; + + // Create the transaction with the provided segments + spi_transaction_t txn = SPI_TXN(segments, segments_len, src_buffer, dest_buffer); + + // We check every segment for validity since they are defined by user. + // This function also counts the number of words of TX and RX the entire + // transaction is composed of. + if (!spi_validate_segments(txn.segments, txn.seglen, &txn.txlen, &txn.rxlen)) + return SPI_CODE_SEGMENT_INVAL; + + // Launch the transaction. All data has been verified, launch doesn't check + // anything. Here user callbacks are used because non-blocking function. + spi_launch(&peripherals[spi->idx], spi, txn, callbacks); + + return SPI_CODE_OK; +} + +/****************************************************************************/ +/** **/ +/* LOCAL FUNCTIONS */ +/** **/ +/****************************************************************************/ + +spi_codes_e spi_check_valid(spi_t* spi) +{ + // Is SPI peripheral identifier valid? + if (SPI_IDX_INVALID(spi->idx)) return SPI_CODE_IDX_INVAL; + // Has the spi been initialized (i.e. base validity checks made)? + if (!spi->init) return SPI_CODE_NOT_INIT; + return SPI_CODE_OK; +} + +spi_codes_e spi_validate_slave(spi_slave_t slave) +{ + spi_codes_e error = SPI_CODE_OK; + // Is chip select line number a valid one? + if (SPI_CSID_INVALID(slave.csid)) error |= SPI_CODE_SLAVE_CSID_INVAL; + // Is the slave max frequency less than the minimum frequency? + if (slave.freq < SPI_MIN_FREQ) error |= SPI_CODE_SLAVE_FREQ_INVAL; + return error; +} + +spi_codes_e spi_set_slave(spi_t* spi) +{ + // Compute the best clock divider + uint16_t clk_div = 0; + if (spi->slave.freq < SYS_FREQ / 2) + { + clk_div = (SYS_FREQ / spi->slave.freq - 2) / 2; + if (SYS_FREQ / (2 * clk_div + 2) > spi->slave.freq) clk_div++; + } + // Build the HAL configopts to be set based on our slave + spi_configopts_t config = { + .clkdiv = clk_div, + .csnidle = spi->slave.csn_idle, + .csntrail = spi->slave.csn_trail, + .csnlead = spi->slave.csn_lead, + .fullcyc = spi->slave.full_cycle, + .cpha = bitfield_read(spi->slave.data_mode, BIT_MASK_1, DATA_MODE_CPHA_OFFS), + .cpol = bitfield_read(spi->slave.data_mode, BIT_MASK_1, DATA_MODE_CPOL_OFFS) + }; + // Set the configopts + spi_return_flags_e config_error = spi_set_configopts(peripherals[spi->idx].instance, + spi->slave.csid, + spi_create_configopts(config)); + // CSID is invalid! This can only happen if user didn't properly initialize spi_t! + if (config_error) return SPI_CODE_SLAVE_INVAL; + // We already made sure csid was valid by calling spi_set_configopts. And we know + // instance is not NULL by definition. Hence won't return any errors. + spi_set_csid(peripherals[spi->idx].instance, spi->slave.csid); + return SPI_CODE_OK; +} + +spi_codes_e spi_prepare_transfer(spi_t* spi) +{ + // Check the idx and init of spi_t parameter. + // Notice that we do not check for slave's validity. This is because we assume + // that the user properly initialized his spi_t and didn't change its slave. + // Anyway spi_set_slave will give an error if the slave is invalid. But user + // should follow guidelines! + spi_codes_e error = spi_check_valid(spi); + if (error) return error; + + // If busy don't start a new transaction... + if (SPI_BUSY(peripherals[spi->idx])) return SPI_CODE_IS_BUSY; + // Check also at hardware level if busy, we don't know if maybe there is a + // problem somewhere + if (spi_get_active(peripherals[spi->idx].instance) == SPI_TRISTATE_TRUE) + return SPI_CODE_NOT_IDLE; + + // If the last spi instance was NOT the same as the current, slave may have + // changed, therefore set the "new" slave. Otherwise don't bother. + if (spi->id != peripherals[spi->idx].last_id) + { + error = spi_set_slave(spi); + if (error) return error; + } + + return SPI_CODE_OK; +} + +uint32_t spi_true_slave_freq(uint32_t freq) +{ + // Compute the best clock divider + uint16_t clk_div = 0; + if (freq < SYS_FREQ / 2) + { + clk_div = (SYS_FREQ / freq - 2) / 2; + if (SYS_FREQ / (2 * clk_div + 2) > freq) clk_div++; + } + // Based on the computed divider return the true frequency the SCK will be at + return SYS_FREQ / (2 * clk_div + 2); +} + +bool spi_validate_segments(const spi_segment_t* segments, uint32_t segments_len, + uint32_t* tx_count, uint32_t* rx_count) +{ + // Check that there are any segments + if (segments_len == 0) return false; + + // Make sure our word counters start at 0 + *tx_count = 0; + *rx_count = 0; + + for (int i = 0; i < segments_len; i++) + { + // Check that speed and direction are compatible and valid. + // Unfortunately this check will be done twice since when we set the command + // through the HAL the check will be done again. + // The problem is that, since starting a full transaction before being sure + // that all segments are valid would be undesirable, we have to check each + // segment before initiating a transaction. + uint8_t direction = bitfield_read(segments[i].mode, DIR_SPD_MASK, DIR_INDEX); + uint8_t speed = bitfield_read(segments[i].mode, DIR_SPD_MASK, SPD_INDEX); + if (!spi_validate_cmd(direction, speed)) return false; + // Translate bytes len to words len + uint32_t word_len = LEN_WORDS(segments[i].len); + // Increase corresponding counter. There are dummy cycles, hence we need to + // specifically check for the exact direction. + if (direction == SPI_DIR_TX_ONLY || direction == SPI_DIR_BIDIR) + *tx_count += word_len; + if (direction == SPI_DIR_RX_ONLY || direction == SPI_DIR_BIDIR) + *rx_count += word_len; + } + + return true; +} + +bool spi_fill_tx(spi_peripheral_t* peri) +{ + // If we have a TX buffer and didn't exceed the count then fill the TX FIFO + if (peri->txn.txbuffer != NULL && peri->txcnt < peri->txn.txlen) { + // While there is still data to be fed and there wasn't an error from HAL + // continue. HAL error in this case means that the fifo is full since + // it's the only possibility. + while ( + peri->txcnt < peri->txn.txlen + && !spi_write_word(peri->instance, peri->txn.txbuffer[peri->txcnt]) + ) peri->txcnt++; // Keep track of counter + return true; + } + return false; +} + +bool spi_empty_rx(spi_peripheral_t* peri) +{ + // If we have a RX buffer and didn't exceed the count then read from RX FIFO + if (peri->txn.rxbuffer != NULL && peri->rxcnt < peri->txn.rxlen) { + // While there is still data to be read and there wasn't an error from HAL + // continue. HAL error in this case means that the fifo is empty since + // it's the only possibility. + while ( + peri->rxcnt < peri->txn.rxlen + && !spi_read_word(peri->instance, &peri->txn.rxbuffer[peri->rxcnt]) + ) peri->rxcnt++; // Keep track of counter + return true; + } + return false; +} + +void spi_launch(spi_peripheral_t* peri, spi_t* spi, spi_transaction_t txn, + spi_callbacks_t callbacks) +{ + // All checks have been made, therefore there can't be any error here. + // This also means that we can safely set the state since we know we will + // proceed to launch without any doubt. + peri->state = SPI_STATE_BUSY; + // Set all transaction data to our static peripheral variable + peri->txn = txn; + // Indicate the callbacks that should be called + peri->callbacks = callbacks; + + // Fill the TX fifo before starting so there is data once command launched + spi_fill_tx(peri); + + // Enable event interrupts since they are enabled only during a transaction + spi_set_events_enabled(peri->instance, TRIGGERING_EVENTS, true); + spi_enable_evt_intr (peri->instance, true); + + // Wait for the SPI peripheral to be ready before writing a command segment. + spi_wait_for_ready(peri->instance); + // Write command segment. This immediately triggers the SPI peripheral into action. + spi_issue_next_seg(peri); +} + +void spi_wait_transaction_done(spi_peripheral_t* peri) +{ + // Convert ms timeout to clock ticks + uint64_t timeout_ticks = ((uint64_t) peri->timeout) * (SYS_FREQ / 1000); + uint32_t start[2]; + uint32_t end[2]; + + // Enable tick counter + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + // Record start tick counter value + CSR_READ(CSR_REG_MCYCLE, &start[0]); + CSR_READ(CSR_REG_MCYCLEH, &start[1]); + + // Wait until transaction has finished or timed-out + do + { + // Read tick counter value + CSR_READ(CSR_REG_MCYCLE, &end[0]); + CSR_READ(CSR_REG_MCYCLEH, &end[1]); + // If ticks elapsed exceed timeout ticks, cancel transaction and return + if (*((uint64_t*)end) - *((uint64_t*)start) > timeout_ticks) + { + // Fully reset spi peripheral to cancel transaction, empty fifos, etc. + spi_reset_peri(peri); + // Indicate to user the transaction has timed-out + peri->state = SPI_STATE_TIMEOUT; + break; + } + + } while (SPI_BUSY((*peri))); +} + +void spi_issue_next_seg(spi_peripheral_t* peri) +{ + const spi_segment_t seg = peri->txn.segments[peri->scnt]; + peri->scnt++; + // Construct our word command to be passed to HAL + uint32_t cmd_reg = spi_create_command((spi_command_t) { + .len = seg.len - 1, // -1 because of SPI Host IP specifications + .csaat = peri->txn.seglen == peri->scnt ? false : true, + .speed = bitfield_read(seg.mode, DIR_SPD_MASK, SPD_INDEX), + .direction = bitfield_read(seg.mode, DIR_SPD_MASK, DIR_INDEX), + }); + // Since all checks were already made we do not need to check the result of function + spi_set_command(peri->instance, cmd_reg); +} + +void spi_reset_peri(spi_peripheral_t* peri) +{ + // Reset static peripheral variables + spi_reset_transaction(peri); + // Reset the SPI peripheral (at hardware level) + spi_sw_reset(peri->instance); + // Enable SPI peripheral. We do not check return value since we know here that + // it will never return an error. + spi_set_enable(peri->instance, true); + spi_output_enable(peri->instance, true); + // Enable all error interrupts so that the SPI peripheral doesn't get stuck if + // there is an error. And we don't check return value since we know it's error free. + spi_set_errors_enabled(peri->instance, SPI_ERROR_IRQALL, true); + spi_enable_error_intr(peri->instance, true); + // Set the watermarks for the specific peripheral. + spi_set_tx_watermark(peri->instance, peri->txwm); + spi_set_rx_watermark(peri->instance, peri->rxwm); + // Just reset the state. + peri->state = SPI_STATE_INIT; + // Force the next transaction to set the slave at hardware level + peri->last_id = 0; +} + +void spi_reset_transaction(spi_peripheral_t* peri) +{ + // Reset all variables relative to the transaction of the static peripheral + // instance + peri->scnt = 0; + peri->txcnt = 0; + peri->rxcnt = 0; + peri->txn = (spi_transaction_t) {0}; + peri->callbacks = NULL_CALLBACKS; +} + +void spi_event_handler(spi_peripheral_t* peri, spi_event_e events) +{ + // Ready means it is ready to accept new command segments. So we have two + // possibilities if the device is ready: + // 1) It is ready but not idle + // 2) It is ready and idle + if (events & SPI_EVENT_READY) + { + // If SPI is ready and there are still commands to execute, issue next command + if (peri->txn.segments != NULL && peri->scnt < peri->txn.seglen) + { + spi_issue_next_seg(peri); + } + // If no more commands and SPI is idle, it means the transaction is over + else if (events & SPI_EVENT_IDLE) + { + // Disable all event interrupts + spi_set_events_enabled(peri->instance, SPI_EVENT_ALL, false); + spi_enable_evt_intr (peri->instance, false); + // Read the last data from the RX fifo + spi_empty_rx(peri); + // Set the state to Transaction is done (meaning successful) + peri->state = SPI_STATE_DONE; + // If there is a callback defined call it + if (peri->callbacks.done_cb != NULL) + { + peri->callbacks.done_cb(peri->txn.txbuffer, peri->txcnt, + peri->txn.rxbuffer, peri->rxcnt); + } + // Reset all transaction related variables + spi_reset_transaction(peri); + return; + } + } + if (events & SPI_EVENT_TXWM) + { + // TX watermark reached. Refill TX fifo if more data + // If there is a callback defined call it + if (spi_fill_tx(peri) && peri->callbacks.txwm_cb != NULL) + { + peri->callbacks.txwm_cb(peri->txn.txbuffer, peri->txcnt, + peri->txn.rxbuffer, peri->rxcnt); + } + } + if (events & SPI_EVENT_RXWM) + { + // RX watermark reached. Empty RX fifo to get more data + // If there is a callback defined call it + if (spi_empty_rx(peri) && peri->callbacks.rxwm_cb != NULL) + { + peri->callbacks.rxwm_cb(peri->txn.txbuffer, peri->txcnt, + peri->txn.rxbuffer, peri->rxcnt); + } + } +} + +void spi_error_handler(spi_peripheral_t* peri, spi_error_e error) +{ + // Disable event interrupts + spi_set_events_enabled(peri->instance, SPI_EVENT_ALL, false); + spi_enable_evt_intr (peri->instance, false); + // If there is a callback defined invoke it + if (peri->callbacks.error_cb != NULL) + { + peri->callbacks.error_cb(peri->txn.txbuffer, peri->txcnt, + peri->txn.rxbuffer, peri->rxcnt); + } + spi_reset_peri(peri); + // Set the state to error + peri->state = SPI_STATE_ERROR; +} + +/****************************************************************************/ +/** **/ +/* INTERRUPTS */ +/** **/ +/****************************************************************************/ + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_event_flash(spi_event_e events) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_FLASH])) return; + spi_event_handler(&peripherals[SPI_IDX_FLASH], events); +} + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_error_flash(spi_error_e errors) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_FLASH])) return; + spi_error_handler(&peripherals[SPI_IDX_FLASH], errors); +} + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_event_host(spi_event_e events) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_HOST])) return; + spi_event_handler(&peripherals[SPI_IDX_HOST], events); +} + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_error_host(spi_error_e errors) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_HOST])) return; + spi_error_handler(&peripherals[SPI_IDX_HOST], errors); +} + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_event_host2(spi_event_e events) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_HOST_2])) return; + spi_event_handler(&peripherals[SPI_IDX_HOST_2], events); +} + +/** + * @brief Implementation of the weak function of the HAL + */ +void spi_intr_handler_error_host2(spi_error_e errors) +{ + if (SPI_NOT_BUSY(peripherals[SPI_IDX_HOST_2])) return; + spi_error_handler(&peripherals[SPI_IDX_HOST_2], errors); +} + +/****************************************************************************/ +/** **/ +/** EOF **/ +/** **/ +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.h new file mode 100644 index 00000000..28982b31 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/spi/spi_sdk.h @@ -0,0 +1,576 @@ +/* + ******************* +******************************* C SOURCE FILE ***************************** +** ******************* +** +** project : X-HEEP +** filename : spi_sdk.h +** version : 1 +** date : 18/04/24 +** +*************************************************************************** +** +** Copyright (c) EPFL contributors. +** All rights reserved. +** +*************************************************************************** +*/ + +/***************************************************************************/ +/***************************************************************************/ +/** +* @file spi_sdk.h +* @date 18/04/24 +* @author Llorenç Muela +* @brief The Serial Peripheral Interface (SPI) SDK to set up and use the +* SPI peripheral +*/ + +#ifndef _SDK_SPI_H_ +#define _SDK_SPI_H_ + +/****************************************************************************/ +/** **/ +/** MODULES USED **/ +/** **/ +/****************************************************************************/ + +#include +#include + +/****************************************************************************/ +/** **/ +/** DEFINITIONS AND MACROS **/ +/** **/ +/****************************************************************************/ + +// Chosen arbitrarily +#define SPI_CSN_TIMES_DEFAULT 15 +// Default timeout for blocking transactions in milliseconds +#define SPI_TIMEOUT_DEFAULT 100 + +/** + * @brief Macro to create a Slave SPI device with standard parameters. + */ +#define SPI_SLAVE(cs_id, freq_max) (spi_slave_t) { \ + .csid = cs_id, \ + .data_mode = SPI_DATA_MODE_0, \ + .full_cycle = false, \ + .csn_lead = SPI_CSN_TIMES_DEFAULT, \ + .csn_trail = SPI_CSN_TIMES_DEFAULT, \ + .csn_idle = SPI_CSN_TIMES_DEFAULT, \ + .freq = freq_max \ +} + +/** + * @brief Macro to instantiate a Dummy Segment + */ +#define SPI_SEG_DUMMY(cycles) (spi_segment_t) { \ + .len = cycles, \ + .mode = SPI_MODE_DUMMY \ +} + +/** + * @brief Macro to instantiate a TX Segment + */ +#define SPI_SEG_TX(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_TX_STD \ +} + +/** + * @brief Macro to instantiate a RX Segment + */ +#define SPI_SEG_RX(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_RX_STD \ +} + +/** + * @brief Macro to instantiate a BIDIR Segment + */ +#define SPI_SEG_BIDIR(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_BIDIR \ +} + +/** + * @brief Macro to instantiate a Dual Speed TX Segment + */ +#define SPI_SEG_TX_DUAL(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_TX_DUAL \ +} + +/** + * @brief Macro to instantiate a Dual Speed RX Segment + */ +#define SPI_SEG_RX_DUAL(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_RX_DUAL \ +} + +/** + * @brief Macro to instantiate a Quad Speed TX Segment + */ +#define SPI_SEG_TX_QUAD(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_TX_QUAD \ +} + +/** + * @brief Macro to instantiate a Quad Speed RX Segment + */ +#define SPI_SEG_RX_QUAD(bytes) (spi_segment_t) { \ + .len = bytes, \ + .mode = SPI_MODE_RX_QUAD \ +} + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/** **/ +/** TYPEDEFS AND STRUCTURES **/ +/** **/ +/****************************************************************************/ + +/** +* @brief SPI Peripheral IDX +*/ +typedef enum { + SPI_IDX_FLASH = 0, // Identifier for the SPI FLASH peripheral + SPI_IDX_HOST = 1, // Identifier for the SPI HOST1 peripheral + SPI_IDX_HOST_2 = 2 // Identifier for the SPI HOST2 peripheral +} spi_idx_e; + +typedef enum { + SPI_CODE_OK = 0x0000, // Everything Okay + SPI_CODE_BASE_ERROR = 0x0001, // HAL complained (should never happen) + SPI_CODE_IDX_INVAL = 0x0002, // The idx of the provided spi_t is not valid + SPI_CODE_WM_EXCEEDS = 0x0004, // The provided watermark is too big + SPI_CODE_NOT_INIT = 0x0008, // The provided spi_t was not initialized + SPI_CODE_SLAVE_CSID_INVAL = 0x0010, // The csid of the slave is not valid + SPI_CODE_SLAVE_FREQ_INVAL = 0x0020, // Max frequency of the slave is too low + SPI_CODE_NOT_IDLE = 0x0040, // The SPI device is busy (but not from SDK) + SPI_CODE_SLAVE_INVAL = 0x0080, // Something was wrong with the slave configuration + SPI_CODE_SEGMENT_INVAL = 0x0100, // The spi_mode_e of the segment was invalid + SPI_CODE_IS_BUSY = 0x0200, // The SPI device is busy + SPI_CODE_TXN_LEN_INVAL = 0x0400, // The transaction length is 0 or too long + SPI_CODE_TIMEOUT_INVAL = 0x0800 // The specified timeout is invalid +} spi_codes_e; + +typedef enum { + SPI_DATA_MODE_0 = 0, // cpol = 0, cpha = 0 + SPI_DATA_MODE_1 = 1, // cpol = 0, cpha = 1 + SPI_DATA_MODE_2 = 2, // cpol = 1, cpha = 0 + SPI_DATA_MODE_3 = 3 // cpol = 1, cpha = 1 +} spi_datamode_e; + +typedef enum { + SPI_MODE_DUMMY = 0, // Dummy SCK command segment + SPI_MODE_RX_STD = 1, // Standard receive command segment + SPI_MODE_TX_STD = 2, // Standard transmit command segment + SPI_MODE_BIDIR = 3, // Standard bidirectional command segment + // 4 is same than DUMMY + SPI_MODE_RX_DUAL = 5, // Dual speed receive command segment + SPI_MODE_TX_DUAL = 6, // Dual speed transmit command segment + // 7 is invalid + // 8 is same than DUMMY + SPI_MODE_RX_QUAD = 9, // Quad speed receive command segment + SPI_MODE_TX_QUAD = 10 // Quad speed transmit command segment + // everything > 10 is invalid +} spi_mode_e; + +// State is useful to know if the peripheral is busy, but also very useful if a +// blocking transaction was made and we want to check the result of the blocking +// transation (i.e. error or success) +typedef enum { + // Indicates SPI device was never initialized (should never happen!) + SPI_STATE_NONE = 0x00, + // Indicates SPI device never executed a transaction + SPI_STATE_INIT = 0x01, + // Indicates SPI device is currently processing a transaction + SPI_STATE_BUSY = 0x02, + // Indicates SPI device has successfully executed a transaction + SPI_STATE_DONE = 0x04, + // Indicates there was an error during transaction + SPI_STATE_ERROR = 0x08, + // Indicates the transaction execution has timed-out + SPI_STATE_TIMEOUT = 0x10, + // Indicates the argument passed to spi_get_state was not valid + SPI_STATE_ARG_INVAL = 0x20 +} spi_state_e; + +/** + * @brief Type defining the configuration of the slave device with whom to communicate + */ +typedef struct { + // The Chip Select line where device connected + uint8_t csid : 2; + // The data sampling and transmitting mode (polarity and phase) + spi_datamode_e data_mode : 2; + // If 1 data is sampled a full cycle after shifting data out, instead of half cycle + bool full_cycle : 1; + // The minimum number of sck half-cycles to hold cs_n high between commands + uint8_t csn_idle : 4; + // The number of half sck cycles, CSNTRAIL+1, to leave between last edge of sck + // and the rising edge of cs_n + uint8_t csn_trail : 4; + // The number of half sck cycles, CSNLEAD+1, to leave between the falling edge + // of cs_n and the first edge of sck + uint8_t csn_lead : 4; + // The maximum frequency in hertz of the slave + uint32_t freq : 32; +} spi_slave_t; + +/** + * @brief Type defining a command segment + */ +typedef struct { + uint32_t len : 24; // Length of data in bytes for the particular segment + spi_mode_e mode : 4; // Communication mode (TX, BIDIR, RX_QUAD, ...) +} spi_segment_t; + +// Event / Error interrupt callback (txbuffer, txlen, rxbuffer, rxlen) +typedef void (*spi_cb_t)(const uint32_t*, uint32_t, uint32_t*, uint32_t); + +/** + * @brief Structure holding all the callbacks for a transaction. + * Each callback may be NULL if you don't want it to be called. + */ +typedef struct { + spi_cb_t done_cb; // Called once transaction is done + spi_cb_t txwm_cb; // Called each time TX watermark event is triggered + spi_cb_t rxwm_cb; // Called each time RX watermark event is triggered + spi_cb_t error_cb; // Called when there was an error during transaction +} spi_callbacks_t; + +/** + * @brief Type holding Information to use SDK. + */ +typedef struct { + spi_idx_e idx; // The identifier for the desired SPI devide + uint32_t id; // spi_t instance ID + bool init; // Indicates if initialization was successful + spi_slave_t slave; // The slave with whom to communicate configuration +} spi_t; + +/****************************************************************************/ +/** **/ +/** EXPORTED VARIABLES **/ +/** **/ +/****************************************************************************/ + +/****************************************************************************/ +/** **/ +/** EXPORTED FUNCTIONS **/ +/** **/ +/****************************************************************************/ + +/** + * @brief Initialize desired SPI device and obtain structure to use SDK functions. + * This method has to be called prior to any use of other functions of the SDK. + * + * Important: This method validates the provided slave and adapts its frequency + * based on the MCU frequency and the SCK divider. If you do not create the spi_t + * structure by calling this function the slave may be invalid resulting in errors. + * + * @param idx spi_idx_e representing the SPI device + * @param slave spi_slave_t correctly configured slave SPI device to interact with + * @return spi_t structure to use SDK functions + */ +spi_t spi_init(spi_idx_e idx, spi_slave_t slave); + +/** + * @brief Uninitializes the spi by unsetting all fields. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + */ +void spi_deinit(spi_t* spi); + +/** + * @brief Completely reset the SPI device (clears all status, stops all transactions, + * empties FIFOs) + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_reset(spi_t* spi); + +/** + * @brief Change the TX watermark of the specific SPI Host peripheral + * Maximum is currently 72. Check SPI_HOST_PARAM_TX_DEPTH in HAL. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param watermark The desired new watermark + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_WM_EXCEEDS if specified watermark is too high + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_set_txwm(spi_t* spi, uint8_t watermark); + +/** + * @brief Get the TX watermark of the specific SPI Host peripheral + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param watermark The current watermark will be stored in this variable + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_get_txwm(spi_t* spi, uint8_t* watermark); + +/** + * @brief Change the RX watermark of the specific SPI Host peripheral + * Maximum is currently 64. Check SPI_HOST_PARAM_RX_DEPTH in HAL. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param watermark The desired new watermark + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_WM_EXCEEDS if specified watermark is too high + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_set_rxwm(spi_t* spi, uint8_t watermark); + +/** + * @brief Get the RX watermark of the specific SPI Host peripheral + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param watermark The current watermark will be stored in this variable + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_get_rxwm(spi_t* spi, uint8_t* watermark); + +/** + * @brief Set the timeout in milliseconds for blocking transactions for the + * specific SPI Host peripheral. + * Maximum is UINT32_MAX * 1000 / core_frequency. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param watermark The desired new watermark + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_TIMEOUT_INVAL if the specified timout is too large + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_set_timeout(spi_t* spi, uint32_t timeout); + +/** + * @brief Get the timeout in milliseconds for blocking transactions for the + * specific SPI Host peripheral. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param timeout The current timeout will be stored in this variable + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_get_timeout(spi_t* spi, uint32_t* timeout); + +/** + * @brief Change the communication frequency of the slave + * /!\ If the frequency is higher than the maximum frequency it will just + * be capped (i.e. no error) + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param freq The new frequency the slave should be changed + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_SLAVE_CSID_INVAL if slave's csid is invalid + * @return SPI_CODE_SLAVE_FREQ_INVAL if new frequency is too low + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_set_slave_freq(spi_t* spi, uint32_t freq); + +/** + * @brief Read the SPI current state. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @return SPI_STATE_NONE : SPI device was never initialized (should never happen!) + * @return SPI_STATE_INIT : SPI device never executed a transaction + * @return SPI_STATE_BUSY : SPI device is currently processing a transaction + * @return SPI_STATE_DONE : SPI device has successfully executed a transaction + * @return SPI_STATE_ERROR : There was an error during transaction + * @return SPI_STATE_ARG_INVAL : The argument passed to this function was not valid + */ +spi_state_e spi_get_state(spi_t* spi); + +/** + * @brief Executes a TX command. + * /!\ Caution: len is in bytes. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param src_buffer An initialized buffer/array with all the data to send + * @param len The size in bytes of the transaction (/!\ must be coherent with + * src_buffer size) + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_transmit(spi_t* spi, const uint32_t* src_buffer, uint32_t len); + +/** + * @brief Executes an RX command. + * /!\ Caution: len is in bytes. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param dest_buffer An initialized buffer/array to store the received data + * @param len The size in bytes of the transaction (/!\ must be coherent with + * dest_buffer size) + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_receive(spi_t* spi, uint32_t* dest_buffer, uint32_t len); + +/** + * @brief Executes a Bidirectional (TX and RX) command. + * /!\ Caution: len is in bytes and is for the TX as well as RX. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param src_buffer An initialized buffer/array with all the data to send + * @param dest_buffer An initialized buffer/array to store the received data + * @param len The size in bytes of the transaction (/!\ must be coherent with + * src_buffer and dest_buffer size) + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_transceive(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len); + +/** + * @brief Executes a transacton composed of multiple command segments. + * Each segment already contains the Information about the length and the + * src/dest buffer concerned. Therefore no need for length parameter here. + * /!\ Caution: please be consistent with the length of src_buffer/dest_buffer + * and the lenghts specified for the segments. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param segments An array of command segments + * @param segments_len The size of segments array + * @param src_buffer An initialized buffer/array with all the data to send + * @param dest_buffer An initialized buffer/array to store the received data + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_SEGMENT_INVAL if segments contains an invalid segment + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_execute(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer); + +/** + * @brief Executes a TX command. This is Non-Blocking, the function will return + * immediately. + * /!\ Caution: len is in bytes. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param src_buffer An initialized buffer/array with all the data to send + * @param len The size in bytes of the transaction (/!\ must be coherent with + * src_buffer size) + * @param done_cb A callback function of type spi_cb_t that gets called when + * transaction is done + * @param error_cb A callback function of type spi_cb_t that gets called when there + * is an error during transaction + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_transmit_nb(spi_t* spi, const uint32_t* src_buffer, uint32_t len, + spi_callbacks_t callbacks); + +/** + * @brief Executes an RX command. This is Non-Blocking, the function will return + * immediately. + * /!\ Caution: len is in bytes. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param dest_buffer An initialized buffer/array to store the received data + * @param len The size in bytes of the transaction (/!\ must be coherent with + * dest_buffer size) + * @param done_cb A callback function of type spi_cb_t that gets called when + * transaction is done + * @param error_cb A callback function of type spi_cb_t that gets called when there + * is an error during transaction + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_receive_nb(spi_t* spi, uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks); + +/** + * @brief Executes a Bidirectional (TX and RX) command. This is Non-Blocking, the + * function will return immediately. + * /!\ Caution: len is in bytes and is for the TX as well as RX. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param src_buffer An initialized buffer/array with all the data to send + * @param dest_buffer An initialized buffer/array to store the received data + * @param len The size in bytes of the transaction (/!\ must be coherent with + * src_buffer and dest_buffer size) + * @param done_cb A callback function of type spi_cb_t that gets called when + * transaction is done + * @param error_cb A callback function of type spi_cb_t that gets called when there + * is an error during transaction + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_transceive_nb(spi_t* spi, const uint32_t* src_buffer, + uint32_t* dest_buffer, uint32_t len, + spi_callbacks_t callbacks); + +/** + * @brief Executes a transacton composed of multiple command segments. This is + * Non-Blocking, the function will return immediately. + * Each segment already contains the Information about the length and the + * src/dest buffer concerned. Therefore no need for length parameter here. + * /!\ Caution: please be consistent with the length of src_buffer/dest_buffer + * and the lenghts specified for the segments. + * + * @param spi Pointer to spi_t structure obtained through spi_init call + * @param segments An array of command segments + * @param segments_len The size of segments array + * @param src_buffer An initialized buffer/array with all the data to send + * @param dest_buffer An initialized buffer/array to store the received data + * @param done_cb A callback function of type spi_cb_t that gets called when + * transaction is done + * @param error_cb A callback function of type spi_cb_t that gets called when there + * is an error during transaction + * @return SPI_CODE_IDX_INVAL if spi.idx not valid + * @return SPI_CODE_NOT_INIT if spi.init false (indicates if spi was initialized) + * @return SPI_CODE_SEGMENT_INVAL if segments contains an invalid segment + * @return SPI_CODE_OK if success + */ +spi_codes_e spi_execute_nb(spi_t* spi, const spi_segment_t* segments, + uint32_t segments_len, const uint32_t* src_buffer, + uint32_t* dest_buffer, spi_callbacks_t callbacks); + +/****************************************************************************/ +/** **/ +/** INLINE FUNCTIONS **/ +/** **/ +/****************************************************************************/ + + +#ifdef __cplusplus +} +#endif + +#endif // _SDK_SPI_H_ + +/****************************************************************************/ +/** **/ +/** EOF **/ +/** **/ +/****************************************************************************/ diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.c new file mode 100644 index 00000000..3e4e2719 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.c @@ -0,0 +1,142 @@ +// Copyright 2023 EPFL and Politecnico di Torino. +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: timer_sdk.c +// Author: Michele Caon, Francesco Poluzzi +// Date: 23/07/2024 +// Description: Timer functions + +#include + +#include "timer_sdk.h" +#include "csr.h" +#include "soc_ctrl.h" + + +/******************************/ +/* ---- GLOBAL VARIABLES ---- */ +/******************************/ + +// Timer value +int32_t hw_timer_value = 0; + +rv_timer_t timer; + +rv_timer_config_t timer_cfg = { + .hart_count = RV_TIMER_PARAM_N_HARTS, + .comparator_count = RV_TIMER_PARAM_N_TIMERS, +}; + +mmio_region_t timer_base = { + .base = (void *)RV_TIMER_AO_START_ADDRESS, +}; + +rv_timer_tick_params_t tick_params; + + +/*************************************/ +/* ---- FUNCTION IMPLEMENTATION ---- */ +/*************************************/ + +uint32_t timer_get_cycles() +{ + uint64_t cycle_count; + rv_timer_counter_read(&timer, 0, &cycle_count); + return (uint32_t)cycle_count; +} + +void timer_irq_enable() +{ + rv_timer_irq_enable(&timer, 0, 0, kRvTimerEnabled); +} + +void timer_irq_clear() +{ + rv_timer_irq_clear(&timer, 0, 0); +} + +void timer_arm_start(uint32_t threshold) +{ + rv_timer_arm(&timer, 0, 0, threshold); + timer_start(); +} + +void timer_arm_stop() +{ + rv_timer_counter_set_enabled(&timer, 0, kRvTimerDisabled); +} + + +void timer_arm_set(uint32_t threshold) +{ + rv_timer_arm(&timer, 0, 0, threshold); +} + +void timer_start() +{ + hw_timer_value = -timer_get_cycles(); + rv_timer_counter_set_enabled(&timer, 0, kRvTimerEnabled); +} + +void timer_reset() +{ + hw_timer_value = 0; + rv_timer_reset(&timer); +} + +uint32_t timer_stop() +{ + hw_timer_value += timer_get_cycles(); + rv_timer_counter_set_enabled(&timer, 0, kRvTimerDisabled); + return hw_timer_value; +} + +// Initialize the timer +void timer_cycles_init() +{ + // Get current Frequency + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + // Initialize the timer + timer_reset(); + rv_timer_init(timer_base, timer_cfg, &timer); + rv_timer_approximate_tick_params(freq_hz, freq_hz, &tick_params); + rv_timer_set_tick_params(&timer, 0, tick_params); +} + +// Initialize the timer +void timer_wait_us(uint32_t us) +{ + // Get current Frequency + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + timer_cycles_init(); + timer_irq_enable(); + timer_arm_start(us*(freq_hz/1000000)-50); // 50 cycles for taking into account initialization + asm volatile ("wfi"); + timer_irq_clear(); + return; +} + +void enable_timer_interrupt() +{ + //enable timer interrupt + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + // Set mie.MEIE bit to one to enable machine-level timer interrupts + const uint32_t mask = 1 << 7; + CSR_SET_BITS(CSR_REG_MIE, mask); +} + +float get_time_from_cycles(uint32_t cycles){ + // Get current Frequency + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl); + + return (float)cycles/((float)freq_hz/1000000); +} \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.h new file mode 100644 index 00000000..154ef30b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/timer/timer_sdk.h @@ -0,0 +1,121 @@ + +// Copyright 2023 EPFL and Politecnico di Torino. +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: timer_sdk.h +// Authors: Michele Caon, Luigi Giuffrida, Francesco Poluzzi +// Date: 23/07/2024 +// Description: Execution time measurements utilities + +#ifndef TIMER_SDK_H_ +#define TIMER_SDK_H_ + +#include + +#include "csr.h" +#include "gpio.h" +#include "rv_timer.h" +#include "rv_timer_regs.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" + +#define FREQ_1MHz 1000000 + +/******************************/ +/* ---- GLOBAL VARIABLES ---- */ +/******************************/ + +// Timer value +extern int32_t hw_timer_value; + +extern rv_timer_t timer; + +/********************************/ +/* ---- EXPORTED FUNCTIONS ---- */ +/********************************/ + +/** + * @brief Get the current value of the HW timer + * +* @return int64_t Current value of the HW timer + */ +uint32_t timer_get_cycles(); + +/** + * @brief Start the timer + * + */ +void timer_start(); + +/** + * @brief Stop and reset the timer to 0 + * + */ +void timer_reset(); + +/** + * @brief Stop the HW timer + * + * @return int64_t Elapsed time in clock cycles + */ +uint32_t timer_stop(); + +/** + * @brief Initialize the timer for counting clock cycles + * @brief Initialize the timer for counting clock cycles + * + */ +void timer_cycles_init(); + +/** + * @brief Enable the timer IRQ + */ +void timer_irq_enable(); + +/** + * @brief Clear the timer IRQ + */ +void timer_irq_clear(); + +/** + * @brief Arms the timer to go off once the counter value is greater than or equal to threshold + * and starts the timer + */ +void timer_arm_start(uint32_t threshold); + +/** + * @brief Stop to output when timer is greater than or equal to threshold previously set + */ +void timer_arm_stop(); + +/** + * @brief Set the timer to go off once the counter value is greater than or equal to threshold, + * without starting the timer + */ +void timer_arm_set(uint32_t threshold); + +/** + * @brief Enable the timer machine-level interrupts for X-Heep + */ +void enable_timer_interrupt(); + +/** + * @brief Wait for a certain amount of microseconds. + * You need to enable timer interrupts with enable_timer_interrupt() before using this function + */ +void timer_wait_us(uint32_t ms); + +/** + * @brief Enable the timer machine-level interrupts for X-Heep + */ +void enable_timer_interrupt(); + +/** + * @brief Get the time taken to execute a certain number of cycles + * + * @return float value representing the time taken in microseconds + */ +float get_time_from_cycles(uint32_t cycles); + +#endif /* TIMER_SDK_H_ */ \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h index c1ef5c5c..072a31e0 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/nexys-a7-100t/x-heep.h @@ -15,6 +15,7 @@ extern "C" { #define REFERENCE_CLOCK_Hz 15*1000*1000 #define UART_BAUDRATE 9600 #define TARGET_NEXYS_A7_100T 1 +#define TARGET_IS_FPGA 1 /** * As the hw is configurable, we can have setups with different number of diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/pynq-z2/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/pynq-z2/x-heep.h index 43cef0d4..2733e716 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/target/pynq-z2/x-heep.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/pynq-z2/x-heep.h @@ -15,6 +15,7 @@ extern "C" { #define REFERENCE_CLOCK_Hz 15*1000*1000 #define UART_BAUDRATE 9600 #define TARGET_PYNQ_Z2 1 +#define TARGET_IS_FPGA 1 /** * As the hw is configurable, we can have setups with different number of diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h b/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h index af1b4cd5..7c0b0602 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/target/zcu104/x-heep.h @@ -14,6 +14,7 @@ extern "C" { #define REFERENCE_CLOCK_Hz 15*1000*1000 #define UART_BAUDRATE 9600 #define TARGET_ZCU104 1 +#define TARGET_IS_FPGA 1 /** * As the hw is configurable, we can have setups with different number of diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl index 7403248d..b499b576 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link.ld.tpl @@ -20,11 +20,9 @@ MEMORY /* Our testbench is a bit weird in that we initialize the RAM (thus allowing initialized sections to be placed there). Infact we dump all sections to ram. */ - ram0 (rwxai) : ORIGIN = 0x${linker_onchip_code_start_address}, LENGTH = 0x${linker_onchip_code_size_address} - ram1 (rwxai) : ORIGIN = 0x${linker_onchip_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} -% if ram_numbanks_cont > 1 and ram_numbanks_il > 0: - ram_il (rwxai) : ORIGIN = 0x${linker_onchip_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} -% endif + % for i, section in enumerate(xheep.iter_linker_sections()): + ram${i} (rwxai) : ORIGIN = ${f"{section.start:#08x}"}, LENGTH = ${f"{section.size:#08x}"} +% endfor } /* @@ -294,14 +292,16 @@ SECTIONS PROVIDE(__freertos_irq_stack_top = .); } >ram1 -% if ram_numbanks_cont > 1 and ram_numbanks_il > 0: - .data_interleaved : +% for i, section in enumerate(xheep.iter_linker_sections()): +% if not section.name in ["code", "data"]: + .${section.name} : { . = ALIGN(4); - *(.xheep_data_interleaved) + *(.xheep_${section.name}) . = ALIGN(4); - } >ram_il + } >ram${i} % endif +% endfor /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl index 8bd9e64e..dca5e456 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_exec.ld.tpl @@ -8,7 +8,7 @@ ENTRY(_start) MEMORY { FLASH (rx) : ORIGIN = 0x${flash_mem_start_address}, LENGTH = 0x${flash_mem_size_address} - RAM (xrw) : ORIGIN = 0x${'{:08X}'.format(int(ram_start_address,16) + 4)}, LENGTH = 0x${'{:08X}'.format(int(ram_size_address,16) - 4)} + RAM (xrw) : ORIGIN = 0x${f'{xheep.ram_start_address()+4:08X}'}, LENGTH = 0x${f'{xheep.ram_size_address()-4:08X}'} } SECTIONS { diff --git a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl index 541b2233..9e7b637f 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/linker/link_flash_load.ld.tpl @@ -7,15 +7,13 @@ ENTRY(_start) MEMORY { - ram0 (rwxai) : ORIGIN = 0x${linker_onchip_code_start_address}, LENGTH = 0x${linker_onchip_code_size_address} - ram1 (rwxai) : ORIGIN = 0x${linker_onchip_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} - FLASH0 (rx) : ORIGIN = 0x${linker_flash_code_start_address}, LENGTH = 0x${linker_onchip_code_size_address} - FLASH1 (rx) : ORIGIN = 0x${linker_flash_data_start_address}, LENGTH = 0x${linker_onchip_data_size_address} - % if ram_numbanks_cont > 1 and ram_numbanks_il > 0: - ram_il (rwxai) : ORIGIN = 0x${linker_onchip_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} - FLASH_il (rx) : ORIGIN = 0x${linker_flash_il_start_address}, LENGTH = 0x${linker_onchip_il_size_address} - % endif - FLASH_left (rx) : ORIGIN = 0x${linker_flash_left_start_address}, LENGTH = 0x${linker_flash_left_size_address} +<%flash_end = 0%> +% for i, section in enumerate(xheep.iter_linker_sections()): + ram${i} (rwxai) : ORIGIN = ${f"{section.start:#08x}"}, LENGTH = ${f"{section.size:#08x}"} + FLASH${i} (rx) : ORIGIN = ${f"{section.start + int(flash_mem_start_address,16):#08x}"}, LENGTH = ${f"{section.size:#08x}"} +<%flash_end = section.end%> +% endfor + FLASH_left (rx) : ORIGIN = ${f"{flash_end + int(flash_mem_start_address,16):#08x}"}, LENGTH = ${f"{int(flash_mem_size_address,16) - flash_end:#08x}"} } @@ -63,7 +61,9 @@ SECTIONS { KEEP (*(.text.spi_read_word*)) KEEP (*(.text.memcpy)) KEEP (*(.text.w25q128jw_read_standard)) /* as this function is used in the crt0, link it in the top, should be before 1024 Bytes loaded by the bootrom */ + KEEP (*(.text.w25q128jw_read_standard.*)) /* sometimes the function is renamed as w25q128jw_read_standard.part */ *(.xheep_init_data_crt0) /* this global variables are used in the crt0 */ + KEEP (*_bswapsi2*(.text)) /* this function is used in the w25q128jw_read_standard */ } >ram0 AT >FLASH0 /* The program code and other data goes into FLASH */ @@ -158,21 +158,23 @@ SECTIONS { PROVIDE(__freertos_irq_stack_top = .); } >ram1 - % if ram_numbanks_cont > 1 and ram_numbanks_il > 0: - .data_interleaved : ALIGN_WITH_INPUT + % for i, section in enumerate(xheep.iter_linker_sections()): + % if not section.name in ["code", "data"]: + .${section.name} : ALIGN_WITH_INPUT { - PROVIDE(__data_interleaved_start = .); - _lma_data_interleaved_start = LOADADDR(.data_interleaved); + PROVIDE(__${section.name}_start = .); + _lma_${section.name}_start = LOADADDR(.${section.name}); . = ALIGN(4); - *(.xheep_data_interleaved) + *(.xheep_${section.name}) . = ALIGN(4); - } >ram_il AT >FLASH_il + } >ram${i} AT >FLASH${i} . = ALIGN(4); - _eddata_interleaved = .; - _lma_data_interleaved_end = _lma_data_interleaved_start + SIZEOF(.data_interleaved); + _ed${section.name} = .; + _lma_${section.name}_end = _lma_${section.name}_start + SIZEOF(.${section.name}); % endif + % endfor .data_flash_only : ALIGN(256) { diff --git a/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl b/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl index a0f295a4..2aafa4e8 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl +++ b/hw/vendor/esl_epfl_x_heep/tb/tb_util.svh.tpl @@ -6,8 +6,8 @@ // Task for loading 'mem' with SystemVerilog system task $readmemh() export "DPI-C" task tb_readHEX; export "DPI-C" task tb_loadHEX; -% for bank in range(ram_numbanks): -export "DPI-C" task tb_writetoSram${bank}; +% for bank in xheep.iter_ram_banks(): +export "DPI-C" task tb_writetoSram${bank.name()}; % endfor export "DPI-C" task tb_getMemSize; export "DPI-C" task tb_set_exit_loop; @@ -16,9 +16,7 @@ import core_v_mini_mcu_pkg::*; task tb_getMemSize; output int mem_size; - output int num_banks; mem_size = core_v_mini_mcu_pkg::MEM_SIZE; - num_banks = core_v_mini_mcu_pkg::NUM_BANKS; endtask task tb_readHEX; @@ -31,11 +29,11 @@ task tb_loadHEX; input string file; //whether to use debug to write to memories logic [7:0] stimuli[core_v_mini_mcu_pkg::MEM_SIZE]; - int i, stimuli_counter, bank, NumBytes, NumBanks; + int i, stimuli_base, w_addr, NumBytes; logic [31:0] addr; tb_readHEX(file, stimuli); - tb_getMemSize(NumBytes, NumBanks); + tb_getMemSize(NumBytes); `ifndef VERILATOR for (i = 0; i < NumBytes; i = i + 4) begin @@ -71,43 +69,34 @@ task tb_loadHEX; release x_heep_system_i.core_v_mini_mcu_i.debug_subsystem_i.dm_obi_top_i.master_wdata_o; `else - - stimuli_counter = 0; -% for bank in range(ram_numbanks_cont): - for (i = 0; i < NumBytes / NumBanks; i = i + 4) begin - tb_writetoSram${bank}(i / 4, stimuli[stimuli_counter+3], stimuli[stimuli_counter+2], - stimuli[stimuli_counter+1], stimuli[stimuli_counter]); - stimuli_counter = stimuli_counter + 4; +% for bank in xheep.iter_ram_banks(): + for (i=${bank.start_address()}; i < ${bank.end_address()}; i = i + 4) begin + if (((i/4) & ${2**bank.il_level()-1}) == ${bank.il_offset()}) begin + w_addr = ((i/4) >> ${bank.il_level()}) % ${bank.size()//4}; + tb_writetoSram${bank.name()}(w_addr, stimuli[i+3], stimuli[i+2], + stimuli[i+1], stimuli[i]); + end end % endfor -% if ram_numbanks_il != 0: - for (i = 0; i < NumBytes / NumBanks; i = i + 4) begin -% for bank in range(ram_numbanks_il): - tb_writetoSram${int(ram_numbanks_cont) + bank}(i / 4, stimuli[stimuli_counter+3], stimuli[stimuli_counter+2], - stimuli[stimuli_counter+1], stimuli[stimuli_counter]); - stimuli_counter = stimuli_counter + 4; -% endfor - end -% endif `endif endtask -% for bank in range(ram_numbanks): -task tb_writetoSram${bank}; +% for bank in xheep.iter_ram_banks(): +task tb_writetoSram${bank.name()}; input int addr; input [7:0] val3; input [7:0] val2; input [7:0] val1; input [7:0] val0; `ifdef VCS - force x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.gen_sram[${bank}].ram_i.tc_ram_i.sram[addr] = { + force x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.ram${bank.name()}_i.tc_ram_i.sram[addr] = { val3, val2, val1, val0 }; - release x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.gen_sram[${bank}].ram_i.tc_ram_i.sram[addr]; + release x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.ram${bank.name()}_i.tc_ram_i.sram[addr]; `else - x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.gen_sram[${bank}].ram_i.tc_ram_i.sram[addr] = { + x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_i.ram${bank.name()}_i.tc_ram_i.sram[addr] = { val3, val2, val1, val0 }; `endif diff --git a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv index 2a4c7040..9008beb4 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv @@ -88,6 +88,17 @@ module testharness #( logic iffifo_in_ready, iffifo_out_valid; logic iffifo_int_o; + // External DMA slots + logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx; + logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx; + + assign ext_dma_slot_tx[0] = iffifo_in_ready; + assign ext_dma_slot_rx[0] = iffifo_out_valid; + if (core_v_mini_mcu_pkg::DMA_CH_NUM > 1) begin + assign ext_dma_slot_tx[core_v_mini_mcu_pkg::DMA_CH_NUM-1:1] = '0; + assign ext_dma_slot_rx[core_v_mini_mcu_pkg::DMA_CH_NUM-1:1] = '0; + end + // External xbar master/slave and peripheral ports obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_master_req; obi_req_t [EXT_XBAR_NMASTER_RND-1:0] heep_slave_req; @@ -153,6 +164,7 @@ module testharness #( $display("%t: the parameter X_EXT is %x", $time, X_EXT); $display("%t: the parameter ZFINX is %x", $time, ZFINX); $display("%t: the parameter JTAG_DPI is %x", $time, JTAG_DPI); + $display("%t: the parameter EXT_DOMAINS is %x", $time, core_v_mini_mcu_pkg::EXTERNAL_DOMAINS); $display("%t: the parameter USE_EXTERNAL_DEVICE_EXAMPLE is %x", $time, USE_EXTERNAL_DEVICE_EXAMPLE); $display("%t: the parameter CLK_FREQUENCY is %d KHz", $time, CLK_FREQUENCY); @@ -261,8 +273,9 @@ module testharness #( .external_subsystem_rst_no(external_subsystem_rst_n), .external_ram_banks_set_retentive_no(external_ram_banks_set_retentive_n), .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n), - .ext_dma_slot_tx_i(iffifo_in_ready), - .ext_dma_slot_rx_i(iffifo_out_valid) + .ext_dma_slot_tx_i(ext_dma_slot_tx), + .ext_dma_slot_rx_i(ext_dma_slot_rx), + .ext_dma_stop_i('0) ); // Testbench external bus @@ -314,7 +327,7 @@ module testharness #( always_ff @(negedge clk_i) begin tb_cpu_subsystem_powergate_switch_ack_n[0] <= x_heep_system_i.cpu_subsystem_powergate_switch_n; tb_peripheral_subsystem_powergate_switch_ack_n[0] <= x_heep_system_i.peripheral_subsystem_powergate_switch_n; - tb_memory_subsystem_banks_powergate_switch_ack_n[0] <= x_heep_system_i.memory_subsystem_banks_powergate_switch_n; + tb_memory_subsystem_banks_powergate_switch_ack_n[0] <= x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_banks_powergate_switch_n; tb_external_subsystem_powergate_switch_ack_n[0] <= external_subsystem_powergate_switch_n; for (int i = 0; i < SWITCH_ACK_LATENCY; i++) begin tb_memory_subsystem_banks_powergate_switch_ack_n[i+1] <= tb_memory_subsystem_banks_powergate_switch_ack_n[i]; @@ -333,12 +346,12 @@ module testharness #( `ifndef VERILATOR force x_heep_system_i.core_v_mini_mcu_i.cpu_subsystem_powergate_switch_ack_ni = delayed_tb_cpu_subsystem_powergate_switch_ack_n; force x_heep_system_i.core_v_mini_mcu_i.peripheral_subsystem_powergate_switch_ack_ni = delayed_tb_peripheral_subsystem_powergate_switch_ack_n; - force x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_banks_powergate_switch_ack_ni = delayed_tb_memory_subsystem_banks_powergate_switch_ack_n; + force x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_banks_powergate_switch_ack_n = delayed_tb_memory_subsystem_banks_powergate_switch_ack_n; force external_subsystem_powergate_switch_ack_n = delayed_tb_external_subsystem_powergate_switch_ack_n; `else x_heep_system_i.cpu_subsystem_powergate_switch_ack_n = delayed_tb_cpu_subsystem_powergate_switch_ack_n; x_heep_system_i.peripheral_subsystem_powergate_switch_ack_n = delayed_tb_peripheral_subsystem_powergate_switch_ack_n; - x_heep_system_i.memory_subsystem_banks_powergate_switch_ack_n = delayed_tb_memory_subsystem_banks_powergate_switch_ack_n; + x_heep_system_i.core_v_mini_mcu_i.memory_subsystem_banks_powergate_switch_ack_n = delayed_tb_memory_subsystem_banks_powergate_switch_ack_n; external_subsystem_powergate_switch_ack_n = delayed_tb_external_subsystem_powergate_switch_ack_n; `endif end @@ -456,6 +469,7 @@ module testharness #( ) dma_i ( .clk_i, .rst_ni, + .ext_dma_stop_i('0), .reg_req_i(ext_periph_slv_req[testharness_pkg::MEMCOPY_CTRL_IDX]), .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::MEMCOPY_CTRL_IDX]), .dma_read_ch0_req_o(ext_master_req[testharness_pkg::EXT_MASTER0_IDX]), diff --git a/hw/vendor/esl_epfl_x_heep/util/MakefileHelp b/hw/vendor/esl_epfl_x_heep/util/MakefileHelp index dc5f2901..8e072d0a 100755 --- a/hw/vendor/esl_epfl_x_heep/util/MakefileHelp +++ b/hw/vendor/esl_epfl_x_heep/util/MakefileHelp @@ -1,8 +1,7 @@ #!/bin/bash - -FILE=Makefile RULE_COLOR="$(tput setaf 6)" SECTION_COLOR="$(tput setaf 3)" +SSECTION_COLOR="$(tput setaf 5)" VARIABLE_COLOR="$(tput setaf 2)" VALUE_COLOR="$(tput setaf 1)" CLEAR_STYLE="$(tput sgr0)" @@ -17,13 +16,14 @@ echo "" TARGET_REGEX="^[a-zA-Z0-9%_\/%-]+:" SECTION_REGEX="^##\s*@section\s*(.*)$" +SSECTION_REGEX="^##\s*@subsection\s*(.*)$" DOCBLOCK_REGEX="^##\s*(.*)$" PARAM_REGEX="@param\s+([a-zA-Z_]+)(=([^\s]+))?\s*(.*$)?" COMMENT="" PARAMS="" PARAMS_DOC="" -cat $FILE | while read line +cat $FILE_FOR_HELP | while read line do # do something with $line here if [[ ! -z $line ]] @@ -31,7 +31,11 @@ do if [[ $line =~ $SECTION_REGEX ]] then SECTION_NAME=$(echo $line | sed -e "s/^##\s*@section\s*\(.*\)$/\1/g") - echo "$SECTION_COLOR$SECTION_NAME$CLEAR_STYLE:" + echo "$SECTION_COLOR$SECTION_NAME:$CLEAR_STYLE" + elif [[ $line =~ $SSECTION_REGEX ]] + then + SECTION_NAME=$(echo $line | sed -e "s/^##\s*@subsection\s*\(.*\)$/\1/g") + echo "$SSECTION_COLOR $SECTION_NAME:$CLEAR_STYLE" elif [[ $line =~ $TARGET_REGEX ]] then # if there is no comment for this target, we don't display it in the docs to keep private targets hidden diff --git a/hw/vendor/esl_epfl_x_heep/util/generate-makefile-help b/hw/vendor/esl_epfl_x_heep/util/generate-makefile-help deleted file mode 100755 index 30e4893c..00000000 --- a/hw/vendor/esl_epfl_x_heep/util/generate-makefile-help +++ /dev/null @@ -1,2 +0,0 @@ -help: - util/MakefileHelp \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py index 5c86308f..31826540 100755 --- a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py +++ b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py @@ -18,6 +18,8 @@ from mako.template import Template import collections from math import log2 +import x_heep_gen.load_config +from x_heep_gen.system import BusType class Pad: @@ -30,13 +32,25 @@ def remove_comma_io_interface(self): def create_pad_ring(self): + # Mapping dictionary from string to integer + mapping_dict = { + 'top' : 'core_v_mini_mcu_pkg::TOP', + 'right' : 'core_v_mini_mcu_pkg::RIGHT', + 'bottom' : 'core_v_mini_mcu_pkg::BOTTOM', + 'left' : 'core_v_mini_mcu_pkg::LEFT' + } + + mapping = '' + if self.pad_mapping is not None: + mapping = ', .SIDE(' + mapping_dict[self.pad_mapping] + ')' + self.interface = ' inout wire ' + self.name + '_io,\n' if self.pad_type == 'input': self.pad_ring_io_interface = ' inout wire ' + self.io_interface + ',' self.pad_ring_ctrl_interface += ' output logic ' + self.signal_name + 'o,' self.pad_ring_instance = \ - 'pad_cell_input #(.PADATTR('+ str(self.attribute_bits) +')) ' + self.cell_name + ' ( \n' + \ + 'pad_cell_input #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ ' .pad_in_i(1\'b0),\n' + \ ' .pad_oe_i(1\'b0),\n' + \ ' .pad_out_o(' + self.signal_name + 'o),\n' + \ @@ -45,7 +59,7 @@ def create_pad_ring(self): self.pad_ring_io_interface = ' inout wire ' + self.io_interface + ',' self.pad_ring_ctrl_interface += ' input logic ' + self.signal_name + 'i,' self.pad_ring_instance = \ - 'pad_cell_output #(.PADATTR('+ str(self.attribute_bits) +')) ' + self.cell_name + ' ( \n' + \ + 'pad_cell_output #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ ' .pad_in_i(' + self.signal_name + 'i),\n' + \ ' .pad_oe_i(1\'b1),\n' + \ ' .pad_out_o(),\n' + \ @@ -56,7 +70,7 @@ def create_pad_ring(self): self.pad_ring_ctrl_interface += ' output logic ' + self.signal_name + 'o,\n' self.pad_ring_ctrl_interface += ' input logic ' + self.signal_name + 'oe_i,' self.pad_ring_instance = \ - 'pad_cell_inout #(.PADATTR('+ str(self.attribute_bits) +')) ' + self.cell_name + ' ( \n' + \ + 'pad_cell_inout #(.PADATTR('+ str(self.attribute_bits) +')' + mapping + ') ' + self.cell_name + ' ( \n' + \ ' .pad_in_i(' + self.signal_name + 'i),\n' + \ ' .pad_oe_i(' + self.signal_name + 'oe_i),\n' + \ ' .pad_out_o(' + self.signal_name + 'o),\n' + \ @@ -195,13 +209,14 @@ def create_pad_ring_bonding(self): self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'oe_i(' + oe_internal_signals + '),' self.x_heep_system_interface += ' inout wire ' + self.signal_name + 'io,' - def __init__(self, name, cell_name, pad_type, index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, has_attribute, attribute_bits): + def __init__(self, name, cell_name, pad_type, pad_mapping, index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, has_attribute, attribute_bits): self.name = name self.cell_name = cell_name self.index = index self.localparam = 'PAD_' + name.upper() self.pad_type = pad_type + self.pad_mapping = pad_mapping self.pad_mux_list = pad_mux_list if('low' in pad_active): @@ -285,12 +300,18 @@ def write_template(tpl_path, outdir, outfile, **kwargs): def main(): parser = argparse.ArgumentParser(prog="mcugen") - parser.add_argument("--cfg", + parser.add_argument("--cfg_peripherals", "-c", metavar="file", type=argparse.FileType('r'), required=True, help="A configuration file") + + parser.add_argument("--config", + metavar="file", + type=str, + required=True, + help="X-Heep general configuration") parser.add_argument("--pads_cfg", "-pc", @@ -380,7 +401,7 @@ def main(): logging.basicConfig(level=logging.DEBUG) # Read HJSON description of System. - with args.cfg as file: + with args.cfg_peripherals as file: try: srcfull = file.read() obj = hjson.loads(srcfull, use_decimal=True) @@ -404,47 +425,21 @@ def main(): outfile = args.outfile + config_override = x_heep_gen.system.Override(None, None, None) + if args.cpu != None and args.cpu != '': cpu_type = args.cpu else: cpu_type = obj['cpu_type'] if args.bus != None and args.bus != '': - bus_type = args.bus - else: - bus_type = obj['bus_type'] + config_override.bus_type = BusType(args.bus) if args.memorybanks != None and args.memorybanks != '': - ram_numbanks_cont = int(args.memorybanks) - else: - ram_numbanks_cont = int(obj['ram']['numbanks']) + config_override.numbanks = int(args.memorybanks) if args.memorybanks_il != None and args.memorybanks_il != '': - ram_numbanks_il = int(args.memorybanks_il) - else: - ram_numbanks_il = int(obj['ram']['numbanks_interleaved']) - - if ram_numbanks_il != 0: - log_ram_numbanks_il = int(log2(ram_numbanks_il)) - - if not log2(ram_numbanks_il).is_integer(): - exit("ram interleaved numbanks must be a power of 2 instead of " + str(ram_numbanks_il)) - else: - log_ram_numbanks_il = 0 - - if ram_numbanks_il != 0 and bus_type == 'onetoM': - exit("bus type must be 'NtoM' instead 'onetoM' to access the interleaved memory banks in parallel" + str(args.bus)) - - if ram_numbanks_cont + ram_numbanks_il < 2 and ram_numbanks_cont + ram_numbanks_il > 16: - exit("ram numbanks must be between 2 and 16 instead of " + str(ram_numbanks_cont + ram_numbanks_il)) - else: - ram_numbanks = ram_numbanks_cont + ram_numbanks_il - - ram_start_address = string2int(obj['ram']['address']) - if int(ram_start_address,16) != 0: - exit("ram start address must be 0 instead of " + str(ram_start_address)) - - ram_size_address = '{:08X}'.format(ram_numbanks*32*1024) + config_override.numbanks_il = int(args.memorybanks_il) if args.external_domains != None and args.external_domains != '': external_domains = int(args.external_domains) @@ -454,6 +449,12 @@ def main(): if external_domains > 32: exit("external_domains must be less than 32 instead of " + str(external_domains)) + + + xheep = x_heep_gen.load_config.load_cfg_file(pathlib.PurePath(str(args.config)), config_override) + + + debug_start_address = string2int(obj['debug']['address']) if int(debug_start_address, 16) < int('10000', 16): exit("debug start address must be greater than 0x10000") @@ -503,7 +504,11 @@ def len_extracted_peripherals(peripherals): ao_peripherals = extract_peripherals(discard_path(obj['ao_peripherals'])) ao_peripherals_count = len(ao_peripherals) + dma_ch_count = ao_peripherals["dma"]["num_channels"] + if int(dma_ch_count, 16) > int('256', 16) or int(dma_ch_count, 16) == 0: + exit("Number of DMA channels has to be between 0 and 256, excluded") + dma_ch_size = ao_peripherals["dma"]["ch_length"] peripheral_start_address = string2int(obj['peripherals']['address']) if int(peripheral_start_address, 16) < int('10000', 16): @@ -519,47 +524,11 @@ def len_extracted_peripherals(peripherals): flash_mem_start_address = string2int(obj['flash_mem']['address']) flash_mem_size_address = string2int(obj['flash_mem']['length']) - linker_onchip_code_start_address = string2int(obj['linker_script']['onchip_ls']['code']['address']) - linker_onchip_code_size_address = string2int(obj['linker_script']['onchip_ls']['code']['lenght']) - - if int(linker_onchip_code_size_address,16) < 32*1024: - exit("The code section must be at least 32KB, instead it is " + str(linker_onchip_code_size_address)) - - linker_onchip_data_start_address = string2int(obj['linker_script']['onchip_ls']['data']['address']) - if (obj['linker_script']['onchip_ls']['data']['lenght'].split()[0].split(",")[0] == "whatisleft"): - if ram_numbanks_il == 0 or (ram_numbanks_cont == 1 and ram_numbanks_il > 0): - linker_onchip_data_size_address = str('{:08X}'.format(int(ram_size_address,16) - int(linker_onchip_code_size_address,16))) - else: - linker_onchip_data_size_address = str('{:08X}'.format(int(ram_size_address,16) - int(linker_onchip_code_size_address,16) - ram_numbanks_il*32*1024)) - else: - if ram_numbanks_il == 0 or (ram_numbanks_cont == 1 and ram_numbanks_il > 0): - linker_onchip_data_size_address = string2int(obj['linker_script']['onchip_ls']['data']['lenght']) - else: - linker_onchip_data_size_address = str('{:08X}'.format(int(string2int(obj['linker_script']['onchip_ls']['data']['lenght']),16) - ram_numbanks_il*32*1024)) - - linker_onchip_il_start_address = str('{:08X}'.format(int(linker_onchip_data_start_address,16) + int(linker_onchip_data_size_address,16))) - linker_onchip_il_size_address = str('{:08X}'.format(ram_numbanks_il*32*1024)) - stack_size = string2int(obj['linker_script']['stack_size']) heap_size = string2int(obj['linker_script']['heap_size']) - linker_flash_code_start_address = str('{:08X}'.format(int(linker_onchip_code_start_address,16) + int(flash_mem_start_address,16))) - linker_flash_data_start_address = str('{:08X}'.format(int(linker_onchip_data_start_address,16) + int(flash_mem_start_address,16))) - linker_flash_il_start_address = str('{:08X}'.format(int(linker_onchip_il_start_address,16) + int(flash_mem_start_address,16))) - - if ram_numbanks_il == 0 or (ram_numbanks_cont == 1 and ram_numbanks_il > 0): - linker_flash_left_start_address = str('{:08X}'.format(int(linker_flash_data_start_address,16) + int(linker_onchip_data_size_address,16))) - linker_flash_left_size_address = str('{:08X}'.format(int(flash_mem_size_address,16) - int(linker_onchip_code_size_address,16) - int(linker_onchip_data_size_address,16))) - else: - linker_flash_left_start_address = str('{:08X}'.format(int(linker_flash_il_start_address,16) + int(linker_onchip_il_size_address,16))) - linker_flash_left_size_address = str('{:08X}'.format(int(flash_mem_size_address,16) - int(linker_onchip_code_size_address,16) - int(linker_onchip_data_size_address,16) - int(linker_onchip_il_size_address,16))) - - - if ((int(linker_onchip_data_size_address,16) + int(linker_onchip_code_size_address,16)) > int(ram_size_address,16)): - exit("The code and data section must fit in the RAM size, instead they takes " + str(linker_onchip_data_size_address + linker_onchip_code_size_address)) - - if ((int(stack_size,16) + int(heap_size,16)) > int(ram_size_address,16)): + if ((int(stack_size,16) + int(heap_size,16)) > xheep.ram_size_address()): exit("The stack and heap section must fit in the RAM size, instead they takes " + str(stack_size + heap_size)) @@ -610,7 +579,7 @@ def len_extracted_peripherals(peripherals): pad_name = key pad_num = pads[key]['num'] - pad_type = pads[key]['type'] + pad_type = pads[key]['type'].strip(',') try: pad_offset = int(pads[key]['num_offset']) @@ -621,6 +590,11 @@ def len_extracted_peripherals(peripherals): pad_active = pads[key]['active'] except KeyError: pad_active = 'high' + + try: + pad_mapping = pads[key]['mapping'].strip(',') + except KeyError: + pad_mapping = None try: pad_mux_list_hjson = pads[key]['mux'] @@ -676,13 +650,13 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_skip_declaration_mux = False - p = Pad(pad_mux, '', pads[key]['mux'][pad_mux]['type'], 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) + p = Pad(pad_mux, '', pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) pad_mux_list.append(p) if pad_num > 1: for p in range(pad_num): pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) if not pad_keep_internal: pad_obj.create_pad_ring() pad_obj.create_core_v_mini_mcu_ctrl() @@ -701,7 +675,7 @@ def len_extracted_peripherals(peripherals): else: pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) if not pad_keep_internal: pad_obj.create_pad_ring() pad_obj.create_core_v_mini_mcu_ctrl() @@ -736,6 +710,11 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_active = 'high' + try: + pad_mapping = external_pads[key]['mapping'] + except KeyError: + pad_mapping = None + try: pad_mux_list_hjson = external_pads[key]['mux'] except KeyError: @@ -782,13 +761,13 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_skip_declaration_mux = False - p = Pad(pad_mux, '', external_pads[key]['mux'][pad_mux]['type'], 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) + p = Pad(pad_mux, '', external_pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) pad_mux_list.append(p) if pad_num > 1: for p in range(pad_num): pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) pad_obj.create_pad_ring() pad_obj.create_pad_ring_bonding() pad_obj.create_internal_signals() @@ -804,7 +783,7 @@ def len_extracted_peripherals(peripherals): else: pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) pad_obj.create_pad_ring() pad_obj.create_pad_ring_bonding() pad_obj.create_internal_signals() @@ -838,21 +817,17 @@ def len_extracted_peripherals(peripherals): total_pad_list.append(last_pad) kwargs = { + "xheep" : xheep, "cpu_type" : cpu_type, - "bus_type" : bus_type, - "ram_start_address" : ram_start_address, - "ram_numbanks" : ram_numbanks, - "ram_numbanks_cont" : ram_numbanks_cont, - "ram_numbanks_il" : ram_numbanks_il, - "log_ram_numbanks_il" : log_ram_numbanks_il, "external_domains" : external_domains, - "ram_size_address" : ram_size_address, "debug_start_address" : debug_start_address, "debug_size_address" : debug_size_address, "ao_peripheral_start_address" : ao_peripheral_start_address, "ao_peripheral_size_address" : ao_peripheral_size_address, "ao_peripherals" : ao_peripherals, "ao_peripherals_count" : ao_peripherals_count, + "dma_ch_count" : dma_ch_count, + "dma_ch_size" : dma_ch_size, "peripheral_start_address" : peripheral_start_address, "peripheral_size_address" : peripheral_size_address, "peripherals" : peripherals, @@ -861,17 +836,6 @@ def len_extracted_peripherals(peripherals): "ext_slave_size_address" : ext_slave_size_address, "flash_mem_start_address" : flash_mem_start_address, "flash_mem_size_address" : flash_mem_size_address, - "linker_flash_code_start_address" : linker_flash_code_start_address, - "linker_flash_data_start_address" : linker_flash_data_start_address, - "linker_flash_il_start_address" : linker_flash_il_start_address, - "linker_flash_left_start_address" : linker_flash_left_start_address, - "linker_flash_left_size_address" : linker_flash_left_size_address, - "linker_onchip_code_start_address" : linker_onchip_code_start_address, - "linker_onchip_code_size_address" : linker_onchip_code_size_address, - "linker_onchip_data_start_address" : linker_onchip_data_start_address, - "linker_onchip_data_size_address" : linker_onchip_data_size_address, - "linker_onchip_il_start_address" : linker_onchip_il_start_address, - "linker_onchip_il_size_address" : linker_onchip_il_size_address, "stack_size" : stack_size, "heap_size" : heap_size, "plic_used_n_interrupts" : plic_used_n_interrupts, diff --git a/hw/vendor/esl_epfl_x_heep/util/structs_periph_gen.py b/hw/vendor/esl_epfl_x_heep/util/structs_periph_gen.py index c737370c..79608eea 100644 --- a/hw/vendor/esl_epfl_x_heep/util/structs_periph_gen.py +++ b/hw/vendor/esl_epfl_x_heep/util/structs_periph_gen.py @@ -1,6 +1,9 @@ import hjson import structs_gen +# Path to the dma file +dma_file_path = "./sw/device/lib/drivers/dma/dma_structs.h" + # Path to the header_structs template template_path = "./sw/device/lib/drivers/template.tpl" @@ -40,6 +43,26 @@ def scan_peripherals(json_list): add_peripheral(p, json_list[p]["path"]) +def format_dma_channels(file_path, new_string): + + try: + # Read the contents of the file + with open(file_path, 'r') as file: + content = file.read() + + # Replace 'DMA_START_ADDRESS' with 'new_address' + updated_content = content.replace('#define dma_peri ((volatile dma *) DMA_START_ADDRESS)', new_string) + + # Write the updated content back to the file + with open(file_path, 'w') as file: + file.write(updated_content) + + print("DMA channel has been successfully updated.") + + except FileNotFoundError: + print(f"The file {file_path} does not exist.") + except Exception as e: + print(f"An error occurred: {str(e)}") # for i in range(len(JSON_FILES)): # print("{}\n{}\n{}\n\n\n".format(PERIPHERAL_NAMES[i], JSON_FILES[i], OUTPUT_FILES[i])) @@ -64,4 +87,7 @@ def scan_peripherals(json_list): # "--peripheral_name", PERIPHERAL_NAMES[i], "--json_filename", JSON_FILES[i], "--output_filename", OUTPUT_FILES[i]] - ) \ No newline at end of file + ) + + new_string = "#define dma_peri(channel) ((volatile dma *) (DMA_START_ADDRESS + DMA_CH_SIZE * channel))" + format_dma_channels(dma_file_path, new_string) \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/test_all.sh b/hw/vendor/esl_epfl_x_heep/util/test_all.sh index 60d45a28..dd0d0374 100755 --- a/hw/vendor/esl_epfl_x_heep/util/test_all.sh +++ b/hw/vendor/esl_epfl_x_heep/util/test_all.sh @@ -338,7 +338,7 @@ sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson if [ $DEBUG -eq 0 ]; then # The MCU is generated with several memory banks to avoid example code not fitting. - make mcu-gen MEMORY_BANKS=3 EXTERNAL_DOMAINS=1 + make mcu-gen X_HEEP_CFG=configs/testall.hjson EXTERNAL_DOMAINS=1 if [ "$SIMULATOR" != "none" ]; then # Make the simualtion model @@ -348,6 +348,14 @@ if [ $DEBUG -eq 0 ]; then echo -e "${WHITE}Building simulation model $SIM_MODEL_CMD ${RESET}" echo -e ${LONG_W} + if [ "$OPT" == "1" ] && [ "$SIMULATOR" == "questasim" ]; then + # Perform optimization + SIM_MODEL_CMD=${SIM_MODEL_CMD}"-opt" + echo -e ${LONG_W} + echo -e "${WHITE}Optimizing simulation model ${RESET}" + echo -e ${LONG_W} + fi + make $SIM_MODEL_CMD fi fi diff --git a/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/__init__.py b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/__init__.py new file mode 100644 index 00000000..c1a6b006 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/__init__.py @@ -0,0 +1,4 @@ +from .system import XHeep +from . import system +from . import load_config +from . import ram_bank \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/linker_section.py b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/linker_section.py new file mode 100644 index 00000000..1f5fe468 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/linker_section.py @@ -0,0 +1,80 @@ +from dataclasses import * +from typing import Optional + +@dataclass +class LinkerSection(): + """ + Object representing a section in the linker configuration. + + If the end address is set to `None` it will be infered in the building process. + """ + + name: str + """ + The name of the section + + The name can be anything that does not collide with section names used by the linker, + except code and data that are used to configure the size of the code and data part. + code and data do not only contain the actual .code and .data section but other related sections. + """ + + start: int + """The start address""" + + end: Optional[int] + """The end address""" + + def __post_init__(self): + self.check() + + def check(self): + """ + Does basic type checking and sanity checking. + + - Checks the type of all members + - Checks that the name is not empty + - Checks that the start address and size are positive + + :raise TypeError: when the type of a member is not the correct ine. + :raise ValueError: when the name is empty or start or size are negative + """ + if type(self.name) is not str: + raise TypeError("name should be of type str") + if type(self.start) is not int: + raise TypeError("start should be of type int") + if type(self.end) is not int and self.end is not None: + raise TypeError("end should be of type int") + + if self.name == "": + raise ValueError("name should not be empty") + if self.start < 0: + raise ValueError("start address should be positif") + if self.end is not None and self.end <= self.start: + raise ValueError("end address should be bigger than the start address") + + @staticmethod + def by_size(name: str, start: int, size: int) -> "LinkerSection": + """ + Creates a Linker Section by it's size rather than end address. + + :param str name: the name of the section + :param int start: the start address + :param int size: the size of the section + :return: the linker section + :rtype: LinkerSection + """ + if type(name) is not str: + raise TypeError("name should be of type str") + if type(start) is not int: + raise TypeError("start should be of type int") + if type(size) is not int: + raise TypeError("size should be of type int") + + return LinkerSection(name, start, start + size) + + @property + def size(self) -> Optional[int]: + """The size in Bytes""" + if self.end is not None: + return self.end - self.start + return None \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/load_config.py b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/load_config.py new file mode 100644 index 00000000..1c2da738 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/load_config.py @@ -0,0 +1,293 @@ +import importlib +from pathlib import PurePath +from typing import List, Optional, Union +import hjson + +from .linker_section import LinkerSection +from .system import BusType, Override, XHeep + +def to_int(input) -> Union[int, None]: + if type(input) is int: + return input + + if type(input) is str: + base = 10 + if len(input) >= 2: + if input[0:2].upper() == "0X": + base = 16 + input = input[2:] + elif input[0:2] == "0o": + base = 8 + input = input[2:] + elif input[0:2].upper() == "0b": + base = 2 + input = input[2:] + + return int(input, base) + return None + + +def ram_list(l: "List[int]", entry): + """ + Parses the hjson ram bank configuration in continuous mode. + + :param List[int] l: the list where bank sizes in kiB should be added + :enrtry: the entry to be parsed. It should be a list an integer or an continuous dictionary + :raise RuntimeError: when an invalid configuration is processed. + """ + if type(l) is not list: + raise TypeError("l should be of type list") + + if type(entry) is int: + l.append(entry) + return + + if type(entry) is list: + for i in entry: + ram_list(l, i) + return + + if type(entry) is hjson.OrderedDict: + num = 1 + if "num" in entry: + if type(entry["num"]) is not int: + raise RuntimeError("if the num field is present in ram configuration it should be an integer") + num = entry["num"] + + if "sizes" in entry: + for _ in range(num): + ram_list(l, entry["sizes"]) + return + else: + raise RuntimeError("dictionaries in continuous ram configuration sections should at least have a sizes entry") + + raise RuntimeError("entries in ram configuration should either be integer, lists, or dictionaries") + + + +def load_ram_configuration(system: XHeep, mem: hjson.OrderedDict): + """ + Reads the whole ram configuration. + + :param XHeep system: the system object where the ram should be added. + :param hjson.OrderedDict mem: The configuration part with the ram informations. + :raise TypeError: when arguments do not have the right type + :raise RuntimeError: when an invalid configuration is processed. + """ + if not isinstance(system, XHeep): + raise TypeError("system should be an instance of XHeep object") + if type(mem) is not hjson.OrderedDict: + raise TypeError("mem should be of type hjson.OrderedDict") + + for key, value in mem.items(): + if type(value) is not hjson.OrderedDict: + raise RuntimeError("Ram configuration entries should be dictionaries") + + section_name = "" + if "auto_section" in value and value["auto_section"] == "auto": + section_name = key + + t = "continuous" + if "type" in value: + t = value["type"] + if type(t) is not str: + raise RuntimeError("ram type should be a string") + if t != "continuous" and t != "interleaved": + raise RuntimeError(f"ram type should be continuous or interleaved not {t}") + + if t == "interleaved": + if "num" not in value or type(value["num"]) is not int: + raise RuntimeError("The num field is required for interleaved ram section and should be an integer") + + if "size" not in value or type(value["size"]) is not int: + raise RuntimeError("The size field is required for interleaved ram section and should be an integer") + + system.add_ram_banks_il(int(value["num"]), int(value["size"]), section_name) + + elif t == "continuous": + banks: List[int] = [] + ram_list(banks, value) + system.add_ram_banks(banks, section_name) + + + +def load_linker_config(system: XHeep, config: list): + """ + Reads the whole linker section configuration. + + :param XHeep system: the system object where the sections should be added. + :param hjson.OrderedDict mem: The configuration part with the section informations. + :raise TypeError: when arguments do not have the right type + :raise RuntimeError: when an invalid configuration is processed. + """ + if type(config) is not list: + raise RuntimeError("Linker Section configuraiton should be a list.") + + for l in config: + if type(l) is not hjson.OrderedDict: + raise RuntimeError("Sections should be represented as Dictionaries") + if "name" not in l: + raise RuntimeError("All sections should have names") + + if "start" not in l: + raise RuntimeError("All sections should have a start") + + name = l["name"] + start = to_int(l["start"]) + + if type(name) is not str: + raise RuntimeError("Section names should be strings") + + if name == "": + raise RuntimeError("Section names should not be empty") + + if type(start) is not int: + raise RuntimeError("The start of a section should be an integer") + + if "size" in l and "end" in l: + raise RuntimeError("Each section should only specify end or size.") + + end = 0 + if "size" in l: + size = to_int(l["size"]) + if size is None: + raise RuntimeError("Section sizes should be an integer") + if size <= 0: + raise RuntimeError("Section sizes should be strictly positive") + end = start + size + + elif "end" in l: + end = to_int(l["end"]) + if end is None: + raise RuntimeError("End address should be an integer") + if end <= start: + raise RuntimeError("Sections should end after their start") + else: + end = None + + system.add_linker_section(LinkerSection(name, start, end)) + + + + +def load_cfg_hjson(src: str, override: Optional[Override] = None) -> XHeep: + """ + Loads the configuration passed as a hjson string and creates an object representing the mcu. + + :param str src: configuration content + :param Optional[Override] override: configs to be overriden + :return: the object representing the mcu configuration + :rtype: XHeep + :raise RuntimeError: when and invalid configuration is passed or when the sanity checks failed + """ + config = hjson.loads(src, parse_int=int, object_pairs_hook=hjson.OrderedDict) + mem_config = None + bus_config = None + ram_address_config = None + linker_config = None + + for key, value in config.items(): + if key == "ram_banks": + mem_config = value + elif key == "bus_type": + bus_config = value + elif key == "ram_address": + ram_address_config = value + elif key == "linker_sections": + linker_config = value + + if mem_config is None: + raise RuntimeError("No memory configuration found") + if bus_config is None: + raise RuntimeError("No bus type configuration found") + + ram_start = 0 + if ram_address_config is not None: + if type(ram_address_config) is not int: + RuntimeError("The ram_address should be an intger") + ram_start = ram_address_config + + system = XHeep(BusType(bus_config), ram_start, override=override) + load_ram_configuration(system, mem_config) + + if linker_config is not None: + load_linker_config(system, linker_config) + + system.build() + if not system.validate(): + raise RuntimeError("Could not validate system configuration") + return system + + + +def _chk_purep(f): + """ + Helper to check the type is `PurePath` + + :param f: object to check + :raise TypeError: when object is of wrong type. + """ + if not isinstance(f, PurePath): + raise TypeError("parameter should be of type PurePath") + + + +def load_cfg_hjson_file(f: PurePath, override: Optional[Override] = None) -> XHeep: + """ + Loads the configuration passed in the path as hjson and creates an object representing the mcu. + + :param PurePath f: path of the configuration + :param Optional[Override] override: configs to be overriden + :return: the object representing the mcu configuration + :rtype: XHeep + :raise RuntimeError: when and invalid configuration is passed or when the sanity checks failed + """ + _chk_purep(f) + + with open(f, "r") as file: + return load_cfg_hjson(file.read(), override) + + + +def load_cfg_script_file(f: PurePath) -> XHeep: + """ + Executes the python file passed as argument to cinfigure the system. + + This file should have a function config that takes no parameters and returns an instance (or subclass) of the XHeep type. + The script can import modules from the util directory. + The script should not have side effects as it is called multiple time in the current makefile. + + :param PurePath f: path of the configuration + :return: the object representing the mcu configuration + :rtype: XHeep + :raise RuntimeError: when and invalid configuration is passed or when the sanity checks failed + """ + _chk_purep(f) + + spec = importlib.util.spec_from_file_location("configs._config", f) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + + return mod.config() + + + +def load_cfg_file(f: PurePath, override: Optional[Override] = None) -> XHeep: + """ + Load the Configuration by extension type. It currently supports .hjson and .py + + :param PurePath f: path of the configuration + :param Optional[Override] override: configs to be overriden + :return: the object representing the mcu configuration + :rtype: XHeep + :raise RuntimeError: when and invalid configuration is passed or when the sanity checks failed + """ + _chk_purep(f) + + if f.suffix == ".hjson": + return load_cfg_hjson_file(f, override) + + if f.suffix == ".py": + return load_cfg_script_file(f) + + raise RuntimeError(f"unsupported file extension {f.suffix}") \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/ram_bank.py b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/ram_bank.py new file mode 100644 index 00000000..20f043eb --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/ram_bank.py @@ -0,0 +1,133 @@ +from dataclasses import * + +def is_pow2(n: int) -> bool: + """ + check if n is a power of two + + :param int n: number to be checked + :return: True if n is a power of two + :rtype: bool + """ + return n > 0 and (n & (n-1)) == 0 + + + +class Bank(): + """ + Represents a ram bank + + :param int size_k: size in kiB + :param int start_address: start address of the bank, in interleaved mode it should be the start address od the whole group + :param int map_idx: index in the global address map. Has to be unique. Interleaved mode banks should have consecutive indices. + :param int il_level: number of bits used for interleaving. + :param int il_offset: position in interleaved bank group if in any else 0. Should be consistent with map_idx. + :raise TypeError: when parameters don't have the right type. + :raise ValueError: when size_k isn't a power of two. + :raise ValueError: when start_address is not aligned on size. + :raise ValueError: when il_offset is to big for the given il_level(). + """ + def __init__(self, size_k: int, start_address: int, map_idx: int, il_level: int = 0, il_offset: int = 0): + if not type(size_k) is int: + raise TypeError("Bank size should be an int") + + if not type(start_address) is int: + raise TypeError("Start address should be an int") + + if not type(map_idx) is int: + raise TypeError("map_idx size should be an int") + + if not type(il_level) is int: + raise TypeError("il_level should be an int") + + if not type(il_offset) is int: + raise TypeError("il_offset size should be an int") + + self._size_k: int = size_k + self._start_address: int = start_address + self._map_idx: int = map_idx + self._il_level: int = il_level + self._il_offset: int = il_offset + + # check if power of 2 + if not is_pow2(self._size_k): + raise ValueError(f"Bank size {self._size_k}kiB is not a positive power of two") + + if self._il_offset >= 2**self._il_level: + raise ValueError(f"il_offset is to big for an il_level of {self._il_level}") + + mask = 0b11 + if not self._start_address & mask == 0: + raise ValueError(f"start_address is not aligned on word size") + + + #TODO: Validate start address + + self._end_address = self._start_address + self._size_k*1024 * 2**self._il_level + + def size(self) -> int: + """ + :return: the bank size in Bytes + :rtype: int + """ + return self._size_k * 1024 + + def name(self) -> str: + """ + :return: the bank name + :rtype: str + """ + return str(self._map_idx-1) #TODO: do something better + + def start_address(self) -> int: + """ + :return: the start address + :rtype: int + """ + return self._start_address + + def end_address(self) -> int: + """ + :return: the end address + :rtype: int + """ + return self._end_address + + def map_idx(self) -> int: + """ + :return: the index used in global bus + :rtype: int + """ + return self._map_idx + + def il_level(self) -> int: + """ + :return: the number of bits used to choose the bank when it is in an interleaved group else 0 + :rtype: int + """ + return self._il_level + + def il_offset(self) -> int: + """ + :return: the position of the bank in an interleaved group. + :rtype: int + """ + return self._il_offset + +@dataclass +class ILRamGroup(): + """ + Dataclass to represent information about interleaved memory banks group. + """ + + start: int + """start address of the group""" + + size: int + """size of the group""" + + n: int + """number of banks in the group""" + + first_name: str + """name of the first bank""" + \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/system.py b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/system.py new file mode 100644 index 00000000..09e4a855 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/util/x_heep_gen/system.py @@ -0,0 +1,430 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import Generator, Iterable, List, Optional, Set, Union +from enum import Enum +from .ram_bank import Bank, is_pow2, ILRamGroup +from .linker_section import LinkerSection + +class BusType(Enum): + """Enumeration of all supported bus types""" + + onetoM = 'onetoM' + NtoM = 'NtoM' + + +@dataclass +class Override(): + """ + Bundles information that can be overriden in the XHeep class. + """ + bus_type: Optional[BusType] + numbanks: Optional[int] + numbanks_il: Optional[int] + + + +class XHeep(): + """ + This object represents the whole mcu. + + An instance of this object is also passed to the mako templates. + + :param BusType bus_type: The bus type chosen for this mcu. + :param int ram_start_address: The address of the first ram bank. For now only 0 is tested. Defaults to 0. + :param Optional[Override] override: configs to be overriden + :raise TypeError: when parameters are of incorrect type. + """ + + IL_COMPATIBLE_BUS_TYPES: "Set[BusType]" = set([BusType.NtoM]) + """Constant set of bus types that support interleaved memory banks""" + + + + def __init__(self, bus_type: BusType, ram_start_address: int = 0, override: Optional[Override] = None): + if not type(bus_type) is BusType: + raise TypeError(f"XHeep.bus_type should be of type BusType not {type(self._bus_type)}") + if not type(ram_start_address) is int: + raise TypeError("ram_start_address should be of type int") + + if ram_start_address != 0: + raise ValueError(f"ram start address must be 0 instead of {ram_start_address}") + + self._bus_type: BusType = bus_type + if override is not None and override.bus_type is not None: + self._bus_type = override.bus_type + + + self._ram_start_address: int = ram_start_address + self._ram_banks: List[Bank] = [] + self._ram_banks_il_idx: List[int] = [] + self._ram_banks_il_groups: List[ILRamGroup] = [] + self._il_banks_present: bool = False + self._ram_next_idx: int = 1 + self._ram_next_addr: int = self._ram_start_address + self._linker_sections: List[LinkerSection] = [] + self._used_section_names: Set[str] = set() + + self._ignore_ram_continous: bool = False + self._ignore_ram_interleaved: bool = False + + if override is not None and override.numbanks is not None: + self.add_ram_banks([32]*override.numbanks) + self._ignore_ram_continous = True + if override is not None and override.numbanks_il is not None: + self._ignore_ram_interleaved = True + self._override_numbanks_il = override.numbanks_il + + + def add_ram_banks(self, bank_sizes: "List[int]", section_name: str = ""): + """ + Add ram banks in continuous address mode to the system. + The bank size should be a power of two and at least 1kiB. + + :param List[int] bank_sizes: list of bank sizes in kiB that should be added to the system + :param str section_name: If not empty adds automatically a linker section for this banks. The names must be unique and not be used by the linker for other purposes. + :raise TypeError: when arguments are of wrong type + :raise ValueError: when banks have an incorrect size. + :raise ValueError: if the name was allready used for another section or the first and second are not code and data. + :raise ValueError: if bank_sizes list is empty + """ + + if self._ignore_ram_continous: + return + + if not type(bank_sizes) == list: + raise TypeError("bank_sizes should be of type list") + if not type(section_name) == str: + raise TypeError("section_name should be of type str") + if len(bank_sizes) == 0: + raise ValueError("bank_sizes is empty") + + banks: List[Bank] = [] + for b in bank_sizes: + banks.append(Bank(b, self._ram_next_addr, self._ram_next_idx, 0, 0)) + self._ram_next_addr = banks[-1]._end_address + self._ram_next_idx += 1 + + if section_name != "": + self.add_linker_section_for_banks(banks, section_name) + # Add all new banks if no error was raised + self._ram_banks += banks + + + + + def add_ram_banks_il(self, num: int, bank_size: int, section_name: str = "", ignore_ignore: bool = False): + """ + Add ram banks in interleaved mode to the system. + The bank size should be a power of two and at least 1kiB, + the number of banks should also be a power of two. + + :param int num: number of banks to add + :param int bank_size: size of the banks in kiB + :param str section_name: If not empty adds automatically a linker section for this banks. The names must be unique and not be used by the linker for other purposes. + :param bool ignore_ignore: Ignores the fact that an override was set. For internal uses to apply this override. + :raise TypeError: when arguments are of wrong type + :raise ValueError: when banks have an incorrect size or their number is not a power of two. + :raise ValueError: if the name was allready used for another section or the first and second are not code and data. + """ + if self._ignore_ram_interleaved and not ignore_ignore: + return + + if not self._bus_type in self.IL_COMPATIBLE_BUS_TYPES: + raise RuntimeError(f"This system has a {self._bus_type} bus, one of {self.IL_COMPATIBLE_BUS_TYPES} is required for interleaved memory") + if not type(num) == int: + raise TypeError("num should be of type int") + if not is_pow2(num): + raise ValueError(f"A power of two is required for the number of banks, got {num}") + if not type(section_name) == str: + raise TypeError("section_name should be of type str") + + first_il = self.ram_numbanks() + + banks: List[Bank] = [] + for i in range(num): + banks.append(Bank(bank_size, self._ram_next_addr, self._ram_next_idx, num.bit_length()-1, i)) + self._ram_next_idx += 1 + + self._ram_next_addr = banks[-1]._end_address + + if section_name != "": + self.add_linker_section_for_banks(banks, section_name) + # Add all new banks if no error was raised + self._ram_banks += banks + + indices = range(first_il, first_il + num) + self._ram_banks_il_idx += indices + self._ram_banks_il_groups.append(ILRamGroup(banks[0].start_address(), bank_size*num*1024, len(banks), banks[0].name())) + self._il_banks_present = True + + + + def add_linker_section_for_banks(self, banks: "List[Bank]", name: str): + """ + Function to add linker sections coupled to some banks. + :param List[Bank] banks: list of banks that compose the section, assumed to be continuous in memory + :param str name: the name of the section. + :raise ValueError: if the name was allready used for another section or the first and second are not code and data. + """ + if name in self._used_section_names: + raise ValueError("linker section names should be unique") + + self._used_section_names.add(name) + self._linker_sections.append(LinkerSection(name, banks[0].start_address(), banks[-1].end_address())) + + def add_linker_section(self, section: LinkerSection): + """ + Function to add a linker section. + :param LinkerSection section: Linker section to add. + :param str name: the name of the section. + :raise ValueError: if the name was allready used for another section or the first and second are not code and data. + """ + + if not isinstance(section, LinkerSection): + raise TypeError("section should be an instance of LinkerSection") + + section.check() + + if section.name in self._used_section_names: + raise ValueError("linker section names should be unique") + + self._used_section_names.add(section.name) + self._linker_sections.append(deepcopy(section)) + + + + def bus_type(self) -> BusType: + """ + :return: the configured bus type + :rtype: BusType + """ + return self._bus_type + + def ram_start_address(self) -> int: + """ + :return: the address of the first ram bank. + :rtype: int + """ + return self._ram_start_address + + def ram_numbanks(self) -> int: + """ + :return: the number of banks. + :rtype: int + """ + return len(self._ram_banks) + + + + def ram_numbanks_il(self) -> int: + """ + :return: the number of interleaved banks. + :rtype: int + """ + return len(self._ram_banks_il_idx) + + + + def ram_numbanks_cont(self) -> int: + """ + :return: the number of continuous banks. + :rtype: int + """ + return self.ram_numbanks() - self.ram_numbanks_il() + + + + def validate(self) -> bool: + """ + Does some basics checks on the configuration + + This should be called before using the XHeep object to generate the project. + + :return: the validity of the configuration + :rtype: bool + """ + if not self.ram_numbanks() in range(2, 17): + print(f"The number of banks should be between 2 and 16 instead of {self.ram_numbanks()}") #TODO: clarify upper limit + return False + + if not ("code" in self._used_section_names and "data" in self._used_section_names): + print("The code and data sections are needed") + return False + + for l in self._linker_sections: + l.check() + + ret = True + old_sec: Union[LinkerSection,None] = None + + for i, sec in enumerate(self._linker_sections): + if i == 0 and sec.name != "code": + print("The first linker section sould be called code.") + ret = False + elif i == 1 and sec.name != "data": + print("The second linker section sould be called data.") + ret = False + + if old_sec is not None: + if sec.start < old_sec.end: + print(f"Section {sec.name} and {old_sec.name} overlap.") + + start = sec.start + found_start = False + found_end = False + for b in self._ram_banks: + if found_start: + if b.start_address() > start: + print(f"Section {sec.name} has a memory hole starting at {start:#08X}") + ret = False + found_end = True + break + else: + start = b.end_address() + + if sec.start >= b.start_address() and sec.start < b.end_address(): + found_start = True + start = b.end_address() + + if sec.end <= b.end_address() and sec.end > b.start_address(): + found_end = True + break + + if not found_start: + print(f"Section {sec.name} does not start in any ram bank.") + ret = False + + if not found_end: + ret = False + print(f"Section {sec.name} does not end in any ram bank.") + + old_sec = sec + + return ret + + + + def ram_size_address(self) -> int: + """ + :return: the size of the addressable ram memory. + :rtype: int + """ + size = 0 + for bank in self._ram_banks: + size += bank.size() + return size + + + + def ram_il_size(self) -> int: + """ + :return: the memory size of the interleaved sizes. + :rtype: int + """ + size = 0 + for i in self._ram_banks_il_idx: + size += self._ram_banks[i].size() + return size + + + + def iter_ram_banks(self) -> Iterable[Bank]: + """ + :return: an iterator over all banks. + :rtype: Iterable[Bank] + """ + return iter(self._ram_banks) + + + + def iter_cont_ram_banks(self) -> Iterable[Bank]: + """ + :return: an iterator over all continuous banks. + :rtype: Iterable[Bank] + """ + m = map((lambda b: None if b[0] in self._ram_banks_il_idx else b[1]), enumerate(self._ram_banks)) + return filter(None, m) + + + + def iter_il_ram_banks(self) -> Iterable[Bank]: + """ + :return: an iterator over all interleaved banks. + :rtype: Iterable[Bank] + """ + m = map((lambda b: None if not b[0] in self._ram_banks_il_idx else b[1]), enumerate(self._ram_banks)) + return filter(None, m) + + + + def has_il_ram(self) -> bool: + """ + :return: `True` if the system has interleaved ram. + :rtype: bool + """ + return self._il_banks_present + + + + def iter_il_groups(self) -> Iterable[ILRamGroup]: + """ + :return: an iterator over the interleaved ram bank groups. + :rtype: Iterable[ILRamGroup] + """ + return iter(self._ram_banks_il_groups) + + + + def iter_linker_sections(self) -> Iterable[LinkerSection]: + """ + :return: an iterator over the linker sections + :rtype: Iterable[LinkerSection] + """ + return iter(self._linker_sections) + + + + def iter_bank_numwords(self) -> Generator[int, None, None]: + """ + Iterates over the size of the ram banks in number of words. + + :return: Generator over the sizes + :rtype: Generator[int, None, None] + """ + sizes = set() + for b in self._ram_banks: + if b.size() not in sizes: + sizes.add(b.size()) + yield b.size() // 4 + + def build(self): + """ + Makes the system ready to be used. + + - Aplies the overrides for the interleaved memory as the normal memory needs to be configured first. + - Sorts the linker sections by starting address. + - Inferes the missing linker section ends with the start of the next section if present. If not it uses the end of the last memory bank. + """ + if self._ignore_ram_interleaved: + sec_name = "" + if self.ram_numbanks() > 1: + sec_name = "data_interleaved" + self.add_ram_banks_il(self._override_numbanks_il, 32, sec_name, ignore_ignore=True) #Add automatically a section for compatibility purposes. + + + self._linker_sections.sort(key=lambda l: l.start) + + old_sec: Optional[LinkerSection] = None + for sec in self._linker_sections: + if old_sec is not None: + old_sec.end = sec.start + + if sec.end is None: + old_sec = sec + else: + old_sec = None + if old_sec is not None: + if len(self._ram_banks) == 0: + raise RuntimeError("There is no ram bank to infere the end of a section") + old_sec.end = self._ram_banks[-1].end_address() + \ No newline at end of file diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index e6880390..ee180557 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/Luigi2898/x-heep.git - rev: 849539ddf996926f9b679837f3bc84c0799287bb + rev: 798fd6ffc9193b613f5a85f54a496bfcc149a07d } } diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index e60b27ec..5457cda2 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/Luigi2898/x-heep.git", - rev: "849539ddf996926f9b679837f3bc84c0799287bb", + rev: "798fd6ffc9193b613f5a85f54a496bfcc149a07d", }, patch_dir: "patches/esl_epfl_x_heep", From 3bc56a8787be6a46aecbaac21f57d2166a2c6f2f Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 1 Oct 2024 13:08:46 +0200 Subject: [PATCH 17/27] fix makefile and .core files --- Makefile | 2 -- heepsilon.core | 2 -- 2 files changed, 4 deletions(-) diff --git a/Makefile b/Makefile index ef581b6d..5be58865 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,6 @@ heepsilon-gen: # This is needed to be done after the X-HEEP mcu-gen because the test-bench to be used is the one from heepsilon, not the one from X-HEEP. mcu-gen: heepsilon-gen $(MAKE) -f $(XHEEP_MAKE) EXTERNAL_DOMAINS=${EXTERNAL_DOMAINS} MEMORY_BANKS=${MEMORY_BANKS} $(MAKECMDGOALS) - cd hw/vendor/esl_epfl_x_heep &&\ - $(PYTHON) util/mcu_gen.py --cfg mcu_cfg.hjson --pads_cfg pad_cfg.hjson --outdir ../../../tb/ --memorybanks $(MEMORY_BANKS) --tpl-sv ../../../tb/tb_util.svh.tpl ## Builds (synthesis and implementation) the bitstream for the FPGA version using Vivado ## @param FPGA_BOARD=nexys-a7-100t,pynq-z2 diff --git a/heepsilon.core b/heepsilon.core index 4970340e..bdd22079 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -118,12 +118,10 @@ filesets: ip-fpga-pynq-z2: files: - - hw/fpga/scripts/pynq-z2/set_board.tcl: { file_type: tclSource } - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } ip-fpga-zcu104: files: - - hw/fpga/scripts/zcu104/set_board.tcl: { file_type: tclSource } - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } fpga-arm-emulation: From 62f41adac5741a9b68f0e0983ec73ad445480ab4 Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 1 Oct 2024 14:06:32 +0200 Subject: [PATCH 18/27] Fixing .core for heepsilon --- heepsilon.core | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/heepsilon.core b/heepsilon.core index bdd22079..164cbe4d 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -13,6 +13,31 @@ filesets: - x-heep::packages - openhwgroup.org:systems:core-v-mini-mcu - eslepfl::cgra + - openhwgroup.org:ip:cv32e40p + - openhwgroup.org:ip:cv32e40x + - openhwgroup:cve2:cve2_top + - esl_epfl:ip:cv32e40px + - pulp-platform.org:ip:gpio + - pulp-platform.org::common_cells + - pulp-platform.org::cluster_interconnect + - pulp-platform.org::riscv_dbg + - pulp-platform.org::register_interface + - openhwgroup.org:ip:soc_ctrl + - lowrisc:ip:uart:0.1 + - lowrisc:ip:rv_plic_example:0.1 + - lowrisc:ip:rv_timer:0.1 + - lowrisc:ip:spi_host:1.0 + - lowrisc:ip:i2c:0.1 + - yosyshq:picorv32_spimemio:0-r1 + - x-heep:obi_spimemio:0.1.0 + - x-heep:ip:boot_rom + - x-heep:ip:dma + - x-heep:ip:dma_subsystem + - x-heep:ip:i2s + - x-heep:ip:power_manager + - x-heep:ip:fast_intr_ctrl + - x-heep:ip:obi_fifo + - x-heep:ip:pdm2pcm files: - hw/rtl/heepsilon_pkg.sv - hw/rtl/heepsilon_top.sv @@ -97,6 +122,8 @@ filesets: file_type: systemVerilogSource rtl-fpga: + depend: + - openhwgroup.org:systems:core-v-mini-mcu-fpga files: - hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv - hw/fpga/sram_wrapper.sv @@ -285,6 +312,7 @@ targets: - x_heep_system - files_rtl_generic # Already added by default? - rtl-fpga + - ip-fpga-pynq-z2 - ip-fpga - xdc-fpga-pynq-z2 - ext_bus @@ -309,9 +337,14 @@ targets: - ext_bus parameters: - COREV_PULP=0 + - FPU + - X_EXT - SYNTHESIS=true + - REMOVE_OBI_FIFO - FPGA_ZCU104=true tools: vivado: part: xczu7ev-ffvc1156-2-e + board_part: xilinx.com:zcu104:part0:1.0 + board_repo_paths: [../../../hw/fpga/board_files/vendor/esl_epfl_zcu104_board_files] toplevel: [xilinx_heepsilon_wrapper] \ No newline at end of file From 291475f93c7c505d5c03c4f0db9d7d865949a3b8 Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 1 Oct 2024 14:09:32 +0200 Subject: [PATCH 19/27] Fixing .core for heepsilon: adding parameters --- heepsilon.core | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/heepsilon.core b/heepsilon.core index 164cbe4d..5731ab91 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -181,11 +181,33 @@ parameters: COREV_PULP: datatype: int paramtype: vlogparam + description: | + Enables COREV_PULP custom RISC-V extension on the CV32E40P core. Admitted values: 1|0. + default: 0 + FPU: + datatype: int + paramtype: vlogparam + description: | + Enables RV32F RISC-V extension on the CV32E40P core. Admitted values: 1|0. default: 0 JTAG_DPI: datatype: int paramtype: vlogparam + description: | + Enables testbench JTAG DIPs. Admitted values: 1|0. + default: 0 + X_EXT: + datatype: int + paramtype: vlogparam + description: | + Enables CORE-V-XIF interface for the CV32E40X and CV32E40PX cores. Admitted values: 1|0. default: 0 + USE_EXTERNAL_DEVICE_EXAMPLE: + datatype: int + paramtype: vlogparam + description: | + Enables testbench modules compilation. Admitted values: 1|0. + default: 1 USE_UPF: datatype: bool paramtype: vlogdefine From c035b4f247efea37d45e650e068a27aca6f9656f Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 1 Oct 2024 14:11:36 +0200 Subject: [PATCH 20/27] Fixing .core for heepsilon: adding parameters v2 --- heepsilon.core | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/heepsilon.core b/heepsilon.core index 5731ab91..327af2f8 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -212,6 +212,11 @@ parameters: datatype: bool paramtype: vlogdefine default: false + REMOVE_OBI_FIFO: + datatype: bool + paramtype: vlogdefine + description: | + Remove the FIFO between the BUS and the peripherals subsystems SYNTHESIS: datatype: bool paramtype: vlogdefine From 4780044ad2cdd3ad0ede9f90830d4ea30d480aa1 Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Thu, 3 Oct 2024 11:10:09 +0200 Subject: [PATCH 21/27] Update .core and xheep vendor --- heepsilon.core | 55 --------------------------- hw/vendor/eslepfl_x_heep.vendor.hjson | 2 +- 2 files changed, 1 insertion(+), 56 deletions(-) diff --git a/heepsilon.core b/heepsilon.core index 327af2f8..b19142a3 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -13,31 +13,6 @@ filesets: - x-heep::packages - openhwgroup.org:systems:core-v-mini-mcu - eslepfl::cgra - - openhwgroup.org:ip:cv32e40p - - openhwgroup.org:ip:cv32e40x - - openhwgroup:cve2:cve2_top - - esl_epfl:ip:cv32e40px - - pulp-platform.org:ip:gpio - - pulp-platform.org::common_cells - - pulp-platform.org::cluster_interconnect - - pulp-platform.org::riscv_dbg - - pulp-platform.org::register_interface - - openhwgroup.org:ip:soc_ctrl - - lowrisc:ip:uart:0.1 - - lowrisc:ip:rv_plic_example:0.1 - - lowrisc:ip:rv_timer:0.1 - - lowrisc:ip:spi_host:1.0 - - lowrisc:ip:i2c:0.1 - - yosyshq:picorv32_spimemio:0-r1 - - x-heep:obi_spimemio:0.1.0 - - x-heep:ip:boot_rom - - x-heep:ip:dma - - x-heep:ip:dma_subsystem - - x-heep:ip:i2s - - x-heep:ip:power_manager - - x-heep:ip:fast_intr_ctrl - - x-heep:ip:obi_fifo - - x-heep:ip:pdm2pcm files: - hw/rtl/heepsilon_pkg.sv - hw/rtl/heepsilon_top.sv @@ -181,42 +156,15 @@ parameters: COREV_PULP: datatype: int paramtype: vlogparam - description: | - Enables COREV_PULP custom RISC-V extension on the CV32E40P core. Admitted values: 1|0. - default: 0 - FPU: - datatype: int - paramtype: vlogparam - description: | - Enables RV32F RISC-V extension on the CV32E40P core. Admitted values: 1|0. default: 0 JTAG_DPI: datatype: int paramtype: vlogparam - description: | - Enables testbench JTAG DIPs. Admitted values: 1|0. - default: 0 - X_EXT: - datatype: int - paramtype: vlogparam - description: | - Enables CORE-V-XIF interface for the CV32E40X and CV32E40PX cores. Admitted values: 1|0. default: 0 - USE_EXTERNAL_DEVICE_EXAMPLE: - datatype: int - paramtype: vlogparam - description: | - Enables testbench modules compilation. Admitted values: 1|0. - default: 1 USE_UPF: datatype: bool paramtype: vlogdefine default: false - REMOVE_OBI_FIFO: - datatype: bool - paramtype: vlogdefine - description: | - Remove the FIFO between the BUS and the peripherals subsystems SYNTHESIS: datatype: bool paramtype: vlogdefine @@ -364,10 +312,7 @@ targets: - ext_bus parameters: - COREV_PULP=0 - - FPU - - X_EXT - SYNTHESIS=true - - REMOVE_OBI_FIFO - FPGA_ZCU104=true tools: vivado: diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index 5457cda2..655e0a58 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/Luigi2898/x-heep.git", - rev: "798fd6ffc9193b613f5a85f54a496bfcc149a07d", + rev: "83f1563fd4894787167b27099006c8b1b042d3d1", }, patch_dir: "patches/esl_epfl_x_heep", From a28285bd9a0e1b50a7beb305fd2a26dd607d1f0b Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Thu, 3 Oct 2024 11:17:52 +0200 Subject: [PATCH 22/27] Re-vendorizing x-heep to last commit --- hw/vendor/esl_epfl_x_heep/Makefile | 4 +- hw/vendor/esl_epfl_x_heep/configs/ci.hjson | 4 +- .../configs/example_interleaved.hjson | 4 +- .../esl_epfl_x_heep/configs/general.hjson | 4 +- .../esl_epfl_x_heep/configs/testall.hjson | 4 +- .../docs/source/How_to/eXtendingHEEP.md | 10 +- .../docs/source/Peripherals/DMA.md | 2293 +++++++++++++---- .../docs/source/Verification/VerifHEEP.md | 186 ++ .../docs/source/images/dma_structure.png | Bin 0 -> 175192 bytes .../ao_peripheral_subsystem.sv | 214 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv | 92 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl | 78 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.vlt | 2 + .../include/core_v_mini_mcu_pkg.sv.tpl | 17 +- .../hw/core-v-mini-mcu/system_bus.sv.tpl | 65 +- .../hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv | 16 +- .../esl_epfl_x_heep/hw/ip/dma/data/dma.hjson | 17 +- hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core | 4 + hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.vlt | 5 + .../esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv | 1404 +++------- .../hw/ip/dma/rtl/dma_obiread_addr_fsm.sv | 168 ++ .../hw/ip/dma/rtl/dma_obiread_fsm.sv | 313 +++ .../hw/ip/dma/rtl/dma_obiwrite_fsm.sv | 358 +++ .../hw/ip/dma/rtl/dma_padding_fsm.sv | 339 +++ .../hw/ip/dma/rtl/dma_reg_pkg.sv | 67 +- .../hw/ip/dma/rtl/dma_reg_top.sv | 10 +- .../hw/ip/dma_subsystem/dma_subsystem.core | 1 + .../hw/ip/dma_subsystem/rtl/dma_NtoM_xbar.sv | 71 + .../hw/ip/dma_subsystem/rtl/dma_subsystem.sv | 205 +- .../data/power_manager.hjson.tpl | 11 + .../power_manager/data/power_manager.sv.tpl | 5 + .../hw/ip/power_manager/power_manager_gen.sh | 0 .../im2col_spc/data/im2col_spc.hjson | 255 ++ .../hw/ip_examples/im2col_spc/im2col_spc.core | 28 + .../hw/ip_examples/im2col_spc/im2col_spc.vlt | 16 + .../ip_examples/im2col_spc/im2col_spc_gen.sh | 8 + .../ip_examples/im2col_spc/rtl/dma_if_pkg.sv | 26 + .../ip_examples/im2col_spc/rtl/im2col_spc.sv | 623 +++++ .../im2col_spc/rtl/im2col_spc_param_fsm.sv | 551 ++++ .../im2col_spc/rtl/im2col_spc_reg_pkg.sv | 227 ++ .../im2col_spc/rtl/im2col_spc_reg_top.sv | 1182 +++++++++ .../rtl/im2col_spc_regintfc_controller.sv | 92 + .../hw/ip_examples/im2col_spc/rtl/pipe_reg.sv | 32 + .../hw/system/x_heep_system.sv.tpl | 40 +- .../hw/vendor/esl_epfl_cv32e40px.lock.hjson | 2 +- .../hw/vendor/esl_epfl_cv32e40px.vendor.hjson | 2 +- .../hw/vendor/esl_epfl_cv32e40px/README.md | 14 +- .../rtl/cv32e40px_controller.sv | 25 +- .../rtl/cv32e40px_id_stage.sv | 23 +- .../rtl/cv32e40px_x_disp.sv | 17 +- .../pulp_platform_register_interface.core | 1 + hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson | 2 + .../esl_epfl_x_heep/mcu_cfg_minimal.hjson | 2 + hw/vendor/esl_epfl_x_heep/pad_cfg.hjson | 8 +- .../examples/im2col_spc_verification.py | 317 +++ .../scripts/verification/examples/plotter.py | 123 + .../scripts/verification/verifheep.py | 498 ++++ .../gen_stimuly.py | 5 +- .../example_data_processing_from_flash/main.c | 6 + .../matrices.h | 292 +-- .../sw/applications/example_dma/main.c | 40 +- .../sw/applications/example_dma_2d/main.c | 213 +- .../applications/example_dma_2d/test_data.h | 7 +- .../applications/example_dma_external/main.c | 11 +- .../example_dma_multichannel/main.c | 53 +- .../sw/applications/example_fft/data.h | 80 + .../sw/applications/example_fft/datagen.py | 204 ++ .../sw/applications/example_fft/fft.h | 331 +++ .../sw/applications/example_fft/main.c | 112 + .../sw/applications/example_i2s/main.c | 6 +- .../sw/applications/example_iffifo/main.c | 12 +- .../example_im2col/im2colGolden.c | 72 - .../example_im2col/im2colGolden.h | 31 - .../example_im2col/im2col_golden.c | 20 + .../example_im2col/im2col_golden.h | 14 + .../example_im2col/im2col_input.c | 16 + .../example_im2col/im2col_input.h | 27 + .../applications/example_im2col/im2col_lib.c | 548 +++- .../applications/example_im2col/im2col_lib.h | 78 +- .../sw/applications/example_im2col/main.c | 94 +- .../applications/example_power_manager/main.c | 24 +- .../example_tensor_format_conv/main.c | 288 +++ .../esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c | 38 +- .../sw/device/bsp/w25q/w25q128jw.h | 2 +- .../esl_epfl_x_heep/sw/device/lib/base/base.h | 16 +- .../sw/device/lib/base/bitfield.c | 30 - .../sw/device/lib/base/bitfield.h | 26 +- .../sw/device/lib/base/memory.c | 3 - .../sw/device/lib/base/memory.h | 4 +- .../esl_epfl_x_heep/sw/device/lib/base/mmio.c | 39 - .../esl_epfl_x_heep/sw/device/lib/base/mmio.h | 30 +- .../sw/device/lib/crt/crt0.S.tpl | 306 +-- .../sw/device/lib/drivers/dma/dma.c | 113 +- .../sw/device/lib/drivers/dma/dma.h | 14 +- .../sw/device/lib/drivers/dma/dma_regs.h | 7 +- .../sw/device/lib/drivers/im2col_spc/im2col.c | 234 ++ .../sw/device/lib/drivers/im2col_spc/im2col.h | 60 + .../lib/drivers/im2col_spc/im2col_spc_regs.h | 188 ++ .../device/lib/runtime/core_v_mini_mcu.h.tpl | 1 + .../sw/device/lib/runtime/hart.h | 2 +- .../sw/device/lib/sdk/dma/dma_sdk.c | 2 +- hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv | 41 +- hw/vendor/esl_epfl_x_heep/tb/tb.vlt | 2 + hw/vendor/esl_epfl_x_heep/tb/testharness.sv | 117 +- .../esl_epfl_x_heep/tb/testharness_pkg.sv | 13 +- hw/vendor/esl_epfl_x_heep/util/mcu_gen.py | 114 +- hw/vendor/esl_epfl_x_heep/util/test_all.sh | 2 +- .../esl_epfl_x_heep/x-heep-tb-utils.core | 2 + hw/vendor/eslepfl_x_heep.lock.hjson | 2 +- 109 files changed, 11083 insertions(+), 2994 deletions(-) create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/Verification/VerifHEEP.md create mode 100644 hw/vendor/esl_epfl_x_heep/docs/source/images/dma_structure.png create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_addr_fsm.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_fsm.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiwrite_fsm.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_padding_fsm.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_NtoM_xbar.sv mode change 100644 => 100755 hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager_gen.sh create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/data/im2col_spc.hjson create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.core create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.vlt create mode 100755 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc_gen.sh create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/dma_if_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_param_fsm.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_pkg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_top.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_regintfc_controller.sv create mode 100644 hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/pipe_reg.sv create mode 100644 hw/vendor/esl_epfl_x_heep/scripts/verification/examples/im2col_spc_verification.py create mode 100644 hw/vendor/esl_epfl_x_heep/scripts/verification/examples/plotter.py create mode 100644 hw/vendor/esl_epfl_x_heep/scripts/verification/verifheep.py create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/data.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/datagen.py create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/fft.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/applications/example_tensor_format_conv/main.c delete mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.c create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.h create mode 100644 hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col_spc_regs.h diff --git a/hw/vendor/esl_epfl_x_heep/Makefile b/hw/vendor/esl_epfl_x_heep/Makefile index ca1a02b0..f65c4640 100644 --- a/hw/vendor/esl_epfl_x_heep/Makefile +++ b/hw/vendor/esl_epfl_x_heep/Makefile @@ -98,7 +98,7 @@ environment.yml: python-requirements.txt ## @section Installation ## Generates mcu files core-v-mini-mcu files and build the design with fusesoc -## @param CPU=[cv32e20(default),cv32e40p,cv32e40x] +## @param CPU=[cv32e20(default),cv32e40p,cv32e40x,cv32e40px] ## @param BUS=[onetoM(default),NtoM] ## @param MEMORY_BANKS=[2(default) to (16 - MEMORY_BANKS_IL)] ## @param MEMORY_BANKS_IL=[0(default),2,4,8] @@ -193,7 +193,7 @@ questasim-sim-opt-upf: questasim-sim $(MAKE) -C build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-modelsim opt-upf ## VCS simulation -## @param CPU=cv32e20(default),cv32e40p,cv32e40x +## @param CPU=cv32e20(default),cv32e40p,cv32e40x,cv32e40px ## @param BUS=onetoM(default),NtoM vcs-sim: $(FUSESOC) --cores-root . run --no-export --target=sim --tool=vcs $(FUSESOC_FLAGS) --build openhwgroup.org:systems:core-v-mini-mcu ${FUSESOC_PARAM} 2>&1 | tee buildsim.log diff --git a/hw/vendor/esl_epfl_x_heep/configs/ci.hjson b/hw/vendor/esl_epfl_x_heep/configs/ci.hjson index 51a278b7..011fe3e8 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/ci.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/ci.hjson @@ -13,11 +13,11 @@ name: code start: 0 #minimum size for freeRTOS and clang - size: 0x00000D800 + size: 0x00000E800 }, { name: data - start: 0x00000D800 + start: 0x00000E800 } ] } \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson b/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson index aac0801e..35d380c6 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/example_interleaved.hjson @@ -30,11 +30,11 @@ name: code start: 0 // minimum size for freeRTOS and clang - size: 0x00000D800 + size: 0x00000E800 }, { name: data - start: 0x00000D800 + start: 0x00000E800 } ] } \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/general.hjson b/hw/vendor/esl_epfl_x_heep/configs/general.hjson index f7040640..0afb35ef 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/general.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/general.hjson @@ -14,11 +14,11 @@ name: code start: 0 #minimum size for freeRTOS and clang - size: 0x00000D800 + size: 0x00000E800 }, { name: data - start: 0x00000D800 + start: 0x00000E800 } ] } \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/configs/testall.hjson b/hw/vendor/esl_epfl_x_heep/configs/testall.hjson index 36828dc8..3e4bad9a 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/testall.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/testall.hjson @@ -13,11 +13,11 @@ name: code start: 0 #minimum size for freeRTOS and clang - size: 0x00000D800 + size: 0x00000E800 }, { name: data - start: 0x00000D800 + start: 0x00000E800 } ] } \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md index 59c1b1e9..41e9bed7 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/How_to/eXtendingHEEP.md @@ -2,14 +2,14 @@ `X-HEEP` is meant to be extended with your own custom IPs. `X-HEEP` itself posseses a hardware-software framework capable of working standalone. If you want to extend it, you will need to merge your hardware and software with `X-HEEP`'s. -For this purpose we support the [CORE-V-XIF](https://docs.openhwgroup.org/projects/openhw-group-core-v-xif/en/latest/intro.html) interface with the [cv32e40x](https://github.com/openhwgroup/cv32e40x) RISCV-CPU, and we expose master and slave ports to/from the bus. +For this purpose we support the [CV-X-IF](https://docs.openhwgroup.org/projects/openhw-group-core-v-xif/en/latest/intro.html) interface with the [cv32e40x](https://github.com/openhwgroup/cv32e40x) or [cv32e40px](https://github.com/esl-epfl/cv32e40px) RISCV-CPU, and we expose master and slave ports to/from the bus. -> `X-HEEP` currently uses the revision [`0.9.0`](https://github.com/openhwgroup/cv32e40x/commit/f17028f2369373d9443e4636f2826218e8d54e0f) of OpenHW Groups's `cv32e40x` core to implement the `CORE-V-XIF`. It is recommended to use the same revision in peripheral IPs to prevent conflicts during RTL compilation. +> We recommend using the `cv32e40px` for pairing with your CV-X-IF compliant coprocessor. If you choose to use the `cv32e40x`, `X-HEEP` currently uses the revision [`0.9.0`](https://github.com/openhwgroup/cv32e40x/commit/f17028f2369373d9443e4636f2826218e8d54e0f). It is recommended to use the same revision in peripheral IPs to prevent conflicts during RTL compilation. Here you can find a list of `X-HEEP` based open-source examples. If you want to include your project in this list, please open an issue with a link to your repository. * [CGRA-X-HEEP](https://github.com/esl-epfl/cgra_x_heep): A CGRA loosely coupled with X-HEEP. -* [F-HEEP](https://github.com/davidmallasen/F-HEEP): System integrating [fpu_ss](https://github.com/pulp-platform/fpu_ss) into X-HEEP via the eXtension interface and cv32e40x. +* [F-HEEP](https://github.com/davidmallasen/F-HEEP): System integrating [fpu_ss](https://github.com/pulp-platform/fpu_ss) into X-HEEP via the eXtension interface and cv32e40px. * [KALIPSO](https://github.com/vlsi-lab/ntt_intt_kyber) and [KRONOS](https://github.com/vlsi-lab/keccak_integration/tree/keccak_xheep): Loosely-coupled, post-quantum cryptography accelerators for NTT/INTT and Keccak hash function integrated into X-HEEP. @@ -98,7 +98,7 @@ To achieve this: * Create a new top-level repository (`BASE`) and vendorize (or add as git submodules) both your `CORE-V-XIF/OBI` compliant coprocessor/accelerator and `X-HEEP`. * Copy the `x-heep/hw/system/x_heep_system.sv` as your new top-level module. Then modify it as needed to include your co-processor and connect it to the `core_v_mini_mcu` with the `XIF`. The `XIF` SystemVerilog interface must be instantiated in the top-level module, where `X-HEEP` and your co-processor are connected. See the `X-HEEP` [testbench](./../../../tb/testharness.sv) as an example. -* Before building software remember to run `make mcu-gen CPU=cv32e40x`. +* Before building software remember to run `make mcu-gen CPU=cv32e40px`. To add this new top-level module to the simulation/synthesis flow you can extend the [FuseSoC](https://fusesoc.readthedocs.io/en/stable/user/index.html) support of `X-HEEP`. @@ -328,7 +328,7 @@ include $(XHEEP_MAKE) * The `verilator-sim` rule will override the `X-HEEP` Makefile's one. * Any other target will be passed straight to `X-HEEP`'s Makefile. For example ```sh -make mcu-gen CPU=cv32e40x +make mcu-gen CPU=cv32e40px ``` diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md index 6b57642f..a3b4d890 100644 --- a/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md +++ b/hw/vendor/esl_epfl_x_heep/docs/source/Peripherals/DMA.md @@ -1,589 +1,1914 @@ # DMA + +## Introduction + The **Direct Memory Access (DMA)** peripheral allows data transfers with reduced CPU interaction. + It can perform *transactions* of data between peripherals and memory, or memory-to-memory (as a `memcpy` would). + The CPU is required to configure the transaction, but once launched it is free to go to sleep, process the incoming data or do anything else. - + +This unit is capable of performing complex tasks that can significantly impact on the performance and power consumption of memory-intense applications. +It can be configured to perform *1D* or *2D* transactions and it can apply **zero padding** and perform **transpositions** on-the-fly, reducing the overhead of matrix operations. + The DMA **Hardware Abstraction Layer (HAL)** facilitates the configuration of transactions from the users application. Furthermore, it adds an additional layer of safety checks to reduce the risk of faulty memory accesses, data override or infinite loops. + + +The DMA **SDK**, on the other hand, offers user-friendly functions for essential *memcpy* and *fill* operations. It does not include the validation capabilities of the HAL nor the 2D and padding features, prioritizing performance at the cost of an increased risk of inconsistencies. + + +
+ +## Structural description + +![DMA subsystem structure](https://github.com/esl-epfl/x-heep/docs/images/dma_structure.png) + +

Figure 1: Structure of the DMA subsystem in X-Heep

+ +#### DMA channels layout + +The DMA subsystem is composed of a parametrized number of control units called **channels**. +Each channel can be configured, by the CPU or by an external controller, to perform a *transaction*, independently of the state of other channels. + +N-channels are connected to a N-to-M bus that exposes M-master ports on the system bus. **Multiple channels** can thus perform multiple transactions in parallel, a feature that enables memory-intense applications to greatly increase their throuhput. + +There are several ways to connect N-channels to the system bus through M-master ports. + +e.g. +Let's consider a DMA subsystem with N = 4 channels and M = 2 master ports. + +There are two possible solutions: +- CH0, CH1 connected to port 0 & CH2, CH3 connected to port 1 +- CH0, CH1, CH2 connected to port 0 & CH3 connected to port 1 + +In order to specify one among these configurations, the user has to set the `num_channels_per_master_port` parameter in `mcu_cfg.hjson`, which defines the _maximum_ channels per master port ratio. + +The first configuration of the previous example has 2 channels per master port, so a channels per master port ratio of 2. +On the other hand, the second solution has a ratio of 3: the first 3 channels are connected to port 0, while the remaining channel is connected to the remaining port 1. + +While the 1st solution is a general purpose, balanced configuration, the 2nd solution might be better suited for applications that need a low latency channel for high priority tasks. + +This mechanism guarantees **maximum flexibility**, enabling the user to adapt the DMA subsystem to its requirements, both in terms of area and performance. +
+ +#### Interrupts + +If enabled, a transaction interrupt is raised every time a DMA transaction is completed. However, due to architectural limitations, there is only a single transaction done signal for the entire DMA subsystem. + +To allow users to identify which channel raised the transaction interrupt, an **interrupt flag register** system has been developed. Here's how it works: when a DMA channel completes its transaction and the interrupt enable register is correctly set, the transaction **IFR** (Interrupt Flag Register) is set. This register is designed to be cleared automatically once read, which is convenient as it eliminates the need for an additional register write. + +The transaction interrupt handler leverages this mechanism to identify the channel that raised the interrupt. As soon as an IFR is read as high, it triggers the actual handler, which can be redefined by the user. An example of this mechanism at work is explained in [Example 7](#7-multichannel-mem2mem-transaction-focus-on-the-irq-handler). + +It is possible that a channel could raise an interrupt while the CPU is processing a previous interrupt from another channel. This is not an issue because the IFR will remain set until the CPU reads its content. However, this situation could introduce additional delay to the execution of the application. + +For this reason, the handler implemented by the user should be as brief as possible. + +#### Data FIFOs configuration + +Each DMA channel uses FIFOs to buffer the data to be read and written, which is crucial for mitigating the combined delays from the system bus and the Always On Peripheral Bus (**AOPB**). + +The **size of the FIFOs is parametric** and is, by default, the same across all channels. + +Some applications can benefit from larger FIFOs because it allows for more values to be buffered in situations where the bus is heavily utilized or the target peripheral, such as the SPI, is too slow. +On the other hand, other applications might not require such large FIFOs, so area can be saved by reducing its size. +A hybrid system, where some channels have large FIFO sizes and others have smaller ones, could benefit both these types of applications. + +It is possible to specify the size of each DMA channel FIFOs in `dma_subsystem.sv`. +These are the steps to follow to take advantage this feature: + +- Uncomment `//'define EN_SET_FIFO_CH_SIZE;` to enable the mechanism +- Adjust the parameters *LARGE_FIFO_CH_SIZE*, *MEDIUM_FIFO_CH_SIZE* and *SMALL_FIFO_CH_SIZE*. They define the size of a large, medium and small FIFOs. +- Modify the parameter `typedef enum {L, M, S} fifo_ch_size_t;` to assign individual sizes to the FIFOs. The number of elements must reflect the number of DMA channels. + +e.g. + +Let's imagine to configure X-Heep to have 4 channels. These are the definitions of the sizes: +- *LARGE_FIFO_CH_SIZE*: 10 +- *MEDIUM_FIFO_CH_SIZE*: 4 +- *SMALL_FIFO_CH_SIZE*: 2 + +Now, let's set the first 2 channels, CH0 and CH1, to the large size, CH2 to small and CH3 to medium. This is the *fifo_ch_size_t* that would result from that configuration: + +
+
typedef enum {L, L, S, M} fifo_ch_size_t;
+
+ +
+ +#### Triggers + +In the case of memory-peripheral operations, it is common for the peripheral to have a reaction time that cannot match the system clock. For example, the SPI trasmits data with a period of circa 30 clock cycles. + +This difference in response times creates the need for a **communication channel** between DMA subsystem and peripheral allowing the DMA operations to be suspended according to the peripheral state. These signals are called __triggers__. + +They can be used both when the peripheral writes data using the DMA and when the DMA reads data from the peripheral. +The DMA can be configured to respond to triggers by enabling the appropriate _slot_ via software, using the DMA HAL. + +
+ +#### Tips for DMA-based accelerator developers + +The DMA subsystem has been developed with specific features to facilitate the creation of custom accelerators that can leverage it to improve memory-intense applications. + +- **Always-On Peripheral Bus** (AOPB): it exposes the register interface of the units in the Always-On subsystem to any Smart Peripheral Controller (SPC). +In the case of the DMA subsystem, this feature allows the developers to configure the DMA subsystem without any CPU action, reducing power consumption while at the same time increasing the performance and effectiveness of the accelerator. +Check out the _im2col SPC_ in the `\ip_examples` folder for a detailed example. +
+ +- **Triggers**: useful to synchronize the data streams to and from the accelerator. +
+ +- **Stop signal**: it can terminate a DMA transaction at any moment. It's particularly useful for accelerators that produce a large quantity of data, but with a variable trasfer size that cannot be known or computed beforehand. +A good example of such an accelerator is a level crossing subsampler, which writes sampled data only when they cross a specific threshold. +
+ +- **VerifHEEP**: this python library has been developed to test computational units and accelerators deployed on X-Heep. +It has been deployed succesfully to verify the _im2col SPC_ as it is expecially useful for data-driven accelerators. +Additional documentation can be found in the **VerifHEEP documentation**, but in brief it includes methods to: + - Generate random inputs and compute the corresponding golden results + - Launch synthesis & simulations on QuestaSim and Verilator + - Compile, program & launch applications on FPGA targets for a tenfold reduction in test and verification times + - Analyze the performance of the tests. +
+ +### Registers description + +This section will describe every register of a DMA channel and their function. +The complete addres of a DMA channel register is the following: + +

DMA_START_ADDRESS + DMA_CH_SIZE * channel + REGISTER_OFFSET

+ +The previous parameters, including the register offsets, can be found at `sw/device/lib/runtime/core_v_mini_mcu.h` and `sw/device/lib/drivers/dma/dma_regs.h` + +
+ +
+
|-------------- 31 : 0 -------------|
+|-------------- PTR_IN -------------|
+
+ +- **SRC_PTR_REG** + - _SW access_: rw + - _Description_: contains the pointer to the source, which could either be data stored in memory or a peripheral. + +
+ +
+
|-------------- 31 : 0 -------------|
+|------------- PTR_OUT -------------|
+
+ +- **DST_PTR_REG** + - _SW access_: rw + - _Description_: contains the pointer to the destination, which could either be data stored in memory or a peripheral. + +
+ +
+
|-------------- 31 : 0 -------------|
+|------------- PTR_ADDR ------------|
+
+ +- **ADDR_PTR_REG** + - _SW access_: rw + - _Description_: Used only with the [address mode](#transaction-modes) . It contains the pointer to the source, which in this case must data stored in memory. + +
+ +
+
|---- 31 : 14 ----|---- 15 : 0 ----|
+|--- Reserved ----|----- SIZE -----|
+
+ +- **SIZE_D1** + - _SW access_: rw + - _Description_: number of elements (not bytes) to be copied by the DMA channel along the first dimension, i.e. using the first counter. As soon as this register is written, the **transaction starts**. + + +
+ +
+
|---- 31 : 14 ----|---- 15 : 0 ----|
+|--- Reserved ----|----- SIZE -----|
+
+ +- **SIZE_D2** + - _SW access_: rw + - _Description_: number of elements (not bytes) to be copied by the DMA channel along the second dimension, i.e. using the second counter. + +
+ +
+
|---- 31 : 2 ----|--- 1 ---|--- 0 ---|
+|--- Reserved ---|- WIN_DN |-- RDY --|
+
+ +- **STATUS** + - _SW access_: ro + - _Description_: this register is used by the DMA to communicate the status of the transaction. READY is 0 when the DMA is busy performing the transaction, 1 otherwise. + +
+ +
+
|---- 31 : 6 ----|---- 5 : 0 ----|
+|--- Reserved ---|----- INC -----|
+
+ +- **SRC_PTR_INC_D1** + - _SW access_: rw + - _Description_: increment in bytes to apply to the source pointer for every copied element. + +
+ +
+
|--- 31 : 23 --|---- 22 : 0 ----|
+|-- Reserved --|------ INC -----|
+
+ +- **SRC_PTR_INC_D2** + - _SW access_: rw + - _Description_: increment in bytes to apply to the source pointer every time a "row" is copied, in order to go to the new line. It's necessary only for 2D transactions. + From an application perspective, this value has to be computed depending on the size of the input matrix and the 2D stride. Check the functional description paragraph for more information or [Example 4](#4-2d-mem2mem-transaction). + +
+ +
+
|---- 31 : 6 ----|---- 5 : 0 ----|
+|--- Reserved ---|----- INC -----|
+
+ +- **DST_PTR_INC_D1** + - _SW access_: rw + - _Description_: increment in bytes to apply to the destination pointer for every copied element. + +
+ +
+
|--- 31 : 23 --|---- 22 : 0 ----|
+|-- Reserved --|------ INC -----|
+
+ +- **DST_PTR_INC_D2** + - _SW access_: rw + - _Description_: increment in bytes to apply to the destination pointer every time a "row" is copied in order to go to the new line. It's necessary only for 2D transactions. + From an application perspective, this value has to be computed depending on the size of the output matrix and the 2D stride. Check the functional description paragraph for more information. + +
+ +
+
|---- 31 : 16 ----|---- 15 : 0 ----|
+|----- TX_TRG ----|---- RX_TRG ----|
+
+ +- **SLOT** + - _SW access_: rw + - _Description_: identifies the triggers for which the DMA channel will stall in writing and/or reading operations. + +
+ +
+
|---- 31 : 2 ----|---- 1 : 0 ----|
+|--- Reserved ---|---- DATA_T ---|
+
+ +- **SRC_DATA_TYPE** + - _SW access_: rw + - _Description_: defines the source data type using this scheme: + - 0: _word_, i.e. 4 bytes + - 1: _half word_, i.e. 2 bytes + - 2 or 3: _byte_ + +
+ +
+
|---- 31 : 2 ----|---- 1 : 0 ----|
+|--- Reserved ---|---- DATA_T ---|
+
+ +- **DST_DATA_TYPE** + - _SW access_: rw + - _Description_: defines the destination data type using this scheme: + - 0: _word_, i.e. 4 bytes + - 1: _half word_, i.e. 2 bytes + - 2 or 3: _byte_ + If wider than the source datatype and sign extension is enabled, the output data will be sign extended + +
+ +
+
|---- 31 : 1 ----|---- 0 : 0 ---|
+|--- Reserved ---|---- SGND ----|
+
+ +- **SIGN_EXT** + - _SW access_: rw + - _Description_: enables the sign extension, which can be performed only if the output datatype is wider than the source datatype + +
+ +
+
|---- 31 : 2 ----|--- 1 : 0 ---|
+|--- Reserved ---|---- MODE ---|
+
+ +- **MODE** + - _SW access_: rw + - _Description_: defines the operation mode of the DMA channel, following this scheme: + - 0: _linear mode_ + - 1: _circular mode_ + - 2: _address mode_ + +
+ +
+
|---- 31 : 1 ----|---- 0 : 0 ----|
+|--- Reserved ---|--- DIM_CFG ---|
+
+ +- **DIM_CONFIG** + - _SW access_: rw + - _Description_: defines the dimensionality of the transaction, i.e. if the transaction is 1D (DMA_DIM = 0) or if it is 2D (DMA_DIM = 1). + +
+ +
+
|---- 31 : 1 ----|--- 0 : 0 ---|
+|--- Reserved ---|---- INV ----|
+
+ +- **DIM_INV** + - _SW access_: rw + - _Description_: enables the transposition of the input source, only with 2D transactions. + +
+ +
+
|---- 31 : 6 ----|--- 5 : 0 ---|
+|--- Reserved ---|---- PAD ----|
+
+ +- **PAD_TOP/BOTTOM/RIGHT/LEFT** + - _SW access_: rw + - _Description_: defines the size of the padding to be applied to the source, in data units. + +
+ +
+
|---- 31 : 13 ---|--- 12 : 0 ---|
+|--- Reserved ---|---- W_SZ ----|
+
+ +- **WINDOW_SIZE** + - _SW access_: rw + - _Description_: defines the size of the window to be copied. + +
+ +
+
|---- 31 : 8 ----|---- 7 : 0 ---|
+|--- Reserved ---|---- W_CNT ---|
+
+ +- **WINDOW_COUNT** + - _SW access_: ro + - _Description_: indicates the number of times the end of the window was reached since the beginning of the transaction. + +
+ +
+
|---- 31 : 2 ----|-- 1 ---|-- 0 ---|
+|--- Reserved ---|- W_DN -|- T_DN -|
+
+ +- **INTERRUPT_EN** + - _SW access_: rw + - _Description_: enables the interrupt for window and/or transaction done. + + +
+ +
+
|---- 31 : 1 ----|--- 0 : 0 ---|
+|--- Reserved ---|--- FLAG ----|
+
+ +- **TRANSACTION_IFR** + - _SW access_: r0 + - _Description_: interrupt flag register for transaction interrupts. It is set to '1' when the transaction interrupts are enabled and the transaction is completed. It is cleared when it's read by the CPU in the IRQ handler. This feature enables the handler to identify which channel raised the interrupt, as explained [here](#interrupts). + +
+ +
+
|---- 31 : 1 ----|--- 0 : 0 ---|
+|--- Reserved ---|--- FLAG ----|
+
+ +- **WINDOW_IFR** + - _SW access_: r0 + - _Description_: interrupt flag register for window interrupts. It is set to '1' when the window interrupts are enabled and the window is done. It is cleared when it's read by the CPU in the IRQ handler. + +## Functional description + +### Dictionary + +The implementation of the software layer introduced some concepts that need to be understood in order to make proper use of the DMA's functionalities. + -## Previous Definitions -The implementation of this software layer introduced some concepts that need to be understood in order to make proper use of the DMA's functionalities . - -### Transaction -A transaction is an operation to be performed by the DMA. It implies copying bytes from a source pointer into a destination pointer. The transaction configuration can be loaded into the DMA registers once it has been cross-checked and it only starts when the size along the *first dimension* of the transaction is written in its corresponding register. The transaction is finished once the DMA has sent all its bytes (which not necessarily means they have been received by the final destination). -Transactions cannot be stopped once they were launched. -While a transaction is running, new transactions can be validated, but not launched or loaded into the DMA. + +#### Transaction + +A transaction is an operation to be performed by the DMA. It implies copying bytes from a source pointer into a destination pointer. +The transaction configuration can be cross-checked before loading it into the DMA registers to avoid potential issues. +The transaction starts only when the size of the *first dimension*, i.e. 1D, of the transaction is written in its corresponding register. The transaction is finished once the DMA has sent all its bytes (which not necessarily means they have been received by the final destination) or when the _external stop signal_ is asserted. + +While a transaction is running, new transactions can be validated, loaded and launched, provided they are not targeting the same DMA channel. + Transactions can be re-launched automatically in `circular mode`. -Once the transaction has finished, a status bit is changed (that can be monitored through polling) and a fast interrupt is triggered. + +Once the transaction has finished, a status bit is changed (that can be monitored through polling) and a fast interrupt is triggered. The channel that raised the interrupt is identified and it's passed to the the handler itself, which can be redefined by the user, as shown in [Example 7](#7-multichannel-mem2mem-transaction-focus-on-the-irq-handler) or in `example_dma_multichannel` in the application folder. -### Source and destination -Sources and destinations are the two pointers that will exchange data. Bytes will be copied from the source and into the destination address. + +#### Source and destination + +Sources and destinations are the two pointers that will exchange data. Bytes will be copied from the source and into the destination address. -### Data type + +#### Data type + The DMA allows transactions in chunks of 1, 2 or 4 Bytes (`Byte`, `Half-Word` and `Word` respectively). The size in bytes of the chosen data type is called _data unit_ (usually abbreviated as `du`). + For example, 16 bytes can be 16 data units if the data type is `Byte`, but 8 data units if the data type is `Half Word`. -Source and destination can have different data types, if the destination type is wider than the source type, data can be sign extended. -### Sign extension -If specified (setting the bit in the corresponding register) and if the destination data type is wider than the source type, sign of the source data is extended to fill the size of the destination data type. +Source and destination can have different data types and if the destination type is larger than the source type, data can be sign extended. + +#### Sign extension +It can be enabled by setting the bit in the corresponding [register](#registers-description). +If the destination data type is larger than the source type, the source data is sign extended to fill up the size of the destination data type. + + +#### Dimensionality -### Dimensionality The DMA can perform both **1D transactions** and **2D transactions**. -When set to perform 1D transactions, the DMA copies the defined number of elements from the source pointer to the destination pointer using a 1D increment. -When set to perform 2D transactions, the DMA copies data from the source pointer to the destination pointer using both a 1D increment and an additional 2D increment. -In this way, two-dimensional data manipulations (e.g. matrix manipulations) can be performed in a single DMA transaction, greatly reducing the CPU time. -### Increment -In the 1D configuration, if source and/or destination data are not to be consecutively read/written, a certain increment can be defined. -For instance, if you have an array of 4-bytes-words, but only want to copy the first 2 bytes of each word, you could define the transaction with a data type of half word, an increment of 2 data units in the source, and 1 data unit in the destination. This way, after each read operation the DMA will increment the read pointer in 4 bytes (2 data units), but the write pointer by only 2 bytes. -In the 2D configuration, a second increment has to be set in order to enable the 2D transaction. -In the context of matrix manipulation, the 2D increment is the number of words that the DMA has to "skip" to move to the next row. -For instance, let's examine the extraction of a continuous 2x2 matrix from a 4x4 matrix, stored in a continuous 2x2 matrix. -``` -| 3 | 5 | 7 | 9 | -| 2 | 4 | 6 | 8 | -> | 3 | 5 | -| 1 | 3 | 5 | 7 | | 2 | 4 | -| 0 | 2 | 4 | 6 | -``` -The total number of elements copied from the source is 4 elements. The increments are: +In a 1D transaction, the DMA copies a certain number of elements from the source pointer to the destination pointer using a single increment. +On the other hand, in a 2D transaction the DMA copies data from the source pointer to the destination pointer using two separate increments, which can be interpreted as a 1D and a 2D increment. +In this way, two-dimensional data manipulations, i.e. matrix manipulations, can be performed in a single DMA transaction. + +#### Increment + +In a 1D transaction, setting the increment appropriately can be leveraged to achieve non-contiguous read and/or write operations. + +For example, let's consider an array of 4 word-type elements. +To copy just the first 2 bytes of each word, follow these steps: + +- Set the datatype of the transaction to **half word**. +- Set the source increment to **2 data units**. +- Set the destination increment to **1 data unit**. + +After each reading operation, the DMA will increment the read pointer by 4 bytes (2 data units) and the write pointer by 2 bytes. + +In the case of 2D transactions, a second increment must be set to perform matrix manipulations. +The 2D increment can be interpreted as the number of words that the DMA has to "skip" to move to the next row of the matrix. + +For example, let's examine the extraction of a contiguous 2x2 matrix from a 4x4 matrix. + + | 3 | 5 | 7 | 9 | + | 2 | 4 | 6 | 8 | -> | 3 | 5 | + | 1 | 3 | 5 | 7 | | 2 | 4 | + | 0 | 2 | 4 | 6 | + +The total number of elements copied from the source is 4. +In order to achieve this result, these are the setup of the increments: - For the source: - 1D increment set to 1 word - 2D increment set to 3 words - For the destination: - 1D increment set to 1 word - 2D increment set to 1 word -By exploiting the 2D increment, it's possible to implement a non-continuous read and/or write by computing the correct 2D increment. Detailed formulas for the computation of 2D increments are reported in the *example_dma_2d* folder. + +Moreover, by exploiting the 2D increment, it is possible to implement a 2D non-continuous read and/or write. + +Detailed formulas for the computation of 2D increments are reported in the example application in the `\example_dma_2d` folder. -### Zero padding +#### Zero padding -The DMA is capable of performing zero padding on the extracted data, both in 1D and 2D transactions. -This is done by by setting four padding parameters: -- **T**op -- **B**ottom -- **L**eft -- **R**ight -e.g. +The DMA is capable of performing zero padding on the extracted data, both in 1D and 2D transactions, within a single transaction. +This is achieved by setting four padding parameters: -``` -| T | T | T | T | T | -| L | x | x | x | R | -| L | x | x | x | R | -| B | B | B | B | B | -``` -It's important to highlight the fact that the padding is performed (conceptually) only *after* the matrix has been extracted. -Let's examine the previous 2x2 extraction example, adding a left and top padding of 1 word: +- **T**op +- **B**ottom +- **L**eft +- **R**ight -``` -| 3 | 5 | 7 | 9 | | 0 | 0 | 0 | -| 2 | 4 | 6 | 8 | -> | 0 | 3 | 5 | -| 1 | 3 | 5 | 7 | | 0 | 2 | 4 | -| 0 | 2 | 4 | 6 | -``` +e.g. Let's consider a 2x3 matrix: + + | T | T | T | T | T | + | L | x | x | x | R | + | L | x | x | x | R | + | B | B | B | B | B | + + +It's important to highlight that the padding is performed (conceptually) only *after* the matrix has been extracted. +So the padding parameters refers only to the extracted matrix, not to the entire source matrix. + +Let's revisit the previous 2x2 extraction example, this time adding a left and top padding of 1 element: + + + | 3 | 5 | 7 | 9 | | 0 | 0 | 0 | + | 2 | 4 | 6 | 8 | -> | 0 | 3 | 5 | + | 1 | 3 | 5 | 7 | | 0 | 2 | 4 | + | 0 | 2 | 4 | 6 | + + +#### Alignment + +When performing transactions with bytes, the DMA can read/write from any pointer. However, if the data type is larger, words should be aligned so the DMA can perform a read/write operation and affect only the chosen bytes. +If a word or half-word's pointer is not a multiple of 4 or 2 (respectively), the pointer is _misaligned_. In some cases the DMA HAL can overcome this problem by reducing the data type (which will reflect on an efficiency loss). -### Alignment -When doing transactions with bytes, the DMA can read/write from any pointer. However, if the data type is larger, words should be aligned so the DMA can perform a read/write operation and affect only the chosen bytes. If a word or half-word's pointer is not a multiple of 4 or 2 (respectively), the pointer is _misaligned_. In some cases the DMA HAL can overcome this problem reducing the data type (which will reflect on an efficiency loss). - -### Environment -An environment is a region of memory that can optionally be defined by the user to let the HAL know that it is allowed to read/write on that region. It is useful to make sure the DMA will not affect reserved memory regions. -Right now, read and write permissions are not supported by environments, meaning that if it is defined, the DMA will be able to read AND write on it. -### Triggers and Slots -If the source or destination pointer is a peripheral, there are lines connecting the peripheral and the DMA that can be used to control the data flow (they behave as _triggers_). These lines are connected to _slots_ on the DMA and they allow/stop the DMA from reading/writing data. + +#### Environment + +An environment is a user-defined region of memory that informs the HAL of permissible read/write areas. This ensures that the DMA does not interfere with reserved memory regions. + +Read and write permissions are not supported by environments. If an environment is defined, the DMA will have both read and write access to it. -### Target -A target is either a region of memory or a peripheral to which the DMA will be able to read/write. When targets are pointing to memory, they can be assigned an environment to make sure that they will comply with memory restrictions. -Targets include a pointer (a point in the memory, or the Rx/Tx buffer in case of peripherals), a size to be copied (if its going to be used as a source), a data type and an increment. + +#### Target + +A target is either a memory region or a peripheral that the DMA can read from or write to. When targets point to memory, they can be assigned an environment to ensure compliance with memory restrictions. + +Targets include: + +- A pointer (either a memory location or the Rx/Tx buffer for peripherals) +- A size to be copied (if used as a source) +- A data type +- An increment + -### Configuration flags + +#### Configuration flags + During the creation or configuration of environments, targets or transactions, there could be inconsistencies or threatening situations (like writing outside the boundaries of a defined region). To provide the user with information about this potentially harmful situations, configuration flags are set while creating each of these entities. They can be unmasked and checked. + In some cases, when the threat is too risky, a _crucial error_ might be raised and the operation of the configuration is halted. + If senseless configurations are input to functions, assertions may halt the whole program. This is reserved for extreme situations that mean the program was not properly coded (e.g. a slot value is provided and is not among the available ones). + -### Transaction modes + +#### Transaction modes + There are three different transaction modes: -**Single Mode:** The default mode, where the DMA will perform the copy from the source target to the destination, and trigger an interrupt once done. -**Circular mode:** To take full advantage of the speed and transparency of the DMA, a _circular_ mode was implemented. When selected, the DMA will relaunch the exactly same transaction upon finishing. This cycle only stops if by the end of a transaction the _transaction mode_ was changed to _single_. The CPU receives a fast interrupt on every transaction finished. + +**Single Mode:** The default mode, where the DMA channel will perform the copy from the source target to the destination, and trigger an interrupt once done. + +**Circular mode:** It takes full advantage of the speed and transparency of the DMA. When selected, the DMA will relaunch the exact same transaction upon finishing. This cycle only stops if by the end of a transaction the _transaction mode_ was changed to _single_. The CPU receives a fast interrupt on every transaction finished. + **Address Mode:** Instead of using the destination pointer and increment to decide where to copy information, an _address list_ must be provided, containing addresses for each data unit being copied. It is only carried out in _single_ mode. In this mode it's possible to perform only 1D transactions. + -### Windows -In order to process information as it arrives, the application can define a _window size_ (smaller than the _transaction size_. Every time the DMA has finished sending that given amount of information will trigger an interrupt through the PLIC. + +#### Windows + +In order to process information as it arrives, the application can define a _window size_ (smaller than the _transaction size_). Every time the DMA has finished sending that amount of information, it will trigger an interrupt through the PLIC. + > :warning: If the window size is a multiple of the transaction size, upon finishing the transaction there will be first an interrupt for the whole transaction (through the FIC), and then an interrupt for the window (through the PLIC, which is slower). + -### Checks and Validations + +#### Checks and Validations + The DMA HAL's interface functions perform two types of checks: + * **Sanity checks**: Make sure that each individual value passed as an argument is reasonable and belongs to the proper domain. This errors will raise an _assertion_ and, depending on how assertions are managed in the application, may result in the program crashing. + * **Integrity checks**: Arguments are cross-checked to make sure that they abide by the rules of the DMA. If configurations are incompatible, contradictory, or a risk for the programs integrity, warnings are raised through the _configuration flags_. In some special cases, a _critical error_ can be raised, which blocks the deployment of the configuration into the DMA registers. + + > :warning: Integrity checks can be disabled to speed up configuration time. Do this only if you have previously checked the configuration and are sure it will not cause any trouble. + + Checks and validations are performed during the transactions creation, loading and launching. + + A transaction is validated if it went through the creation-checks without raising critical errors. + -### End events -The DMA considers a certain amount of bytes to have been transferred once it has sent them. It does not wait for a confirmation from the recipient. When a transaction/window is finished the DMA performs a series of event. These may include: + +#### End events + +The DMA considers a certain amount of bytes to have been transferred once it has sent them. It does not wait for a confirmation from the recipient, but can be interrupted at any time using the `ext_dma_stop` signal. +When a transaction/window is finished the DMA performs a series of events. These may include: + * Changing its status register. + * Raising a _transaction done_ interrupt. + * Raising a _window done_ interrupt. + -The DMA HAL can follow up on these changes or let the application be in charge. For this purpose, three different types of _end events_ are defined: + +The DMA HAL can follow up on these changes or let the application be in charge of them. For this purpose, three different types of _end events_ are defined: + * **Polling**: The HAL will disable interrupts from the DMA. The application will need to frequently query the status of the DMA to know when a transaction has finished. + * **Interrupt**: Interrupts will be enabled. The _window done interrupt_ is enabled if a window size is provided. + * **Interrupt wait**: The DMA HAL will block the program in a `wfi()` state until the _transaction done interrupt_ is triggered. + + +## Software stack: HAL and SDK - -## Operation -This section will explain the operation of the DMA through the DMA HAL. -There is a DMA instance inside X-HEEP, but others can be connected outside through the bus (see the `example_external_peripheral` application in `sw/aplications/example_external_peripheral/main.c`). As long as the DMA instance is the same and the registers are memory mapped with the same structure, the DMA HAL can be used. - -The DMA HAL adds an extra computational overhead to transactions in order to check the consistency of the transaction configurations. By-passing this layer (and the steps here described) is disadvised. For the efficiency-hungry applications, doing at least one pass with the whole validation process is recommended. The HAL allows to load and launch transactions with minimum overhead afterwards. - -The following explanation makes use of Figure 1. - -![DMA HAL-HW + addresses](https://github.com/esl-epfl/x-heep/assets/54960111/3092faa5-c72c-4cd9-a4d4-4c87de63d1c7) -

Figure 1: Example operation of the DMA and its HAL

- ---- - -The use of the DMA starts with the application creating a set of targets (**a**) . In the figure, the source target is a peripheral connected to an SPI and to the DMA. The address of the reception FIFO (_Rx FIFO_) of this SPI is `0x70` (**b**) . The destination target is a region of memory of address `0x16` (**c**). It is located inside an environment that spans from `0x12` to `0x35`. Any number of environments and targets can be created, and not used. - -Additionally, in the application the transaction is created. The _operation mode_ and _window size_ are selected. - -The application calls the validation function of the HAL. If the configurations do not raise a critical flag, it then calls the loading function. By doing so, the desired values are written into their corresponding registers (**d**). The only register that is not immediately written is the _transaction size_, as it is the one responsible for launching the transaction when changed from zero to a non-zero value. It is only written once the application calls the launching function (**e**). - -Note that there could be some changes between the configuration input in the application and the values written in the registers. For example, a _window size_ of 2 refers to _2 data units_ (i.e. 2 half-words, as such is the data type of the source in Figure 1); however, when writing on the register, this is translated to bytes, so 4 is written instead. - -Once launched, the transaction will execute completely (it cannot be stopped). Upon finishing, it will check the _operation mode_ and _transaction size_ registers. If any of both is non-zero, it will relaunch. Note that the selecting _circular mode_ during the configuration loading does not launch the transaction (despite what step (**f**) might suggest, which is only illustrative). - - -Once the transaction is launched, the DMA will take care of copying as many data units as were requested from the source target (**g**), and pasting them into the destination target (**h**). The data width of the transaction is determined by the _data type_ of the source target (**i**). However, this might be changed (for a smaller width) in case of misalignment. It is possible to reject changes by the DMA HAL and raise an error in case of misalignments instead. - -The selected slot will query the state of a trigger from the peripheral (**j**). In case the peripheral's FIFO is empty/full (for reception/transmission respectively), the transaction is paused until the trigger enables it again. - -The source and destination increments will determine the amount of steps the pointer should jump after every read and write, respectively. For peripherals it should always be zero (as it should always take the first element of the FIFO). - -The DMA will consider a data unit was transferred once it is sent (**k**). It does not wait for an acknowledge by the destination target. - -The _interrupts_ register controls whether the events triggered by the DMA upon finishing a window or a whole transaction should be propagated as interrupts (**l**). - -Every time _window size_ data units have been transferred the window count is incremented and a PLIC interrupt is triggered (if enabled) (**m**). - -Every time a transaction is finished a FIC interrupt is triggered and the restart condition is evaluated (**f**). - -If the window size is a multiple of the transaction size, upon finishing the transaction there will be first an interrupt for the whole transaction (through the FIC), and then an interrupt for the window (through the PLIC, which is slower). - - -The DMA HAL has weak implementations to handle each interrupt. It is up to the application to do something useful with this. the HAL will only forward the interrupt (**n**). - -> :warning: If the window size is too small (i.e. the time the DMA requires to make the copy is smaller than the time required to attend the interrupt handling), data might be lost. The HAL implements a warning in case the transaction-window size ratio is to small. The warning can be re-configured to an appropriate threshold by overriding a weak implementation. The user should do its own testing and choose this threshold accordingly. The same type of issue might be found on circular mode. The user should be sure it can attend an interrupt before the next one occurs. There is no warning from the HAL in this case. - -The same result from this example could have been achieved by setting the transaction mode to _address_. It requires an array of destination addresses (**p**) that must be provided as the destination target pointer. Instead of copying information to that pointer, the DMA will read from there and copy the information into the addresses stored in each word (**o**). -This use case is very impractical as it doubles the memory usage. It is intended to be used along In-Memory-Computing architectures and algorithms. - -## Usage -This section will explain a basic usage of the DMA as a `memcpy`, and a slightly more complex situation involving a peripheral connected via an SPI. - -### Basic application -This example will provide a simplified code for copying data from one region of memory to another. For a real implementation please refer to the `dma_example` application in `sw/applications/dma_example/main.c`. - -The objective of this app would be to copy the content of an array into another. - ---- - -Start the application by calling -```C -dma_init( NULL ); -``` - -This will reset the DMA registers. The `NULL` parameter tells the HAL that the devices internal DMA is to be used. - -The most basic implementation requires the creation of **two targets** and a **transaction** relating them both. - -A target will include the information of the source or destination pointer and the characteristics of the expected transaction. - -Theoretically, there is no required difference between a _source_ and _destination_ target. They will only be differentiated once the transaction is created. Eventually, they could be interchanged from one transaction to the next. In this example they will be given explicit names and will take different arguments for the sake of clarity. - -```C -static dma_target_t tgt_src = { - .ptr = copy_buffer, - .inc_du = 1, - .size_du = sizeof(copy_buffer), - .type = DMA_DATA_TYPE_WORD - }; -``` - -Here, `ptr = copy_buffer` is a `uint32_t` pointer from where the information will be extracted. `inc_du = 1` is telling the DMA that for each word copied, the pointer should be incremented by 1 unit, therefore words will be copied consecutively without gaps. - -This configuration is implicitly initializing the rest of the target configurations as zero (as of [C99](https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)). This means that: -* No environment is set. -* Data type is set to _word_ (32-bits). -* The trigger is set to _memory_ (vs. a peripheral). +Like every other computational unit in X-Heep, a DMA transaction can be set up and launched using direct register writes. This method achieves minimal overhead and optimal performance, as thoroughly documented in `sw/applications/example_dma_2d` and `sw/applications/example_dma_multichannel`. + +However, this strategy carries **significant risks**. For instance, the transaction starts immediately after writing to the size register, so the order of register writes must be strictly followed. If the code is compiled with aggressive optimization flags, these write operations might be reordered, potentially compromising the DMA functionality. Additionally, errors in setting the transaction size or increments can lead to memory corruption. + +Given the criticality of DMA operations and the potential for destructive errors, direct register writes should be approached with utmost _caution_. To mitigate these risks and ease the application development, two software stacks have been developed: + +- **HAL**: Provides functions for initializing DMA channels, validating and correcting issues within the targets, loading and launching transactions. +
+ +- **SDK**: Offers user-friendly functions for basic but essential *memcpy* and *fill* operations. It does not include the validation capabilities of the HAL nor the 2D and padding features, prioritizing performance at the cost of an increased risk of failure. + +### DMA HAL + +This section will include a brief overview of the functionalities offered by the DMA HAL. For more practical example, please refer to the next chapter, _"Usecases and examples"_. + +Let's start with the structures that enable users to define a DMA transaction and its targets, defined in `dma.h`: + +> :warning: Remember to declare these structure as **global**, i.e. outside the main() function, or **static** if they need to be local. This is **critical** as it ensures that the fields that are not needed are initialized correctly. + +#### dma_target_t + +The dma_target_t structure represents a target for a DMA transaction, either as a source or a destination. It encapsulates the parameters required to define a memory region or a peripheral for DMA operations. Furthermore, control parameters can be added to prevent the DMA from reading/writing outside the boundaries of the target. + +#### dma_trans_t + +The dma_trans_t structure defines a DMA transaction, encapsulating all the necessary parameters and configurations required to perform a DMA operation. Each member of the structure is designed to handle specific aspects of the transaction, from source and destination targets to increments, transaction sizes, data types, and operational modes. +
+Let's examine the main functions to be called in order to correctly perform a DMA transaction. + +#### dma_init() + +*Purpose*: +The dma_init function initializes the DMA subsystem by cresetting transaction structures and clearing DMA registers of each channel. + +*Parameters*: +- dma *dma_peri: Pointer to the DMA peripheral. If this pointer is provided, it uses the given DMA peripheral; otherwise (NULL), it uses the integrated DMA peripheral. + +#### dma_validate_transaction() + +_Purpose_: +The dma_validate_transaction function ensures the configuration of a DMA transaction is correct, checking for potential issues that could prevent the transaction from executing properly. It performs sanity checks, verifies target configurations, and addresses any alignment, increment, padding, trigger, and mode inconsistencies. + +_Parameters_: +- dma_trans_t *p_trans: Pointer to the DMA transaction structure that contains the transaction configuration. +- dma_en_realign_t p_enRealign: Flag indicating whether realignment is enabled. +- dma_perf_checks_t p_check: Flag indicating whether integrity checks should be performed. + +_Return Values_: +- dma_config_flags_t: Configuration flags indicating the status of the transaction validation. They provide information about the validity of the transaction and any detected errors or warnings. + +#### dma_load_transaction() + +_Purpose_: +The dma_load_transaction function configures and loads a DMA transaction into a DMA channel. It checks for critical errors defined by the validation function, ensures no other transaction is running, and sets various parameters such as interrupts, pointers, increments, padding, and operation modes by writing in the correct registers. The only register that is not written is the +SIZE_D1 register so it doesn't launch the transaction. + +_Parameters_: +- dma_trans_t *p_trans: Pointer to the DMA transaction structure that contains the configuration for the transaction. + +_Return Values_: +- DMA_CONFIG_OK: Indicates that the transaction was successfully loaded. +- DMA_CONFIG_CRITICAL_ERROR: Indicates that the transaction contains a critical error and cannot be loaded. +- DMA_CONFIG_TRANS_OVERRIDE: Indicates that another transaction is currently running and cannot be overridden. + +#### dma_launch() + +_Purpose_: +The dma_launch function initiates a DMA transaction that has been previously configured and loaded into a DMA channel. It ensures the transaction is valid, checks for any ongoing transactions, and then starts the new transaction. If the end event is set to wait for an interrupt, the function will block until the interrupt is received. + +_Parameters_: +- dma_trans_t *p_trans: Pointer to the DMA transaction structure that contains the configuration for the transaction. + +_Return Values_: +- DMA_CONFIG_OK: Indicates that the transaction was successfully launched. +- DMA_CONFIG_CRITICAL_ERROR: Indicates that the transaction could not be launched due to a critical error. +- DMA_CONFIG_TRANS_OVERRIDE: Indicates that another transaction is currently running and cannot be overridden. + +#### fic_irq_dma() + +_Purpose_: +The *fic_irq_dma* function is called whenever one of the DMA channels raises the fast interrupt line, signaling the FIC (Fast Interrupt Controller) that a transaction has completed. As thoroughly explained in Example 7 of the next section, this function identifies the channel that triggered the interrupt and calls a handler function, *dma_intr_handler_trans_done()*, passing the channel ID. + +This function can be redefined by the user to perform specific actions, provided that the computational load of these tasks is kept to a minimum. + +_Parameters_: +- None + +_Return Values_: +- None (void type) + +
+ +#### handler_irq_dma() + +_Purpose_: +The *handler_irq_dma* function is very similar to *fic_irq_dma*, but its called whenever one of the DMA channels triggers a window donw interrupt, i.e. the transaction has copied N elements. Just like the previous one, this function identifies the channel that triggered the interrupt and calls a handler function, *dma_intr_handler_window_done()*, passing the channel ID. + +_Parameters_: +- None + +_Return Values_: +- None (void type) + +
+ +## Usecases and examples + +This section will examine and explain several use cases in detail to provide users with a comprehensive understanding of the DMA subsystem and how to leverage it to enhance their application's performance. + +These examples focus on the use of the DMA HAL and the padding and multichannel capabilities of the DMA. The DMA SDK is straightforward enough to be fully understood through the structural and operational descriptions provided in the previous sections. + +Here is a brief overview of the examples: + +1) Simple mem2mem transaction, i.e., 1D memcpy +2) Simple mem2mem transaction with address mode +3) Sign extension +4) 2D mem2mem transaction, i.e., 2D memcpy +5) Matrix transposition +6) Matrix zero padding +7) Multichannel mem2mem transaction, focusing on the IRQ handler +8) Multichannel flash2mem transaction using the SPI FLASH + +The complete code for these examples can be found in `sw/applications/example_dma`, `sw/applications/example_dma_2d`, `sw/applications/example_dma_multichannel` and `sw/applications/example_dma_sdk`. These applications offer both verification and performance estimation modes, enabling users to verify the DMA and measure the application's execution time. + +The user is strongly incouraged to look at these applications, as well as any other application that employs the DMA, to gain insight in practical examples of the use of this peripheral. Some aspects or specific usecases might in fact not be present in this guide and could be found in the applications. + +> :warning: If you have any relevant questions about the DMA or other topics, feel free to open a _question_ on our GitHub repository page! + +
+ +### 1. Simple mem2mem transaction + +The goal of this example is to develop a function that copies the content of a source array to a destination array. + +Let's start! + +#### Setting targets & transaction structs + +The first step is to define the source and destination target structs, as well as the transaction structs. + +> :warning: Declare the targets and the transaction structs globally to ensure that the fields unused in this example are automatically initialized to zero. +This practice prevents unintentional data corruption or unexpected behavior during the DMA transaction. + +In this example, an array of six 32-bit words is used. +The data type for both the source and destination is specified in the `.type` field of their respective dma_target_t structures. +Since the data is stored in RAM, the trigger, `.trig`, will be the default one, i.e. *DMA_TRIG_MEMORY*. + +In this example, a 4-element array will be extracted from the 6-element source. The size of the transaction, which is the number of elements to be copied, is specified in `.size_d1_du`. + +The transaction mode will be set to single mode, so the `.mode` field will be configured as *DMA_TRANS_MODE_SINGLE*. +Finally, let's set the end event, `.end`, to *DMA_TRANS_END_INTR_WAIT*, to leave the HAL to wait for the interrupt. + ```C -static dma_target_t tgt_dst = { - .ptr = copy_buffer, - .inc_du = 1, - .size_du = sizeof(copy_buffer), - .type = DMA_DATA_TYPE_WORD - }; + + int size = 4; + uint32_t src[6] = {0x12345678, 0x76543210, 0xfedcba98, 0x579a6f90, 0x657d5bee, 0x758ee41f}; + uint32_t dst[4]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .size_d1_du = size, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` -Both destination and source targets have to contain a data type (they can be different) and size in data units (they should be the same). -Finally, a transaction is created to relate both targets: + +#### Perform validation, loading and launching + +This second step is also the final one! The only thing left to do is to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. For convenience, let's put these calls inside a dedicated function, called *run_dma_trans()*. + +The *DMA_ENABLE_REALIGN* flag signals the HAL to perform realignment when necessary. Similarly, the *DMA_PERFORMS_CHECKS_INTEGRITY* flag instructs the HAL to perform integrity checks. + +The return values of these HAL calls will be stored and returned to check for any potential issues. + +``` C + +dma_config_flags_t run_dma_trans(dma_trans_t *trans) +{ + dma_config_flags_t res; -```C -static dma_trans_t trans = { - .src = &tgt_src, - .dst = &tgt_dst, - }; + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(&trans); + res |= dma_launch(&trans); + + return res; +} + ``` - -This will also imply some configurations set to zero: -* Mode is set to singular (only one transaction will be executed). -* There will be no window interrupts. -* The application will have to do polling to know when the transaction has finished. - -The transaction can now be created (some extra configurations are computed from the targets), loaded into the DMA and launched. - -```C -dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); -dma_load_transaction( &trans ); -dma_launch( &trans ); - + +The datatype *dma_config_flags_t* is defined in the HAL header and is provided below for convenience: + +``` C + +typedef enum +{ + DMA_CONFIG_OK = 0x0000, /*!< DMA transfer was successfully + configured. */ + DMA_CONFIG_SRC = 0x0001, /*!< An issue was encountered in the + source arrangement. */ + DMA_CONFIG_DST = 0x0002, /*!< An issue was encountered in the + destination arrangement. */ + DMA_CONFIG_MISALIGN = 0x0004, /*!< An arrangement is misaligned. */ + DMA_CONFIG_OVERLAP = 0x0008, /*!< The increment is smaller than the + data type size. */ + DMA_CONFIG_DISCONTINUOUS = 0x0010, /*!< The increment is larger than the + data type size. */ + DMA_CONFIG_OUTBOUNDS = 0x0020, /*!< The operation goes beyond the + memory boundaries. */ + DMA_CONFIG_INCOMPATIBLE = 0x0040, /*!< Different arguments result in + incompatible requests. */ + DMA_CONFIG_WINDOW_SIZE = 0x0080, /*!< A small window size might result + in loss of syncronism. If the processing of the window takes longer than the + time it takes to the DMA to finish the next window, the application will not + be able to cope. Although "how small is too small" is highly dependent on + the length of the processing, this flag will be raised when the transaction + and window size ratio is smaller than an arbitrarily chosen ratio as a mere + reminder. This value can be overriden buy means of defining a non-weak + implementation of the dma_window_ratio_warning_threshold function. */ + DMA_CONFIG_TRANS_OVERRIDE = 0x0100, /*!< A transaction is running. Its + values cannot be modified, nor can it be re-launched. */ + DMA_CONFIG_CRITICAL_ERROR = 0x0200, /*!< This flag determines the function + will return without the DMA performing any actions. */ +} dma_config_flags_t; + ``` + +Now, the function can be called inside the `main` function, and the flags should be checked to ensure the transaction was executed correctly. + +``` C + +... + +int main() +{ + dma_init(NULL); -When creating the transaction, the two last parameters are allowing the DMA to perform integrity checks and try some fixes (at the expense of efficiency) if misalignments are found. - -As there will be no interrupts set, the application has to check by itself the status of the transaction. - -```C -while( ! dma_is_ready() ){} -// The transaction has finished! + dma_config_flags_t result = run_dma_trans(); + + if (result != 0) + { + printf("Error! DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + return 0; + } +} + ``` - - -### Complete Application -The objective of this example is to show various special cases, precautions and considerations that can be taken. For a real example refer to the `spi_flash_write` application in `sw/applications/spi_flash_write/main.c`. - -This example will copy every other byte from a buffer in RAM to a FLASH connected via an SPI to the DMA. Then, it will copy information from an SPI peripheral continuously into a small buffer. - -This explanation assumes you have read the previous example. - ---- - -Start the application by calling +
+ +### 2. Simple mem2mem transaction with address mode + +The goal of this example is to develop a function that copies the content of a source array to a destination array using the address mode. + +Let's start! + +#### Setting targets & transaction structs + +Just like in example 1., the first step is to define the source and destination target structs, as well as the transaction structs. + +This time, the address mode will be used. The DMA channel will use the content of an array as destination pointers, instead of computing them itself. These addresses will be generated in the *main()* as showed later on. + ```C -dma_init( NULL ); + + int size = 4; + uint32_t src[6] = {0x12345678, 0x76543210, 0xfedcba98, 0x579a6f90, 0x657d5bee, 0x758ee41f}; + uint32_t dst[size]; + uint32_t addr[6]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_addr = { + .ptr = (uint8_t *) addr, + .inc_d1_du = 1, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .src_addr = &tgt_addr; + .size_d1_du = size, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_ADDR, + .win_du = 0, + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` + +#### Perform validation, loading and launching + +Once again, only two steps! Time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. +Let's put these calls inside a dedicated function, called *run_dma_addr_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result, i.e. the extracted matrix. + +``` C + +dma_config_flags_t run_dma_addr_trans(dma_trans_t *trans) +{ + dma_config_flags_t res; -The first source target will be pointing to a `uint16_t` buffer in memory. Data will be copied in chunks of 1 byte. For every half-word (16 bits), the only the second half (second 8 bits) will be copied. + res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(&trans); + res |= dma_launch(&trans); + + return res; +} + +... + +int main() +{ + dma_init(NULL); + + // Data setup for address mode + for (int i = 0; i < 6; i++) + { + addr[i] = &src[i]; + } -```C -static dma_target_t tgt1= { - .ptr = (uint8_t*)(copy_buffer + 1), - .inc_du = 2, - .size_du = sizeof(copy_buffer), - .type = DMA_DATA_TYPE_BYTE, - }; + dma_config_flags_t result = run_dma_addr_trans(); + + if (result != 0) + { + printf("Error! DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + return 0; + } +} + ``` - -To start copying information from the second byte of `copy_buffer`, the source pointer is set to the address of `copy_buffer` plus one byte. -In order to copy one byte and skip another, the data type is set to byte, and the increment is set to two data units (i.e. two bytes). As for every half-word of the buffer a data unit will be copied, the transaction size is the same as the size of the `copy_buffer`. - - -The second target will point to the address of the SPI FLASH transmission FIFO. On this example, this value was already computed and stored in a constant `ADDRESS_SPI_FLASH_TX_FIFO`. - - +
+ +### 3. Sign extension + +The goal of this example is to develop a function that transforms an array of bytes in an array of words, performing sign extension when necessary. + +Many examples of sign extensions are present in *TEST_SINGLE* in `example_dma`. + +Let's start! + +#### Setting targets & transaction structs + +First step: define the source and destination target structs, as well as the transaction structs. This time, it's important to pay attention to the data types and ensure that the sign extension feature is enabled. + + ```C -static uint32_t *spi_flash_fifo_tx = ADDRESS_SPI_FLASH_TX_FIFO; - - -static dma_target_t tgt2= { - .inc_du = 0, - .trig = DMA_TRIG_SLOT_SPI_FLASH_TX, - }; -tgt2.ptr = spi_flash_fifo_tx; + + #define SIZE 6 + uint8_t src[SIZE] = {0xe7, 0x32, 0x89, 0x0a, 0x12, 0xfd}; // {-25, 50, -119, 18, -3} + uint32_t dst[SIZE]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_BYTE, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .type = DMA_DATA_TYPE_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans = { + .src = &tgt_src, + .dst = &tgt_dst, + .size_d1_du = size, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .sign_ext = 1; // This flag enables sign extension! + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` + +#### Perform validation, loading and launching + +Once again, only two steps! Time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. +Let's put these calls inside a dedicated function, called *run_dma_signext_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result. + +``` C + +dma_config_flags_t run_dma_signext_trans(dma_trans_t *trans) +{ + dma_config_flags_t res; -Because structure initializers need to be constants, the pointer value (which is a non-constant variable) needs to be initialized outside the designated initializer. - - -There is no need to assign a value of transaction size or data type. By default, the DMA will use the source's values. The data type could eventually be modified by the HAL if there is a misalignment and `DMA_ENABLE_REALIGN` is set when creating the transaction. - -The increment needs to be set to zero as the pointer should always be set to the FIFO address. - -Because the SPI FLASH transmission FIFO has a line connected to slot number 4 (codified as a `1` in the fourth bit of the `trig` element) to let the DMA know if the FIFO is full, a trigger is set in that position by passing `.trig = DMA_TRIG_SLOT_SPI_FLASH_TX`. - + res = dma_validate_transaction(trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(trans); + res |= dma_launch(trans); + + return res; +} + +... + +int main() +{ + dma_init(NULL); -The transaction is formed by selecting the source and destination targets + dma_config_flags_t result = run_dma_signext_trans(&trans); + + if (result != 0) + { + printf("Error! DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + + for (int i=0; i +
SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1)
+ + +In this case, the source 2D increment will be 3 data units. On the other hand, the destination increment will always be 1 when the destination stride is 1. + +Finally, set the dimensionality flag to 1 to configure it for 2D transactions. + ```C -dma_config_flags_t res; -res = dma_validate_transaction( &trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); + + #define SIZE_IN_D1 4 + #define SIZE_IN_D2 4 + #define SIZE_EXTR_D1 2 + #define SIZE_EXTR_D2 2 + #define SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1) + #define DST_INC_D2 = 1 + + uint16_t src[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1234, 0x7654, 0xfedc, 0xffff, + 0x5912, 0xabcd, 0xcdef, 0xfafa, + 0x579a, 0x657d, 0x758e, 0xabba, + 0xa1a1, 0xc3c3, 0xb2b2, 0xf4f4 + }; + uint16_t dst[SIZE_EXTR_D1*SIZE_EXTR_D2]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans_2d = { + .src = &tgt_src, + .dst = &tgt_dst, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .dim = DMA_DIM_CONF_2D, // This is the dimensionality flag! + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` - -The result variable `res` contains configuration flags that can be used to check that no errors or warnings were raised. These are codified as bits in the 16-bit `res` variable. -If only one flag was raised, the value of `res` will be equal to it. Otherwise, they can be checked by selecting individual bits, with inequalities, or comparing the result to a bitwise-or of flags. - + +
+ +### 5. Matrix transposition + +The goal of this example is to develop a function that extracts a submatrix from a source matrix, transpose it and copies it to a destination matrix. + +Let's start! + +#### Setting targets & transaction structs + +Once again, the first step is to define the source and destination target structs, as well as the transaction structs. + +Let's use the same formula as in example 2 to extract a 2x2 matrix from a 4x4 source matrix. So in this case too, the source 2D increment will be 3 data units, while the destination increment will be 1. + +To perform the transposition, we simply need to set a specific tag in the transaction struct, *.dim_inv*. + ```C -if( res == DMA_CONFIG_OK ) // Everything was ok. -if( res & DMA_CONFIG_CRITICAL_ERROR ) // A critical error was found. It has to be fixed or the transaction will not be loaded. -if( res >= DMA_CONFIG_OVERLAP && res =< DMA_CONFIG_TRANS_OVERRIDE ) // One or more warning flags were raised between those two. -if( res & ( DMA_CONFIG_SRC | DMA_CONFIG_DST) ) // Either one of the flags was raised. + + #define SIZE_IN_D1 4 + #define SIZE_IN_D2 4 + #define SIZE_EXTR_D1 2 + #define SIZE_EXTR_D2 2 + #define SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1) + #define DST_INC_D2 = 1 + + uint16_t src[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1234, 0x7654, 0xfedc, 0xffff, + 0x5912, 0xabcd, 0xcdef, 0xfafa, + 0x579a, 0x657d, 0x758e, 0xabba, + 0xa1a1, 0xc3c3, 0xb2b2, 0xf4f4 + }; + uint16_t dst[SIZE_EXTR_D1*SIZE_EXTR_D2]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans_2d = { + .src = &tgt_src, + .dst = &tgt_dst, + .src_addr = NULL, + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .dim = DMA_DIM_CONF_2D, + .dim_inv = 1; // This is the transposition flag! + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` + +#### Perform validation, loading and launching + +Once again, only two steps! Time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. +Let's put these calls inside a dedicated function, called *run_dma_2d_transp_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result, i.e. the extracted matrix. + +``` C + +dma_config_flags_t run_dma_2d_transp_trans(dma_trans_t *trans) +{ + dma_config_flags_t res; -The transaction can then be loaded into the DMA registers by calling the load function -```C -res = dma_load_transaction( &trans ); -``` + res = dma_validate_transaction(trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(trans); + res |= dma_launch(trans); + + return res; +} + +... + +int main() +{ + dma_init(NULL); -and launched -```C -res = dma_load_transaction( &trans ); -``` + dma_config_flags_t result = run_dma_2d_transp_trans(&trans); + + if (result != 0) + { + printf("Error! 2D DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + + for (int i=0; i -.tg {border-collapse:collapse;border-spacing:0;} -.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; -overflow:hidden;padding:10px 5px;word-break:normal;} -.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; -font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;} -.tg .tg-wp8o{border-color:#000000;text-align:center;vertical-align:top} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RAMFLASH
ABCD000B
EFGH000D
IJKL000F
........
- - ---- - - -For the second part of this example, the targets will be modified and their role switched. - -The source of the data will be a peripheral connected to the SPI, which will be continuously sending information in half-word format, in streams of 4096 bytes (2048 half-words). Every 1024 half-words there should be a `MILESTONE-CHARACTER`, if there is not, the data flow should be stopped. - + +The rest of the code remains unchanged w.r.t. the square matrix example. + +
+ +### 6. Matrix zero padding + +The goal of this example is to develop a function that extracts a submatrix from a source matrix, applies zero padding on it and copies it to a destination matrix. + +Let's start! + +#### Setting targets & transaction structs + +Once again, the first step is to define the source and destination target structs, as well as the transaction structs. + +Let's use the same formula as in example 2 to extract a 2x2 matrix from a 4x4 source matrix. So in this case too, the source 2D increment will be 3 data units, while the destination increment will be 1. + +As thoroughly explained in [the functional description](#zero-padding), the padding is performed on the fly but is conceptually applied to the extracted matrix, not to the entire input matrix. In this example, a right padding of 1 and a top padding of 2 will be applied. Since the padding modifies the size of the output, the output dimensions will need to be adjusted accordingly. The formula used are the same used in `example_dma_2d`. + ```C -tgt2.ptr = spi_peripheral_fifo_rx; -tgt2.size_du = 2048; -tgt2.type = DMA_DATA_TYPE_HALF_WORD; -tgt2.trig = DMA_TRIG_SLOT_SPI_RX; + + #define SIZE_IN_D1 4 + #define SIZE_IN_D2 4 + #define SIZE_EXTR_D1 2 + #define SIZE_EXTR_D2 2 + #define TOP_PAD 2 + #define RIGHT_PAD 1 + #define LEFT_PAD 0 + #define RIGHT_PAD 0 + + #define OUT_D1_PAD ( SIZE_EXTR_D1 + LEFT_PAD + RIGHT_PAD ) + #define OUT_D2_PAD ( SIZE_EXTR_D2 + TOP_PAD + BOTTOM_PAD ) + #define OUT_DIM_1D ( OUT_D1_PAD ) + #define OUT_DIM_2D ( OUT_D1_PAD * OUT_D2_PAD ) + + #define SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1) + #define DST_INC_D2 = 1 + + uint16_t src[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1234, 0x7654, 0xfedc, 0xffff, + 0x5912, 0xabcd, 0xcdef, 0xfafa, + 0x579a, 0x657d, 0x758e, 0xabba, + 0xa1a1, 0xc3c3, 0xb2b2, 0xf4f4 + }; + uint16_t dst[OUT_DIM_1D*OUT_DIM_2D]; + + dma_target_t tgt_src = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst = { + .ptr = (uint8_t *) dst, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans_2d = { + .src = &tgt_src, + .dst = &tgt_dst, + .src_addr = NULL, + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .pad_top_du = TOP_PAD, + .pad_bottom_du = BOTTOM_PAD, + .pad_left_du = LEFT_PAD, + .pad_right_du = RIGHT_PAD, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .dim = DMA_DIM_CONF_2D, + .end = DMA_TRANS_END_INTR_WAIT, + }; + ``` + +#### Perform validation, loading and launching + +Once again, only two steps! Time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. +Let's put these calls inside a dedicated function, called *run_dma_2d_pad_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result. + +``` C + +dma_config_flags_t run_dma_2d_pad_trans(dma_trans_t *trans) +{ + dma_config_flags_t res; -The source pointer is set to the reception FIFO of the SPI, and the appropriate slot is chosen. -The increment is kept in zero. + res = dma_validate_transaction(trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(trans); + res |= dma_launch(trans); + + return res; +} + +... + +int main() +{ + dma_init(NULL); -The destination pointer will be given by a function. + dma_config_flags_t result = run_dma_2d_pad_trans(&trans); + + if (result != 0) + { + printf("Error! 2D DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + + for (int i=0; i :warning: Make sure to configure X-Heep to have at least two DMA channels! + +Let's start! + +#### Setting targets & transaction structs + +Just like in previous examples, the first step is to define the source and destination target structs, as well as the transaction structs. + +Using the same formula as in example 2 to extract a 2x2 matrix from a 4x4 source matrix, the source 2D increment will be 3 data units, while the destination increment will be 1. + +Let's use the DMA CH0 to copy the {0x1234, 0x7654, 0x5912, 0xabcd} 2x2 matrix and the DMA CH1 to copy the {0x758e, 0xabba, 0xb2b2, 0xf4f4} matrix. These channels will copy the extracted matrices to two different destinations, *dst_ch0* and *dst_ch1*. Each transaction struct should have its _.ch_ field set accordingly. + +Finally, let's set the end event to *DMA_TRANS_END_INTR* to handle manually the interrupt event. + ```C -static dma_env_t safe_zone = { - .start = ADDRESS_START_OF_SAFE_ZONE, - .end = ADDRESS_END_OF_SAFE_ZONE, -}; + + #define SIZE_IN_D1 4 + #define SIZE_IN_D2 4 + #define SIZE_EXTR_D1 2 + #define SIZE_EXTR_D2 2 + #define SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1) + #define DST_INC_D2 = 1 + + uint16_t src[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1234, 0x7654, 0xfedc, 0xffff, + 0x5912, 0xabcd, 0xcdef, 0xfafa, + 0x579a, 0x657d, 0x758e, 0xabba, + 0xa1a1, 0xc3c3, 0xb2b2, 0xf4f4 + }; + uint16_t dst_ch0[SIZE_EXTR_D1*SIZE_EXTR_D2], dst_ch1[SIZE_EXTR_D1*SIZE_EXTR_D2]; + + dma_target_t tgt_src_ch0 = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_src_ch1 = { + .ptr = (uint8_t *) &src[10], // This is the address of the "0x758e" element + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst_ch0 = { + .ptr = (uint8_t *) dst_ch0, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst_ch1 = { + .ptr = (uint8_t *) dst_ch1, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans_2d_ch0 = { + .src = &tgt_src, + .dst = &tgt_dst_ch0, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .dim = DMA_DIM_CONF_2D, + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_INTR, + .ch = 0 // This flag specifies the channel used to run the transaction! + }; + + dma_trans_t trans_2d_ch1 = { + .src = &tgt_src, + .dst = &tgt_dst_ch1, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .dim = DMA_DIM_CONF_2D, + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_INTR, + .ch = 1 // This flag specifies the channel used to run the transaction! + }; + ``` - -The environment can be assigned to the target. + +#### IRQ handler + +Due to hardware limitations, there is just a **single fast interrupt** line dedicated to the DMA subsystem. In order to identify which channel raised the interrupt line, the DMA HAL performs a check on the IFR of each channel. +As soon as an IFR is read high, the HAL calls a weak implementation of the interrupt handler, called **dma_intr_handler_trans_done()** and it passed the channel ID. +After the call, the loop continues to look for interrupts in other channels, and then returns. + +There is, however, an **additional level of customization** provided by the HAL. +It's possible to set an index to differentiate between low and high priority channels by setting *DMA_HP_INTR_INDEX* in `dma.h`. In other words, when a channel whose ID is lower or equal to that index raises an interrupt, the *handler_irq_dma()* calls the user-defined IRQ handler and then returns, instead of compleating the loop. +This means that low ID channels, i.e. high priority channels, have a higher probability of being serviced that the rest of the channels. + +However, this feature could cause low priority channels to never be serviced if the high priority interrupts are raised at a faster frequency and the user-defined handler executes long and complex operations. + +There are two solutions to this problem: +- Use the **universal good design practice** of minimizing the tasks to perform in the IRQ handler. +- Set *DMA_NUM_HP_INTR* to limit the number of consecutive IRQ handler calls that high priority channels can make without checking for low priority interrupts. + +This mechanism is reported from `dma.c` here below: + ```C -tgt1.env = &safe_zone; -tgt1.inc_du = 1; + +void fic_irq_dma(void) +{ + /* + * Find out which channel raised the interrupt and call + * either the weak implementation provided in this module, + * or the non-weak implementation. + */ + + for (int i = 0; i < DMA_CH_NUM; i++) + { + if (dma_subsys_per[i].peri->TRANSACTION_IFR == 1) + { + dma_subsys_per[i].intrFlag = 1; + dma_intr_handler_trans_done(i); + + #ifdef DMA_HP_INTR_INDEX + /* + * If the channel that raised the interrupt is among the high priority channels, + * return to break the loop. + */ + + #ifdef DMA_NUM_HP_INTR + + if (i <= DMA_HP_INTR_INDEX && dma_hp_tr_intr_counter < DMA_NUM_HP_INTR) + { + dma_hp_tr_intr_counter++; + return; + } + else if (i > DMA_HP_INTR_INDEX) + { + dma_hp_tr_intr_counter = 0; + } + + #else + + if (i <= DMA_HP_INTR_INDEX) + { + return; + } + #endif + + #endif + } + } + return; +} + ``` - -Size and data type is up to the source, and the rest of the configurations are inherited from the last transaction. - -The transaction is conformed as: -```C -window_size_du = 1024; - -trans.src = &tgt2; -trans.dst = &tgt1; -trans.mode = DMA_TRANS_MODE_CIRCULAR; -trans.win_du = window_size_du; - + +Everything that has been explained in this paragraph is true for the **window count interrupts** too. + +In this example, none of these additional functionalities are necessary, as the IRQ handler will be used to simply set a flag. +A detailed explaination of how these mechanisms work was still necessary, since they are very useful in a variety of applications. + +Let's redefine *dma_intr_handler_trans_done()* to set some flags: + +``` C +char intr_ch0_flag = 0; +char intr_ch1_flag = 0; + +/* Strong transaction ISR implementation */ +void dma_intr_handler_trans_done(uint8_t channel) +{ + if (channel == 0){ + intr_ch0_flag = 1; + } else { + intr_ch1_flag = 1; + } + return; +} + ``` - -Meaning that the information will start to flow into the target 1 from target 2, and every 1024 half-words transferred the application will get an interrupt to check if the `MILESTONE_SYMBOL` is present. Upon finishing the transaction, it shall start again to refill the buffer as it was set in `CIRCULAR_MODE`. - -The amount of times the buffer was filled will be updated on every _transaction done_ interrupt. -```C -void dma_intr_handler_trans_done() { - transaction_count++; + +#### Perform validation, loading and launching + +Once again, only two steps! Time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. +Let's put these calls inside a dedicated function, called *run_dma_2d_multi_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result and to check on the interrupt flags. + +Last but not least, **wait for CH1** to finish its transaction and raise the interrupt. Since both transactions has identical size there is no risk of the first one finishing before the other, so it's safe to assume that CH1 will be the last to terminate. + +``` C + +dma_config_flags_t run_dma_2d_multi_trans(dma_trans_t *trans_ch0, dma_trans_t *trans_ch1) +{ + dma_config_flags_t res; + + res = dma_validate_transaction(trans_ch0, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_validate_transaction(trans_ch1, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(trans_ch0); + res |= dma_load_transaction(trans_ch1); + res |= dma_launch(trans_ch0); + res |= dma_launch(trans_ch1); + + return res; +} + +... + +int main() +{ + dma_init(NULL); + + dma_config_flags_t result = run_dma_2d_multi_trans(&trans); + + // Wait for CH1 to finish + while (!dma_is_ready(1)) + { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (dma_is_ready(1) == 0) + { + wait_for_interrupt(); + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } + + if (result != 0) + { + printf("Error! 2D DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + + printf("Output CH0:\n\r"); + for (int i=0; i + +### 8. Multichannel flash2mem transaction using the SPI FLASH + +The goal of this example is to develop a function that performs: +- A matrix extraction from a source matrix stored in the FLASH +- A matrix extraction from a source matrix stored in the RAM +These operations are performed using CH0 and CH1 in parallel. + +> :warning: This example can be executed only on QuestaSim or FPGA targets with the appropriate compilation flags. +Checkout the SPI documentation or `example_dma_multichannel` for additional information. + +> :warning: Make sure to configure X-Heep to have at least two DMA channels! + +Let's start! + +#### Setting targets & transaction structs + +Just like in previous examples, the first step is to define the source and destination target structs, as well as the transaction structs. This time we only need to set up the CH1 transaction, as for the + +Most of this example is similar to the previous one, but particular care is required for the setup of FLASH stored data. In x-Heep, this is achieved by using the directive: + +

__attribute__((section(".xheep_data_flash_only")))

+ ```C -void dma_intr_handler_window_done() { - /* The current window is obtained. The count is zero when no windows have yet been written. When it is set to one, the window zero is ready. */ - window_count = dma_get_window_count() -1; - /* The pointer to the symbol is obtained from the destination pointer + the amount of half-words that have been written. this assumes the symbol is on the first element of each chunk.*/ - address = (uint16_t *)trans.dst->ptr + window_count*window_size_du; - symbol = *address; - if( symbol != MILESTONE_SYMBOL ){ - /* If the symbol was not the expected one, future transactions should not be carried out.*/ - dma_stop_circular(); - /* The number of the first window with error is saved to analyze it later.*/ - error_window = error_window == 0 ? window_count : error_window; - } -} + + #define SIZE_IN_D1 4 + #define SIZE_IN_D2 4 + #define SIZE_EXTR_D1 2 + #define SIZE_EXTR_D2 2 + #define SRC_INC_D2 = SIZE_IN_D1 - (SIZE_EXTR_D1 - 1) + #define DST_INC_D2 = 1 + + uint16_t __attribute__((section(".xheep_data_flash_only"))) src_flash[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1234, 0x7654, 0xfedc, 0xffff, + 0x5912, 0xabcd, 0xcdef, 0xfafa, + 0x579a, 0x657d, 0x758e, 0xabba, + 0xa1a1, 0xc3c3, 0xb2b2, 0xf4f4 + }; + + uint16_t src[SIZE_IN_D1*SIZE_IN_D2] = { + 0x1111, 0x2222, 0x3333, 0xfccf, + 0x4444, 0x5555, 0x6666, 0xfbba, + 0x7777, 0x8888, 0x9999, 0xadda, + 0x1010, 0x1212, 0x4142, 0xfca4 + }; + + uint16_t dst_ch0[SIZE_EXTR_D1*SIZE_EXTR_D2], dst_ch1[SIZE_EXTR_D1*SIZE_EXTR_D2]; + + dma_target_t tgt_src_ch1 = { + .ptr = (uint8_t *) src, + .inc_d1_du = 1, + .inc_d2_du = SRC_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_target_t tgt_dst_ch1 = { + .ptr = (uint8_t *) dst_ch1, + .inc_d1_du = 1, + .inc_d2_du = DST_INC_D2, + .type = DMA_DATA_TYPE_HALF_WORD, + .trig = DMA_TRIG_MEMORY, + }; + + dma_trans_t trans_2d_ch1 = { + .src = &tgt_src, + .dst = &tgt_dst_ch1, + .src_addr = NULL, + .mode = DMA_TRANS_MODE_SINGLE, + .dim = DMA_DIM_CONF_2D, + .size_d1_du = SIZE_EXTR_D1, + .size_d2_du = SIZE_EXTR_D2, + .mode = DMA_TRANS_MODE_SINGLE, + .win_du = 0, + .end = DMA_TRANS_END_INTR, + .ch = 1 // This flag specifies the channel used to run the transaction! + }; + ``` -> :warning: Interrupt attention routines are advised to be kept as short as possible. This example is merely illustrative. - -Once the `dma_stop_circular()` function is called, the DMA will still finish the transaction it is currently executing (which could be a whole transaction if the faulty window was the last one). It is important to save valuable information that might be overridden by the ongoing transaction (like the faulty window number). - - -## Testing -This section will describe the available example application in X-HEEP using the DMA, and will outline the testing that needs to be performed in order to validate its proper operation. - - -### Available Applications - -There are 6 applications using the DMA: -* `dma_example`: Tests memory-to-memory transfer, the blocking of transactions while another one is in progress, and window interrupts. -* `example_external_peripheral`: Tests the use of the DMA HAL one a DMA instance external to X-HEEP. Only available for simulation. -* `example_virtual_flash`: Tests the transfer to/from an external flash through the DMA. -* `spi_flash_write`: Tests the transfer to/from the flash. Tests circular mode. Not available on FPGA if linker is `flash-exec`. Should be used with `mcu gen BUS=NtoM CPU=cv32e40p` to test circular mode. -* `spi_host_dma_exampe`: Test the transfer of data through the SPI host. Not available on Verilator. -* `spi_host_dma_power_gate_example`: Test the transfer of data through the SPI host. Not available on Verilator. - - -## 😎 X-pert Zone: - -If you know what you are doing and want to minimize the overhead of using the DMA, you can try by-passing the HAL and writing directly on the configuration registers. - -```c -/* We will copy a set of 25 half-words of 16 bits into a buffer of 32-bit words. -Each word in the destination buffer will have its 16 MSB set to 0, and the 16 LSB with the corresponding value from the source.*/ -#define HALF_WORDS_TO_COPY 25 -static uint16_t src_buffer[HALF_WORDS_TO_COPY]; // The source buffer -static uint32_t dst_buffer[HALF_WORDS_TO_COPY]; // The destination buffer - -/* Set the DMA's control block's peripheral structure to point to the address defined in core_v_mini_mcu.h */ -dma_cb.peri = dma_peri; -/* Activate interrupts*/ -dma_cb.peri->INTERRUPT_EN |= INTR_EN_TRANS_DONE; -/* Set the source and destination pointers*/ -dma_cb.peri->SRC_PTR = (uint16_t*) source_buffer; -dma_cb.peri->DST_PTR = (uint32_t*) dst_buffer; - -/* Set the source increment as 2 bytes (because the source buffer is uint16_t). -Set the destination increment as 4 bytes (because the destination buffer is uint32_t). -We write 1026 = 0000 0100 0000 0010, -as the first 8 LSB refer to the source, and the next 8 bits for the destination. */ -dma_cb.peri->PTR_INC = (uint32_t) 1026; - -/* Make sure that the DMA will point to memory.*/ -dma_cb.peri->SLOT = DMA_TRIG_MEMORY; - -/* Set the data transfer type as half-words.*/ -dma_cb.peri->TYPE = DMA_DATA_TYPE_HALF_WORD; - -/* Set the transaction size, this will launch the transaction. -If you want to restart the same transaction again, just run from here.*/ -dma_cb.peri->SIZE = HALF_WORDS_TO_COPY; - -/* Go to sleep until the DMA finishes.*/ -while( dma_cb.peri->STATUS == 0 ) { - /* Disable the interrupts MSTATUS to avoid going to sleep AFTER the interrupt - was triggered.*/ - CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); - /* If the transaction has not yet finished, go to sleep*/ - if (dma_cb.peri->STATUS == 0) { - /* If a interrupt happened before, the core would still wake-up, - but will not jump to the interrupt handler MSTATUS is not re-set. */ - { asm volatile("wfi"); } - } - /* Restore the interrupts. */ - CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + +#### Set up of the SPI FLASH + +There are just a few step to follow to correctly set up the SPI for the FLASH transaction. + +The first step is the initialization of the *soc_ctrl*, followed by the pick of the correct SPI device, based on the target, and the bridge set up. + +> :warning: Remember to use *flash_load* when compiling the software! + +```C +void SPI_setup(){ + + soc_ctrl_t soc_ctrl; + soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); + + /* Pick the correct spi device based on simulation type */ + spi_host_t *spi; + + #ifndef USE_SPI_FLASH + spi = spi_host1; + #else + spi = spi_flash; + #endif + + /* Init SPI host and SPI<->Flash bridge parameters */ + if (w25q128jw_init(spi) != FLASH_OK) + { + PRINTF("Error initializing the flash SPI\n\r"); + return EXIT_FAILURE; + } } - - ``` + +#### Perform validation, loading and launching + +Once the SPI has been set up, the next step it's time to perform the __validation__ of the transaction, __load__ the parameters, and __launch__ of it. + +As for the SPI, there is a function defined in `w25q.c` that simplifies the operation: + +

w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_init_dma, uint8_t no_sanity_checks)

+ + +The flags *no_wait_init_dma* and *no_sanity_checks* are necessary for running the application, as they prevent the DMA from being reset or using a blocking wait for its interrupt. However, the function is quite handy since it takes care of everything else. +Note that the *w25q128jw_read_standard_dma()* uses **CH0**! + +**Suggestion:** To further understand how to interface the DMA with the SPI, study the functions in `w25q.c` that employ it. + +As usual, let's put these calls inside a dedicated function, called *run_dma_2d_spi_trans()* and launch it in the *main()*. Finally, let's add a simple for loop to print out the result and to check on the interrupt flags. + +Last but not least, **wait for CH0** to finish its transaction and raise the interrupt, since the SPI will always be slower than a standard DMA transaction of equal size. + +``` C + +dma_config_flags_t run_dma_2d_spi_trans(dma_trans_t *trans_ch0, dma_trans_t *trans_ch1) +{ + dma_config_flags_t res; + + res |= dma_validate_transaction(trans_ch1, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res |= dma_load_transaction(trans_ch1); + res |= dma_launch(trans_ch1); + + return res; +} + +... + +int main() +{ + dma_init(NULL); + + dma_config_flags_t result = run_dma_2d_multi_trans(&trans); + + /* Start the reading process from the SPI, avoiding both sanity checks and waiting for the DMA to finish */ + w25q_error_codes_t status = w25q128jw_read_standard_dma(TEST_DATA_FLASH_PTR, copied_test_data_flash, TEST_DATA_FLASH_SIZE*4, 1, 1); + if (status != FLASH_OK) + { + PRINTF("Error reading from flash\n\r"); + return EXIT_FAILURE; + } + + // Wait for CH1 to finish + while (!dma_is_ready(1)) + { + CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); + if (dma_is_ready(1) == 0) + { + wait_for_interrupt(); + } + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + } + + if (result != 0) + { + printf("Error! 2D DMA transaction failed with code: %d\n", result); + return 1; + } else { + printf("Success!\n"); + + printf("Output CH0:\n\r"); + for (int i=0; i :warning: Make sure to follow the preliminary steps explained in `im2col_spc_verification.py` in order to test it! + +This guide aims to address any questions that might arise from studying the *im2col_spc* example. It provides a detailed explanation of each method in VerifHeep, along with the parameters required for its proper functioning. + +> :bulb: The FPGA synthesis must be performed with the **Xilinx scan chains** enabled, as these will be used to load the program. +Additionally, the EPFL programmer will be used for serial communication with the board. Without these two lines of communication, it would be impossible to load the program and read the serial stream. + +## Methods description + +#### __init__ + +_Purpose_: +The initialization function is used to create the VerifHeep object. During this process, it's required to indicate the target of the verification and its directory. Furthermore, an optimization flag can be set when synthesis or simulation module building will be performed. + +_Parameters_: +- **target**: Indicated the target of the verification environment, must be one of the following: + - `pynq-z2` + - `questasim` + - `verilator` +- **xheep_dir**: Sets the directory of the X-Heep project, necessary to run scripts. +- **opt_en**: By default set to _false_, this flag indicates whether optimization should be performed when building the simulation model. Available **only** with QuestaSim! + +#### compileModel + +_Purpose_: +This method is used to compile a simulation model for both Verilator and QuestaSim, i.e. run _make mcu-gen_, provided they are properly installed on the host system. + +_Parameters_: +- **mem_banks**: By default set to 6, this flag indicates how many memory banks will be included in the X-Heep model. No interleaved banks are supported. +- **cpu**: By default set to `cv32e40px`, this flags indicates which CPU will be included in the model. +- **bus**: By default set to `1toN`, this flag indicates the bus type. + +#### buildModel + +_Purpose_: +This method is used to either build a simulation model for Verilator or QuestaSim or to synthesize the project with Xilinx Vivado, provided they are properly installed on the host system. + +_Parameters_: +- **mem_banks**: By default set to *6*, this flag indicates how many memory banks will be included. No interleaved banks are supported. +- **cpu**: By default set to `cv32e40px`, this flags indicates which CPU will be included. +- **bus**: By default set to `1toN`, this flag indicates the bus type. + +#### serialBegin + +_Purpose_: +This method is used to set up the serial communication with the _pynq-z2_ FPGA board. + +> :bulb: **Tip:** Checkout which USB port is connected to the _pynq-z2_ by running a simple hello world (no flash load since the scan chains are used). +Set the USB port parameter of the verification environment as a global variable to quickly modify it. Its value might change! + +_Parameters_: +- **port**: Indicates the USB port connected to the EPFL programmer for the pynq-z2. +- **baudrate**: Indicates the connection speed, usually set to 9600. + +_Return value_: +- **Outcome of the connection**, which is _False_ for unsuccessful. + +#### setupDeb + +_Purpose_: +This method is used to set up the GDB debugger. It creates a process on which the debug communication will be run, thus making this function conveniently non-blocking. + +> :warning: This method should obviously be called at the beginning of the verification process, but not only then! Empirical evidence suggests **resetting the debug connection** approximately **every 100 iterations** to ensure reliable operation. + +_Parameters_: +None + +#### stopDeb + +_Purpose_: +This method is used to close the debugger. Useful both at the end of a script or during the cyclical reset of the debug connection, as explained before. + +_Parameters_: +None + +#### genInputDataset + +_Purpose_: +This method is used to generate random data that the application can use to perform verification. It's possible to set the range of the data, the dimension of the array, the datatype and its variable identifier. In addition, it's possible to obtain a single _.h_ file or both a _.c_ and a _.h_ file. + +_Parameters_: +- **dataset_size**: Indicates the size of the input array to be generated. +- **parameters**: This optional argument is a *dictionary* of parameters that might be useful for the application. It has *no impact on the value generation* but it will be written in the *.h* file. +- **row_size**: By default set to *0*, this parameter is used to organize the array in the case of matrix generation. In other words, every *row_size* words, the matrix will have a new line. +- **range_min** / **range_max**: These are used to set the range of the random data. They can be both negative and float, if the datatype supports it. +- **dataset_dir**: Indicates the directory in which the generated file will be saved, including the name of the file itself. +- **dataset_dir_c**: By default *empty*, when set to a directory it forces the method to generate both a _.c_ and a _.h_, the first with the data definition and the second with its declaration. +- **dataset_name**: Indicates the name of the dataset. +- **datatype**: By default set to *uint32_t*, indicates the datatype of the array to be generated. + +#### genGoldenResult + +_Purpose_: +This method is used to generate golden data from an input dataset, enabling applications to verify the functionality of a unit or accelerator. This feature is performed by a user-defined function, passed as a parameter, which processes the input data. + +Similar to input generation, users can specify the data range, array dimensions, data type, and variable identifier. Additionally, the output can be configured to produce either a single _.h_ file or both a _.c_ and a _.h_ file. + +_Parameters_: +- **function**: This function is the one used by the method to generate the golden results. +- **golden_size**: Indicates the size of the output array to be computed. +- **parameters**:This optional argument is a *dictionary* of parameters that might be useful for the application. It has no impact on the golden result computation but it will be written in the *.h* file. +- **row_size**: By default set to *0*, this parameter is used to organize the array in the case of matrix generation. In other words, every *row_size* words, the matrix will have a new line. +- **range_min** / **range_max**: These are used to set the range of the random data. They can be both negative and float, if the datatype supports it. +- **golden_dir**: Indicates the directory in which the generated file will be saved, including the name of the file itself. +- **golden_dir_c**: By default *empty*, when set to a directory it forces the method to generate both a _.c_ and a _.h_, the first with the data definition and the second with its declaration. +- **input_dir**: Indicates the input data used to generate the golden result. +- **golden_name**: Indicates the name of the golden result array. +- **output_datatype**: By default set to *uint32_t*, indicates the datatype of the array to be computed. + +#### modifyFile + +_Purpose_: +This method is simple yet very useful in particular situations. It allows the user to modify a row with a replacement of its choice. It can be used to modify _#define_ that could change the behaviour of the application. + +For example, the im2col SPC verification example makes use of this feature twice. The first time it modifies the format of the output of the application to be adherent to the verification procedure (which by default it is not). +The second time it reduces the verification times, by avoiding to repeat unnecessary tests. + +_Parameters_: +- **file_dir**: Indicates the directory of the file that the user wants to modify. +- **pattern**: Indicates the pattern to look for in the file, using the library **re**. +- **replacement**: Indicates the row that will be put in place instead of the pattern found. + +#### chronoStart/chronoStop + +_Purpose_:This method is used to track the execution time of an iteration and, by extension, to estimate the total execution time of the verification process. + +_Parameters_: +None + +#### chronoExecutionEst + +_Purpose_:This method estimates the total execution time of the verification process, assuming the verification consists of a loop with N iterations. It requires that the `_chronoStart_` method is called at the beginning and the `_chronoStop_` method is called at the end of each iteration. + +_Parameters_: +- **loop_size**: Size of the loop, i.e. number of iterations of the entire verification process. If it's composed of nested loops, the total number of iterations is obtained by multiplying the size of each loop. + +_Return value_: +- **Remaining time**, a _dictionary_: + - _"hours"_ + - _"minutes"_ + - _"seconds"_ + +#### launchTest + +_Purpose_: +This method is crucial in the verification process, as it's in charge of compiling the application, loading it on the FPGA using the scan chains and GDB, waiting for the results and storing then in *self.results*. + +Its important to note that this method expects a **specific output format** from the application, which needs to be strictly respected otherwise the whole verification would be disrupted. +By default, this is the format expected: + +
+
 test_id:cycles:outcome
+  ...
+  & 
+
+ +An application can send N lines composed of: +- **test_id**: the ID of the test being performed. A single application can test multiple aspects or features, so different tests can be performed in a single run. In the **im2col_spc** application, this is exactly what happens: three different tests are perfomed each run. +- **cycles**: the number of cycles needed by the system to perform that specific test. In order to keep track of the execution cycles, a `timer_sdk` has been developed. Please refer to `example_timer_sdk` for a practical implementation. +- **outcome**: the outcome of the verification performed by the application itself. For example, the application might set up the DMA to perform a transaction and then check that the result corresponds to the golden result. + +Each of these fields can be **left blank** or with whatever ASCII character, but the format has to be followed nonetheless. For example, one could be interested only in verify its design, avoiding the performance estimation. In such case, _cycles_ could be always set to _0_. + +At the end of the run, the application **must send the end character** `&`. + +If needed, the format of the data sent by the application can be modified by changing the _pattern_ parameter. + +_Parameters_: +- **example_name**: Name of the example folder in X-Heep sw/application. e.g. For the DMA verification, this field would have been *example_dma*. +- **input_size**: This field will be appended to the data obtained by the simulation, not mandatory but might be useful for data processing. +- **pattern**: By default set to *test_id:cycles:outcome*. It can be changed by the user, with **caution**. +- **en_timeout_term**: By default set to _False_, if enabled it terminates the application in case that the board doesn't reply in time. + diff --git a/hw/vendor/esl_epfl_x_heep/docs/source/images/dma_structure.png b/hw/vendor/esl_epfl_x_heep/docs/source/images/dma_structure.png new file mode 100644 index 0000000000000000000000000000000000000000..1000debbe7a41ec27e062c279e135572cf6a2cb6 GIT binary patch literal 175192 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 -s%LHDqt+G?lth{ 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 MlA2=Cbrb*p15D`e`~Uy| literal 0 HcmV?d00001 diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv index dd9246df..f054c37b 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/ao_peripheral_subsystem.sv @@ -7,15 +7,20 @@ module ao_peripheral_subsystem import reg_pkg::*; import power_manager_pkg::*; #( + parameter AO_SPC_NUM = 0, //do not touch these parameters + parameter AO_SPC_NUM_RND = AO_SPC_NUM == 0 ? 1 : AO_SPC_NUM, parameter EXT_DOMAINS_RND = core_v_mini_mcu_pkg::EXTERNAL_DOMAINS == 0 ? 1 : core_v_mini_mcu_pkg::EXTERNAL_DOMAINS, parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT ) ( input logic clk_i, input logic rst_ni, - input obi_req_t slave_req_i, - output obi_resp_t slave_resp_o, + input reg_req_t slave_req_i, + output reg_rsp_t slave_resp_o, + + input reg_req_t [AO_SPC_NUM_RND-1:0] spc2ao_req_i, + output reg_rsp_t [AO_SPC_NUM_RND-1:0] ao2spc_resp_o, // SOC CTRL input logic boot_select_i, @@ -62,14 +67,14 @@ module ao_peripheral_subsystem output logic rv_timer_1_intr_o, // DMA - output obi_req_t dma_read_ch0_req_o, - input obi_resp_t dma_read_ch0_resp_i, - output obi_req_t dma_write_ch0_req_o, - input obi_resp_t dma_write_ch0_resp_i, - output obi_req_t dma_addr_ch0_req_o, - input obi_resp_t dma_addr_ch0_resp_i, - output logic dma_done_intr_o, - output logic dma_window_intr_o, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_resp_i, + output logic dma_done_intr_o, + output logic dma_window_intr_o, // External PADs output reg_req_t pad_req_o, @@ -104,21 +109,32 @@ module ao_peripheral_subsystem output reg_req_t ext_peripheral_slave_req_o, input reg_rsp_t ext_peripheral_slave_resp_i, - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i, + // SPC interface + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, + output logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_o - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i ); import core_v_mini_mcu_pkg::*; import tlul_pkg::*; - import rv_plic_reg_pkg::*; + localparam DMA_GLOBAL_TRIGGER_SLOT_NUM = 5; + localparam DMA_EXT_TRIGGER_SLOT_NUM = core_v_mini_mcu_pkg::DMA_CH_NUM * 2; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* NOTE: Additional xbars signals defined in the xbar generate statement */ + + /* Peripheral register inteface */ reg_pkg::reg_req_t peripheral_req; reg_pkg::reg_rsp_t peripheral_rsp; - reg_pkg::reg_req_t [core_v_mini_mcu_pkg::AO_PERIPHERALS-1:0] ao_peripheral_slv_req; reg_pkg::reg_rsp_t [core_v_mini_mcu_pkg::AO_PERIPHERALS-1:0] ao_peripheral_slv_rsp; + logic [AO_PERIPHERALS_PORT_SEL_WIDTH-1:0] peripheral_select; tlul_pkg::tl_h2d_t rv_timer_tl_h2d; tlul_pkg::tl_d2h_t rv_timer_tl_d2h; @@ -126,53 +142,71 @@ module ao_peripheral_subsystem tlul_pkg::tl_h2d_t uart_tl_h2d; tlul_pkg::tl_d2h_t uart_tl_d2h; - logic [AO_PERIPHERALS_PORT_SEL_WIDTH-1:0] peripheral_select; - + /* SPI memory signals */ logic use_spimemio; - logic spi_flash_rx_valid; logic spi_flash_tx_ready; + /* GPIOs signals */ logic [23:0] intr_gpio_unused; logic [23:0] cio_gpio_unused; logic [23:0] cio_gpio_en_unused; + /* DMA signals */ + logic dma_clk_gate_en_n[core_v_mini_mcu_pkg::DMA_CH_NUM-1:0]; + power_manager_out_t dma_subsystem_pwr_ctrl[core_v_mini_mcu_pkg::DMA_CH_NUM-1:0]; + logic [DMA_GLOBAL_TRIGGER_SLOT_NUM-1:0] dma_global_trigger_slots; + logic [DMA_EXT_TRIGGER_SLOT_NUM-1:0] dma_ext_trigger_slots; + obi_pkg::obi_req_t slave_fifoout_req; + obi_pkg::obi_resp_t slave_fifoout_resp; + reg_req_t perconv2regdemux_req; + reg_rsp_t regdemux2perconv_resp; + + /*_________________________________________________________________________________________________________________________________ */ - obi_pkg::obi_req_t slave_fifo_req_sel; - obi_pkg::obi_resp_t slave_fifo_resp_sel; + /* Signal assignment */ + /* Peripheral demuxed register interface */ assign ext_peripheral_slave_req_o = ao_peripheral_slv_req[core_v_mini_mcu_pkg::EXT_PERIPHERAL_IDX]; assign ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::EXT_PERIPHERAL_IDX] = ext_peripheral_slave_resp_i; + assign pad_req_o = ao_peripheral_slv_req[core_v_mini_mcu_pkg::PAD_CONTROL_IDX]; + assign ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::PAD_CONTROL_IDX] = pad_resp_i; -`ifdef REMOVE_OBI_FIFO + assign dma_global_trigger_slots[0] = spi_rx_valid_i; + assign dma_global_trigger_slots[1] = spi_tx_ready_i; + assign dma_global_trigger_slots[2] = spi_flash_rx_valid; + assign dma_global_trigger_slots[3] = spi_flash_tx_ready; + assign dma_global_trigger_slots[4] = i2s_rx_valid_i; - assign slave_fifo_req_sel = slave_req_i; - assign slave_resp_o = slave_fifo_resp_sel; + generate + for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_CH_NUM; i++) begin : dma_trigger_slots_gen + assign dma_ext_trigger_slots[2*i] = ext_dma_slot_tx_i[i]; + assign dma_ext_trigger_slots[2*i+1] = ext_dma_slot_rx_i[i]; + end + endgenerate -`else + /* DMA clock gating */ + generate + for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_CH_NUM; i++) begin : dma_clk_gate_gen + assign dma_clk_gate_en_n[i] = dma_subsystem_pwr_ctrl[i].clkgate_en_n; + end + endgenerate - obi_pkg::obi_req_t slave_fifoin_req; - obi_pkg::obi_resp_t slave_fifoin_resp; + /*_________________________________________________________________________________________________________________________________ */ - obi_pkg::obi_req_t slave_fifoout_req; - obi_pkg::obi_resp_t slave_fifoout_resp; + /* Module instantiation */ + /* System bus to AO OBI FIFO */ obi_fifo obi_fifo_i ( .clk_i, .rst_ni, - .producer_req_i (slave_fifoin_req), - .producer_resp_o(slave_fifoin_resp), + .producer_req_i (slave_req_i), + .producer_resp_o(slave_resp_o), .consumer_req_o (slave_fifoout_req), .consumer_resp_i(slave_fifoout_resp) ); - assign slave_fifo_req_sel = slave_fifoout_req; - assign slave_fifoout_resp = slave_fifo_resp_sel; - assign slave_fifoin_req = slave_req_i; - assign slave_resp_o = slave_fifoin_resp; - -`endif - + /* Peripheral to register interface converter*/ periph_to_reg #( .req_t(reg_pkg::reg_req_t), .rsp_t(reg_pkg::reg_rsp_t), @@ -180,28 +214,65 @@ module ao_peripheral_subsystem ) periph_to_reg_i ( .clk_i, .rst_ni, - .req_i(slave_fifo_req_sel.req), - .add_i(slave_fifo_req_sel.addr), - .wen_i(~slave_fifo_req_sel.we), - .wdata_i(slave_fifo_req_sel.wdata), - .be_i(slave_fifo_req_sel.be), + .req_i(slave_fifoout_req.req), + .add_i(slave_fifoout_req.addr), + .wen_i(~slave_fifoout_req.we), + .wdata_i(slave_fifoout_req.wdata), + .be_i(slave_fifoout_req.be), .id_i('0), - .gnt_o(slave_fifo_resp_sel.gnt), - .r_rdata_o(slave_fifo_resp_sel.rdata), + .gnt_o(slave_fifoout_resp.gnt), + .r_rdata_o(slave_fifoout_resp.rdata), .r_opc_o(), .r_id_o(), - .r_valid_o(slave_fifo_resp_sel.rvalid), + .r_valid_o(slave_fifoout_resp.rvalid), .reg_req_o(peripheral_req), .reg_rsp_i(peripheral_rsp) ); + /* SPC crossbar & FIFOs */ + generate + if (AO_SPC_NUM_RND > 0) begin + /* Assign the bus port to the first input port of the AOPB */ + reg_req_t [AO_SPC_NUM_RND:0] packet_req; + reg_rsp_t [AO_SPC_NUM_RND:0] packet_rsp; + + assign packet_req[0] = peripheral_req; + assign peripheral_rsp = packet_rsp[0]; + + for (genvar i = 0; i < AO_SPC_NUM_RND; i++) begin : gen_spc + assign packet_req[i+1] = spc2ao_req_i[i]; + assign ao2spc_resp_o[i] = packet_rsp[i+1]; + end + + reg_mux #( + .NoPorts(AO_SPC_NUM_RND + 1), + .req_t (reg_pkg::reg_req_t), + .rsp_t (reg_pkg::reg_rsp_t), + .AW (32), + .DW (32) + ) reg_mux_i ( + .clk_i, + .rst_ni, + .in_req_i (packet_req), + .in_rsp_o (packet_rsp), + .out_req_o(perconv2regdemux_req), + .out_rsp_i(regdemux2perconv_resp) + ); + + end else begin + assign perconv2regdemux_req = peripheral_req; + assign peripheral_rsp = regdemux2perconv_resp; + end + endgenerate + + /* Address decoder for the peripheral registers */ addr_decode #( .NoIndices(core_v_mini_mcu_pkg::AO_PERIPHERALS), .NoRules(core_v_mini_mcu_pkg::AO_PERIPHERALS), .addr_t(logic [31:0]), .rule_t(addr_map_rule_pkg::addr_map_rule_t) ) i_addr_decode_soc_regbus_periph_xbar ( - .addr_i(peripheral_req.addr), + .addr_i(perconv2regdemux_req.addr), .addr_map_i(core_v_mini_mcu_pkg::AO_PERIPHERALS_ADDR_RULES), .idx_o(peripheral_select), .dec_valid_o(), @@ -210,6 +281,7 @@ module ao_peripheral_subsystem .default_idx_i('0) ); + /* Register demux */ reg_demux #( .NoPorts(core_v_mini_mcu_pkg::AO_PERIPHERALS), .req_t (reg_pkg::reg_req_t), @@ -218,8 +290,8 @@ module ao_peripheral_subsystem .clk_i, .rst_ni, .in_select_i(peripheral_select), - .in_req_i(peripheral_req), - .in_rsp_o(peripheral_rsp), + .in_req_i(perconv2regdemux_req), + .in_rsp_o(regdemux2perconv_resp), .out_req_o(ao_peripheral_slv_req), .out_rsp_i(ao_peripheral_slv_rsp) ); @@ -239,11 +311,13 @@ module ao_peripheral_subsystem .exit_value_o ); + /* Boot ROM */ boot_rom boot_rom_i ( .reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::BOOTROM_IDX]), .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::BOOTROM_IDX]) ); + /* SPI subsystem */ spi_subsystem spi_subsystem_i ( .clk_i, .rst_ni, @@ -267,6 +341,7 @@ module ao_peripheral_subsystem .spi_flash_tx_ready_o(spi_flash_tx_ready) ); + /* Power manager */ power_manager #( .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t) @@ -285,7 +360,8 @@ module ao_peripheral_subsystem .cpu_subsystem_pwr_ctrl_i, .peripheral_subsystem_pwr_ctrl_i, .memory_subsystem_pwr_ctrl_i, - .external_subsystem_pwr_ctrl_i + .external_subsystem_pwr_ctrl_i, + .dma_subsystem_pwr_ctrl_o(dma_subsystem_pwr_ctrl) ); reg_to_tlul #( @@ -314,25 +390,6 @@ module ao_peripheral_subsystem .intr_timer_expired_1_0_o(rv_timer_1_intr_o) ); - parameter DMA_GLOBAL_TRIGGER_SLOT_NUM = 5; - parameter DMA_EXT_TRIGGER_SLOT_NUM = core_v_mini_mcu_pkg::DMA_CH_NUM * 2; - - logic [DMA_GLOBAL_TRIGGER_SLOT_NUM-1:0] dma_global_trigger_slots; - logic [DMA_EXT_TRIGGER_SLOT_NUM-1:0] dma_ext_trigger_slots; - - assign dma_global_trigger_slots[0] = spi_rx_valid_i; - assign dma_global_trigger_slots[1] = spi_tx_ready_i; - assign dma_global_trigger_slots[2] = spi_flash_rx_valid; - assign dma_global_trigger_slots[3] = spi_flash_tx_ready; - assign dma_global_trigger_slots[4] = i2s_rx_valid_i; - - generate - for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_CH_NUM; i++) begin : dma_trigger_slots_gen - assign dma_ext_trigger_slots[2*i] = ext_dma_slot_tx_i[i]; - assign dma_ext_trigger_slots[2*i+1] = ext_dma_slot_rx_i[i]; - end - endgenerate - dma_subsystem #( .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t), @@ -343,24 +400,23 @@ module ao_peripheral_subsystem ) dma_subsystem_i ( .clk_i, .rst_ni, + .clk_gate_en_ni(dma_clk_gate_en_n), .reg_req_i(ao_peripheral_slv_req[core_v_mini_mcu_pkg::DMA_IDX]), .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::DMA_IDX]), - .dma_read_ch0_req_o, - .dma_read_ch0_resp_i, - .dma_write_ch0_req_o, - .dma_write_ch0_resp_i, - .dma_addr_ch0_req_o, - .dma_addr_ch0_resp_i, + .dma_read_req_o, + .dma_read_resp_i, + .dma_write_req_o, + .dma_write_resp_i, + .dma_addr_req_o, + .dma_addr_resp_i, .global_trigger_slot_i(dma_global_trigger_slots), .ext_trigger_slot_i(dma_ext_trigger_slots), .ext_dma_stop_i(ext_dma_stop_i), .dma_done_intr_o(dma_done_intr_o), - .dma_window_intr_o(dma_window_intr_o) + .dma_window_intr_o(dma_window_intr_o), + .dma_done_o(dma_done_o) ); - assign pad_req_o = ao_peripheral_slv_req[core_v_mini_mcu_pkg::PAD_CONTROL_IDX]; - assign ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::PAD_CONTROL_IDX] = pad_resp_i; - fast_intr_ctrl #( .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t) @@ -373,6 +429,7 @@ module ao_peripheral_subsystem .fast_intr_o ); + /* GPIO subsystem */ gpio #( .reg_req_t(reg_pkg::reg_req_t), .reg_rsp_t(reg_pkg::reg_rsp_t) @@ -406,6 +463,7 @@ module ao_peripheral_subsystem .reg_rsp_o(ao_peripheral_slv_rsp[core_v_mini_mcu_pkg::UART_IDX]) ); + /* UART */ uart uart_i ( .clk_i, .rst_ni, diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv index 4cfb3d9d..3ebc1e77 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv @@ -11,8 +11,10 @@ module core_v_mini_mcu parameter ZFINX = 0, parameter EXT_XBAR_NMASTER = 0, parameter X_EXT = 0, // eXtension interface in cv32e40x + parameter AO_SPC_NUM = 0, parameter EXT_HARTS = 0, //do not touch these parameters + parameter AO_SPC_NUM_RND = AO_SPC_NUM == 0 ? 1 : AO_SPC_NUM, parameter EXT_XBAR_NMASTER_RND = EXT_XBAR_NMASTER == 0 ? 1 : EXT_XBAR_NMASTER, parameter EXT_DOMAINS_RND = core_v_mini_mcu_pkg::EXTERNAL_DOMAINS == 0 ? 1 : core_v_mini_mcu_pkg::EXTERNAL_DOMAINS, parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT, @@ -285,19 +287,22 @@ module core_v_mini_mcu input obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_req_i, output obi_resp_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_resp_o, + input reg_req_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_slave_req_i, + output reg_rsp_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_slave_resp_o, + // External slave ports - output obi_req_t ext_core_instr_req_o, - input obi_resp_t ext_core_instr_resp_i, - output obi_req_t ext_core_data_req_o, - input obi_resp_t ext_core_data_resp_i, - output obi_req_t ext_debug_master_req_o, - input obi_resp_t ext_debug_master_resp_i, - output obi_req_t ext_dma_read_ch0_req_o, - input obi_resp_t ext_dma_read_ch0_resp_i, - output obi_req_t ext_dma_write_ch0_req_o, - input obi_resp_t ext_dma_write_ch0_resp_i, - output obi_req_t ext_dma_addr_ch0_req_o, - input obi_resp_t ext_dma_addr_ch0_resp_i, + output obi_req_t ext_core_instr_req_o, + input obi_resp_t ext_core_instr_resp_i, + output obi_req_t ext_core_data_req_o, + input obi_resp_t ext_core_data_resp_i, + output obi_req_t ext_debug_master_req_o, + input obi_resp_t ext_debug_master_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_resp_i, input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, @@ -325,8 +330,10 @@ module core_v_mini_mcu output logic [31:0] exit_value_o, - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i + // External SPC interface + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i, + output logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_o ); import core_v_mini_mcu_pkg::*; @@ -355,12 +362,12 @@ module core_v_mini_mcu obi_resp_t core_data_resp; obi_req_t debug_master_req; obi_resp_t debug_master_resp; - obi_req_t dma_read_ch0_req; - obi_resp_t dma_read_ch0_resp; - obi_req_t dma_write_ch0_req; - obi_resp_t dma_write_ch0_resp; - obi_req_t dma_addr_ch0_req; - obi_resp_t dma_addr_ch0_resp; + obi_req_t [0:0] dma_read_req; + obi_resp_t [0:0] dma_read_resp; + obi_req_t [0:0] dma_write_req; + obi_resp_t [0:0] dma_write_resp; + obi_req_t [0:0] dma_addr_req; + obi_resp_t [0:0] dma_addr_resp; // ram signals obi_req_t [core_v_mini_mcu_pkg::NUM_BANKS-1:0] ram_slave_req; @@ -568,12 +575,12 @@ module core_v_mini_mcu .core_data_resp_o(core_data_resp), .debug_master_req_i(debug_master_req), .debug_master_resp_o(debug_master_resp), - .dma_read_ch0_req_i(dma_read_ch0_req), - .dma_read_ch0_resp_o(dma_read_ch0_resp), - .dma_write_ch0_req_i(dma_write_ch0_req), - .dma_write_ch0_resp_o(dma_write_ch0_resp), - .dma_addr_ch0_req_i(dma_addr_ch0_req), - .dma_addr_ch0_resp_o(dma_addr_ch0_resp), + .dma_read_req_i(dma_read_req), + .dma_read_resp_o(dma_read_resp), + .dma_write_req_i(dma_write_req), + .dma_write_resp_o(dma_write_resp), + .dma_addr_req_i(dma_addr_req), + .dma_addr_resp_o(dma_addr_resp), .ext_xbar_master_req_i(ext_xbar_master_req_i), .ext_xbar_master_resp_o(ext_xbar_master_resp_o), .ram_req_o(ram_slave_req), @@ -592,12 +599,12 @@ module core_v_mini_mcu .ext_core_data_resp_i(ext_core_data_resp_i), .ext_debug_master_req_o(ext_debug_master_req_o), .ext_debug_master_resp_i(ext_debug_master_resp_i), - .ext_dma_read_ch0_req_o(ext_dma_read_ch0_req_o), - .ext_dma_read_ch0_resp_i(ext_dma_read_ch0_resp_i), - .ext_dma_write_ch0_req_o(ext_dma_write_ch0_req_o), - .ext_dma_write_ch0_resp_i(ext_dma_write_ch0_resp_i), - .ext_dma_addr_ch0_req_o(ext_dma_addr_ch0_req_o), - .ext_dma_addr_ch0_resp_i(ext_dma_addr_ch0_resp_i) + .ext_dma_read_req_o(ext_dma_read_req_o), + .ext_dma_read_resp_i(ext_dma_read_resp_i), + .ext_dma_write_req_o(ext_dma_write_req_o), + .ext_dma_write_resp_i(ext_dma_write_resp_i), + .ext_dma_addr_req_o(ext_dma_addr_req_o), + .ext_dma_addr_resp_i(ext_dma_addr_resp_i) ); memory_subsystem #( @@ -613,11 +620,15 @@ module core_v_mini_mcu .set_retentive_ni(memory_subsystem_banks_set_retentive_n) ); - ao_peripheral_subsystem ao_peripheral_subsystem_i ( + ao_peripheral_subsystem #( + .AO_SPC_NUM(AO_SPC_NUM) + ) ao_peripheral_subsystem_i ( .clk_i, .rst_ni(rst_ni && debug_reset_n), .slave_req_i(ao_peripheral_slave_req), .slave_resp_o(ao_peripheral_slave_resp), + .spc2ao_req_i(ext_ao_peripheral_slave_req_i), + .ao2spc_resp_o(ext_ao_peripheral_slave_resp_o), .boot_select_i, .execute_from_flash_i, .exit_valid_o, @@ -646,12 +657,12 @@ module core_v_mini_mcu .external_subsystem_pwr_ctrl_i(external_subsystem_pwr_ctrl_in), .rv_timer_0_intr_o(rv_timer_intr[0]), .rv_timer_1_intr_o(rv_timer_intr[1]), - .dma_read_ch0_req_o(dma_read_ch0_req), - .dma_read_ch0_resp_i(dma_read_ch0_resp), - .dma_write_ch0_req_o(dma_write_ch0_req), - .dma_write_ch0_resp_i(dma_write_ch0_resp), - .dma_addr_ch0_req_o(dma_addr_ch0_req), - .dma_addr_ch0_resp_i(dma_addr_ch0_resp), + .dma_read_req_o(dma_read_req), + .dma_read_resp_i(dma_read_resp), + .dma_write_req_o(dma_write_req), + .dma_write_resp_i(dma_write_resp), + .dma_addr_req_o(dma_addr_req), + .dma_addr_resp_i(dma_addr_resp), .dma_done_intr_o(dma_done_intr), .dma_window_intr_o(dma_window_intr), .spi_flash_intr_event_o(spi_flash_intr), @@ -680,7 +691,8 @@ module core_v_mini_mcu .ext_peripheral_slave_resp_i, .ext_dma_slot_tx_i, .ext_dma_slot_rx_i, - .ext_dma_stop_i + .ext_dma_stop_i, + .dma_done_o ); peripheral_subsystem peripheral_subsystem_i ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl index cb571752..aedf2e2c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv.tpl @@ -11,8 +11,10 @@ module core_v_mini_mcu parameter ZFINX = 0, parameter EXT_XBAR_NMASTER = 0, parameter X_EXT = 0, // eXtension interface in cv32e40x + parameter AO_SPC_NUM = 0, parameter EXT_HARTS = 0, //do not touch these parameters + parameter AO_SPC_NUM_RND = AO_SPC_NUM == 0 ? 1 : AO_SPC_NUM, parameter EXT_XBAR_NMASTER_RND = EXT_XBAR_NMASTER == 0 ? 1 : EXT_XBAR_NMASTER, parameter EXT_DOMAINS_RND = core_v_mini_mcu_pkg::EXTERNAL_DOMAINS == 0 ? 1 : core_v_mini_mcu_pkg::EXTERNAL_DOMAINS, parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT, @@ -39,6 +41,9 @@ ${pad.core_v_mini_mcu_interface} input obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_req_i, output obi_resp_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_resp_o, + input reg_req_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_slave_req_i, + output reg_rsp_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_slave_resp_o, + // External slave ports output obi_req_t ext_core_instr_req_o, input obi_resp_t ext_core_instr_resp_i, @@ -46,12 +51,12 @@ ${pad.core_v_mini_mcu_interface} input obi_resp_t ext_core_data_resp_i, output obi_req_t ext_debug_master_req_o, input obi_resp_t ext_debug_master_resp_i, - output obi_req_t ext_dma_read_ch0_req_o, - input obi_resp_t ext_dma_read_ch0_resp_i, - output obi_req_t ext_dma_write_ch0_req_o, - input obi_resp_t ext_dma_write_ch0_resp_i, - output obi_req_t ext_dma_addr_ch0_req_o, - input obi_resp_t ext_dma_addr_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_resp_i, input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, @@ -79,8 +84,10 @@ ${pad.core_v_mini_mcu_interface} output logic [31:0] exit_value_o, + // External SPC interface input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx_i, - input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx_i, + output logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_o ); import core_v_mini_mcu_pkg::*; @@ -109,12 +116,12 @@ ${pad.core_v_mini_mcu_interface} obi_resp_t core_data_resp; obi_req_t debug_master_req; obi_resp_t debug_master_resp; - obi_req_t dma_read_ch0_req; - obi_resp_t dma_read_ch0_resp; - obi_req_t dma_write_ch0_req; - obi_resp_t dma_write_ch0_resp; - obi_req_t dma_addr_ch0_req; - obi_resp_t dma_addr_ch0_resp; + obi_req_t [${int(num_dma_master_ports)-1}:0]dma_read_req; + obi_resp_t [${int(num_dma_master_ports)-1}:0]dma_read_resp; + obi_req_t [${int(num_dma_master_ports)-1}:0]dma_write_req; + obi_resp_t [${int(num_dma_master_ports)-1}:0]dma_write_resp; + obi_req_t [${int(num_dma_master_ports)-1}:0]dma_addr_req; + obi_resp_t [${int(num_dma_master_ports)-1}:0]dma_addr_resp; // ram signals obi_req_t [core_v_mini_mcu_pkg::NUM_BANKS-1:0] ram_slave_req; @@ -318,12 +325,12 @@ ${pad.core_v_mini_mcu_interface} .core_data_resp_o(core_data_resp), .debug_master_req_i(debug_master_req), .debug_master_resp_o(debug_master_resp), - .dma_read_ch0_req_i(dma_read_ch0_req), - .dma_read_ch0_resp_o(dma_read_ch0_resp), - .dma_write_ch0_req_i(dma_write_ch0_req), - .dma_write_ch0_resp_o(dma_write_ch0_resp), - .dma_addr_ch0_req_i(dma_addr_ch0_req), - .dma_addr_ch0_resp_o(dma_addr_ch0_resp), + .dma_read_req_i(dma_read_req), + .dma_read_resp_o(dma_read_resp), + .dma_write_req_i(dma_write_req), + .dma_write_resp_o(dma_write_resp), + .dma_addr_req_i(dma_addr_req), + .dma_addr_resp_o(dma_addr_resp), .ext_xbar_master_req_i(ext_xbar_master_req_i), .ext_xbar_master_resp_o(ext_xbar_master_resp_o), .ram_req_o(ram_slave_req), @@ -342,12 +349,12 @@ ${pad.core_v_mini_mcu_interface} .ext_core_data_resp_i(ext_core_data_resp_i), .ext_debug_master_req_o(ext_debug_master_req_o), .ext_debug_master_resp_i(ext_debug_master_resp_i), - .ext_dma_read_ch0_req_o(ext_dma_read_ch0_req_o), - .ext_dma_read_ch0_resp_i(ext_dma_read_ch0_resp_i), - .ext_dma_write_ch0_req_o(ext_dma_write_ch0_req_o), - .ext_dma_write_ch0_resp_i(ext_dma_write_ch0_resp_i), - .ext_dma_addr_ch0_req_o(ext_dma_addr_ch0_req_o), - .ext_dma_addr_ch0_resp_i(ext_dma_addr_ch0_resp_i) + .ext_dma_read_req_o(ext_dma_read_req_o), + .ext_dma_read_resp_i(ext_dma_read_resp_i), + .ext_dma_write_req_o(ext_dma_write_req_o), + .ext_dma_write_resp_i(ext_dma_write_resp_i), + .ext_dma_addr_req_o(ext_dma_addr_req_o), + .ext_dma_addr_resp_i(ext_dma_addr_resp_i) ); memory_subsystem #( @@ -363,11 +370,15 @@ ${pad.core_v_mini_mcu_interface} .set_retentive_ni(memory_subsystem_banks_set_retentive_n) ); - ao_peripheral_subsystem ao_peripheral_subsystem_i ( + ao_peripheral_subsystem #( + .AO_SPC_NUM(AO_SPC_NUM) + ) ao_peripheral_subsystem_i ( .clk_i, .rst_ni(rst_ni && debug_reset_n), .slave_req_i(ao_peripheral_slave_req), .slave_resp_o(ao_peripheral_slave_resp), + .spc2ao_req_i(ext_ao_peripheral_slave_req_i), + .ao2spc_resp_o(ext_ao_peripheral_slave_resp_o), .boot_select_i, .execute_from_flash_i, .exit_valid_o, @@ -394,12 +405,12 @@ ${pad.core_v_mini_mcu_interface} .external_subsystem_pwr_ctrl_i(external_subsystem_pwr_ctrl_in), .rv_timer_0_intr_o(rv_timer_intr[0]), .rv_timer_1_intr_o(rv_timer_intr[1]), - .dma_read_ch0_req_o(dma_read_ch0_req), - .dma_read_ch0_resp_i(dma_read_ch0_resp), - .dma_write_ch0_req_o(dma_write_ch0_req), - .dma_write_ch0_resp_i(dma_write_ch0_resp), - .dma_addr_ch0_req_o(dma_addr_ch0_req), - .dma_addr_ch0_resp_i(dma_addr_ch0_resp), + .dma_read_req_o(dma_read_req), + .dma_read_resp_i(dma_read_resp), + .dma_write_req_o(dma_write_req), + .dma_write_resp_i(dma_write_resp), + .dma_addr_req_o(dma_addr_req), + .dma_addr_resp_i(dma_addr_resp), .dma_done_intr_o(dma_done_intr), .dma_window_intr_o(dma_window_intr), .spi_flash_intr_event_o(spi_flash_intr), @@ -428,7 +439,8 @@ ${pad.core_v_mini_mcu_interface} .ext_peripheral_slave_resp_i, .ext_dma_slot_tx_i, .ext_dma_slot_rx_i, - .ext_dma_stop_i + .ext_dma_stop_i, + .dma_done_o ); peripheral_subsystem peripheral_subsystem_i ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.vlt b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.vlt index e1493802..11f96091 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.vlt @@ -8,6 +8,7 @@ lint_off -rule UNUSED -file "*/core_v_mini_mcu.sv" -match "*" lint_off -rule UNUSED -file "*/cpu_subsystem.sv" -match "Signal is not used: 'apu*'*" lint_off -rule UNDRIVEN -file "*/memory_subsystem.sv" -match "Bits of signal are not driven: 'ram*_resp_o'[32]*" lint_off -rule UNOPTFLAT -file "*/system_xbar.sv" -match "Signal unoptimizable*" +lint_off -rule UNOPTFLAT -file "*/ao_peripheral_subsystem.sv" -match "*" lint_off -rule UNOPTFLAT -file "*/xbar_varlat_one_to_n.sv" -match "Signal unoptimizable: Feedback to clock or circular logic: *" lint_off -rule UNOPTFLAT -file "*/xbar_varlat_n_to_one.sv" -match "Signal unoptimizable: Feedback to clock or circular logic: *" lint_off -rule UNUSED -file "*/reg_to_tlul.sv" -match "Bits of signal are not used: 'tl_i'*" @@ -28,3 +29,4 @@ lint_off -rule LITENDIAN -file "*/x_heep_system.sv" -match "*" lint_off -rule WIDTH -file "*/ao_peripheral_subsystem.sv" -match "Input port connection 'reg_req_i' expects 70 bits on the pin connection, but pin connection's SEL generates 34 bits.*" lint_off -rule UNDRIVEN -file "*ip/power_manager/rtl/power_manager.sv" -match "Signal is not driven: 'external_ram_banks_set_retentive*'" lint_off -rule UNDRIVEN -file "*ip/power_manager/rtl/power_manager.sv" -match "Signal is not driven: 'external_subsystem_clkgate_en*'" +lint_off -rule UNUSED -file "*vendor/pulp_platform_register_interface/src/reg_mux.sv" -match "*" diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl index ba99d50f..00ffc025 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/include/core_v_mini_mcu_pkg.sv.tpl @@ -38,11 +38,11 @@ package core_v_mini_mcu_pkg; localparam logic [31:0] CORE_INSTR_IDX = 0; localparam logic [31:0] CORE_DATA_IDX = 1; localparam logic [31:0] DEBUG_MASTER_IDX = 2; - localparam logic [31:0] DMA_READ_CH0_IDX = 3; - localparam logic [31:0] DMA_WRITE_CH0_IDX = 4; - localparam logic [31:0] DMA_ADDR_CH0_IDX = 5; + localparam logic [31:0] DMA_READ_P0_IDX = 3; + localparam logic [31:0] DMA_WRITE_P0_IDX = 4; + localparam logic [31:0] DMA_ADDR_P0_IDX = 5; - localparam SYSTEM_XBAR_NMASTER = 6; + localparam SYSTEM_XBAR_NMASTER = ${3 + int(num_dma_master_ports)*3}; // Internal slave memory map and index // ----------------------------------- @@ -139,7 +139,14 @@ package core_v_mini_mcu_pkg; // --------------------- localparam AO_PERIPHERALS = ${ao_peripherals_count}; localparam DMA_CH_NUM = ${dma_ch_count}; - + localparam DMA_CH_SIZE = 32'h${dma_ch_size}; + localparam DMA_NUM_MASTER_PORTS = ${num_dma_master_ports}; +% if int(num_dma_master_ports) > 1: + localparam int DMA_XBAR_MASTERS [DMA_NUM_MASTER_PORTS] = '{${dma_xbar_masters_array[::-1]}}; +% else: + localparam int DMA_XBAR_MASTERS [DMA_NUM_MASTER_PORTS] = '{${dma_xbar_masters_array}}; +% endif + % for peripheral, addr in ao_peripherals.items(): localparam logic [31:0] ${peripheral.upper()}_START_ADDRESS = AO_PERIPHERAL_START_ADDRESS + 32'h${addr["offset"]}; localparam logic [31:0] ${peripheral.upper()}_SIZE = 32'h${addr["length"]}; diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl index 19bb8622..221ec067 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/system_bus.sv.tpl @@ -37,14 +37,14 @@ module system_bus input obi_req_t debug_master_req_i, output obi_resp_t debug_master_resp_o, - input obi_req_t dma_read_ch0_req_i, - output obi_resp_t dma_read_ch0_resp_o, + input obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_req_i, + output obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_resp_o, - input obi_req_t dma_write_ch0_req_i, - output obi_resp_t dma_write_ch0_resp_o, + input obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_req_i, + output obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_resp_o, - input obi_req_t dma_addr_ch0_req_i, - output obi_resp_t dma_addr_ch0_resp_o, + input obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_req_i, + output obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_resp_o, // External master ports input obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_xbar_master_req_i, @@ -76,14 +76,14 @@ module system_bus output obi_req_t ext_debug_master_req_o, input obi_resp_t ext_debug_master_resp_i, - output obi_req_t ext_dma_read_ch0_req_o, - input obi_resp_t ext_dma_read_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_resp_i, - output obi_req_t ext_dma_write_ch0_req_o, - input obi_resp_t ext_dma_write_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_resp_i, - output obi_req_t ext_dma_addr_ch0_req_o, - input obi_resp_t ext_dma_addr_ch0_resp_i + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_resp_i ); import core_v_mini_mcu_pkg::*; @@ -119,9 +119,12 @@ module system_bus assign int_master_req[core_v_mini_mcu_pkg::CORE_INSTR_IDX] = core_instr_req_i; assign int_master_req[core_v_mini_mcu_pkg::CORE_DATA_IDX] = core_data_req_i; assign int_master_req[core_v_mini_mcu_pkg::DEBUG_MASTER_IDX] = debug_master_req_i; - assign int_master_req[core_v_mini_mcu_pkg::DMA_READ_CH0_IDX] = dma_read_ch0_req_i; - assign int_master_req[core_v_mini_mcu_pkg::DMA_WRITE_CH0_IDX] = dma_write_ch0_req_i; - assign int_master_req[core_v_mini_mcu_pkg::DMA_ADDR_CH0_IDX] = dma_addr_ch0_req_i; + + % for i in range(int(num_dma_master_ports)): + assign int_master_req[${3+i*3}] = dma_read_req_i[${i}]; + assign int_master_req[${4+i*3}] = dma_write_req_i[${i}]; + assign int_master_req[${5+i*3}] = dma_addr_req_i[${i}]; + % endfor // Internal + external master requests generate @@ -142,10 +145,13 @@ module system_bus assign core_instr_resp_o = int_master_resp[core_v_mini_mcu_pkg::CORE_INSTR_IDX]; assign core_data_resp_o = int_master_resp[core_v_mini_mcu_pkg::CORE_DATA_IDX]; assign debug_master_resp_o = int_master_resp[core_v_mini_mcu_pkg::DEBUG_MASTER_IDX]; - assign dma_read_ch0_resp_o = int_master_resp[core_v_mini_mcu_pkg::DMA_READ_CH0_IDX]; - assign dma_write_ch0_resp_o = int_master_resp[core_v_mini_mcu_pkg::DMA_WRITE_CH0_IDX]; - assign dma_addr_ch0_resp_o = int_master_resp[core_v_mini_mcu_pkg::DMA_ADDR_CH0_IDX]; + % for i in range(int(num_dma_master_ports)): + assign dma_read_resp_o[${i}] = int_master_resp[${3+i*3}]; + assign dma_write_resp_o[${i}] = int_master_resp[${4+i*3}]; + assign dma_addr_resp_o[${i}] = int_master_resp[${5+i*3}]; + % endfor + // External master responses if (EXT_XBAR_NMASTER == 0) begin assign ext_xbar_master_resp_o = '0; @@ -169,9 +175,14 @@ module system_bus assign ext_core_instr_req_o = demux_xbar_req[CORE_INSTR_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; assign ext_core_data_req_o = demux_xbar_req[CORE_DATA_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; assign ext_debug_master_req_o = demux_xbar_req[DEBUG_MASTER_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; - assign ext_dma_read_ch0_req_o = demux_xbar_req[DMA_READ_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; - assign ext_dma_write_ch0_req_o = demux_xbar_req[DMA_WRITE_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; - assign ext_dma_addr_ch0_req_o = demux_xbar_req[DMA_ADDR_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX]; + generate + for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS; i++) begin : gen_ext_dma_master_req_map + assign ext_dma_read_req_o[i] = demux_xbar_req[core_v_mini_mcu_pkg::DMA_READ_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX]; + assign ext_dma_write_req_o[i] = demux_xbar_req[core_v_mini_mcu_pkg::DMA_WRITE_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX]; + assign ext_dma_addr_req_o[i] = demux_xbar_req[core_v_mini_mcu_pkg::DMA_ADDR_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX]; + end + endgenerate + // Internal slave responses assign int_slave_resp[core_v_mini_mcu_pkg::ERROR_IDX] = error_slave_resp; @@ -187,10 +198,14 @@ module system_bus assign demux_xbar_resp[CORE_INSTR_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_core_instr_resp_i; assign demux_xbar_resp[CORE_DATA_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_core_data_resp_i; assign demux_xbar_resp[DEBUG_MASTER_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_debug_master_resp_i; - assign demux_xbar_resp[DMA_READ_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_read_ch0_resp_i; - assign demux_xbar_resp[DMA_WRITE_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_write_ch0_resp_i; - assign demux_xbar_resp[DMA_ADDR_CH0_IDX][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_addr_ch0_resp_i; - + generate + for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS; i++) begin : gen_ext_dma_master_resp_map + assign demux_xbar_resp[core_v_mini_mcu_pkg::DMA_READ_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_read_resp_i[i]; + assign demux_xbar_resp[core_v_mini_mcu_pkg::DMA_WRITE_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_write_resp_i[i]; + assign demux_xbar_resp[core_v_mini_mcu_pkg::DMA_ADDR_P0_IDX+3*i][DEMUX_XBAR_EXT_SLAVE_IDX] = ext_dma_addr_resp_i[i]; + end + endgenerate + `ifndef SYNTHESIS always_ff @(posedge clk_i, negedge rst_ni) begin : check_out_of_bound if (rst_ni) begin diff --git a/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv b/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv index fc9c53fb..343bda8e 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv @@ -133,16 +133,18 @@ module xilinx_core_v_mini_mcu_wrapper .ext_core_data_resp_i('0), .ext_debug_master_req_o(), .ext_debug_master_resp_i('0), - .ext_dma_read_ch0_req_o(), - .ext_dma_read_ch0_resp_i('0), - .ext_dma_write_ch0_req_o(), - .ext_dma_write_ch0_resp_i('0), - .ext_dma_addr_ch0_req_o(), - .ext_dma_addr_ch0_resp_i('0), + .ext_dma_read_req_o(), + .ext_dma_read_resp_i('0), + .ext_dma_write_req_o(), + .ext_dma_write_resp_i('0), + .ext_dma_addr_req_o(), + .ext_dma_addr_resp_i('0), .ext_peripheral_slave_req_o(), .ext_peripheral_slave_resp_i('0), + .ext_ao_peripheral_req_i('0), + .ext_ao_peripheral_resp_o(), .external_subsystem_powergate_switch_no(), - .external_subsystem_powergate_switch_ack_ni(), + .external_subsystem_powergate_switch_ack_ni('0), .external_subsystem_powergate_iso_no(), .external_subsystem_rst_no(), .external_ram_banks_set_retentive_no(), diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson index 58f6d3a0..4f144c61 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/data/dma.hjson @@ -34,7 +34,7 @@ ] }, { name: "SIZE_D1", - desc: "Number of bytes to copy from, defined with respect to the first dimension - Once a value is written, the copy starts", + desc: "Number of elements to copy from, defined with respect to the first dimension - Once a value is written, the copy starts", swaccess: "rw", hwaccess: "hro", hwqe: "true", // enable `qe` latched signal of software write pulse @@ -44,10 +44,9 @@ ] }, { name: "SIZE_D2", - desc: "Number of bytes to copy from, defined with respect to the second dimension", + desc: "Number of elements to copy from, defined with respect to the second dimension", swaccess: "rw", hwaccess: "hro", - hwqe: "true", // enable `qe` latched signal of software write pulse // Dimensioned to 16 bits to allow for 64kB transfers on 2D fields: [ { bits: "15:0", name: "SIZE", desc: "DMA counter D2" } @@ -118,7 +117,7 @@ { name: "SLOT", desc: '''The DMA will wait for the signal connected to the selected trigger_slots to be high - on the read and write side respectivly''', + on the read and write side respectively''', swaccess: "rw", hwaccess: "hro", resval: 0, @@ -185,6 +184,7 @@ desc: '''Set the operational mode of the DMA''', swaccess: "rw", hwaccess: "hro", + resval: 0, fields: [ { bits: "1:0", name: "MODE", desc: "DMA operation mode", @@ -218,7 +218,6 @@ desc: '''Set the top padding''', swaccess: "rw", hwaccess: "hro", - hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding resval: 0, fields: [ { bits: "5:0", name: "PAD", desc: "Top margin padding (2D)"} @@ -228,7 +227,6 @@ desc: '''Set the bottom padding''', swaccess: "rw", hwaccess: "hro", - hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding resval: 0, fields: [ { bits: "5:0", name: "PAD", desc: "Bottom margin padding (2D)"} @@ -238,7 +236,6 @@ desc: '''Set the right padding''', swaccess: "rw", hwaccess: "hro", - hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding resval: 0, fields: [ { bits: "5:0", name: "PAD", desc: "Right margin padding (1D/2D)"} @@ -248,7 +245,6 @@ desc: '''Set the left padding''', swaccess: "rw", hwaccess: "hro", - hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding resval: 0, fields: [ { bits: "5:0", name: "PAD", desc: "Left margin padding (1D/2D)"} @@ -259,6 +255,7 @@ Set to 0 to disable.''', swaccess: "rw", hwaccess: "hro", + resval: 0, fields: [ { bits: "12:0", name: "WINDOW_SIZE", desc: ""} ] @@ -267,7 +264,6 @@ desc: '''Number of times the end of the window was reached since the beginning. Reset at start''', swaccess: "ro", - // hwext: "true", hwaccess: "hrw", resval: 0, fields: [ @@ -279,6 +275,7 @@ (Only the interrupt with the lowest id will be triggered)''', swaccess: "rw", hwaccess: "hro", + resval: 0, fields: [ { bits: "0", name: "TRANSACTION_DONE", desc: "Enables transaction done interrupt" } { bits: "1", name: "WINDOW_DONE", desc: "Enables window done interrupt" } @@ -306,5 +303,5 @@ { bits: "0", name: "FLAG", desc: "Set for window done interrupt" } ] } - ] + ] } diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core index 86255b7a..0bf343e7 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.core @@ -14,6 +14,10 @@ filesets: files: - rtl/dma_reg_pkg.sv - rtl/dma_reg_top.sv + - rtl/dma_padding_fsm.sv + - rtl/dma_obiread_fsm.sv + - rtl/dma_obiread_addr_fsm.sv + - rtl/dma_obiwrite_fsm.sv - rtl/dma.sv file_type: systemVerilogSource diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.vlt index 1034666a..70cee9b4 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.vlt +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/dma.vlt @@ -7,8 +7,13 @@ lint_off -rule DECLFILENAME -file "*/dma_reg_top.sv" lint_off -rule WIDTH -file "*/rtl/dma_reg_top.sv" -match "Operator ASSIGNW expects *" +lint_off -rule WIDTH -file "*/rtl/dma.sv" -match "Operator ASSIGNW expects *" lint_off -rule UNUSED -file "*/rtl/dma.sv" -match "Signal is not used: 'data_out_rvalid'" lint_off -rule UNUSED -file "*/rtl/dma.sv" -match "Signal is not used: 'data_out_rdata'" +lint_off -rule UNUSED -file "*/rtl/dma_obiread_fsm.sv" -match "Bits of signal are not used: *" +lint_off -rule UNUSED -file "*/rtl/dma_obiwrite_fsm.sv" -match "Bits of signal are not used: *" +lint_off -rule UNUSED -file "*/rtl/dma_obiread_addr_fsm.sv" -match "Bits of signal are not used: *" +lint_off -rule UNUSED -file "*/rtl/dma_padding_fsm.sv" -match "Bits of signal are not used: *" lint_off -rule UNUSED -file "*/rtl/dma.sv" -match "Bits of signal are not used: *" diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv index 4bfe0219..923b5a1f 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma.sv @@ -1,11 +1,11 @@ /* - * Copyright 2022 EPFL + * Copyright 2024 EPFL * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Info: Direct Memory Access (DMA) channel module. */ -/* DMA assume a read request is not granted before previous request rvalid is asserted */ - module dma #( parameter int unsigned FIFO_DEPTH = 4, parameter type reg_req_t = logic, @@ -16,156 +16,125 @@ module dma #( ) ( input logic clk_i, input logic rst_ni, + input logic clk_gate_en_ni, input logic ext_dma_stop_i, input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, - output obi_req_t dma_read_ch0_req_o, - input obi_resp_t dma_read_ch0_resp_i, + output obi_req_t dma_read_req_o, + input obi_resp_t dma_read_resp_i, - output obi_req_t dma_write_ch0_req_o, - input obi_resp_t dma_write_ch0_resp_i, + output obi_req_t dma_write_req_o, + input obi_resp_t dma_write_resp_i, - output obi_req_t dma_addr_ch0_req_o, - input obi_resp_t dma_addr_ch0_resp_i, + output obi_req_t dma_addr_req_o, + input obi_resp_t dma_addr_resp_i, input logic [SLOT_NUM-1:0] trigger_slot_i, output dma_done_intr_o, - output dma_window_intr_o + output dma_window_intr_o, + + output dma_done_o ); import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + localparam int unsigned LastFifoUsage = FIFO_DEPTH - 1; localparam int unsigned Addr_Fifo_Depth = (FIFO_DEPTH > 1) ? $clog2(FIFO_DEPTH) : 1; - dma_reg2hw_t reg2hw; - dma_hw2reg_t hw2reg; - - logic [ 31:0] src_ptr_reg; - logic [ 31:0] read_ptr_reg; - logic [ 31:0] addr_ptr_reg; - logic [ 31:0] read_ptr_valid_reg; - logic [ 31:0] write_ptr_reg; - logic [ 31:0] write_address; - logic [ 31:0] dma_addr_cnt; - logic [ 2:0] dma_src_cnt_du; - logic [ 2:0] dma_dst_cnt_du; - logic dma_start; - logic dma_done; - logic dma_window_event; - - logic window_done_q; - - logic [Addr_Fifo_Depth-1:0] fifo_usage; - logic fifo_alm_full; - - logic [Addr_Fifo_Depth-1:0] fifo_addr_usage; - logic fifo_addr_alm_full; - - logic data_in_req; - logic data_in_we; - logic [ 3:0] data_in_be; - logic [ 31:0] data_in_addr; - logic data_in_gnt; - logic data_in_rvalid; - logic [ 31:0] data_in_rdata; - - logic data_addr_in_req; - logic data_addr_in_we; - logic [ 3:0] data_addr_in_be; - logic [ 31:0] data_addr_in_addr; - logic data_addr_in_gnt; - logic data_addr_in_rvalid; - logic [ 31:0] data_addr_in_rdata; - - logic data_out_req; - logic data_out_we; - logic [ 3:0] data_out_be; - logic [ 31:0] data_out_addr; - logic [ 31:0] data_out_wdata; - logic data_out_gnt; - logic data_out_rvalid; - logic [ 31:0] data_out_rdata; - - /* Sign extension signals */ - logic sign_extend; - - /* 2D signals */ - - /* Dimensionality configuration */ - logic dma_conf_1d; // Dimensionality configuration: 0-> 1D, 1-> 2D - logic dma_conf_2d; // Dimensionality configuration: 0-> 1D, 1-> 2D - - /* Counters */ - logic [ 16:0] dma_src_cnt_d1; // d1 src counter - logic [ 16:0] dma_src_cnt_d2; // d2 src counter - logic [ 16:0] dma_dst_cnt_d1; // d2 dst counter - - /* Increments */ - logic [ 5:0] dma_src_d1_inc; // d1 source increment - logic [ 22:0] dma_src_d2_inc; // d2 source increment - logic [ 5:0] dma_dst_d1_inc; // d1 destination increment - logic [ 22:0] dma_dst_d2_inc; // d2 destination increment - - /* Flags */ - logic pad_fifo_on; // Padding flag for FIFO - logic pad_cnt_on; // Padding flag for counters - logic read_ptr_update_sel; // Select the read pointer update source - - /* Padding FSM conditions */ - logic idle_to_left_ex; - logic idle_to_top_ex; - logic idle_to_right_ex; - logic idle_to_bottom_ex; - logic top_ex_to_top_dn; - logic top_ex_to_left_ex; - logic top_dn_to_right_ex; - logic top_dn_to_bottom_ex; - logic top_dn_to_idle; - logic left_ex_to_left_dn; - logic left_dn_to_left_ex; - logic left_dn_to_right_ex; - logic left_dn_to_bottom_ex; - logic left_dn_to_idle; - logic right_ex_to_right_dn; - logic right_ex_to_left_ex; - logic right_dn_to_right_ex; - logic right_dn_to_idle; - logic right_ex_to_bottom_ex; - logic bottom_ex_to_idle; - - /* Padding synchronization signals */ - logic data_in_rvalid_virt; - logic data_in_rvalid_virt_n; - logic data_in_rvalid_virt_n_n; - logic data_in_gnt_virt; - logic data_in_gnt_virt_n; - logic data_in_gnt_virt_n_n; + /*_________________________________________________________________________________________________________________________________ */ - /* Interrupt Flag Register signals */ - logic transaction_ifr; - logic dma_done_intr_n; - logic dma_done_intr; - logic window_ifr; - logic dma_window_intr; - logic dma_window_intr_n; + /* Signals declaration */ - /* FIFO signals */ - logic fifo_flush; - logic fifo_full; - logic fifo_empty; + /* Gated clock */ + logic clk_cg; + + /* Registers */ + dma_reg2hw_t reg2hw; + dma_hw2reg_t hw2reg; + + /* General signals */ + logic dma_padding_fsm_on; + logic padding_fsm_done; + + logic dma_start; + logic dma_done; + logic dma_window_event; + + logic window_done_q; + + logic data_in_req; + logic data_in_we; + logic [3:0] data_in_be; + logic [31:0] data_in_addr; + logic data_in_gnt; + logic data_in_rvalid; + logic [31:0] data_in_rdata; - logic fifo_addr_flush; - logic fifo_addr_full; - logic fifo_addr_empty, fifo_addr_empty_check; + logic data_addr_in_req; + logic data_addr_in_we; + logic [3:0] data_addr_in_be; + logic [31:0] data_addr_in_addr; + logic data_addr_in_gnt; + logic data_addr_in_rvalid; + logic [31:0] data_addr_in_rdata; + logic data_out_req; + logic data_out_we; + logic [3:0] data_out_be; + logic [31:0] data_out_addr; + logic [31:0] data_out_wdata; + logic data_out_gnt; + logic data_out_rvalid; + logic [31:0] data_out_rdata; + + /* Interrupt Flag Register signals */ + logic transaction_ifr; + logic dma_done_intr_n; + logic dma_done_intr; + logic window_ifr; + logic dma_window_intr; + logic dma_window_intr_n; + + /* FIFO signals */ + logic [Addr_Fifo_Depth-1:0] read_fifo_usage; + logic [Addr_Fifo_Depth-1:0] read_addr_fifo_usage; + logic [Addr_Fifo_Depth-1:0] write_fifo_usage; + + logic fifo_flush; + logic read_fifo_full; + logic read_fifo_empty; + logic read_fifo_alm_full; + logic read_fifo_pop; + logic [31:0] read_fifo_input; + logic [31:0] read_fifo_output; + + logic read_addr_fifo_full; + logic read_addr_fifo_empty; + logic read_addr_fifo_alm_full; + logic [31:0] read_addr_fifo_output; + + logic write_fifo_full; + logic write_fifo_empty; + logic write_fifo_alm_full; + logic write_fifo_push; + logic write_fifo_pop; + logic [31:0] write_fifo_input; + logic [31:0] write_fifo_output; + + /* Trigger signals */ logic wait_for_rx; logic wait_for_tx; + /* Datatypes */ typedef enum logic [1:0] { DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_HALF_WORD, @@ -173,21 +142,8 @@ module dma #( DMA_DATA_TYPE_BYTE_ } dma_data_type_t; - dma_data_type_t dst_data_type; - dma_data_type_t src_data_type; - - logic [31:0] fifo_input; - logic [31:0] fifo_addr_input; - logic [31:0] fifo_output; - logic [31:0] fifo_addr_output; - - logic [ 3:0] byte_enable_out; - - logic circular_mode; - logic address_mode; - - logic dma_start_pending; + /* FSM states */ enum { DMA_READY, DMA_STARTING, @@ -195,173 +151,195 @@ module dma #( } dma_state_q, dma_state_d; - /* Padding FSM states */ - - enum { - PAD_IDLE, - TOP_PAD_EXEC, - LEFT_PAD_EXEC, - RIGHT_PAD_EXEC, - BOTTOM_PAD_EXEC, - TOP_PAD_DONE, - LEFT_PAD_DONE, - RIGHT_PAD_DONE, - BOTTOM_PAD_DONE - } - pad_state_q, pad_state_d, pad_state_x; - - enum logic { - DMA_READ_FSM_IDLE, - DMA_READ_FSM_ON - } - dma_read_fsm_state, dma_read_fsm_n_state, dma_read_addr_fsm_state, dma_read_addr_fsm_n_state; + logic circular_mode; + logic address_mode; - enum logic { - DMA_WRITE_FSM_IDLE, - DMA_WRITE_FSM_ON - } - dma_write_fsm_state, dma_write_fsm_n_state; + logic dma_start_pending; - logic [Addr_Fifo_Depth-1:0] outstanding_req, outstanding_addr_req; logic [31:0] window_counter; - assign dma_read_ch0_req_o.req = data_in_req && ~pad_fifo_on; - assign dma_read_ch0_req_o.we = data_in_we; - assign dma_read_ch0_req_o.be = data_in_be; - assign dma_read_ch0_req_o.addr = data_in_addr; - assign dma_read_ch0_req_o.wdata = 32'h0; + /*_________________________________________________________________________________________________________________________________ */ - assign data_in_gnt = dma_read_ch0_resp_i.gnt || (data_in_gnt_virt & pad_fifo_on); - assign data_in_rvalid = dma_read_ch0_resp_i.rvalid || (data_in_rvalid_virt & pad_fifo_on); - assign data_in_rdata = dma_read_ch0_resp_i.rdata; + /* Module instantiation */ - assign dma_addr_ch0_req_o.req = data_addr_in_req; - assign dma_addr_ch0_req_o.we = data_addr_in_we; - assign dma_addr_ch0_req_o.be = data_addr_in_be; - assign dma_addr_ch0_req_o.addr = data_addr_in_addr; - assign dma_addr_ch0_req_o.wdata = 32'h0; + /* Clock gating cell */ - assign data_addr_in_gnt = dma_addr_ch0_resp_i.gnt; - assign data_addr_in_rvalid = dma_addr_ch0_resp_i.rvalid; - assign data_addr_in_rdata = dma_addr_ch0_resp_i.rdata; +`ifndef FPGA_SYNTHESIS +`ifndef VERILATOR + tc_clk_gating clk_gating_cell ( + .clk_i, + .en_i(clk_gate_en_ni), + .test_en_i(1'b0), + .clk_o(clk_cg) + ); - assign dma_write_ch0_req_o.req = data_out_req; - assign dma_write_ch0_req_o.we = data_out_we; - assign dma_write_ch0_req_o.be = data_out_be; - assign dma_write_ch0_req_o.addr = data_out_addr; - assign dma_write_ch0_req_o.wdata = data_out_wdata; +`else + assign clk_cg = clk_i & clk_gate_en_ni; +`endif - assign data_out_gnt = dma_write_ch0_resp_i.gnt; - assign data_out_rvalid = dma_write_ch0_resp_i.rvalid; - assign data_out_rdata = dma_write_ch0_resp_i.rdata; +`else + assign clk_cg = clk_i & clk_gate_en_ni; +`endif - assign dma_done_intr = transaction_ifr; - assign dma_window_intr = window_ifr; - assign dma_done_intr_o = dma_done_intr_n; - assign hw2reg.transaction_ifr.d = transaction_ifr; - assign dma_window_intr_o = dma_window_intr_n; - assign hw2reg.window_ifr.d = window_ifr; - assign dst_data_type = dma_data_type_t'(reg2hw.dst_data_type.q); - assign src_data_type = dma_data_type_t'(reg2hw.src_data_type.q); + /* Read FIFO */ + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1) + ) dma_read_fifo_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(read_fifo_full), + .empty_o(read_fifo_empty), + .usage_o(read_fifo_usage), + // as long as the queue is not full we can push new data + .data_i(read_fifo_input), + .push_i(data_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(read_fifo_output), + .pop_i(read_fifo_pop) + ); - assign hw2reg.status.ready.d = (dma_state_q == DMA_READY); + /* Read address mode FIFO */ + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1) + ) dma_read_addr_fifo_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(read_addr_fifo_full), + .empty_o(read_addr_fifo_empty), + .usage_o(read_addr_fifo_usage), + // as long as the queue is not full we can push new data + .data_i(data_addr_in_rdata), + .push_i(data_addr_in_rvalid), + // as long as the queue is not empty we can pop new elements + .data_o(read_addr_fifo_output), + .pop_i(write_fifo_pop && address_mode) // not an error! + ); - assign hw2reg.status.window_done.d = window_done_q; + /* Write FIFO */ + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1) + ) dma_write_fifo_i ( + .clk_i(clk_cg), + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(write_fifo_full), + .empty_o(write_fifo_empty), + .usage_o(write_fifo_usage), + // as long as the queue is not full we can push new data + .data_i(write_fifo_input), + .push_i(write_fifo_push), + // as long as the queue is not empty we can pop new elements + .data_o(write_fifo_output), + .pop_i(write_fifo_pop) + ); - assign circular_mode = reg2hw.mode.q == 1; - assign address_mode = reg2hw.mode.q == 2; + dma_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) dma_reg_top_i ( + .clk_i(clk_cg), + .rst_ni, + .reg_req_i, + .reg_rsp_o, + .reg2hw, + .hw2reg, + .devmode_i(1'b1) + ); - /* DMA Dimensionality configuration flags */ - assign dma_conf_1d = reg2hw.dim_config.q == 0; - assign dma_conf_2d = reg2hw.dim_config.q == 1; - - /* DMA read pointer source selection */ - assign read_ptr_update_sel = reg2hw.dim_inv.q; - - /* DMA 2D increment */ - assign dma_src_d2_inc = reg2hw.src_ptr_inc_d2.q; - assign dma_src_d1_inc = reg2hw.src_ptr_inc_d1.q; - assign dma_dst_d2_inc = reg2hw.dst_ptr_inc_d2.q; - assign dma_dst_d1_inc = reg2hw.dst_ptr_inc_d1.q; - - /* Sign extend flag */ - - assign sign_extend = reg2hw.sign_ext.q & ( (src_data_type[1] & ~dst_data_type[1]) | ((src_data_type[1] == dst_data_type[1]) & (src_data_type[0] & ~dst_data_type[0]))); - - /* Padding FSM conditions assignments */ - - assign idle_to_top_ex = {|reg2hw.pad_top.q == 1'b1 && dma_start == 1'b1}; - assign idle_to_left_ex = { - |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b1 && dma_start == 1'b1 - }; - assign idle_to_right_ex = { - |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 - && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) - }; - assign idle_to_bottom_ex = { - |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 - && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) - }; - assign top_ex_to_top_dn = { - dma_src_cnt_d2 == ({1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 - }; - assign top_ex_to_left_ex = { - dma_src_cnt_d2 == ({1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b1 - }; - assign top_dn_to_right_ex = { - |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) - }; - assign top_dn_to_bottom_ex = { - |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) - }; - assign top_dn_to_idle = { - |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0 - }; - assign left_ex_to_left_dn = { - dma_src_cnt_d1 == ({1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) - }; - assign left_dn_to_left_ex = { - dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({14'h0, dma_dst_cnt_du} + {11'h0, reg2hw.pad_bottom.q}) && |reg2hw.pad_right.q == 1'b0 - }; - assign left_dn_to_right_ex = { - |reg2hw.pad_right.q == 1'b1 && dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) - }; - assign left_dn_to_bottom_ex = { - |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) - }; - assign left_dn_to_idle = { - |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0 - }; - assign right_ex_to_right_dn = { - dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 - }; - assign right_ex_to_left_ex = { - dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) && dma_src_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b1 - }; - assign right_ex_to_bottom_ex = { - |reg2hw.pad_bottom.q == 1'b1 && dma_src_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + {14'h0, dma_dst_cnt_du}) && dma_src_cnt_d1 == ({14'h0, dma_dst_cnt_du}) - }; - assign right_dn_to_right_ex = { - dma_src_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + {14'h0, dma_dst_cnt_du}) && |reg2hw.pad_left.q == 1'b0 - }; - assign right_dn_to_idle = {|reg2hw.pad_bottom.q == 1'b0 && |dma_src_cnt_d2 == 1'b0}; - assign bottom_ex_to_idle = { - dma_src_cnt_d1 == {14'h0, dma_dst_cnt_du} && dma_src_cnt_d2 == {14'h0, dma_dst_cnt_du} - }; - - assign write_address = address_mode ? fifo_addr_output : write_ptr_reg; + /* Read FSM */ + dma_obiread_fsm dma_obiread_fsm_i ( + .clk_i(clk_cg), + .rst_ni, + .reg2hw_i(reg2hw), + .dma_start_i(dma_start), + .dma_done_i(dma_done), + .ext_dma_stop_i, + .read_fifo_full_i(read_fifo_full), + .read_fifo_alm_full_i(read_fifo_alm_full), + .wait_for_rx_i(wait_for_rx), + .data_in_gnt_i(data_in_gnt), + .data_in_rvalid_i(data_in_rvalid), + .data_in_rdata_i(data_in_rdata), + .fifo_input_o(read_fifo_input), + .data_in_req_o(data_in_req), + .data_in_we_o(data_in_we), + .data_in_be_o(data_in_be), + .data_in_addr_o(data_in_addr), + .read_fifo_flush_o(fifo_flush) + ); - assign wait_for_rx = |(reg2hw.slot.rx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); - assign wait_for_tx = |(reg2hw.slot.tx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); + /* Read address FSM */ + dma_obiread_addr_fsm dma_obiread_addr_fsm_i ( + .clk_i(clk_cg), + .rst_ni, + .reg2hw_i(reg2hw), + .dma_start_i(dma_start), + .ext_dma_stop_i, + .read_fifo_addr_full_i(read_addr_fifo_full), + .read_fifo_addr_alm_full_i(read_addr_fifo_alm_full), + .address_mode_i(address_mode), + .data_in_gnt_i(data_addr_in_gnt), + .data_addr_in_req_o(data_addr_in_req), + .data_addr_in_we_o(data_addr_in_we), + .data_addr_in_be_o(data_addr_in_be), + .data_addr_in_addr_o(data_addr_in_addr) + ); - assign fifo_addr_empty_check = fifo_addr_empty && address_mode; + /* DMA padding FSM */ + dma_padding_fsm dma_padding_fsm_i ( + .clk_i(clk_cg), + .rst_ni, + .reg2hw_i(reg2hw), + .dma_padding_fsm_on_i(dma_padding_fsm_on), + .dma_start_i(dma_start), + .read_fifo_empty_i(read_fifo_empty), + .write_fifo_full_i(write_fifo_full), + .write_fifo_alm_full_i(write_fifo_alm_full), + .data_read_i(read_fifo_output), + .padding_fsm_done_o(padding_fsm_done), + .write_fifo_push_o(write_fifo_push), + .read_fifo_pop_o(read_fifo_pop), + .data_write_o(write_fifo_input) + ); + + /* Write FSM */ + dma_obiwrite_fsm dma_obiwrite_fsm_i ( + .clk_i(clk_cg), + .rst_ni, + .reg2hw_i(reg2hw), + .dma_start_i(dma_start), + .write_fifo_empty_i(write_fifo_empty), + .read_addr_fifo_empty_i(read_addr_fifo_empty), + .fifo_output_i(write_fifo_output), + .wait_for_tx_i(wait_for_tx), + .address_mode_i(address_mode), + .padding_fsm_done_i(padding_fsm_done), + .fifo_addr_output_i(read_addr_fifo_output), + .data_out_gnt_i(data_out_gnt), + .data_out_req_o(data_out_req), + .data_out_we_o(data_out_we), + .data_out_be_o(data_out_be), + .data_out_addr_o(data_out_addr), + .data_out_wdata_o(data_out_wdata), + .dma_done_o(dma_done) + ); - assign fifo_alm_full = (fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); - assign fifo_addr_alm_full = (fifo_addr_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + /*_________________________________________________________________________________________________________________________________ */ - assign dma_start = (dma_state_q == DMA_STARTING); + /* FSMs instantiation */ // // Main DMA state machine @@ -393,7 +371,7 @@ module dma #( end /* Update DMA state */ - always_ff @(posedge clk_i, negedge rst_ni) begin + always_ff @(posedge clk_cg, negedge rst_ni) begin if (~rst_ni) begin dma_state_q <= DMA_READY; end else begin @@ -402,7 +380,7 @@ module dma #( end /* DMA pulse start when dma_start register is written */ - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_start + always_ff @(posedge clk_cg or negedge rst_ni) begin : proc_dma_start if (~rst_ni) begin dma_start_pending <= 1'b0; end else begin @@ -414,560 +392,8 @@ module dma #( end end - /*/ Store input data pointer and increment everytime read request is granted */ - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_in_reg - if (~rst_ni) begin - read_ptr_reg <= '0; - end else begin - if (dma_start == 1'b1) begin - read_ptr_reg <= reg2hw.src_ptr.q; - end else if (data_in_gnt == 1'b1) begin - if (dma_conf_1d == 1'b1) begin - /* Increase the pointer by the amount written in ptr_inc */ - read_ptr_reg <= read_ptr_reg + {26'h0, dma_src_d1_inc}; - end else if (dma_conf_2d == 1'b1 && pad_cnt_on == 1'b0) begin - if (read_ptr_update_sel == 1'b0) begin - if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1) begin - /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d1)*data_unit */ - read_ptr_reg <= read_ptr_reg + {9'h0, dma_src_d2_inc}; - end else begin - read_ptr_reg <= read_ptr_reg + {26'h0, dma_src_d1_inc}; /* Increment of the d1 increment (stride) */ - end - end else begin - if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1) begin - /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d2)*data_unit */ - read_ptr_reg <= src_ptr_reg; - end else begin - read_ptr_reg <= read_ptr_reg + {9'h0, dma_src_d2_inc}; /* Increment of the d1 increment (stride) */ - end - end - end - end - end - end - - /* - * Store input data pointer in source_ptr_reg and increment it every time read request is granted, - * if the d1 has finished reading and the read pointer update is set to 1'b1 - */ - - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_src_ptr_reg - if (~rst_ni) begin - src_ptr_reg <= '0; - end else begin - if (dma_start == 1'b1) begin - src_ptr_reg <= reg2hw.src_ptr.q + {26'h0, dma_src_d1_inc}; - end else if (data_in_gnt == 1'b1 && dma_conf_2d == 1'b1 && pad_cnt_on == 1'b0 && read_ptr_update_sel == 1'b1 && - (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du} && |dma_src_cnt_d2 == 1'b1)) begin - src_ptr_reg <= src_ptr_reg + {26'h0, dma_src_d1_inc}; - end - end - end - - // Store address data pointer and increment everytime read request is granted - only in address mode - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_addr_reg - if (~rst_ni) begin - addr_ptr_reg <= '0; - end else begin - if (dma_start == 1'b1 && address_mode) begin - addr_ptr_reg <= reg2hw.addr_ptr.q; - end else if (data_addr_in_gnt == 1'b1 && address_mode) begin - addr_ptr_reg <= addr_ptr_reg + 32'h4; //always continuos in 32b - end - end - end - - // Only update read_ptr_valid_reg when the data is stored in the fifo. - // Since every input grant is followed by a rvalid, the read_ptr_valid_reg is a mere sample of the read_ptr_reg - // synched with the rvalid signal. - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_valid_in_reg - if (~rst_ni) begin - read_ptr_valid_reg <= '0; - end else begin - if (dma_start == 1'b1) begin - read_ptr_valid_reg <= reg2hw.src_ptr.q; - end else if (data_in_rvalid == 1'b1) begin - read_ptr_valid_reg <= read_ptr_reg; - end - end - end - - // Store output data pointer and increment everytime write request is granted - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_out_reg - if (~rst_ni) begin - write_ptr_reg <= '0; - end else begin - if (dma_start == 1'b1) begin - write_ptr_reg <= reg2hw.dst_ptr.q; - end else if (data_out_gnt == 1'b1) begin - if (dma_conf_1d == 1'b1) begin - write_ptr_reg <= write_ptr_reg + {26'h0, dma_dst_d1_inc}; - end else if (dma_conf_2d == 1'b1) begin - if (dma_dst_cnt_d1 == {14'h0, dma_dst_cnt_du}) begin - // In this case, the d1 is finished, so we need to increment the pointer by sizeof(d1)*data_unit*strides - write_ptr_reg <= write_ptr_reg + {9'h0, dma_dst_d2_inc}; - end else begin - write_ptr_reg <= write_ptr_reg + {26'h0, dma_dst_d1_inc}; // Increment just of one du, since we need to increase the 1d - end - end - end - end - end - - // Store dma transfer size and decrement it everytime input data rvalid is asserted. - // Perform additional checks for 2D DMA - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_src_cnt_reg - if (~rst_ni) begin - dma_src_cnt_d1 <= '0; - dma_src_cnt_d2 <= '0; - end else begin - if (dma_start == 1'b1) begin - dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; - dma_src_cnt_d2 <= {1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_top.q} + {11'h0, reg2hw.pad_bottom.q}; - end else if (data_in_gnt == 1'b1) begin - if (dma_conf_1d == 1'b1) begin - // 1D case - dma_src_cnt_d1 <= dma_src_cnt_d1 - {14'h0, dma_src_cnt_du}; - end else if (dma_conf_2d == 1'b1) begin - // 2D case - if (dma_src_cnt_d1 == {14'h0, dma_src_cnt_du}) begin - // In this case, the d1 is finished, so we need to decrement the d2 size and reset the d2 size - dma_src_cnt_d2 <= dma_src_cnt_d2 - {14'h0, dma_src_cnt_du}; - dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; - end else begin - // In this case, the d1 isn't finished, so we need to decrement the d1 size - dma_src_cnt_d1 <= dma_src_cnt_d1 - {14'h0, dma_src_cnt_du}; - end - end - end - end - end - - // Store dma transfer size and decrement it everytime input data write request is granted. - // The need for two separate counters for reading and writing operations is due to the lack of synchronization between them. - // Since the check on the read side is done on the rvalid signal, we need only an additional counter, for d1. - // Performs additional checks for 2D DMA. - - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_dst_cnt_reg - if (~rst_ni) begin - dma_dst_cnt_d1 <= '0; - end else begin - if (dma_start == 1'b1) begin - dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; - end else if (data_out_gnt == 1'b1) begin - if (dma_conf_1d == 1'b1) begin - // 1D case - dma_dst_cnt_d1 <= dma_dst_cnt_d1 - {14'h0, dma_dst_cnt_du}; - end else if (dma_conf_2d == 1'b1) begin - // 2D case - if (dma_dst_cnt_d1 == {14'h0, dma_dst_cnt_du}) begin - // In this case, the d1 is finished, so we need to reset the d2 size - dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; - end else begin - // In this case, the d1 isn't finished, so we need to decrement the d1 size - dma_dst_cnt_d1 <= dma_dst_cnt_d1 - {14'h0, dma_dst_cnt_du}; - end - end - end - end - end - - // Store dma transfer size for the address port - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_addr_cnt_reg - if (~rst_ni) begin - dma_addr_cnt <= '0; - end else begin - if (dma_start == 1'b1 && address_mode) begin - dma_addr_cnt <= {16'h0, reg2hw.size_d1.q}; - end else if (data_addr_in_gnt == 1'b1 && address_mode) begin - dma_addr_cnt <= dma_addr_cnt - 32'h4; //address always 32b - end - end - end - - always_comb begin - case (dst_data_type) - DMA_DATA_TYPE_WORD: dma_dst_cnt_du = 3'h4; - DMA_DATA_TYPE_HALF_WORD: dma_dst_cnt_du = 3'h2; - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: dma_dst_cnt_du = 3'h1; - endcase - end - - always_comb begin - case (src_data_type) - DMA_DATA_TYPE_WORD: dma_src_cnt_du = 3'h4; - DMA_DATA_TYPE_HALF_WORD: dma_src_cnt_du = 3'h2; - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: dma_src_cnt_du = 3'h1; - endcase - end - - always_comb begin : proc_byte_enable_out - case (dst_data_type) // Data type 00 Word, 01 Half word, 11,10 byte - DMA_DATA_TYPE_WORD: byte_enable_out = 4'b1111; // Writing a word (32 bits) - - DMA_DATA_TYPE_HALF_WORD: begin // Writing a half-word (16 bits) - case (write_address[1]) - 1'b0: byte_enable_out = 4'b0011; - 1'b1: byte_enable_out = 4'b1100; - endcase - ; // case(write_address[1:0]) - end - - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: begin // Writing a byte (8 bits) - case (write_address[1:0]) - 2'b00: byte_enable_out = 4'b0001; - 2'b01: byte_enable_out = 4'b0010; - 2'b10: byte_enable_out = 4'b0100; - 2'b11: byte_enable_out = 4'b1000; - endcase - ; // case(write_address[1:0]) - end - endcase - ; // case (dst_data_type) - end - - // Output data shift - always_comb begin : proc_output_data - - data_out_wdata[7:0] = fifo_output[7:0]; - data_out_wdata[15:8] = fifo_output[15:8]; - data_out_wdata[23:16] = fifo_output[23:16]; - data_out_wdata[31:24] = fifo_output[31:24]; - - case (write_address[1:0]) - 2'b00: begin - if (sign_extend) begin - case ({ - src_data_type, dst_data_type - }) - {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; - { - DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD - } : - data_out_wdata[31:16] = {16{fifo_output[15]}}; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD - } : - data_out_wdata[31:8] = {24{fifo_output[7]}}; - {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD - } : - data_out_wdata[15:8] = {8{fifo_output[7]}}; - default: ; - endcase - end else begin - case ({ - src_data_type, dst_data_type - }) - {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; - {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD} : data_out_wdata[31:16] = 16'b0; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD - } : - data_out_wdata[31:8] = 24'b0; - {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD - } : - data_out_wdata[15:8] = 8'b0; - default: ; - endcase - end - end - 2'b01: data_out_wdata[15:8] = fifo_output[7:0]; // Writing a byte, no need for sign extension - 2'b10: begin // Writing a half-word or a byte - data_out_wdata[23:16] = fifo_output[7:0]; - data_out_wdata[31:24] = fifo_output[15:8]; - - if (sign_extend) begin - case ({ - src_data_type, dst_data_type - }) - {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD - } : - data_out_wdata[31:24] = {8{fifo_output[7]}}; - default: ; - endcase - end else begin - case ({ - src_data_type, dst_data_type - }) - {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; - { - DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD - }, { - DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD - } : - data_out_wdata[31:24] = 8'b0; - default: ; - endcase - end - end - 2'b11: - data_out_wdata[31:24] = fifo_output[7:0]; // Writing a byte, no need for sign extension - endcase - end - - - assign fifo_addr_input = data_addr_in_rdata; //never misaligned, always 32b - - // Input data shift: shift the input data to be on the LSB of the fifo - always_comb begin : proc_input_data - - if (pad_fifo_on) begin - fifo_input = 32'h0; - end else begin - fifo_input[7:0] = data_in_rdata[7:0]; - fifo_input[15:8] = data_in_rdata[15:8]; - fifo_input[23:16] = data_in_rdata[23:16]; - fifo_input[31:24] = data_in_rdata[31:24]; - - case (read_ptr_valid_reg[1:0]) - 2'b00: ; - 2'b01: fifo_input[7:0] = data_in_rdata[15:8]; - - 2'b10: begin - fifo_input[7:0] = data_in_rdata[23:16]; - fifo_input[15:8] = data_in_rdata[31:24]; - end - - 2'b11: fifo_input[7:0] = data_in_rdata[31:24]; - endcase - end - end - - // FSM state update - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_fsm_state - if (~rst_ni) begin - dma_read_fsm_state <= DMA_READ_FSM_IDLE; - dma_write_fsm_state <= DMA_WRITE_FSM_IDLE; - dma_read_addr_fsm_state <= DMA_READ_FSM_IDLE; - outstanding_req <= '0; - outstanding_addr_req <= '0; - end else begin - dma_read_fsm_state <= dma_read_fsm_n_state; - dma_write_fsm_state <= dma_write_fsm_n_state; - dma_read_addr_fsm_state <= dma_read_addr_fsm_n_state; - - outstanding_req <= outstanding_req + (data_in_req && data_in_gnt) - data_in_rvalid; - - if (address_mode) - outstanding_addr_req <= outstanding_addr_req + (data_addr_in_req && data_addr_in_gnt) - data_addr_in_rvalid; - - end - end - - /* Padding synchronization signal generation - * When the pad_fifo_on is asserted, this logic mimics the behaviour of the data_in_rvalid and data_in_gnt signals - * coming from the memory. This is done in order to keep the read/write operations working even without an - * actual response from memory, reducing power consumptionnby avoiding unnecessary memory accesses. - */ - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_pad_sync_signal - if (~rst_ni) begin - data_in_rvalid_virt <= 1'b0; - data_in_rvalid_virt_n <= 1'b1; - data_in_rvalid_virt_n_n <= 1'b0; - data_in_gnt_virt <= 1'b1; - data_in_gnt_virt_n <= 1'b0; - data_in_gnt_virt_n_n <= 1'b0; - end else begin - if (data_in_req == 1'b1 && pad_fifo_on == 1'b1) begin - data_in_rvalid_virt <= data_in_rvalid_virt_n; - data_in_rvalid_virt_n <= data_in_rvalid_virt_n_n; - data_in_rvalid_virt_n_n <= data_in_rvalid; - data_in_gnt_virt <= data_in_gnt_virt_n; - data_in_gnt_virt_n <= data_in_gnt_virt_n_n; - data_in_gnt_virt_n_n <= data_in_gnt; - end else begin - data_in_rvalid_virt <= 1'b0; - data_in_rvalid_virt_n <= 1'b1; - data_in_rvalid_virt_n_n <= 1'b0; - data_in_gnt_virt <= 1'b1; - data_in_gnt_virt_n <= 1'b0; - data_in_gnt_virt_n_n <= 1'b0; - end - end - end - - // Padding FSM state update - always_ff @(posedge clk_i or negedge rst_ni) begin : proc_pad_state - if (~rst_ni) begin - pad_state_q <= PAD_IDLE; - pad_state_x <= PAD_IDLE; - end else if (dma_conf_2d == 1'b1) begin - if (dma_start == 1'b1 && |reg2hw.pad_top.q == 1'b1) begin - pad_state_q <= TOP_PAD_EXEC; - pad_state_x <= TOP_PAD_EXEC; - end else if (dma_start == 1'b1 && |reg2hw.pad_left.q == 1'b1) begin - pad_state_q <= LEFT_PAD_EXEC; - pad_state_x <= LEFT_PAD_EXEC; - end else begin - pad_state_x <= pad_state_d; - if (data_in_rvalid == 1'b1) begin - pad_state_q <= pad_state_x; - end - end - end - end - - // Pad fifo flag logic - always_comb begin : proc_pad_fifo_on - if (dma_conf_2d == 1'b1) begin - case (pad_state_q) - TOP_PAD_EXEC, LEFT_PAD_EXEC, RIGHT_PAD_EXEC, BOTTOM_PAD_EXEC: pad_fifo_on = 1'b1; - - default: pad_fifo_on = 1'b0; - endcase - end else begin - pad_fifo_on = 1'b0; - end - end - - // Pad counter flag logic - always_comb begin : proc_pad_cnt_on - case (pad_state_q) - PAD_IDLE: begin - if (idle_to_right_ex || idle_to_bottom_ex || idle_to_left_ex || idle_to_top_ex) begin - pad_cnt_on = 1'b1; - end else begin - pad_cnt_on = pad_fifo_on; - end - end - - TOP_PAD_DONE: begin - if (top_dn_to_right_ex) begin - pad_cnt_on = 1'b1; - end else begin - pad_cnt_on = pad_fifo_on; - end - end - - LEFT_PAD_DONE: begin - if (left_dn_to_right_ex) begin - pad_cnt_on = 1'b1; - end else begin - pad_cnt_on = pad_fifo_on; - end - end - - RIGHT_PAD_DONE: begin - if (right_dn_to_right_ex) begin - pad_cnt_on = 1'b1; - end else begin - pad_cnt_on = pad_fifo_on; - end - end - - RIGHT_PAD_EXEC: begin - if (right_ex_to_right_dn || right_ex_to_left_ex) begin - pad_cnt_on = 1'b0; - end else begin - pad_cnt_on = pad_fifo_on; - end - end - - default: pad_cnt_on = pad_fifo_on; - endcase - end - - // Padding FSM logic - always_comb begin : proc_pad_fsm_logic - if (dma_conf_1d == 1'b1) begin - pad_state_d = PAD_IDLE; - end else begin - if (dma_start == 1'b1 && |reg2hw.pad_top.q == 1'b1) begin - pad_state_d = TOP_PAD_EXEC; - end else if (dma_start == 1'b1 && |reg2hw.pad_left.q == 1'b1) begin - pad_state_d = LEFT_PAD_EXEC; - end else begin - pad_state_d = pad_state_x; - end - end - - unique case (pad_state_x) - PAD_IDLE: begin - if (idle_to_top_ex) begin - pad_state_d = TOP_PAD_EXEC; - end else if (idle_to_left_ex) begin - pad_state_d = LEFT_PAD_EXEC; - end else if (idle_to_right_ex) begin - pad_state_d = RIGHT_PAD_EXEC; - end else if (idle_to_bottom_ex) begin - pad_state_d = BOTTOM_PAD_EXEC; - end - end - - TOP_PAD_EXEC: begin - if (top_ex_to_left_ex) begin - pad_state_d = LEFT_PAD_EXEC; - end else if (top_ex_to_top_dn) begin - pad_state_d = TOP_PAD_DONE; - end - end - TOP_PAD_DONE: begin - if (top_dn_to_right_ex) begin - pad_state_d = RIGHT_PAD_EXEC; - end else if (top_dn_to_bottom_ex) begin - pad_state_d = BOTTOM_PAD_EXEC; - end else if (top_dn_to_idle) begin - pad_state_d = PAD_IDLE; - end - end - LEFT_PAD_EXEC: begin - if (left_ex_to_left_dn) begin - pad_state_d = LEFT_PAD_DONE; - end - end - LEFT_PAD_DONE: begin - if (left_dn_to_right_ex) begin - pad_state_d = RIGHT_PAD_EXEC; - end else if (left_dn_to_bottom_ex) begin - pad_state_d = BOTTOM_PAD_EXEC; - end else if (left_dn_to_left_ex) begin - pad_state_d = LEFT_PAD_EXEC; - end else if (left_dn_to_idle) begin - pad_state_d = PAD_IDLE; - end - end - RIGHT_PAD_EXEC: begin - if (right_ex_to_right_dn) begin - pad_state_d = RIGHT_PAD_DONE; - end else if (right_ex_to_left_ex) begin - pad_state_d = LEFT_PAD_EXEC; - end else if (right_ex_to_bottom_ex) begin - pad_state_d = BOTTOM_PAD_EXEC; - end - end - RIGHT_PAD_DONE: begin - if (right_dn_to_idle) begin - pad_state_d = PAD_IDLE; - end else if (right_dn_to_right_ex) begin - pad_state_d = RIGHT_PAD_EXEC; - end - end - BOTTOM_PAD_EXEC: begin - if (bottom_ex_to_idle) begin - pad_state_d = PAD_IDLE; - end - end - endcase - end - /* Transaction IFR update */ - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_transaction_ifr + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_ff_transaction_ifr if (~rst_ni) begin transaction_ifr <= '0; end else if (reg2hw.interrupt_en.transaction_done.q == 1'b1) begin @@ -982,7 +408,7 @@ module dma #( end /* Delayed transaction interrupt signals */ - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_intr + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_ff_intr if (~rst_ni) begin dma_done_intr_n <= '0; end else begin @@ -991,7 +417,7 @@ module dma #( end /* Window IFR update */ - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_window_ifr + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_ff_window_ifr if (~rst_ni) begin window_ifr <= '0; end else if (reg2hw.interrupt_en.window_done.q == 1'b1) begin @@ -1006,7 +432,7 @@ module dma #( end /* Delayed window interrupt signals */ - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_window_intr + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_ff_window_intr if (~rst_ni) begin dma_window_intr_n <= '0; end else begin @@ -1014,211 +440,8 @@ module dma #( end end - // Read master FSM - always_comb begin : proc_dma_read_fsm_logic - - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - - data_in_req = '0; - data_in_we = '0; - data_in_be = '0; - data_in_addr = '0; - - fifo_flush = 1'b0; - - unique case (dma_read_fsm_state) - - DMA_READ_FSM_IDLE: begin - // Wait for start signal - if (dma_start == 1'b1) begin - dma_read_fsm_n_state = DMA_READ_FSM_ON; - fifo_flush = 1'b1; - end else begin - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - end - end - // Read one word - DMA_READ_FSM_ON: begin - // If all input data read exit - if (ext_dma_stop_i == 1'b0) begin - if (dma_conf_1d == 1'b1) begin - // 1D DMA case - if (|dma_src_cnt_d1 == 1'b0) begin - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - end else begin - dma_read_fsm_n_state = DMA_READ_FSM_ON; - // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). - if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin - data_in_req = 1'b1; - data_in_we = 1'b0; - data_in_be = 4'b1111; // always read all bytes - data_in_addr = read_ptr_reg; - end - end - end else if (dma_conf_2d == 1'b1) begin - // 2D DMA case: exit only if both 1d and 2d counters are at 0 - if (dma_src_cnt_d1 == {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q} && |dma_src_cnt_d2 == 1'b0) begin - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - end else begin - // The read operation is the same in both cases - dma_read_fsm_n_state = DMA_READ_FSM_ON; - // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). - if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin - data_in_req = 1'b1; - data_in_we = 1'b0; - data_in_be = 4'b1111; // always read all bytes - data_in_addr = read_ptr_reg; - end - end - end - end else begin - dma_read_fsm_n_state = DMA_READ_FSM_IDLE; - end - end - endcase - end - - // Read address master FSM - always_comb begin : proc_dma_addr_read_fsm_logic - - dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; - - data_addr_in_req = '0; - data_addr_in_we = '0; - data_addr_in_be = '0; - data_addr_in_addr = '0; - - fifo_addr_flush = 1'b0; - - unique case (dma_read_addr_fsm_state) - - DMA_READ_FSM_IDLE: begin - // Wait for start signal - if (dma_start == 1'b1 && address_mode) begin - dma_read_addr_fsm_n_state = DMA_READ_FSM_ON; - fifo_addr_flush = 1'b1; - end else begin - dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; - end - end - // Read one word - DMA_READ_FSM_ON: begin - // If all input data read exit - if (|dma_addr_cnt == 1'b0) begin - dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; - end else begin - dma_read_addr_fsm_n_state = DMA_READ_FSM_ON; - // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). - if (fifo_addr_full == 1'b0 && fifo_addr_alm_full == 1'b0) begin - data_addr_in_req = 1'b1; - data_addr_in_we = 1'b0; - data_addr_in_be = 4'b1111; // always read all bytes - data_addr_in_addr = addr_ptr_reg; - end - end - end - endcase - end - - // Write master FSM - always_comb begin : proc_dma_write_fsm_logic - - dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; - dma_done = 1'b0; - - data_out_req = '0; - data_out_we = '0; - data_out_be = '0; - data_out_addr = '0; - - unique case (dma_write_fsm_state) - - DMA_WRITE_FSM_IDLE: begin - // Wait for start signal - if (dma_start == 1'b1) begin - dma_write_fsm_n_state = DMA_WRITE_FSM_ON; - end else begin - dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; - end - end - // Read one word - DMA_WRITE_FSM_ON: begin - // If all input data read exit - if (fifo_empty == 1'b1 && dma_read_fsm_state == DMA_READ_FSM_IDLE) begin - dma_done = outstanding_req == '0 && outstanding_addr_req == '0; - // If all input data has been read (dma_read_fsm_state == DMA_READ_FSM_IDLE, set when all data has been read) - // and all requests have been granted, (outstanding_req == 0) then we are done - dma_write_fsm_n_state = dma_done ? DMA_WRITE_FSM_IDLE : DMA_WRITE_FSM_ON; - end else begin - dma_write_fsm_n_state = DMA_WRITE_FSM_ON; - // Wait if fifo is empty or if the SPI TX is not ready for new data (only in SPI mode 2). - if (fifo_empty == 1'b0 && wait_for_tx == 1'b0 && fifo_addr_empty_check == 1'b0) begin - data_out_req = 1'b1; - data_out_we = 1'b1; - data_out_be = byte_enable_out; - data_out_addr = write_address; - end - end - end - endcase - end - - fifo_v3 #( - .DEPTH(FIFO_DEPTH) - ) dma_fifo_i ( - .clk_i, - .rst_ni, - .flush_i(fifo_flush), - .testmode_i(1'b0), - // status flags - .full_o(fifo_full), - .empty_o(fifo_empty), - .usage_o(fifo_usage), - // as long as the queue is not full we can push new data - .data_i(fifo_input), - .push_i(data_in_rvalid), - // as long as the queue is not empty we can pop new elements - .data_o(fifo_output), - .pop_i(data_out_gnt) - ); - - fifo_v3 #( - .DEPTH(FIFO_DEPTH) - ) dma_addr_fifo_i ( - .clk_i, - .rst_ni, - .flush_i(fifo_addr_flush), - .testmode_i(1'b0), - // status flags - .full_o(fifo_addr_full), - .empty_o(fifo_addr_empty), - .usage_o(fifo_addr_usage), - // as long as the queue is not full we can push new data - .data_i(fifo_addr_input), - .push_i(data_addr_in_rvalid), - // as long as the queue is not empty we can pop new elements - .data_o(fifo_addr_output), - .pop_i(data_out_gnt && address_mode) - ); - dma_reg_top #( - .reg_req_t(reg_req_t), - .reg_rsp_t(reg_rsp_t) - ) dma_reg_top_i ( - .clk_i, - .rst_ni, - .reg_req_i, - .reg_rsp_o, - .reg2hw, - .hw2reg, - .devmode_i(1'b1) - ); - - // WINDOW EVENT - // Count gnt write transaction and generate event pulse if WINDOW_SIZE is reached - assign dma_window_event = |reg2hw.window_size.q & data_out_gnt & (window_counter + 'h1 >= {19'h0, reg2hw.window_size.q}); - - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_dma_window_cnt + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_dma_window_cnt if (~rst_ni) begin window_counter <= 'h0; end else begin @@ -1251,7 +474,7 @@ module dma #( // update window_done flag // set on dma_window_event // reset on read - always_ff @(posedge clk_i, negedge rst_ni) begin : proc_dma_window_done + always_ff @(posedge clk_cg, negedge rst_ni) begin : proc_dma_window_done if (~rst_ni) begin window_done_q <= 1'b0; end else begin @@ -1260,5 +483,84 @@ module dma #( end end + always_ff @(posedge clk_cg, negedge rst_ni) begin + if (~rst_ni) begin + dma_padding_fsm_on <= 1'b0; + end else begin + if (dma_start == 1'b1) begin + dma_padding_fsm_on <= 1'b1; + end else if (dma_done == 1'b1) begin + dma_padding_fsm_on <= 1'b0; + end + end + end + + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + assign dma_done_o = dma_done; + assign dma_start = (dma_state_q == DMA_STARTING); + + /* OBI signals */ + assign dma_read_req_o.req = data_in_req; + assign dma_read_req_o.we = data_in_we; + assign dma_read_req_o.be = data_in_be; + assign dma_read_req_o.addr = data_in_addr; + assign dma_read_req_o.wdata = 32'h0; + + assign data_in_gnt = dma_read_resp_i.gnt; + assign data_in_rvalid = dma_read_resp_i.rvalid; + assign data_in_rdata = dma_read_resp_i.rdata; + + assign dma_addr_req_o.req = data_addr_in_req; + assign dma_addr_req_o.we = data_addr_in_we; + assign dma_addr_req_o.be = data_addr_in_be; + assign dma_addr_req_o.addr = data_addr_in_addr; + assign dma_addr_req_o.wdata = 32'h0; + + assign data_addr_in_gnt = dma_addr_resp_i.gnt; + assign data_addr_in_rvalid = dma_addr_resp_i.rvalid; + assign data_addr_in_rdata = dma_addr_resp_i.rdata; + + assign dma_write_req_o.req = data_out_req; + assign dma_write_req_o.we = data_out_we; + assign dma_write_req_o.be = data_out_be; + assign dma_write_req_o.addr = data_out_addr; + assign dma_write_req_o.wdata = data_out_wdata; + + assign data_out_gnt = dma_write_resp_i.gnt; + assign data_out_rvalid = dma_write_resp_i.rvalid; + assign data_out_rdata = dma_write_resp_i.rdata; + + /* FIFO signals */ + assign write_fifo_pop = (dma_state_q == DMA_RUNNING) & data_out_gnt; // @TOD0: check if this is correct + + assign dma_done_intr = transaction_ifr; + assign dma_done_intr_o = dma_done_intr_n; + assign dma_window_intr = window_ifr; + assign dma_window_intr_o = dma_window_intr_n; + + assign hw2reg.transaction_ifr.d = transaction_ifr; + assign hw2reg.window_ifr.d = window_ifr; + + assign hw2reg.status.ready.d = (dma_state_q == DMA_READY); + assign hw2reg.status.window_done.d = window_done_q; + + assign circular_mode = reg2hw.mode.q == 1; + assign address_mode = reg2hw.mode.q == 2; + + assign wait_for_rx = |(reg2hw.slot.rx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); + assign wait_for_tx = |(reg2hw.slot.tx_trigger_slot.q[SLOT_NUM-1:0] & (~trigger_slot_i)); + + assign read_fifo_alm_full = (read_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + assign read_addr_fifo_alm_full = (read_addr_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + assign write_fifo_alm_full = (write_fifo_usage == LastFifoUsage[Addr_Fifo_Depth-1:0]); + + + // WINDOW EVENT + // Count gnt write transaction and generate event pulse if WINDOW_SIZE is reached + assign dma_window_event = |reg2hw.window_size.q & data_out_gnt & (window_counter + 'h1 >= {19'h0, reg2hw.window_size.q}); endmodule : dma diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_addr_fsm.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_addr_fsm.sv new file mode 100644 index 00000000..7eb3e635 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_addr_fsm.sv @@ -0,0 +1,168 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Reading FSM for DMA channel in address mode, controls the input FIFO. + */ + +module dma_obiread_addr_fsm + import dma_reg_pkg::*; +#( +) ( + input logic clk_i, + input logic rst_ni, + input dma_reg2hw_t reg2hw_i, + input logic dma_start_i, + input logic ext_dma_stop_i, + input logic read_fifo_addr_full_i, + input logic read_fifo_addr_alm_full_i, + input logic address_mode_i, + input logic data_in_gnt_i, + output logic data_addr_in_req_o, + output logic data_addr_in_we_o, + output logic [3:0] data_addr_in_be_o, + output logic [31:0] data_addr_in_addr_o +); + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + + import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Registers */ + dma_reg2hw_t reg2hw; + + /* Control signals */ + logic dma_start; + logic ext_dma_stop; + + enum logic { + DMA_READ_FSM_IDLE, + DMA_READ_FSM_ON + } + dma_read_addr_fsm_state, dma_read_addr_fsm_n_state; + + logic fifo_addr_full; + logic fifo_addr_alm_full; + + logic data_addr_in_gnt; + logic data_addr_in_req; + logic data_addr_in_we; + logic [3:0] data_addr_in_be; + logic [31:0] data_addr_in_addr; + + logic address_mode; + logic [31:0] addr_ptr_reg; + logic [31:0] dma_addr_cnt; + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + // Store address data pointer and increment everytime read request is granted - only in address mode + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_addr_reg + if (~rst_ni) begin + addr_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1 && address_mode) begin + addr_ptr_reg <= reg2hw.addr_ptr.q; + end else if (data_addr_in_gnt == 1'b1 && address_mode) begin + addr_ptr_reg <= addr_ptr_reg + 32'h4; //always continuos in 32b + end + end + end + + // Store dma transfer size for the address port + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_addr_cnt_reg + if (~rst_ni) begin + dma_addr_cnt <= '0; + end else begin + if (dma_start == 1'b1 && address_mode) begin + dma_addr_cnt <= {16'h0, reg2hw.size_d1.q}; + end else if (data_addr_in_gnt == 1'b1 && address_mode) begin + dma_addr_cnt <= dma_addr_cnt - 1; //address always 32b + end + end + end + + // FSM state update + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_fsm_state + if (~rst_ni) begin + dma_read_addr_fsm_state <= DMA_READ_FSM_IDLE; + end else begin + dma_read_addr_fsm_state <= dma_read_addr_fsm_n_state; + end + end + + // Read address master FSM + always_comb begin : proc_dma_addr_read_fsm_logic + + dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; + + data_addr_in_req = '0; + data_addr_in_we = '0; + data_addr_in_be = '0; + data_addr_in_addr = '0; + + + unique case (dma_read_addr_fsm_state) + + DMA_READ_FSM_IDLE: begin + // Wait for start signal + if (dma_start == 1'b1 && address_mode) begin + dma_read_addr_fsm_n_state = DMA_READ_FSM_ON; + end else begin + dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; + end + end + // Read one word + DMA_READ_FSM_ON: begin + if (ext_dma_stop == 1'b0) begin + // If all input data read exit + if (|dma_addr_cnt == 1'b0) begin + dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + dma_read_addr_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). + if (fifo_addr_full == 1'b0 && fifo_addr_alm_full == 1'b0) begin + data_addr_in_req = 1'b1; + data_addr_in_we = 1'b0; + data_addr_in_be = 4'b1111; // always read all bytes + data_addr_in_addr = addr_ptr_reg; + end + end + end else begin + dma_read_addr_fsm_n_state = DMA_READ_FSM_IDLE; + end + end + endcase + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + /* Renaming */ + assign address_mode = address_mode_i; + assign reg2hw = reg2hw_i; + assign data_addr_in_gnt = data_in_gnt_i; + assign fifo_addr_full = read_fifo_addr_full_i; + assign fifo_addr_alm_full = read_fifo_addr_alm_full_i; + assign dma_start = dma_start_i; + assign ext_dma_stop = ext_dma_stop_i; + assign data_addr_in_be_o = data_addr_in_be; + assign data_addr_in_addr_o = data_addr_in_addr; + assign data_addr_in_req_o = data_addr_in_req; + assign data_addr_in_we_o = data_addr_in_we; + + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_fsm.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_fsm.sv new file mode 100644 index 00000000..15103796 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiread_fsm.sv @@ -0,0 +1,313 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Reading FSM for DMA channel, controls the input FIFO. + */ + +module dma_obiread_fsm + import dma_reg_pkg::*; +#( +) ( + input logic clk_i, + input logic rst_ni, + input dma_reg2hw_t reg2hw_i, + input logic dma_start_i, + input logic dma_done_i, + input logic ext_dma_stop_i, + input logic read_fifo_full_i, + input logic read_fifo_alm_full_i, + input logic wait_for_rx_i, + input logic data_in_gnt_i, + input logic data_in_rvalid_i, + input logic [31:0] data_in_rdata_i, + + output logic [31:0] fifo_input_o, + output logic data_in_req_o, + output logic data_in_we_o, + output logic [3:0] data_in_be_o, + output logic [31:0] data_in_addr_o, + output logic read_fifo_flush_o +); + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + + import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Registers */ + dma_reg2hw_t reg2hw; + + enum logic { + DMA_READ_FSM_IDLE, + DMA_READ_FSM_ON + } + dma_read_fsm_state, dma_read_fsm_n_state; + + logic data_in_gnt; + logic fifo_full; + logic fifo_alm_full; + logic fifo_flush; + logic dma_start; + logic ext_dma_stop; + logic read_ptr_update_sel; + logic dma_conf_1d; + logic dma_conf_2d; + logic data_in_rvalid; + + logic wait_for_rx; + + logic [16:0] dma_src_cnt_d1; + logic [16:0] dma_src_cnt_d2; + + logic [31:0] trsp_src_ptr_reg; + logic [31:0] read_ptr_reg; + + logic data_in_req; + logic data_in_we; + logic [3:0] data_in_be; + logic [31:0] data_in_addr; + logic [31:0] data_in_rdata; + + logic [31:0] read_ptr_valid_reg; + logic [31:0] dma_src_d1_inc; + logic [31:0] dma_src_d2_inc; + + /* FIFO signals */ + logic [31:0] fifo_input; + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + /* Sign extension of the increments */ + always_comb begin + dma_src_d1_inc = {{26{reg2hw.src_ptr_inc_d1.q[5]}}, reg2hw.src_ptr_inc_d1.q}; + dma_src_d2_inc = {{9{reg2hw.src_ptr_inc_d2.q[22]}}, reg2hw.src_ptr_inc_d2.q}; + end + + /* Counters for the reading fsm */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_src_cnt_reg + if (~rst_ni) begin + dma_src_cnt_d1 <= '0; + dma_src_cnt_d2 <= '0; + end else begin + if (dma_start == 1'b1) begin + dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q}; + dma_src_cnt_d2 <= {1'h0, reg2hw.size_d2.q}; + end else if (dma_done_i == 1'b1) begin + dma_src_cnt_d1 <= '0; + dma_src_cnt_d2 <= '0; + end else if (data_in_gnt == 1'b1) begin + if (dma_conf_1d == 1'b1) begin + // 1D case + dma_src_cnt_d1 <= dma_src_cnt_d1 - 1; + end else if (dma_conf_2d == 1'b1) begin + // 2D case + if (dma_src_cnt_d1 == 1) begin + // In this case, the d1 is finished, so we need to decrement the d2 size and reset the d2 size + dma_src_cnt_d2 <= dma_src_cnt_d2 - 1; + dma_src_cnt_d1 <= {1'h0, reg2hw.size_d1.q}; + end else begin + // In this case, the d1 isn't finished, so we need to decrement the d1 size + dma_src_cnt_d1 <= dma_src_cnt_d1 - 1; + end + end + end + end + end + + /* + * Store input data pointer in source_ptr_reg and increment it every time read request is granted, + * if the d1 has finished reading and the read pointer update is set to 1'b1 + */ + + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_src_ptr_reg + if (~rst_ni) begin + trsp_src_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + trsp_src_ptr_reg <= reg2hw.src_ptr.q + dma_src_d1_inc; + end else if (data_in_gnt == 1'b1 && dma_conf_2d == 1'b1 && read_ptr_update_sel == 1'b1 && + (dma_src_cnt_d1 == 1 && |dma_src_cnt_d2 == 1'b1)) begin + trsp_src_ptr_reg <= trsp_src_ptr_reg + dma_src_d1_inc; + end + end + end + + /* Store input data pointer and increment everytime read request is granted */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_in_reg + if (~rst_ni) begin + read_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + read_ptr_reg <= reg2hw.src_ptr.q; + end else if (data_in_gnt == 1'b1) begin + if (dma_conf_1d == 1'b1) begin + /* Increase the pointer by the amount written in ptr_inc */ + read_ptr_reg <= read_ptr_reg + dma_src_d1_inc; + end else if (dma_conf_2d == 1'b1) begin + if (read_ptr_update_sel == 1'b0) begin + if (dma_src_cnt_d1 == 1 && |dma_src_cnt_d2 == 1'b1) begin + /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d1)*data_unit */ + read_ptr_reg <= read_ptr_reg + dma_src_d2_inc; + end else begin + read_ptr_reg <= read_ptr_reg + dma_src_d1_inc; /* Increment of the d1 increment (stride) */ + end + end else begin + /* In this case, perform the transposition */ + if (dma_src_cnt_d1 == 1 && |dma_src_cnt_d2 == 1'b1) begin + /* In this case, the d1 is almost finished, so we need to increment the pointer by sizeof(d1)*data_unit */ + read_ptr_reg <= trsp_src_ptr_reg; + end else begin + read_ptr_reg <= read_ptr_reg + dma_src_d2_inc; /* Increment of the d2 increment (stride) */ + end + end + end + end + end + end + + // FSM state update + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_fsm_state + if (~rst_ni) begin + dma_read_fsm_state <= DMA_READ_FSM_IDLE; + end else begin + dma_read_fsm_state <= dma_read_fsm_n_state; + end + end + + // Read master FSM + always_comb begin : proc_dma_read_fsm_logic + + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + + data_in_req = '0; + data_in_we = '0; + data_in_be = '0; + data_in_addr = '0; + + fifo_flush = 1'b0; + + unique case (dma_read_fsm_state) + + DMA_READ_FSM_IDLE: begin + // Wait for start signal + if (dma_start == 1'b1) begin + dma_read_fsm_n_state = DMA_READ_FSM_ON; + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end + end + // Read one word + DMA_READ_FSM_ON: begin + // If all input data read exit + if (ext_dma_stop == 1'b0) begin + if (dma_conf_1d == 1'b1) begin + // 1D DMA case + if (|dma_src_cnt_d1 == 1'b0) begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). + if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin + data_in_req = 1'b1; + data_in_we = 1'b0; + data_in_be = 4'b1111; // always read all bytes + data_in_addr = read_ptr_reg; + end + end + end else if (dma_conf_2d == 1'b1) begin + // 2D DMA case: exit only if both 1d and 2d counters are at 0 + if (dma_src_cnt_d1 == {1'h0, reg2hw.size_d1.q} && |dma_src_cnt_d2 == 1'b0) begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end else begin + // The read operation is the same in both cases + dma_read_fsm_n_state = DMA_READ_FSM_ON; + // Wait if fifo is full, almost full (last data), or if the SPI RX does not have valid data (only in SPI mode 1). + if (fifo_full == 1'b0 && fifo_alm_full == 1'b0 && wait_for_rx == 1'b0) begin + data_in_req = 1'b1; + data_in_we = 1'b0; + data_in_be = 4'b1111; // always read all bytes + data_in_addr = read_ptr_reg; + end + end + end + end else begin + dma_read_fsm_n_state = DMA_READ_FSM_IDLE; + end + end + endcase + end + + // Only update read_ptr_valid_reg when the data is stored in the fifo. + // Since every input grant is followed by a rvalid, the read_ptr_valid_reg is a mere sample of the read_ptr_reg + // synched with the rvalid signal. + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_valid_in_reg + if (~rst_ni) begin + read_ptr_valid_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + read_ptr_valid_reg <= reg2hw.src_ptr.q; + end else if (data_in_rvalid == 1'b1) begin + read_ptr_valid_reg <= read_ptr_reg; + end + end + end + + // Input data shift: shift the input data to be on the LSB of the fifo + always_comb begin : proc_input_data + + fifo_input[7:0] = data_in_rdata[7:0]; + fifo_input[15:8] = data_in_rdata[15:8]; + fifo_input[23:16] = data_in_rdata[23:16]; + fifo_input[31:24] = data_in_rdata[31:24]; + + case (read_ptr_valid_reg[1:0]) + 2'b00: ; + 2'b01: fifo_input[7:0] = data_in_rdata[15:8]; + + 2'b10: begin + fifo_input[7:0] = data_in_rdata[23:16]; + fifo_input[15:8] = data_in_rdata[31:24]; + end + + 2'b11: fifo_input[7:0] = data_in_rdata[31:24]; + endcase + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + /* Renaming */ + assign reg2hw = reg2hw_i; + assign data_in_gnt = data_in_gnt_i; + assign fifo_full = read_fifo_full_i; + assign fifo_alm_full = read_fifo_alm_full_i; + assign dma_start = dma_start_i; + assign ext_dma_stop = ext_dma_stop_i; + assign read_ptr_update_sel = reg2hw.dim_inv.q; + assign dma_conf_1d = reg2hw.dim_config.q == 0; + assign dma_conf_2d = reg2hw.dim_config.q == 1; + assign data_in_be_o = data_in_be; + assign data_in_addr_o = data_in_addr; + assign data_in_req_o = data_in_req; + assign data_in_we_o = data_in_we; + assign read_fifo_flush_o = fifo_flush; + assign wait_for_rx = wait_for_rx_i; + assign data_in_rvalid = data_in_rvalid_i; + assign data_in_rdata = data_in_rdata_i; + assign fifo_input_o = fifo_input; + + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiwrite_fsm.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiwrite_fsm.sv new file mode 100644 index 00000000..5b83c400 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_obiwrite_fsm.sv @@ -0,0 +1,358 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Writing FSM for DMA channel, process data coming out of the output FIFO. Performs the sign extension if needed. + */ + +module dma_obiwrite_fsm + import dma_reg_pkg::*; +#( +) ( + input logic clk_i, + input logic rst_ni, + input dma_reg2hw_t reg2hw_i, + input logic dma_start_i, + input logic write_fifo_empty_i, + input logic read_addr_fifo_empty_i, + input logic [31:0] fifo_output_i, + input logic wait_for_tx_i, + input logic address_mode_i, + input logic padding_fsm_done_i, + input logic data_out_gnt_i, + input logic [31:0] fifo_addr_output_i, + + output logic data_out_req_o, + output logic data_out_we_o, + output logic [3:0] data_out_be_o, + output logic [31:0] data_out_addr_o, + output logic [31:0] data_out_wdata_o, + output logic dma_done_o +); + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + + import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Registers */ + dma_reg2hw_t reg2hw; + + logic dma_conf_1d; + logic dma_conf_2d; + logic dma_done; + logic address_mode; + logic dma_start; + + enum logic { + DMA_WRITE_FSM_IDLE, + DMA_WRITE_FSM_ON + } + dma_write_fsm_state, dma_write_fsm_n_state; + + typedef enum logic [1:0] { + DMA_DATA_TYPE_WORD, + DMA_DATA_TYPE_HALF_WORD, + DMA_DATA_TYPE_BYTE, + DMA_DATA_TYPE_BYTE_ + } dma_data_type_t; + + dma_data_type_t dst_data_type; + dma_data_type_t src_data_type; + + logic data_out_req; + logic data_out_we; + logic data_out_gnt; + logic [3:0] data_out_be; + logic [31:0] data_out_addr; + logic [31:0] data_out_wdata; + logic [31:0] write_address; + logic [31:0] write_ptr_reg; + logic [3:0] byte_enable_out; + + logic [31:0] dma_dst_d1_inc; + logic [31:0] dma_dst_d2_inc; + logic [16:0] dma_dst_cnt_d1; + + logic wait_for_tx; + + /* Sign extension signals */ + logic sign_extend; + + /* FIFO signals */ + logic write_fifo_empty; + logic read_addr_fifo_empty; + logic [31:0] fifo_output; + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + /* Sign extension of the increments */ + always_comb begin + dma_dst_d1_inc = {{26{reg2hw.dst_ptr_inc_d1.q[5]}}, reg2hw.dst_ptr_inc_d1.q}; + dma_dst_d2_inc = {{9{reg2hw.dst_ptr_inc_d2.q[22]}}, reg2hw.dst_ptr_inc_d2.q}; + end + + /* Counters for the reading fsm */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_dma_dst_cnt_reg + if (~rst_ni) begin + dma_dst_cnt_d1 <= '0; + end else begin + if (dma_start == 1'b1) begin + dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else if (dma_done == 1'b1) begin + dma_dst_cnt_d1 <= '0; + end else if (data_out_gnt == 1'b1) begin + if (dma_conf_1d == 1'b1) begin + // 1D case + dma_dst_cnt_d1 <= dma_dst_cnt_d1 - 1; + end else if (dma_conf_2d == 1'b1) begin + // 2D case + if (dma_dst_cnt_d1 == 1) begin + // In this case, the d1 is finished, so we need to reset the d2 size + dma_dst_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else begin + // In this case, the d1 isn't finished, so we need to decrement the d1 size + dma_dst_cnt_d1 <= dma_dst_cnt_d1 - 1; + end + end + end + end + end + + /* Determine the byte enable depending on the datatype */ + always_comb begin : proc_byte_enable_out + case (dst_data_type) // Data type 00 Word, 01 Half word, 11,10 byte + DMA_DATA_TYPE_WORD: byte_enable_out = 4'b1111; // Writing a word (32 bits) + + DMA_DATA_TYPE_HALF_WORD: begin // Writing a half-word (16 bits) + case (write_ptr_reg[1]) + 1'b0: byte_enable_out = 4'b0011; + 1'b1: byte_enable_out = 4'b1100; + endcase + ; // case(write_ptr_reg[1:0]) + end + + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_BYTE_: begin // Writing a byte (8 bits) + case (write_ptr_reg[1:0]) + 2'b00: byte_enable_out = 4'b0001; + 2'b01: byte_enable_out = 4'b0010; + 2'b10: byte_enable_out = 4'b0100; + 2'b11: byte_enable_out = 4'b1000; + endcase + ; // case(write_ptr_reg[1:0]) + end + endcase + ; // case (dst_data_type) + end + + /* Store output data pointer and increment everytime write request is granted */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ptr_out_reg + if (~rst_ni) begin + write_ptr_reg <= '0; + end else begin + if (dma_start == 1'b1) begin + write_ptr_reg <= reg2hw.dst_ptr.q; + end else if (data_out_gnt == 1'b1) begin + if (dma_conf_1d == 1'b1) begin + write_ptr_reg <= write_ptr_reg + dma_dst_d1_inc; + end else if (dma_conf_2d == 1'b1) begin + if (dma_dst_cnt_d1 == 1) begin + // In this case, the d1 is finished, so we need to increment the pointer by sizeof(d1)*data_unit*strides + write_ptr_reg <= write_ptr_reg + dma_dst_d2_inc; + end else begin + write_ptr_reg <= write_ptr_reg + dma_dst_d1_inc; // Increment just of one du, since we need to increase the 1d + end + end + end + end + end + + /* FSM state update */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_fsm_state + if (~rst_ni) begin + dma_write_fsm_state <= DMA_WRITE_FSM_IDLE; + end else begin + dma_write_fsm_state <= dma_write_fsm_n_state; + end + end + + /* Write master FSM */ + always_comb begin : proc_dma_write_fsm_logic + + dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; + dma_done = 1'b0; + + data_out_req = '0; + data_out_we = '0; + data_out_be = '0; + data_out_addr = '0; + + unique case (dma_write_fsm_state) + + DMA_WRITE_FSM_IDLE: begin + // Wait for start signal + if (dma_start == 1'b1) begin + dma_write_fsm_n_state = DMA_WRITE_FSM_ON; + end else begin + dma_write_fsm_n_state = DMA_WRITE_FSM_IDLE; + end + end + // Read one word + DMA_WRITE_FSM_ON: begin + // If all input data read exit + if (padding_fsm_done_i == 1'b1 && write_fifo_empty == 1'b1) begin + dma_done = (write_fifo_empty == 1'b1); + // If all input data has been processed and written, exit, otherwise finish storing the data + dma_write_fsm_n_state = dma_done ? DMA_WRITE_FSM_IDLE : DMA_WRITE_FSM_ON; + end else begin + dma_write_fsm_n_state = DMA_WRITE_FSM_ON; + // Wait if write fifo is empty or if the SPI TX is not ready for new data (only in SPI mode 2). + if (write_fifo_empty == 1'b0 && wait_for_tx == 1'b0 && (read_addr_fifo_empty && address_mode) == 1'b0) begin + data_out_req = 1'b1; + data_out_we = 1'b1; + data_out_be = byte_enable_out; + data_out_addr = write_address; + end + end + end + endcase + end + + /* Perform the data shift */ + always_comb begin : proc_output_data + + data_out_wdata[7:0] = fifo_output[7:0]; + data_out_wdata[15:8] = fifo_output[15:8]; + data_out_wdata[23:16] = fifo_output[23:16]; + data_out_wdata[31:24] = fifo_output[31:24]; + + case (write_ptr_reg[1:0]) + 2'b00: begin + if (sign_extend) begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; + { + DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:16] = {16{fifo_output[15]}}; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:8] = {24{fifo_output[7]}}; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[15:8] = {8{fifo_output[7]}}; + default: ; + endcase + end else begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_WORD, DMA_DATA_TYPE_WORD} : ; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_WORD} : data_out_wdata[31:16] = 16'b0; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_WORD + } : + data_out_wdata[31:8] = 24'b0; + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[15:8] = 8'b0; + default: ; + endcase + end + end + 2'b01: data_out_wdata[15:8] = fifo_output[7:0]; // Writing a byte, no need for sign extension + 2'b10: begin // Writing a half-word or a byte + data_out_wdata[23:16] = fifo_output[7:0]; + data_out_wdata[31:24] = fifo_output[15:8]; + + if (sign_extend) begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[31:24] = {8{fifo_output[7]}}; + default: ; + endcase + end else begin + case ({ + src_data_type, dst_data_type + }) + {DMA_DATA_TYPE_HALF_WORD, DMA_DATA_TYPE_HALF_WORD} : ; + { + DMA_DATA_TYPE_BYTE, DMA_DATA_TYPE_HALF_WORD + }, { + DMA_DATA_TYPE_BYTE_, DMA_DATA_TYPE_HALF_WORD + } : + data_out_wdata[31:24] = 8'b0; + default: ; + endcase + end + end + 2'b11: + data_out_wdata[31:24] = fifo_output[7:0]; // Writing a byte, no need for sign extension + endcase + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + /* Renaming */ + assign dma_start = dma_start_i; + assign reg2hw = reg2hw_i; + assign data_out_gnt = data_out_gnt_i; + assign dma_done_o = dma_done; + assign dst_data_type = dma_data_type_t'(reg2hw.dst_data_type.q); + assign src_data_type = dma_data_type_t'(reg2hw.src_data_type.q); + assign data_out_wdata_o = data_out_wdata; + assign write_fifo_empty = write_fifo_empty_i; + assign fifo_output = fifo_output_i; + assign wait_for_tx = wait_for_tx_i; + assign data_out_be_o = data_out_be; + assign data_out_addr_o = data_out_addr; + assign data_out_req_o = data_out_req; + assign data_out_we_o = data_out_we; + assign read_addr_fifo_empty = read_addr_fifo_empty_i; + assign address_mode = address_mode_i; + assign dma_conf_1d = reg2hw.dim_config.q == 0; + assign dma_conf_2d = reg2hw.dim_config.q == 1; + + /* Write address */ + assign write_address = address_mode ? fifo_addr_output_i : write_ptr_reg; + + /* Sign extension */ + assign sign_extend = reg2hw.sign_ext.q & ( (src_data_type[1] & ~dst_data_type[1]) | ((src_data_type[1] == dst_data_type[1]) & (src_data_type[0] & ~dst_data_type[0]))); + + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_padding_fsm.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_padding_fsm.sv new file mode 100644 index 00000000..d16c0bf3 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_padding_fsm.sv @@ -0,0 +1,339 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Padding FSM for DMA channel. + */ + +module dma_padding_fsm + import dma_reg_pkg::*; +#( +) ( + input logic clk_i, + input logic rst_ni, + input dma_reg2hw_t reg2hw_i, + input logic dma_padding_fsm_on_i, + input logic dma_start_i, + input logic read_fifo_empty_i, + input logic write_fifo_full_i, + input logic write_fifo_alm_full_i, + input logic [31:0] data_read_i, + + output logic padding_fsm_done_o, + output logic write_fifo_push_o, + output logic read_fifo_pop_o, + output logic [31:0] data_write_o +); + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + + import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Registers */ + dma_reg2hw_t reg2hw; + + /* General signals */ + logic read_fifo_en; + logic write_fifo_en; + logic pad_on; + logic read_fifo_empty; + logic write_fifo_full; + logic write_fifo_alm_full; + logic dma_start; + logic [16:0] dma_cnt_d1; + logic [16:0] dma_cnt_d2; + logic dma_conf_1d; + logic dma_conf_2d; + + /* Padding FSM states */ + enum { + PAD_IDLE, + TOP_PAD_EXEC, + LEFT_PAD_EXEC, + RIGHT_PAD_EXEC, + BOTTOM_PAD_EXEC, + TOP_PAD_DONE, + LEFT_PAD_DONE, + RIGHT_PAD_DONE, + BOTTOM_PAD_DONE + } + pad_state_q, pad_state_d; + + /* Padding FSM conditions */ + logic idle_to_left_ex; + logic idle_to_top_ex; + logic idle_to_right_ex; + logic idle_to_bottom_ex; + logic top_ex_to_top_dn; + logic top_ex_to_left_ex; + logic top_dn_to_right_ex; + logic top_dn_to_bottom_ex; + logic top_dn_to_idle; + logic left_ex_to_left_dn; + logic left_dn_to_left_ex; + logic left_dn_to_right_ex; + logic left_dn_to_bottom_ex; + logic left_dn_to_idle; + logic right_ex_to_right_dn; + logic right_ex_to_left_ex; + logic right_dn_to_right_ex; + logic right_dn_to_idle; + logic right_ex_to_idle; + logic right_ex_to_bottom_ex; + logic bottom_ex_to_idle; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Module instantiation */ + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + /* Padding FSM state update */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_pad_state + if (~rst_ni) begin + pad_state_q <= PAD_IDLE; + end else begin + /* Advance in the FSM only if the write FIFO is available */ + if (write_fifo_en == 1'b1 && dma_padding_fsm_on_i == 1'b1 && padding_fsm_done_o == 1'b0) begin + pad_state_q <= pad_state_d; + end + end + end + + /* Padding FSM logic */ + always_comb begin : proc_pad_fsm_logic + pad_state_d = pad_state_q; + + unique case (pad_state_q) + PAD_IDLE: begin + /* If the padding is done, stay idle */ + if (padding_fsm_done_o == 1'b1) begin + pad_state_d = PAD_IDLE; + end else begin + if (idle_to_top_ex) begin + pad_state_d = TOP_PAD_EXEC; + end else if (idle_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (idle_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (idle_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end + end + end + + TOP_PAD_EXEC: begin + if (top_ex_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (top_ex_to_top_dn) begin + pad_state_d = TOP_PAD_DONE; + end + end + TOP_PAD_DONE: begin + if (top_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (top_dn_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end else if (top_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + LEFT_PAD_EXEC: begin + if (left_ex_to_left_dn) begin + pad_state_d = LEFT_PAD_DONE; + end + end + LEFT_PAD_DONE: begin + if (left_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end else if (left_dn_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end else if (left_dn_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (left_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + RIGHT_PAD_EXEC: begin + if (right_ex_to_right_dn) begin + pad_state_d = RIGHT_PAD_DONE; + end else if (right_ex_to_left_ex) begin + pad_state_d = LEFT_PAD_EXEC; + end else if (right_ex_to_bottom_ex) begin + pad_state_d = BOTTOM_PAD_EXEC; + end else if (right_ex_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + RIGHT_PAD_DONE: begin + if (right_dn_to_idle) begin + pad_state_d = PAD_IDLE; + end else if (right_dn_to_right_ex) begin + pad_state_d = RIGHT_PAD_EXEC; + end + end + BOTTOM_PAD_EXEC: begin + if (bottom_ex_to_idle) begin + pad_state_d = PAD_IDLE; + end + end + endcase + end + + /* Data transfer */ + always_comb begin : proc_data_transfer + data_write_o = '0; + write_fifo_push_o = 1'b0; + read_fifo_pop_o = 1'b0; + + if (dma_padding_fsm_on_i == 1'b1 && padding_fsm_done_o == 1'b0) begin + /* + * If we need to pad, there is no need to wait for the read fifo to have some values. + * If we don't have to pad, we need to wait for the read fifo to be not empty. + * In both cases, we need to wait for the write fifo to have some space. + */ + if (pad_on == 1'b1 & write_fifo_en == 1'b1) begin + write_fifo_push_o = 1'b1; + end else if (read_fifo_en == 1'b1 & write_fifo_en == 1'b1) begin + data_write_o = data_read_i; + write_fifo_push_o = 1'b1; + read_fifo_pop_o = 1'b1; + end + end + end + + /* Counters for the padding fsm */ + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_cnt + if (~rst_ni) begin + dma_cnt_d1 <= '0; + dma_cnt_d2 <= '0; + end else begin + if (dma_start == 1'b1) begin + dma_cnt_d1 <= ({1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}); + dma_cnt_d2 <= {1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_top.q} + {11'h0, reg2hw.pad_bottom.q}; + end else if (padding_fsm_done_o == 1'b1) begin + dma_cnt_d1 <= '0; + dma_cnt_d2 <= '0; + end else if ((dma_padding_fsm_on_i == 1'b1 && padding_fsm_done_o == 1'b0) & + ((pad_on == 1'b1 & write_fifo_en == 1'b1) || + (read_fifo_en == 1'b1 & write_fifo_en == 1'b1))) begin + if (dma_conf_1d == 1'b1) begin + // 1D case + dma_cnt_d1 <= dma_cnt_d1 - 1; + end else if (dma_conf_2d == 1'b1) begin + // 2D case + if (dma_cnt_d1 == 1) begin + // In this case, the d1 is finished, so we need to decrement the d2 size and reset the d2 size + dma_cnt_d2 <= dma_cnt_d2 - 1; + dma_cnt_d1 <= {1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_left.q} + {11'h0, reg2hw.pad_right.q}; + end else begin + // In this case, the d1 isn't finished, so we need to decrement the d1 size + dma_cnt_d1 <= dma_cnt_d1 - 1; + end + end + end + end + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + /* Renaming */ + assign read_fifo_empty = read_fifo_empty_i; + assign write_fifo_full = write_fifo_full_i; + assign write_fifo_alm_full = write_fifo_alm_full_i; + assign dma_start = dma_start_i; + assign reg2hw = reg2hw_i; + assign dma_conf_1d = reg2hw.dim_config.q == 0; + assign dma_conf_2d = reg2hw.dim_config.q == 1; + + /* Padding flag */ + assign pad_on = (pad_state_q != PAD_IDLE && pad_state_q != TOP_PAD_DONE && pad_state_q != LEFT_PAD_DONE && pad_state_q != RIGHT_PAD_DONE && pad_state_q != BOTTOM_PAD_DONE); + + /* Read FIFO pop signal */ + assign read_fifo_en = (read_fifo_empty == 1'b0); + + /* Write FIFO push signal */ + assign write_fifo_en = (write_fifo_full == 1'b0 && write_fifo_alm_full == 1'b0); + + /* Padding done signal */ + assign padding_fsm_done_o = ((dma_conf_2d == 1'b1 && |dma_cnt_d2 == 1'b0 && dma_padding_fsm_on_i == 1'b1) + | (dma_conf_1d == 1'b1 && |dma_cnt_d1 == 1'b0 && dma_padding_fsm_on_i == 1'b1)); + + /* Padding FSM conditions assignments */ + assign idle_to_top_ex = {|reg2hw.pad_top.q == 1'b1 && dma_padding_fsm_on_i == 1'b1}; + assign idle_to_left_ex = { + |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b1 && dma_padding_fsm_on_i == 1'b1 + }; + assign idle_to_right_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 + && dma_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + 1) + }; + assign idle_to_bottom_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_top.q == 1'b0 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 + && dma_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 + }; + assign top_ex_to_top_dn = { + write_fifo_push_o == 1'b1 && dma_cnt_d2 == ( {1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 && |reg2hw.pad_left.q == 1'b0 + }; + assign top_ex_to_left_ex = { + write_fifo_push_o == 1'b1 && dma_cnt_d2 == ({1'h0, reg2hw.size_d2.q} + {11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 && |reg2hw.pad_left.q == 1'b1 + }; + assign top_dn_to_right_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b1 && dma_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + 1) + }; + assign top_dn_to_bottom_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 + }; + assign top_dn_to_idle = { + |reg2hw.pad_left.q == 1'b0 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && dma_cnt_d2 == 1 && dma_cnt_d1 == 1 + }; + assign left_ex_to_left_dn = { + write_fifo_push_o == 1'b1 && dma_cnt_d1 == ({1'h0, reg2hw.size_d1.q} + {11'h0, reg2hw.pad_right.q} + 1) + }; + assign left_dn_to_left_ex = { + write_fifo_push_o == 1'b1 && dma_cnt_d1 == 1 && dma_cnt_d2 != (1'b1 + {11'h0, reg2hw.pad_bottom.q}) && |reg2hw.pad_right.q == 1'b0 + }; + assign left_dn_to_right_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_right.q == 1'b1 && dma_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + 1) + }; + assign left_dn_to_bottom_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b1 && dma_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 + }; + assign left_dn_to_idle = { + |reg2hw.pad_right.q == 1'b0 && |reg2hw.pad_bottom.q == 1'b0 && dma_cnt_d2 == 1 && dma_cnt_d1 == 1 + }; + assign right_ex_to_right_dn = { + write_fifo_push_o == 1'b1 && dma_cnt_d1 == 1 && dma_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + 1) && |reg2hw.pad_left.q == 1'b0 + }; + assign right_ex_to_left_ex = { + write_fifo_push_o == 1'b1 && dma_cnt_d1 == 1 && dma_cnt_d2 != ({11'h0, reg2hw.pad_bottom.q} + 1) && |reg2hw.pad_left.q == 1'b1 + }; + assign right_ex_to_bottom_ex = { + write_fifo_push_o == 1'b1 && |reg2hw.pad_bottom.q == 1'b1 && dma_cnt_d2 == ({11'h0, reg2hw.pad_bottom.q} + 1) && dma_cnt_d1 == 1 + }; + assign right_dn_to_right_ex = { + write_fifo_push_o == 1'b1 && dma_cnt_d1 == ({11'h0, reg2hw.pad_right.q} + 1) && |reg2hw.pad_left.q == 1'b0 + }; + assign right_dn_to_idle = {|reg2hw.pad_bottom.q == 1'b0 && dma_cnt_d2 == 1 && dma_cnt_d1 == 1}; + assign bottom_ex_to_idle = {dma_cnt_d1 == 1 && dma_cnt_d2 == 1 && dma_cnt_d1 == 1}; + + assign right_ex_to_idle = {|reg2hw.pad_bottom.q == 1'b0 && dma_cnt_d2 == 1 && dma_cnt_d1 == 1}; + + + + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv index f2fe4761..4e98968c 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -24,10 +24,7 @@ package dma_reg_pkg; logic qe; } dma_reg2hw_size_d1_reg_t; - typedef struct packed { - logic [15:0] q; - logic qe; - } dma_reg2hw_size_d2_reg_t; + typedef struct packed {logic [15:0] q;} dma_reg2hw_size_d2_reg_t; typedef struct packed { struct packed { @@ -65,25 +62,13 @@ package dma_reg_pkg; typedef struct packed {logic q;} dma_reg2hw_dim_inv_reg_t; - typedef struct packed { - logic [5:0] q; - logic qe; - } dma_reg2hw_pad_top_reg_t; + typedef struct packed {logic [5:0] q;} dma_reg2hw_pad_top_reg_t; - typedef struct packed { - logic [5:0] q; - logic qe; - } dma_reg2hw_pad_bottom_reg_t; + typedef struct packed {logic [5:0] q;} dma_reg2hw_pad_bottom_reg_t; - typedef struct packed { - logic [5:0] q; - logic qe; - } dma_reg2hw_pad_right_reg_t; + typedef struct packed {logic [5:0] q;} dma_reg2hw_pad_right_reg_t; - typedef struct packed { - logic [5:0] q; - logic qe; - } dma_reg2hw_pad_left_reg_t; + typedef struct packed {logic [5:0] q;} dma_reg2hw_pad_left_reg_t; typedef struct packed {logic [12:0] q;} dma_reg2hw_window_size_reg_t; @@ -120,27 +105,27 @@ package dma_reg_pkg; // Register -> HW type typedef struct packed { - dma_reg2hw_src_ptr_reg_t src_ptr; // [287:256] - dma_reg2hw_dst_ptr_reg_t dst_ptr; // [255:224] - dma_reg2hw_addr_ptr_reg_t addr_ptr; // [223:192] - dma_reg2hw_size_d1_reg_t size_d1; // [191:175] - dma_reg2hw_size_d2_reg_t size_d2; // [174:158] - dma_reg2hw_status_reg_t status; // [157:154] - dma_reg2hw_src_ptr_inc_d1_reg_t src_ptr_inc_d1; // [153:148] - dma_reg2hw_src_ptr_inc_d2_reg_t src_ptr_inc_d2; // [147:125] - dma_reg2hw_dst_ptr_inc_d1_reg_t dst_ptr_inc_d1; // [124:119] - dma_reg2hw_dst_ptr_inc_d2_reg_t dst_ptr_inc_d2; // [118:96] - dma_reg2hw_slot_reg_t slot; // [95:64] - dma_reg2hw_src_data_type_reg_t src_data_type; // [63:62] - dma_reg2hw_dst_data_type_reg_t dst_data_type; // [61:60] - dma_reg2hw_sign_ext_reg_t sign_ext; // [59:59] - dma_reg2hw_mode_reg_t mode; // [58:57] - dma_reg2hw_dim_config_reg_t dim_config; // [56:56] - dma_reg2hw_dim_inv_reg_t dim_inv; // [55:55] - dma_reg2hw_pad_top_reg_t pad_top; // [54:48] - dma_reg2hw_pad_bottom_reg_t pad_bottom; // [47:41] - dma_reg2hw_pad_right_reg_t pad_right; // [40:34] - dma_reg2hw_pad_left_reg_t pad_left; // [33:27] + dma_reg2hw_src_ptr_reg_t src_ptr; // [282:251] + dma_reg2hw_dst_ptr_reg_t dst_ptr; // [250:219] + dma_reg2hw_addr_ptr_reg_t addr_ptr; // [218:187] + dma_reg2hw_size_d1_reg_t size_d1; // [186:170] + dma_reg2hw_size_d2_reg_t size_d2; // [169:154] + dma_reg2hw_status_reg_t status; // [153:150] + dma_reg2hw_src_ptr_inc_d1_reg_t src_ptr_inc_d1; // [149:144] + dma_reg2hw_src_ptr_inc_d2_reg_t src_ptr_inc_d2; // [143:121] + dma_reg2hw_dst_ptr_inc_d1_reg_t dst_ptr_inc_d1; // [120:115] + dma_reg2hw_dst_ptr_inc_d2_reg_t dst_ptr_inc_d2; // [114:92] + dma_reg2hw_slot_reg_t slot; // [91:60] + dma_reg2hw_src_data_type_reg_t src_data_type; // [59:58] + dma_reg2hw_dst_data_type_reg_t dst_data_type; // [57:56] + dma_reg2hw_sign_ext_reg_t sign_ext; // [55:55] + dma_reg2hw_mode_reg_t mode; // [54:53] + dma_reg2hw_dim_config_reg_t dim_config; // [52:52] + dma_reg2hw_dim_inv_reg_t dim_inv; // [51:51] + dma_reg2hw_pad_top_reg_t pad_top; // [50:45] + dma_reg2hw_pad_bottom_reg_t pad_bottom; // [44:39] + dma_reg2hw_pad_right_reg_t pad_right; // [38:33] + dma_reg2hw_pad_left_reg_t pad_left; // [32:27] dma_reg2hw_window_size_reg_t window_size; // [26:14] dma_reg2hw_window_count_reg_t window_count; // [13:6] dma_reg2hw_interrupt_en_reg_t interrupt_en; // [5:4] diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv index a4004830..ea7897c0 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma/rtl/dma_reg_top.sv @@ -278,7 +278,7 @@ module dma_reg_top #( .d ('0), // to internal hardware - .qe(reg2hw.size_d2.qe), + .qe(), .q (reg2hw.size_d2.q), // to register interface (read) @@ -661,7 +661,7 @@ module dma_reg_top #( .d ('0), // to internal hardware - .qe(reg2hw.pad_top.qe), + .qe(), .q (reg2hw.pad_top.q), // to register interface (read) @@ -688,7 +688,7 @@ module dma_reg_top #( .d ('0), // to internal hardware - .qe(reg2hw.pad_bottom.qe), + .qe(), .q (reg2hw.pad_bottom.q), // to register interface (read) @@ -715,7 +715,7 @@ module dma_reg_top #( .d ('0), // to internal hardware - .qe(reg2hw.pad_right.qe), + .qe(), .q (reg2hw.pad_right.q), // to register interface (read) @@ -742,7 +742,7 @@ module dma_reg_top #( .d ('0), // to internal hardware - .qe(reg2hw.pad_left.qe), + .qe(), .q (reg2hw.pad_left.q), // to register interface (read) diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core index 1fa1b17b..d611de9d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/dma_subsystem.core @@ -13,6 +13,7 @@ filesets: - pulp-platform.org::common_cells files: - rtl/dma_subsystem.sv + - rtl/dma_NtoM_xbar.sv file_type: systemVerilogSource targets: diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_NtoM_xbar.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_NtoM_xbar.sv new file mode 100644 index 00000000..b1a4f39f --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_NtoM_xbar.sv @@ -0,0 +1,71 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Generated N-to-M crossbar. + * This module has been developed to be used in the DMA subsystem, in which it is not possible to use an NtoM crossbar. + * The problem is that each slave port of the DMA xbar is actually a master port of the system bus. The DMA xbar slave ports + * cannot be indexed by the master's request address because they all perform the same function, they all can read/write + * to/from the same memory spaces. + * This module is a workaround to this problem, as it is composed by a number of N-to-1 crossbars, each for a different slave + * (which would be a system bus master port). + * The amount of masters per crossbar is defined by the parameter NUM_MASTERS_PER_XBAR. + * It is thus possible, from an application point of view, to use channels that are guaranteed to have a dedicated master port, + * reducing the need for additional arbitration logic. + */ + +module dma_NtoM_xbar #( + parameter int unsigned XBAR_NMASTER = 4, + parameter int unsigned XBAR_MSLAVE = 2 +) ( + input logic clk_i, + input logic rst_ni, + + // Master ports + input obi_pkg::obi_req_t [XBAR_NMASTER-1:0] master_req_i, + output obi_pkg::obi_resp_t [XBAR_NMASTER-1:0] master_resp_o, + + // slave ports + output obi_pkg::obi_req_t [XBAR_MSLAVE-1:0] slave_req_o, + input obi_pkg::obi_resp_t [XBAR_MSLAVE-1:0] slave_resp_i +); + import obi_pkg::*; + import core_v_mini_mcu_pkg::*; + + /* Generation of the crossbars */ + generate + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[0]) + ) xbar_i ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .master_req_i(master_req_i[core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[0]-1:0]), + .master_resp_o(master_resp_o[core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[0]-1:0]), + .slave_req_o(slave_req_o[0]), + .slave_resp_i(slave_resp_i[0]) + ); + + for (genvar i = 1; i < XBAR_MSLAVE; i++) begin : gen_xbar + if (core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i] == 1) begin + assign slave_req_o[i] = master_req_i[i+core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[0]-1]; + assign master_resp_o[i+core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[0]-1] = slave_resp_i[i]; + end else begin + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i]) + ) xbar_i ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .master_req_i(master_req_i[core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i] + core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i-1]-1:core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i-1]]), + .master_resp_o(master_resp_o[core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i] + core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i-1]-1:core_v_mini_mcu_pkg::DMA_XBAR_MASTERS[i-1]]), + .slave_req_o(slave_req_o[i]), + .slave_resp_i(slave_resp_i[i]) + ); + end + end + endgenerate + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv index 22274b69..6ac3df37 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/dma_subsystem/rtl/dma_subsystem.sv @@ -3,7 +3,8 @@ * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 * - * Author: Tommaso Terzano + * Author: Tommaso Terzano + * * * Info: DMA subsystem, it instantiates 1 to 8 DMA channels and manages the data transfers. */ @@ -19,18 +20,19 @@ module dma_subsystem #( ) ( input logic clk_i, input logic rst_ni, + input logic clk_gate_en_ni [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0], input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, - output obi_req_t dma_read_ch0_req_o, - input obi_resp_t dma_read_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_read_resp_i, - output obi_req_t dma_write_ch0_req_o, - input obi_resp_t dma_write_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_write_resp_i, - output obi_req_t dma_addr_ch0_req_o, - input obi_resp_t dma_addr_ch0_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] dma_addr_resp_i, input logic [GLOBAL_SLOT_NUM-1:0] global_trigger_slot_i, input logic [EXT_SLOT_NUM-1:0] ext_trigger_slot_i, @@ -38,13 +40,41 @@ module dma_subsystem #( input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_stop_i, output dma_done_intr_o, - output dma_window_intr_o + output dma_window_intr_o, + + output logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_o ); + /*_________________________________________________________________________________________________________________________________ */ + + /* Imports and parameters */ import obi_pkg::*; import reg_pkg::*; + /* + * It's possible to define individually the sizes of each DMA channel's FIFOs. + * For example, a FIFO_CH_ARRAY like this {L, M, M, S} means that CH0 will be small, + * CH1 and CH2 will be medium and CH3 will be large. + * + * This is useful in applications that require different bandwidths for different channels. + * To enable this functionality, decomment EN_SET_FIFO_CH_SIZE and set the desired sizes. + */ + + //`define EN_SET_FIFO_CH_SIZE; + + `ifdef EN_SET_FIFO_CH_SIZE + + localparam int unsigned LARGE_FIFO_CH_SIZE = 8; + localparam int unsigned MEDIUM_FIFO_CH_SIZE = 4; + localparam int unsigned SMALL_FIFO_CH_SIZE = 2; + + typedef enum {L, M, S} fifo_ch_size_t; + + localparam fifo_ch_size_t FIFO_CH_ARRAY [core_v_mini_mcu_pkg::DMA_CH_NUM] = '{L, M, M, S}; + + `endif + /*_________________________________________________________________________________________________________________________________ */ /* Signals declaration */ @@ -74,73 +104,136 @@ module dma_subsystem #( /* DMA modules */ generate for (genvar i = 0; i < core_v_mini_mcu_pkg::DMA_CH_NUM; i++) begin : dma_i_gen + + /* FIFO size assignment */ + localparam int fifo_size = + `ifdef EN_SET_FIFO_CH_SIZE + (FIFO_CH_ARRAY[i] == L) ? LARGE_FIFO_CH_SIZE : + ((FIFO_CH_ARRAY[i] == M) ? MEDIUM_FIFO_CH_SIZE : SMALL_FIFO_CH_SIZE); + `else + 4; + `endif + dma #( .reg_req_t (reg_pkg::reg_req_t), .reg_rsp_t (reg_pkg::reg_rsp_t), .obi_req_t (obi_pkg::obi_req_t), .obi_resp_t(obi_pkg::obi_resp_t), - .SLOT_NUM (GLOBAL_SLOT_NUM + 2) + .SLOT_NUM (GLOBAL_SLOT_NUM + 2), + .FIFO_DEPTH (fifo_size) ) dma_i ( .clk_i, .rst_ni, + .clk_gate_en_ni(clk_gate_en_ni[i]), .ext_dma_stop_i(ext_dma_stop_i[i]), .reg_req_i(submodules_req[i]), .reg_rsp_o(submodules_rsp[i]), - .dma_read_ch0_req_o(xbar_read_req[i]), - .dma_read_ch0_resp_i(xbar_read_resp[i]), - .dma_write_ch0_req_o(xbar_write_req[i]), - .dma_write_ch0_resp_i(xbar_write_resp[i]), - .dma_addr_ch0_req_o(xbar_address_req[i]), - .dma_addr_ch0_resp_i(xbar_address_resp[i]), + .dma_read_req_o(xbar_read_req[i]), + .dma_read_resp_i(xbar_read_resp[i]), + .dma_write_req_o(xbar_write_req[i]), + .dma_write_resp_i(xbar_write_resp[i]), + .dma_addr_req_o(xbar_address_req[i]), + .dma_addr_resp_i(xbar_address_resp[i]), .trigger_slot_i({ ext_trigger_slot_i[2*i+1], ext_trigger_slot_i[2*i], global_trigger_slot_i }), .dma_done_intr_o(dma_trans_done[i]), - .dma_window_intr_o(dma_window_done[i]) + .dma_window_intr_o(dma_window_done[i]), + .dma_done_o(dma_done_o[i]) ); end endgenerate generate - if (core_v_mini_mcu_pkg::DMA_CH_NUM > 1) begin : xbar_varlat_n_to_one_gen + if (core_v_mini_mcu_pkg::DMA_CH_NUM > 1) begin : xbar_varlat_gen /* Register interface routing signals */ logic [core_v_mini_mcu_pkg::DMA_CH_PORT_SEL_WIDTH-1:0] submodules_select; - /* Read, write & address mode operations xbar*/ - xbar_varlat_n_to_one #( - .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) - ) xbar_read_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .master_req_i (xbar_read_req), - .master_resp_o(xbar_read_resp), - .slave_req_o (dma_read_ch0_req_o), - .slave_resp_i (dma_read_ch0_resp_i) - ); - - xbar_varlat_n_to_one #( - .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) - ) xbar_write_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .master_req_i (xbar_write_req), - .master_resp_o(xbar_write_resp), - .slave_req_o (dma_write_ch0_req_o), - .slave_resp_i (dma_write_ch0_resp_i) - ); - - xbar_varlat_n_to_one #( - .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) - ) xbar_address_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .master_req_i (xbar_address_req), - .master_resp_o(xbar_address_resp), - .slave_req_o (dma_addr_ch0_req_o), - .slave_resp_i (dma_addr_ch0_resp_i) - ); + if (core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS > 1 && core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS != core_v_mini_mcu_pkg::DMA_CH_NUM) begin : xbar_n_to_m_gen + + /* Read, write & address mode operations xbar*/ + dma_NtoM_xbar #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM), + .XBAR_MSLAVE(core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS) + ) xbar_read_i ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .master_req_i(xbar_read_req), + .master_resp_o(xbar_read_resp), + .slave_req_o(dma_read_req_o), + .slave_resp_i(dma_read_resp_i) + ); + + dma_NtoM_xbar #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM), + .XBAR_MSLAVE(core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS) + ) xbar_write_i ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .master_req_i(xbar_write_req), + .master_resp_o(xbar_write_resp), + .slave_req_o(dma_write_req_o), + .slave_resp_i(dma_write_resp_i) + ); + + dma_NtoM_xbar #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM), + .XBAR_MSLAVE(core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS) + ) xbar_address_i ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .master_req_i(xbar_address_req), + .master_resp_o(xbar_address_resp), + .slave_req_o(dma_addr_req_o), + .slave_resp_i(dma_addr_resp_i) + ); + end else if (core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS > 1 && core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS == core_v_mini_mcu_pkg::DMA_CH_NUM) begin : xbar_n_to_n_gen + for (genvar i = 0 ; i < core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS; i++) begin + assign dma_read_req_o[i] = xbar_read_req[i]; + assign xbar_read_resp[i] = dma_read_resp_i[i]; + assign dma_write_req_o[i] = xbar_write_req[i]; + assign xbar_write_resp[i] = dma_write_resp_i[i]; + assign dma_addr_req_o[i] = xbar_address_req[i]; + assign xbar_address_resp[i] = dma_addr_resp_i[i]; + end + + end else begin : xbar_n_to_1_gen + /* Read, write & address mode operations xbar*/ + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_read_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_read_req), + .master_resp_o(xbar_read_resp), + .slave_req_o (dma_read_req_o[0]), + .slave_resp_i (dma_read_resp_i[0]) + ); + + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_write_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_write_req), + .master_resp_o(xbar_write_resp), + .slave_req_o (dma_write_req_o[0]), + .slave_resp_i (dma_write_resp_i[0]) + ); + + xbar_varlat_n_to_one #( + .XBAR_NMASTER(core_v_mini_mcu_pkg::DMA_CH_NUM) + ) xbar_address_i ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .master_req_i (xbar_address_req), + .master_resp_o(xbar_address_resp), + .slave_req_o (dma_addr_req_o[0]), + .slave_resp_i (dma_addr_resp_i[0]) + ); + end /* Internal address decoder */ addr_decode #( @@ -176,12 +269,12 @@ module dma_subsystem #( end else begin /* Bus ports routing in the case of a single DMA */ - assign dma_read_ch0_req_o = xbar_read_req[0]; - assign xbar_read_resp[0] = dma_read_ch0_resp_i; - assign dma_write_ch0_req_o = xbar_write_req[0]; - assign xbar_write_resp[0] = dma_write_ch0_resp_i; - assign dma_addr_ch0_req_o = xbar_address_req[0]; - assign xbar_address_resp[0] = dma_addr_ch0_resp_i; + assign dma_read_req_o[0] = xbar_read_req[0]; + assign xbar_read_resp[0] = dma_read_resp_i[0]; + assign dma_write_req_o[0] = xbar_write_req[0]; + assign xbar_write_resp[0] = dma_write_resp_i[0]; + assign dma_addr_req_o[0] = xbar_address_req[0]; + assign xbar_address_resp[0] = dma_addr_resp_i[0]; assign submodules_req[0] = reg_req_i; assign reg_rsp_o = submodules_rsp[0]; end diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl index 0d336255..6c564b96 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.hjson.tpl @@ -223,6 +223,17 @@ ] } +% for channel in range(int(dma_ch_count)): + { name: "DMA_CH${channel}_CLK_GATE", + desc: "Clock-gates the DMA CH${channel}", + resval: "0x00000000" + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", name: "DMA_CH${channel}_CLK_GATE", desc: "Clock-gates the DMA CH${channel}" } + ] + } +% endfor % for bank in xheep.iter_ram_banks(): { name: "RAM_${bank.name()}_CLK_GATE", diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl index 0e126670..a6abf35d 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/data/power_manager.sv.tpl @@ -49,6 +49,7 @@ module power_manager import power_manager_pkg::*; #( output power_manager_out_t peripheral_subsystem_pwr_ctrl_o, output power_manager_out_t memory_subsystem_pwr_ctrl_o[core_v_mini_mcu_pkg::NUM_BANKS-1:0], output power_manager_out_t external_subsystem_pwr_ctrl_o[EXT_DOMAINS_RND-1:0], + output power_manager_out_t dma_subsystem_pwr_ctrl_o[core_v_mini_mcu_pkg::DMA_CH_NUM-1:0], // Power Manager input signals input power_manager_in_t cpu_subsystem_pwr_ctrl_i, @@ -131,6 +132,10 @@ module power_manager import power_manager_pkg::*; #( assign memory_subsystem_pwr_ctrl_o[${bank.name()}].clkgate_en_n = ~reg2hw.ram_${bank.name()}_clk_gate.q; % endfor +% for channel in range(int(dma_ch_count)): + assign dma_subsystem_pwr_ctrl_o[${channel}].clkgate_en_n = ~reg2hw.dma_ch${channel}_clk_gate.q; +% endfor + % if external_domains != 0: % for ext in range(external_domains): assign external_subsystem_pwr_ctrl_o[${ext}].pwrgate_en_n = external_subsystem_powergate_switch_n[${ext}]; diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager_gen.sh b/hw/vendor/esl_epfl_x_heep/hw/ip/power_manager/power_manager_gen.sh old mode 100644 new mode 100755 diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/data/im2col_spc.hjson b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/data/im2col_spc.hjson new file mode 100644 index 00000000..0319c03b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/data/im2col_spc.hjson @@ -0,0 +1,255 @@ +// Copyright EPFL contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +{ name: "im2col_spc", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + regwidth: "32", + registers: [ + { name: "SRC_PTR", + desc: "Input data pointer (word aligned)", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", name: "PTR_IN", desc: "Input data pointer (word aligned)" } + ] + }, + { name: "DST_PTR", + desc: "Output data pointer (word aligned)", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", name: "PTR_OUT", desc: "Output data pointer (word aligned)" } + ] + }, + { name: "IW", + desc: "Image width", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "15:0", name: "SIZE", desc: "Image width" } + ] + }, + { name: "IH", + desc: "Image heigth", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "15:0", name: "SIZE", desc: "Image heigth" } + ] + }, + { name: "FW", + desc: "Filter width", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:0", name: "SIZE", desc: "Filter width" } + ] + }, + { name: "FH", + desc: "Filter heigth", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:0", name: "SIZE", desc: "Filter heigth" } + ] + }, + { name: "BATCH", + desc: "Batch number", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:0", name: "SIZE", desc: "Batch size" } + ] + }, + { name: "NUM_CH", + desc: "Number of channels. When written, the im2col will start executing", + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", + fields: [ + { bits: "7:0", name: "NUM", desc: "Number of channels" } + ] + }, + { name: "CH_COL", + desc: "Number of iterations to perform", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "15:0", name: "NUM", desc: "Number of iterations" } + ] + }, + { name: "N_PATCHES_W", + desc: "Number of patches along W", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "15:0", name: "NUM", desc: "Number of patches" } + ] + }, + { name: "N_PATCHES_H", + desc: "Number of patches along H", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "15:0", name: "NUM", desc: "Number of patches" } + ] + }, + { name: "ADPT_PAD_RIGHT", + desc: "Adapted right padded region", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:0", name: "SIZE", desc: "Size of the adapted padded region" } + ] + }, + { name: "ADPT_PAD_BOTTOM", + desc: "Adapted bottom padded region", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:0", name: "SIZE", desc: "Size of the adapted padded region" } + ] + }, + { name: "LOG_STRIDES_D1", + desc: "Logarithmic number of strides along D1, set to 1 for no stride", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "3:0", name: "SIZE", desc: "Stride size" } + ] + }, + { name: "LOG_STRIDES_D2", + desc: "Logarithmic number of strides along D2, set to 1 for no stride", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "3:0", name: "SIZE", desc: "Stride size" } + ] + }, + { name: "STATUS", + desc: '''Status bit is set to one when the im2col SPC is ready''', + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + hwre: "true", // enable `re` latched signal of software read pulse + resval: 1, + fields: [ + { bits: "0", name: "READY", desc: "SPC is done"}, + ] + }, + { name: "SLOT", + desc: '''The DMA will wait for the signal + connected to the selected trigger_slots to be high + on the read and write side respectivly''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "15:0", name: "RX_TRIGGER_SLOT", + desc: "Slot selection mask" + }, + { bits: "31:16", name: "TX_TRIGGER_SLOT", + desc: "Slot selection mask" + } + ] + }, + { name: "DATA_TYPE", + desc: '''Width/type of the data to transfer''', + swaccess: "rw", + hwaccess: "hro", + resval: 0, + fields: [ + { bits: "1:0", name: "DATA_TYPE", + desc: "Data type", + enum: [ + { value: "0", name: "DMA_32BIT_WORD", desc: "Transfers 32 bits"}, + { value: "1", name: "DMA_16BIT_WORD", desc: "Transfers 16 bits"}, + { value: "2", name: "DMA_8BIT_WORD" , desc: "Transfers 8 bits"}, + { value: "3", name: "DMA_8BIT_WORD_2",desc: "Transfers 8 bits"}, + ] + } + ] + }, + { name: "PAD_TOP", + desc: '''Set the top padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Top margin padding (2D)"} + ] + }, + { name: "PAD_BOTTOM", + desc: '''Set the bottom padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Bottom margin padding (2D)"} + ] + }, + { name: "PAD_RIGHT", + desc: '''Set the right padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Right margin padding (1D/2D)"} + ] + }, + { name: "PAD_LEFT", + desc: '''Set the left padding''', + swaccess: "rw", + hwaccess: "hro", + hwqe: "true", // enable `qe` latched signal of software write pulse: used to trigger the padding + resval: 0, + fields: [ + { bits: "5:0", name: "PAD", desc: "Left margin padding (1D/2D)"} + ] + }, + { name: "INTERRUPT_EN", + desc: '''Interrupt Enable Register''', + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", name: "EN", desc: "Enables operation done interrupt" } + ] + }, + { name: "SPC_IFR", + desc: '''Interrupt Flag Register for the SPC operation''', + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + hwre: "true", // latched signal of software write pulse + resval: 0, + fields: [ + { bits: "0", name: "FLAG", desc: "Set for operation done interrupt" } + ] + }, + { name: "SPC_CH_MASK", + desc: '''Mask that defines which DMA channel the SPC can access''', + swaccess: "rw", + hwaccess: "hro", + resval: 1, + fields: [ + { bits: "31:0", name: "MASK", desc: "Mask of DMA channel" } + ] + }, + { name: "SPC_CH_OFFSET", + desc: '''Offset of the DMA channel the SPC can access''', + swaccess: "rw", + hwaccess: "hro", + resval: 1, + fields: [ + { bits: "31:0", name: "OFF", desc: "Offset of DMA channels" } + ] + } + ] +} diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.core b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.core new file mode 100644 index 00000000..e196ccac --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.core @@ -0,0 +1,28 @@ +CAPI=2: + +name: "example:ip:im2col_spc" +description: "im2col smart peripheral controller" + +# Copyright 2024 OpenHW Group +# Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +filesets: + files_rtl: + depend: + - pulp-platform.org::common_cells + - x-heep:ip:dma + files: + - rtl/im2col_spc_reg_pkg.sv + - rtl/im2col_spc_reg_top.sv + - rtl/dma_if_pkg.sv + - rtl/pipe_reg.sv + - rtl/im2col_spc_regintfc_controller.sv + - rtl/im2col_spc_param_fsm.sv + - rtl/im2col_spc.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_rtl diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.vlt b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.vlt new file mode 100644 index 00000000..1106245e --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc.vlt @@ -0,0 +1,16 @@ +// Copyright 2022 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +`verilator_config + +lint_off -rule DECLFILENAME -file "*/im2col_spc_reg_top.sv" + +lint_off -rule WIDTH -file "*/rtl/im2col_spc_reg_top.sv" -match "Operator ASSIGNW expects *" + +lint_off -rule UNUSED -file "*/rtl/im2col_spc.sv" -match "Signal is not used: 'data_out_rvalid'" +lint_off -rule UNUSED -file "*/rtl/im2col_spc.sv" -match "Signal is not used: 'data_out_rdata'" + +lint_off -rule UNUSED -file "*/rtl/im2col_spc.sv" -match "Bits of signal are not used: *" +lint_off -rule UNUSED -file "*/rtl/im2col_spc_param_fsm.sv" -match "Bits of signal are not used: *" +lint_off -rule UNUSED -file "*/rtl/im2col_spc_regintfc_controller.sv" -match "Bits of signal are not used: *" diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc_gen.sh b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc_gen.sh new file mode 100755 index 00000000..c8050ec6 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/im2col_spc_gen.sh @@ -0,0 +1,8 @@ +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +echo "Generating RTL" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py -r -t rtl data/im2col_spc.hjson +echo "Generating SW" +${PYTHON} ../../vendor/pulp_platform_register_interface/vendor/lowrisc_opentitan/util/regtool.py --cdefines -o ../../../sw/device/lib/drivers/im2col_spc/im2col_spc_regs.h data/im2col_spc.hjson diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/dma_if_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/dma_if_pkg.sv new file mode 100644 index 00000000..fd9ceb56 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/dma_if_pkg.sv @@ -0,0 +1,26 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: This module defines the interface structure for the DMA registers. + */ + +package dma_if_pkg; + + typedef struct packed { + logic [31:0] input_ptr; + logic [31:0] output_ptr; + logic [22:0] in_inc_d2; + logic [7:0] n_zeros_top; + logic [7:0] n_zeros_bottom; + logic [7:0] n_zeros_left; + logic [7:0] n_zeros_right; + logic [15:0] size_du_d1; + logic [15:0] size_du_d2; + } dma_if_t; + +endpackage diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc.sv new file mode 100644 index 00000000..be59baa2 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc.sv @@ -0,0 +1,623 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Im2col accelerator implemented as a Smart Peripheral Controller. + * It accesses the DMA channels to perform the matrix manipulation operation known as + * "image to column" (im2col), which enables efficient CNN inference by transforming + * the input tensor to use the GEMM library. + */ + +module im2col_spc + import obi_pkg::*; + import reg_pkg::*; +#( +) ( + input logic clk_i, + input logic rst_ni, + + input reg_rsp_t aopb2im2col_resp_i, + output reg_req_t im2col2aopb_req_o, + + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + input logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_i, + output logic im2col_spc_done_int_o +); + + import core_v_mini_mcu_pkg::*; + import dma_if_pkg::*; + import im2col_spc_reg_pkg::*; + import dma_reg_pkg::*; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Parameter definition */ + + /* FIFO dimension */ + localparam FIFO_DEPTH = 8; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* General status signal */ + enum { + READY, + BUSY + } im2col_status; + + /* Control Unit signals */ + logic im2col_start; + logic im2col_fsms_done; + logic im2col_done; + + /* Interrupt management signals */ + logic im2col_spc_ifr; + + /* DMA FIFO signals */ + logic fifo_flush; + logic fifo_full; + logic fifo_empty; + dma_if_t fifo_input; + logic fifo_push; + dma_if_t fifo_output; + logic fifo_pop; + logic [$clog2(FIFO_DEPTH)-1:0] fifo_usage; + + /* DMA interface unit signals */ + logic im2col_param_done; + logic dma_ch_free; + logic dma_ch_first_write; + logic [31:0] dma_ch_en_mask; + logic [31:0] dma_ch_offset; + logic [31:0] dma_addr; + logic [31:0] dma_wdata; + logic dma_if_loaded; + logic dma_regintfc_start; + logic dma_regintfc_done; + + /* Regtool signals */ + im2col_spc_reg2hw_t reg2hw; + im2col_spc_hw2reg_t hw2reg; + + enum { + READY_IF_CU, + IDLE_IF_CU, + GET_TRANSACTION, + LOAD_TRANSACTION + } + dma_if_cu_q, dma_if_cu_d; + + enum { + IDLE_IF_LOAD, + WRITE_DIMENSIONALITY, + WRITE_SLOTS, + WRITE_SRC_DATATYPE, + WRITE_DST_DATATYPE, + WRITE_TOP_PAD, + WRITE_BOTTOM_PAD, + WRITE_LEFT_PAD, + WRITE_RIGHT_PAD, + WRITE_INPUT_PTR, + WRITE_OUTPUT_PTR, + WRITE_INC_SRC_D1, + WRITE_INC_SRC_D2, + WRITE_INC_DST_D1, + WRITE_INC_DST_D2, + WRITE_SIZE_D2, + WRITE_SIZE_D1, + DONE + } + dma_if_cu_load_q, dma_if_cu_load_d; + + /*_________________________________________________________________________________________________________________________________ */ + + /* Module instantiation */ + + /* Regtool top module */ + im2col_spc_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) im2col_spc_reg_top_i ( + .clk_i, + .rst_ni, + .reg_req_i, + .reg_rsp_o, + .reg2hw, + .hw2reg, + .devmode_i(1'b1) + ); + + /* DMA FIFO */ + fifo_v3 #( + .DEPTH(FIFO_DEPTH), + .FALL_THROUGH(1'b1), + .dtype(dma_if_t) + ) dma_fifo_i ( + .clk_i, + .rst_ni, + .flush_i(fifo_flush), + .testmode_i(1'b0), + // status flags + .full_o(fifo_full), + .empty_o(fifo_empty), + .usage_o(fifo_usage), + // as long as the queue is not full we can push new data + .data_i(fifo_input), + .push_i(fifo_push), + // as long as the queue is not empty we can pop new elements + .data_o(fifo_output), + .pop_i(fifo_pop) + ); + + /* Parameter FSM */ + im2col_spc_param_fsm im2col_spc_param_fsm_i ( + .clk_i, + .rst_ni, + .reg2hw_i(reg2hw), + .im2col_done_i(im2col_done), + .im2col_start_i(im2col_start), + .fifo_full_i(fifo_full), + .fifo_push_o(fifo_push), + .im2col_param_done_o(im2col_param_done), + .fifo_input_o(fifo_input) + ); + + /* Register interface control FSM */ + im2col_spc_regintfc_controller im2col_spc_regintfc_controller_i ( + .clk_i, + .rst_ni, + .addr_i(dma_addr), + .wdata_i(dma_wdata), + .start_i(dma_regintfc_start), + .aopb_resp_i(aopb2im2col_resp_i), + .aopb_req_o(im2col2aopb_req_o), + .done_o(dma_regintfc_done) + ); + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + /* General status */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_im2col_status + if (!rst_ni) begin + im2col_status <= READY; + end else begin + if (im2col_done == 1'b1) begin + im2col_status <= READY; + end else if (im2col_start == 1'b1) begin + im2col_status <= BUSY; + end + end + end + + /* DMA interface unit state transition logic */ + always_comb begin : proc_comb_dma_if_fsm + + unique case (dma_if_cu_d) + IDLE_IF_CU: begin + if (fifo_empty == 1'b0 && im2col_fsms_done == 1'b0 && dma_ch_free == 1'b1) begin + dma_if_cu_q = GET_TRANSACTION; + end else begin + dma_if_cu_q = IDLE_IF_CU; + end + end + + GET_TRANSACTION: begin + if (fifo_empty == 1'b0 && dma_ch_free == 1'b1) begin + dma_if_cu_q = LOAD_TRANSACTION; + end else begin + dma_if_cu_q = IDLE_IF_CU; + end + end + + LOAD_TRANSACTION: begin + if (dma_if_loaded == 1'b1) begin + if (im2col_fsms_done == 1'b0 && dma_ch_free == 1'b1) begin + dma_if_cu_q = GET_TRANSACTION; + end else begin + dma_if_cu_q = IDLE_IF_CU; + end + end else begin + dma_if_cu_q = LOAD_TRANSACTION; + end + end + + default: begin + dma_if_cu_q = IDLE_IF_CU; + end + endcase + end + + /* DMA interface unit state transition ff */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_dma_if_fsm + if (!rst_ni) begin + dma_if_cu_d <= IDLE_IF_CU; + end else begin + dma_if_cu_d <= dma_if_cu_q; + end + end + + /* DMA interface unit transaction loading state transition logic */ + always_comb begin : proc_comb_dma_if_trans_load_fsm + unique case (dma_if_cu_load_d) + IDLE_IF_LOAD: begin + if (dma_if_cu_d == GET_TRANSACTION && im2col_fsms_done == 1'b0 && dma_ch_free == 1'b1) begin + if (dma_ch_first_write == 1'b0) begin + dma_if_cu_load_q = WRITE_DIMENSIONALITY; + end else begin + dma_if_cu_load_q = WRITE_TOP_PAD; + end + end else begin + dma_if_cu_load_q = IDLE_IF_LOAD; + end + end + + WRITE_DIMENSIONALITY: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_SLOTS; + end else if (dma_if_cu_d == IDLE_IF_CU) begin + dma_if_cu_load_q = IDLE_IF_LOAD; + end else begin + dma_if_cu_load_q = WRITE_DIMENSIONALITY; + end + end + + WRITE_SLOTS: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_SRC_DATATYPE; + end else if (dma_if_cu_d == IDLE_IF_CU) begin + dma_if_cu_load_q = IDLE_IF_LOAD; + end else begin + dma_if_cu_load_q = WRITE_SLOTS; + end + end + + WRITE_SRC_DATATYPE: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_DST_DATATYPE; + end else begin + dma_if_cu_load_q = WRITE_SRC_DATATYPE; + end + end + + WRITE_DST_DATATYPE: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_TOP_PAD; + end else begin + dma_if_cu_load_q = WRITE_DST_DATATYPE; + end + end + + WRITE_TOP_PAD: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_BOTTOM_PAD; + end else begin + dma_if_cu_load_q = WRITE_TOP_PAD; + end + end + + WRITE_BOTTOM_PAD: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_LEFT_PAD; + end else begin + dma_if_cu_load_q = WRITE_BOTTOM_PAD; + end + end + + WRITE_LEFT_PAD: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_RIGHT_PAD; + end else begin + dma_if_cu_load_q = WRITE_LEFT_PAD; + end + end + + WRITE_RIGHT_PAD: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_INPUT_PTR; + end else begin + dma_if_cu_load_q = WRITE_RIGHT_PAD; + end + end + + WRITE_INPUT_PTR: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_OUTPUT_PTR; + end else begin + dma_if_cu_load_q = WRITE_INPUT_PTR; + end + end + + WRITE_OUTPUT_PTR: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_INC_SRC_D1; + end else begin + dma_if_cu_load_q = WRITE_OUTPUT_PTR; + end + end + + WRITE_INC_SRC_D1: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_INC_SRC_D2; + end else begin + dma_if_cu_load_q = WRITE_INC_SRC_D1; + end + end + + WRITE_INC_SRC_D2: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_INC_DST_D1; + end else begin + dma_if_cu_load_q = WRITE_INC_SRC_D2; + end + end + + WRITE_INC_DST_D1: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_INC_DST_D2; + end else begin + dma_if_cu_load_q = WRITE_INC_DST_D1; + end + end + + WRITE_INC_DST_D2: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_SIZE_D2; + end else begin + dma_if_cu_load_q = WRITE_INC_DST_D2; + end + end + + WRITE_SIZE_D2: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = WRITE_SIZE_D1; + end else begin + dma_if_cu_load_q = WRITE_SIZE_D2; + end + end + + WRITE_SIZE_D1: begin + if (dma_regintfc_done == 1'b1) begin + dma_if_cu_load_q = DONE; + end else begin + dma_if_cu_load_q = WRITE_SIZE_D1; + end + end + + DONE: begin + dma_if_cu_load_q = IDLE_IF_LOAD; + end + + default: begin + dma_if_cu_load_q = IDLE_IF_LOAD; + end + + endcase + end + + always_comb begin : proc_comb_dma_if_trans_load_fsm_regintfc + dma_if_loaded = 1'b0; + dma_regintfc_start = 1'b0; + fifo_pop = 1'b0; + dma_wdata = '0; + dma_addr = '0; + + unique case (dma_if_cu_load_d) + IDLE_IF_LOAD: begin + end + + WRITE_DIMENSIONALITY: begin + dma_wdata = 32'h1; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_DIM_CONFIG_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_SLOTS: begin + dma_wdata = {reg2hw.slot.tx_trigger_slot.q, reg2hw.slot.rx_trigger_slot.q}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SLOT_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_SRC_DATATYPE: begin + dma_wdata = {30'h0, reg2hw.data_type.q} & 32'h3; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SRC_DATA_TYPE_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_DST_DATATYPE: begin + dma_wdata = {30'h0, reg2hw.data_type.q} & 32'h3; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_DST_DATA_TYPE_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_TOP_PAD: begin + dma_wdata = {24'h0, fifo_output.n_zeros_top}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_PAD_TOP_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_BOTTOM_PAD: begin + dma_wdata = {24'h0, fifo_output.n_zeros_bottom}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_PAD_BOTTOM_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_LEFT_PAD: begin + dma_wdata = {24'h0, fifo_output.n_zeros_left}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_PAD_LEFT_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_RIGHT_PAD: begin + dma_wdata = {24'h0, fifo_output.n_zeros_right}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_PAD_RIGHT_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_INPUT_PTR: begin + dma_wdata = fifo_output.input_ptr; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SRC_PTR_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_OUTPUT_PTR: begin + dma_wdata = fifo_output.output_ptr; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_DST_PTR_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_INC_SRC_D1: begin + dma_wdata = (1 << {28'h0, reg2hw.log_strides_d1.q}) << (2 - reg2hw.data_type.q) & 32'h3f; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SRC_PTR_INC_D1_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_INC_SRC_D2: begin + dma_wdata = {9'h0, fifo_output.in_inc_d2} << (2 - reg2hw.data_type.q) & 32'h7fffff; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SRC_PTR_INC_D2_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_INC_DST_D1: begin + dma_wdata = (4 >> reg2hw.data_type.q) & 32'h3f; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_DST_PTR_INC_D1_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_INC_DST_D2: begin + dma_wdata = (4 >> reg2hw.data_type.q) & 32'h7fffff; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_DST_PTR_INC_D2_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_SIZE_D2: begin + dma_wdata = {16'h0, fifo_output.size_du_d2}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SIZE_D2_OFFSET}; + dma_regintfc_start = 1'b1; + end + + WRITE_SIZE_D1: begin + dma_wdata = {16'h0, fifo_output.size_du_d1}; + dma_addr = dma_ch_offset + {25'h0, dma_reg_pkg::DMA_SIZE_D1_OFFSET}; + dma_regintfc_start = 1'b1; + end + + DONE: begin + dma_if_loaded = 1'b1; + fifo_pop = 1'b1; + end + endcase + end + + /* DMA interface unit transaction loading state transition ff */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_dma_if_trans_load_dq + if (!rst_ni) begin + dma_if_cu_load_d <= IDLE_IF_LOAD; + end else begin + dma_if_cu_load_d <= dma_if_cu_load_q; + end + end + + /* Channel tracker */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_control_unit + if (!rst_ni) begin + dma_ch_free <= 1'b1; + dma_ch_first_write <= 1'b0; + end else begin + /* Set the dma_ch_free when im2col starts or when a transaction is finished */ + if (im2col_start == 1'b1) begin + dma_ch_first_write <= 1'b0; + dma_ch_free <= 1'b1; + end + + if (|(dma_ch_en_mask[core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] & dma_done_i) == 1'b1) begin + dma_ch_free <= 1'b1; + end + + /* Clear the ch free flag only if the next state won't be the IDLE state */ + if (dma_if_cu_d == GET_TRANSACTION && dma_if_cu_q != IDLE_IF_CU) begin + dma_ch_first_write <= 1'b1; + dma_ch_free <= 1'b0; + end + end + end + + /* FIFO reset */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_fifo_reset + if (!rst_ni) begin + fifo_flush <= 1'b1; + end else begin + fifo_flush <= 1'b0; + end + end + + /* Transaction IFR update */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_spc_ifr + if (~rst_ni) begin + im2col_spc_ifr <= '0; + end else if (reg2hw.interrupt_en.q == 1'b1) begin + // Enter here only if the im2col_done interrupt is enabled + if (im2col_done == 1'b1) begin + im2col_spc_ifr <= 1'b1; + end else if (reg2hw.spc_ifr.re == 1'b1) begin + // If the IFR bit is read, we must clear the transaction_ifr + im2col_spc_ifr <= 1'b0; + end + end + end + + /* Global fsm done signal update logic */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_spc_done + if (!rst_ni) begin + im2col_fsms_done <= 1'b0; + end else begin + if (im2col_done == 1'b1) begin + im2col_fsms_done <= 1'b0; + end else if (dma_if_cu_load_d == DONE && im2col_param_done == 1'b1 && fifo_usage == 1) begin + im2col_fsms_done <= 1'b1; + end + end + end + + /* Global done signal update logic */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_done + if (!rst_ni) begin + im2col_done <= 1'b0; + end else begin + if (im2col_fsms_done == 1'b1 && dma_ch_free == 1'b1) begin + im2col_done <= 1'b1; + end else begin + im2col_done <= 1'b0; + end + end + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + /* Start signal assignment */ + assign im2col_start = (reg2hw.num_ch.qe == 1'b1); + + /* Transaction loading process */ + assign hw2reg.status.d = im2col_status == READY; + + /* Interrupt management */ + assign hw2reg.spc_ifr.d = im2col_spc_ifr; + assign im2col_spc_done_int_o = im2col_spc_ifr; + + /* DMA channels mask register */ + assign dma_ch_en_mask = reg2hw.spc_ch_mask.q; + + /* DMA channel offset */ + assign dma_ch_offset = reg2hw.spc_ch_offset.q; + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_param_fsm.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_param_fsm.sv new file mode 100644 index 00000000..2bd1d190 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_param_fsm.sv @@ -0,0 +1,551 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Parameter FSM of the im2col accelerator. + */ + +module im2col_spc_param_fsm + import im2col_spc_reg_pkg::*; + import dma_if_pkg::*; +( + input logic clk_i, + input logic rst_ni, + input im2col_spc_reg2hw_t reg2hw_i, + input logic im2col_done_i, + input logic fifo_full_i, + input logic im2col_start_i, + output logic fifo_push_o, + output logic im2col_param_done_o, + output dma_if_t fifo_input_o + +); + /*_________________________________________________________________________________________________________________________________ */ + + /* Signals declaration */ + + /* Register interface */ + im2col_spc_reg2hw_t reg2hw; + + /* + * Every "comp" state refers to variable computations that precede the DMA call in the + * loop, while any "param" state refers to the DMA parameters computation that follows the DMA call. + */ + enum { + IDLE, + N_ZEROS_PRECOMP, + ZEROS_COND_EVAL, + N_ZEROS_COMP_1, + N_ZEROS_COMP_2, + N_ZEROS_COMP_3, + OUT_PTR_UPDATE, + IM_OFFSET_UPDATE, + INDEX_COMP_1, + INDEX_COMP_2, + INDEX_COMP_3, + START_DMA_RUN + } + param_state_q, param_state_d; + + /* Parameters computation signals */ + logic [7:0] w_offset; + logic [7:0] h_offset; + logic [7:0] im_c; + logic [7:0] im_row; + logic [7:0] im_col; + logic [7:0] fw_min_w_offset; + logic [7:0] fh_min_h_offset; + logic [7:0] n_zeros_left; + logic [7:0] n_zeros_right; + logic [7:0] n_zeros_top; + logic [7:0] n_zeros_bottom; + logic [15:0] size_transfer_1d; + logic [15:0] size_transfer_2d; + logic [31:0] index; + logic [31:0] h_offset_counter; + logic [31:0] im_c_counter; + logic [15:0] ch_col_counter; + logic [7:0] batch_counter; + logic [31:0] input_data_ptr; + logic [31:0] output_data_ptr; + logic [31:0] source_inc_d2; + logic [31:0] out_data_ptr_inc; + logic left_zero_cond; + logic top_zero_cond; + logic right_zero_cond; + logic bottom_zero_cond; + logic [7:0] n_zeros_left_std; + logic [7:0] n_zeros_top_std; + logic [7:0] n_zeros_right_std; + logic [7:0] n_zeros_bottom_std; + + /* Pipelining control signals */ + logic output_data_ptr_en; + logic im_offset_en; + logic batch_inc_en; + logic batch_rst; + logic zeros_phase1_en; + logic zeros_phase2_en; + logic zeros_rst; + logic output_data_ptr_rst; + logic pipe_rst; + + /* Status signals */ + logic im2col_param_done; + logic im2col_done; + logic im2col_start; + logic fifo_push; + logic fifo_full; + + /* Pipelining signals */ + logic [7:0] n_zeros_left_comp1_n; + logic [7:0] n_zeros_top_comp1_n; + logic [7:0] n_zeros_right_comp1_n; + logic [7:0] n_zeros_bottom_comp1_n; + logic [7:0] n_zeros_left_comp1; + logic [7:0] n_zeros_top_comp1; + logic [7:0] n_zeros_right_comp1; + logic [7:0] n_zeros_bottom_comp1; + logic [31:0] index_comp1_n; + logic [31:0] index_comp2_n; + logic [31:0] index_comp3_n; + logic [31:0] index_comp4_n; + logic [31:0] index_comp1; + logic [31:0] index_comp2; + logic [31:0] index_comp3; + logic [31:0] index_comp4; + + /*_________________________________________________________________________________________________________________________________ */ + + /* FSMs instantiation */ + + /* Parameter computation state transition ff */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_param_state_dq + if (!rst_ni) begin + param_state_d <= IDLE; + end else begin + param_state_d <= param_state_q; + end + end + + /* Parameter computation done signal update */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_param_done + if (!rst_ni) begin + im2col_param_done <= 1'b0; + end else begin + if (im2col_done == 1'b1) begin + im2col_param_done <= 1'b0; + end else if (ch_col_counter == (reg2hw.ch_col.q - 1) && batch_counter == reg2hw.batch.q) begin + im2col_param_done <= 1'b1; + end + end + end + + /* Parameter computation state transition FSM */ + always_comb begin : proc_comb_param_state_fsm + fifo_push = 1'b0; + batch_inc_en = 1'b0; + batch_rst = 1'b0; + output_data_ptr_en = 1'b0; + im_offset_en = 1'b0; + zeros_phase1_en = 1'b0; + zeros_phase2_en = 1'b0; + zeros_rst = 1'b0; + output_data_ptr_rst = 1'b0; + + unique case (param_state_d) + + IDLE: begin + batch_rst = 1'b1; + zeros_rst = 1'b1; + output_data_ptr_rst = 1'b1; + if (im2col_start == 1'b1) begin + param_state_q = N_ZEROS_PRECOMP; + end else begin + param_state_q = IDLE; + end + end + + /* Cycle needed to precompute parts of both the zero condition and the number of zero computations + * and to reduce the datapath for FPGA targets. Every signal is identical to the IDLE state. + * @Tod0: is this really necessary? + */ + N_ZEROS_PRECOMP: begin + batch_rst = 1'b1; + zeros_rst = 1'b1; + output_data_ptr_rst = 1'b1; + param_state_q = ZEROS_COND_EVAL; + end + + ZEROS_COND_EVAL: begin + if (im2col_param_done == 1'b1) begin + param_state_q = IDLE; + end else begin + param_state_q = N_ZEROS_COMP_1; + end + end + + N_ZEROS_COMP_1: begin + zeros_phase1_en = 1'b1; + param_state_q = N_ZEROS_COMP_2; + end + + N_ZEROS_COMP_2: begin + zeros_phase2_en = 1'b1; + param_state_q = N_ZEROS_COMP_3; + end + + N_ZEROS_COMP_3: begin + zeros_phase2_en = 1'b1; + param_state_q = INDEX_COMP_1; + end + + INDEX_COMP_1: begin + param_state_q = INDEX_COMP_2; + end + + INDEX_COMP_2: begin + param_state_q = INDEX_COMP_3; + end + + INDEX_COMP_3: begin + if (fifo_full == 1'b0) begin + param_state_q = START_DMA_RUN; + end else begin + param_state_q = INDEX_COMP_3; + end + end + + OUT_PTR_UPDATE: begin + batch_inc_en = 1'b1; + output_data_ptr_en = 1'b1; + if (batch_counter == reg2hw.batch.q - 1) begin + param_state_q = IM_OFFSET_UPDATE; + end else begin + param_state_q = ZEROS_COND_EVAL; + end + end + + IM_OFFSET_UPDATE: begin + batch_rst = 1'b1; + im_offset_en = 1'b1; + param_state_q = ZEROS_COND_EVAL; + end + + START_DMA_RUN: begin + fifo_push = 1'b1; + param_state_q = OUT_PTR_UPDATE; + end + + default: begin + param_state_q = IDLE; + end + + endcase + end + + /* Number of zeros computation */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_zeros_phase1_comp + if (!rst_ni) begin + fw_min_w_offset <= '0; + fh_min_h_offset <= '0; + end else begin + if (zeros_phase1_en == 1'b1) begin + fw_min_w_offset <= reg2hw.fw.q - 1 - w_offset; + fh_min_h_offset <= reg2hw.fh.q - 1 - h_offset; + end else if (zeros_rst == 1'b1) begin + fw_min_w_offset <= '0; + fh_min_h_offset <= '0; + end + end + end + + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_zeros_phase2_comp + if (!rst_ni) begin + n_zeros_left <= '0; + n_zeros_right <= '0; + n_zeros_top <= '0; + n_zeros_bottom <= '0; + end else begin + if (zeros_phase2_en == 1'b1) begin + /* Left zeros computation */ + if (w_offset >= {2'h0, reg2hw.pad_left.q}) begin + n_zeros_left <= 0; + end else begin + n_zeros_left <= n_zeros_left_std + {7'h0, left_zero_cond}; // Sum a 1 if the condition is true + end + + /* Top zeros computation */ + if (h_offset >= {2'h0, reg2hw.pad_top.q}) begin + n_zeros_top <= 0; + end else begin + n_zeros_top <= n_zeros_top_std + {7'h0, top_zero_cond}; + end + + /* Right zeros computation */ + if (fw_min_w_offset >= {2'h0, reg2hw.pad_right.q} || reg2hw.adpt_pad_right.q == 0) begin + n_zeros_right <= 0; + end else begin + n_zeros_right <= n_zeros_right_std + {7'h0, right_zero_cond}; + end + + /* Bottom zeros computation */ + if (fh_min_h_offset >= {2'h0, reg2hw.pad_bottom.q} || reg2hw.adpt_pad_bottom.q == 0) begin + n_zeros_bottom <= 0; + end else begin + n_zeros_bottom <= n_zeros_bottom_std + {7'h0, bottom_zero_cond}; + end + end else if (zeros_rst == 1'b1) begin + n_zeros_left <= '0; + n_zeros_right <= '0; + n_zeros_top <= '0; + n_zeros_bottom <= '0; + end + end + end + + + /* Batch counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_batch_counter + if (!rst_ni) begin + batch_counter <= '0; + end else begin + if (batch_inc_en == 1'b1) begin + batch_counter <= batch_counter + 1; + end else if (batch_rst == 1'b1) begin + batch_counter <= '0; + end + end + end + + /* w_offset counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_w_offset_counter + if (!rst_ni) begin + w_offset <= '0; + end else begin + if (im2col_param_done == 1'b1) begin + w_offset <= '0; + end else if (im_offset_en == 1'b1) begin + if (w_offset == reg2hw.fw.q - 1) begin + w_offset <= '0; + end else begin + w_offset <= w_offset + 1; + end + end + end + end + + /* h_offset counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_h_offset_counter + if (!rst_ni) begin + h_offset <= '0; + h_offset_counter <= '0; + end else begin + if (im2col_param_done == 1'b1) begin + h_offset <= '0; + h_offset_counter <= '0; + end else if (im_offset_en == 1'b1) begin + if (h_offset_counter == {24'h0, reg2hw.fw.q} - 1) begin + h_offset_counter <= '0; + if (h_offset == reg2hw.fh.q - 1) begin + h_offset <= '0; + end else begin + h_offset <= h_offset + 1; + end + end else begin + h_offset_counter <= h_offset_counter + 1; + end + end + end + end + + /* im_c counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_im_c_counter + if (!rst_ni) begin + im_c <= '0; + im_c_counter <= '0; + end else begin + if (im2col_param_done == 1'b1) begin + im_c <= '0; + im_c_counter <= '0; + end else if (im_offset_en == 1'b1) begin + if (im_c_counter == {24'h0, reg2hw.fh.q} * {24'h0, reg2hw.fw.q} - 1) begin + im_c_counter <= '0; + im_c <= im_c + 1; + end else begin + im_c_counter <= im_c_counter + 1; + end + end + end + end + + /* ch_col counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_ch_col_counter + if (!rst_ni) begin + ch_col_counter <= '0; + end else begin + if (im2col_param_done == 1'b1) begin + ch_col_counter <= '0; + end else if (im_offset_en == 1'b1) begin + if (ch_col_counter == reg2hw.ch_col.q - 1) begin + ch_col_counter <= '0; + end else begin + ch_col_counter <= ch_col_counter + 1; + end + end + end + end + + /* Output data pointer counter */ + always_ff @(posedge clk_i, negedge rst_ni) begin : proc_ff_output_data_ptr + if (!rst_ni) begin + output_data_ptr <= reg2hw.dst_ptr.q; + end else begin + if (output_data_ptr_en == 1'b1) begin + output_data_ptr <= output_data_ptr + out_data_ptr_inc; + end else if (output_data_ptr_rst == 1'b1) begin + output_data_ptr <= reg2hw.dst_ptr.q; + end + end + end + + /*_________________________________________________________________________________________________________________________________ */ + + /* Modules instantiation */ + + /* Pipeline modules */ + pipe_reg #( + .WIDTH(8) + ) pipe_reg_left_zeros ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (n_zeros_left_comp1_n), + .data_out(n_zeros_left_comp1) + ); + + pipe_reg #( + .WIDTH(8) + ) pipe_reg_top_zeros ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (n_zeros_top_comp1_n), + .data_out(n_zeros_top_comp1) + ); + + pipe_reg #( + .WIDTH(8) + ) pipe_reg_right_zeros ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (n_zeros_right_comp1_n), + .data_out(n_zeros_right_comp1) + ); + + pipe_reg #( + .WIDTH(8) + ) pipe_reg_bottom_zeros ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (n_zeros_bottom_comp1_n), + .data_out(n_zeros_bottom_comp1) + ); + + pipe_reg #( + .WIDTH(32) + ) pipe_reg_index_comp1 ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (index_comp1_n), + .data_out(index_comp1) + ); + + pipe_reg #( + .WIDTH(32) + ) pipe_reg_index_comp2 ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (index_comp2_n), + .data_out(index_comp2) + ); + + pipe_reg #( + .WIDTH(32) + ) pipe_reg_index_comp3 ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (index_comp3_n), + .data_out(index_comp3) + ); + + pipe_reg #( + .WIDTH(32) + ) pipe_reg_index_comp4 ( + .clk_i, + .rst_ni (pipe_rst), + .data_in (index_comp4_n), + .data_out(index_comp4) + ); + + + /*_________________________________________________________________________________________________________________________________ */ + + /* Signal assignments */ + + assign im_row = h_offset - {2'h0, reg2hw.pad_top.q}; // im_row = h_offset - TOP_PAD; + assign im_col = w_offset - {2'h0, reg2hw.pad_left.q}; // im_col = w_offset - LEFT_PAD; + + assign n_zeros_left_comp1_n = ({2'h0, reg2hw.pad_left.q} - w_offset); + assign n_zeros_left_std = n_zeros_left_comp1 >> {4'h0, reg2hw.log_strides_d1.q}; + + assign n_zeros_top_comp1_n = ({2'h0, reg2hw.pad_top.q} - h_offset); + assign n_zeros_top_std = n_zeros_top_comp1 >> {4'h0, reg2hw.log_strides_d2.q}; + + assign n_zeros_right_comp1_n = (reg2hw.adpt_pad_right.q - fw_min_w_offset); + assign n_zeros_right_std = n_zeros_right_comp1 >> {4'h0, reg2hw.log_strides_d1.q}; + + assign n_zeros_bottom_comp1_n = (reg2hw.adpt_pad_bottom.q - fh_min_h_offset); + assign n_zeros_bottom_std = n_zeros_bottom_comp1 >> {4'h0, reg2hw.log_strides_d2.q}; + + assign size_transfer_1d = reg2hw.n_patches_w.q - {8'h0, n_zeros_left} - {8'h0, n_zeros_right}; + assign size_transfer_2d = reg2hw.n_patches_h.q - {8'h0, n_zeros_top} - {8'h0, n_zeros_bottom}; + + assign index_comp1_n = ({24'h0, batch_counter} * {24'h0, reg2hw.num_ch.q} + {24'h0, im_c}); + assign index_comp2_n = index_comp1 * {16'h0, reg2hw.ih.q}; + assign index_comp3_n = (index_comp2 + ({{24{im_row[7]}}, im_row} + ({24'h0, n_zeros_top} << {4'h0, reg2hw.log_strides_d2.q}))); + assign index_comp4_n = index_comp3 * {16'h0, reg2hw.iw.q} + {{24{im_col[7]}}, im_col}; + assign index = index_comp4 + ({24'h0, n_zeros_left} << {24'h0, reg2hw.log_strides_d1.q}); + + assign source_inc_d2 = (({16'h0, reg2hw.iw.q} << {24'h0, reg2hw.log_strides_d2.q}) - (({16'h0, size_transfer_1d} - 1) << {24'h0, reg2hw.log_strides_d1.q})); + assign input_data_ptr = reg2hw.src_ptr.q + (index << (2 - reg2hw.data_type.q)); + assign out_data_ptr_inc = ({16'h0, reg2hw.n_patches_h.q} * {16'h0, reg2hw.n_patches_w.q}) << (2 - reg2hw.data_type.q); + + assign left_zero_cond = |((n_zeros_left_comp1) & ((1 << {reg2hw.log_strides_d1.q}) - 1)); + assign top_zero_cond = |((n_zeros_top_comp1) & ((1 << {reg2hw.log_strides_d2.q}) - 1)); + assign right_zero_cond = |((n_zeros_right_comp1) & ((1 << {reg2hw.log_strides_d1.q}) - 1)); + assign bottom_zero_cond = |((n_zeros_bottom_comp1) & ((1 << {reg2hw.log_strides_d2.q}) - 1)); + + assign pipe_rst = (rst_ni && param_state_d != IDLE); + + /* Output signals */ + assign im2col_param_done_o = im2col_param_done; + assign reg2hw = reg2hw_i; + assign im2col_done = im2col_done_i; + assign im2col_start = im2col_start_i; + assign fifo_push_o = fifo_push; + assign fifo_full = fifo_full_i; + + assign fifo_input_o.input_ptr = input_data_ptr; + assign fifo_input_o.output_ptr = output_data_ptr; + assign fifo_input_o.in_inc_d2 = source_inc_d2[22:0]; + assign fifo_input_o.n_zeros_top = n_zeros_top; + assign fifo_input_o.n_zeros_bottom = n_zeros_bottom; + assign fifo_input_o.n_zeros_left = n_zeros_left; + assign fifo_input_o.n_zeros_right = n_zeros_right; + assign fifo_input_o.size_du_d1 = size_transfer_1d; + assign fifo_input_o.size_du_d2 = size_transfer_2d; + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_pkg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_pkg.sv new file mode 100644 index 00000000..2db852b7 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_pkg.sv @@ -0,0 +1,227 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package im2col_spc_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 7; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed {logic [31:0] q;} im2col_spc_reg2hw_src_ptr_reg_t; + + typedef struct packed {logic [31:0] q;} im2col_spc_reg2hw_dst_ptr_reg_t; + + typedef struct packed {logic [15:0] q;} im2col_spc_reg2hw_iw_reg_t; + + typedef struct packed {logic [15:0] q;} im2col_spc_reg2hw_ih_reg_t; + + typedef struct packed {logic [7:0] q;} im2col_spc_reg2hw_fw_reg_t; + + typedef struct packed {logic [7:0] q;} im2col_spc_reg2hw_fh_reg_t; + + typedef struct packed {logic [7:0] q;} im2col_spc_reg2hw_batch_reg_t; + + typedef struct packed { + logic [7:0] q; + logic qe; + } im2col_spc_reg2hw_num_ch_reg_t; + + typedef struct packed {logic [15:0] q;} im2col_spc_reg2hw_ch_col_reg_t; + + typedef struct packed {logic [15:0] q;} im2col_spc_reg2hw_n_patches_w_reg_t; + + typedef struct packed {logic [15:0] q;} im2col_spc_reg2hw_n_patches_h_reg_t; + + typedef struct packed {logic [7:0] q;} im2col_spc_reg2hw_adpt_pad_right_reg_t; + + typedef struct packed {logic [7:0] q;} im2col_spc_reg2hw_adpt_pad_bottom_reg_t; + + typedef struct packed {logic [3:0] q;} im2col_spc_reg2hw_log_strides_d1_reg_t; + + typedef struct packed {logic [3:0] q;} im2col_spc_reg2hw_log_strides_d2_reg_t; + + typedef struct packed { + logic q; + logic re; + } im2col_spc_reg2hw_status_reg_t; + + typedef struct packed { + struct packed {logic [15:0] q;} rx_trigger_slot; + struct packed {logic [15:0] q;} tx_trigger_slot; + } im2col_spc_reg2hw_slot_reg_t; + + typedef struct packed {logic [1:0] q;} im2col_spc_reg2hw_data_type_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } im2col_spc_reg2hw_pad_top_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } im2col_spc_reg2hw_pad_bottom_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } im2col_spc_reg2hw_pad_right_reg_t; + + typedef struct packed { + logic [5:0] q; + logic qe; + } im2col_spc_reg2hw_pad_left_reg_t; + + typedef struct packed {logic q;} im2col_spc_reg2hw_interrupt_en_reg_t; + + typedef struct packed { + logic q; + logic re; + } im2col_spc_reg2hw_spc_ifr_reg_t; + + typedef struct packed {logic [31:0] q;} im2col_spc_reg2hw_spc_ch_mask_reg_t; + + typedef struct packed {logic [31:0] q;} im2col_spc_reg2hw_spc_ch_offset_reg_t; + + typedef struct packed {logic d;} im2col_spc_hw2reg_status_reg_t; + + typedef struct packed {logic d;} im2col_spc_hw2reg_spc_ifr_reg_t; + + // Register -> HW type + typedef struct packed { + im2col_spc_reg2hw_src_ptr_reg_t src_ptr; // [331:300] + im2col_spc_reg2hw_dst_ptr_reg_t dst_ptr; // [299:268] + im2col_spc_reg2hw_iw_reg_t iw; // [267:252] + im2col_spc_reg2hw_ih_reg_t ih; // [251:236] + im2col_spc_reg2hw_fw_reg_t fw; // [235:228] + im2col_spc_reg2hw_fh_reg_t fh; // [227:220] + im2col_spc_reg2hw_batch_reg_t batch; // [219:212] + im2col_spc_reg2hw_num_ch_reg_t num_ch; // [211:203] + im2col_spc_reg2hw_ch_col_reg_t ch_col; // [202:187] + im2col_spc_reg2hw_n_patches_w_reg_t n_patches_w; // [186:171] + im2col_spc_reg2hw_n_patches_h_reg_t n_patches_h; // [170:155] + im2col_spc_reg2hw_adpt_pad_right_reg_t adpt_pad_right; // [154:147] + im2col_spc_reg2hw_adpt_pad_bottom_reg_t adpt_pad_bottom; // [146:139] + im2col_spc_reg2hw_log_strides_d1_reg_t log_strides_d1; // [138:135] + im2col_spc_reg2hw_log_strides_d2_reg_t log_strides_d2; // [134:131] + im2col_spc_reg2hw_status_reg_t status; // [130:129] + im2col_spc_reg2hw_slot_reg_t slot; // [128:97] + im2col_spc_reg2hw_data_type_reg_t data_type; // [96:95] + im2col_spc_reg2hw_pad_top_reg_t pad_top; // [94:88] + im2col_spc_reg2hw_pad_bottom_reg_t pad_bottom; // [87:81] + im2col_spc_reg2hw_pad_right_reg_t pad_right; // [80:74] + im2col_spc_reg2hw_pad_left_reg_t pad_left; // [73:67] + im2col_spc_reg2hw_interrupt_en_reg_t interrupt_en; // [66:66] + im2col_spc_reg2hw_spc_ifr_reg_t spc_ifr; // [65:64] + im2col_spc_reg2hw_spc_ch_mask_reg_t spc_ch_mask; // [63:32] + im2col_spc_reg2hw_spc_ch_offset_reg_t spc_ch_offset; // [31:0] + } im2col_spc_reg2hw_t; + + // HW -> register type + typedef struct packed { + im2col_spc_hw2reg_status_reg_t status; // [1:1] + im2col_spc_hw2reg_spc_ifr_reg_t spc_ifr; // [0:0] + } im2col_spc_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] IM2COL_SPC_SRC_PTR_OFFSET = 7'h0; + parameter logic [BlockAw-1:0] IM2COL_SPC_DST_PTR_OFFSET = 7'h4; + parameter logic [BlockAw-1:0] IM2COL_SPC_IW_OFFSET = 7'h8; + parameter logic [BlockAw-1:0] IM2COL_SPC_IH_OFFSET = 7'hc; + parameter logic [BlockAw-1:0] IM2COL_SPC_FW_OFFSET = 7'h10; + parameter logic [BlockAw-1:0] IM2COL_SPC_FH_OFFSET = 7'h14; + parameter logic [BlockAw-1:0] IM2COL_SPC_BATCH_OFFSET = 7'h18; + parameter logic [BlockAw-1:0] IM2COL_SPC_NUM_CH_OFFSET = 7'h1c; + parameter logic [BlockAw-1:0] IM2COL_SPC_CH_COL_OFFSET = 7'h20; + parameter logic [BlockAw-1:0] IM2COL_SPC_N_PATCHES_W_OFFSET = 7'h24; + parameter logic [BlockAw-1:0] IM2COL_SPC_N_PATCHES_H_OFFSET = 7'h28; + parameter logic [BlockAw-1:0] IM2COL_SPC_ADPT_PAD_RIGHT_OFFSET = 7'h2c; + parameter logic [BlockAw-1:0] IM2COL_SPC_ADPT_PAD_BOTTOM_OFFSET = 7'h30; + parameter logic [BlockAw-1:0] IM2COL_SPC_LOG_STRIDES_D1_OFFSET = 7'h34; + parameter logic [BlockAw-1:0] IM2COL_SPC_LOG_STRIDES_D2_OFFSET = 7'h38; + parameter logic [BlockAw-1:0] IM2COL_SPC_STATUS_OFFSET = 7'h3c; + parameter logic [BlockAw-1:0] IM2COL_SPC_SLOT_OFFSET = 7'h40; + parameter logic [BlockAw-1:0] IM2COL_SPC_DATA_TYPE_OFFSET = 7'h44; + parameter logic [BlockAw-1:0] IM2COL_SPC_PAD_TOP_OFFSET = 7'h48; + parameter logic [BlockAw-1:0] IM2COL_SPC_PAD_BOTTOM_OFFSET = 7'h4c; + parameter logic [BlockAw-1:0] IM2COL_SPC_PAD_RIGHT_OFFSET = 7'h50; + parameter logic [BlockAw-1:0] IM2COL_SPC_PAD_LEFT_OFFSET = 7'h54; + parameter logic [BlockAw-1:0] IM2COL_SPC_INTERRUPT_EN_OFFSET = 7'h58; + parameter logic [BlockAw-1:0] IM2COL_SPC_SPC_IFR_OFFSET = 7'h5c; + parameter logic [BlockAw-1:0] IM2COL_SPC_SPC_CH_MASK_OFFSET = 7'h60; + parameter logic [BlockAw-1:0] IM2COL_SPC_SPC_CH_OFFSET_OFFSET = 7'h64; + + // Reset values for hwext registers and their fields + parameter logic [0:0] IM2COL_SPC_STATUS_RESVAL = 1'h1; + parameter logic [0:0] IM2COL_SPC_STATUS_READY_RESVAL = 1'h1; + parameter logic [0:0] IM2COL_SPC_SPC_IFR_RESVAL = 1'h0; + parameter logic [0:0] IM2COL_SPC_SPC_IFR_FLAG_RESVAL = 1'h0; + + // Register index + typedef enum int { + IM2COL_SPC_SRC_PTR, + IM2COL_SPC_DST_PTR, + IM2COL_SPC_IW, + IM2COL_SPC_IH, + IM2COL_SPC_FW, + IM2COL_SPC_FH, + IM2COL_SPC_BATCH, + IM2COL_SPC_NUM_CH, + IM2COL_SPC_CH_COL, + IM2COL_SPC_N_PATCHES_W, + IM2COL_SPC_N_PATCHES_H, + IM2COL_SPC_ADPT_PAD_RIGHT, + IM2COL_SPC_ADPT_PAD_BOTTOM, + IM2COL_SPC_LOG_STRIDES_D1, + IM2COL_SPC_LOG_STRIDES_D2, + IM2COL_SPC_STATUS, + IM2COL_SPC_SLOT, + IM2COL_SPC_DATA_TYPE, + IM2COL_SPC_PAD_TOP, + IM2COL_SPC_PAD_BOTTOM, + IM2COL_SPC_PAD_RIGHT, + IM2COL_SPC_PAD_LEFT, + IM2COL_SPC_INTERRUPT_EN, + IM2COL_SPC_SPC_IFR, + IM2COL_SPC_SPC_CH_MASK, + IM2COL_SPC_SPC_CH_OFFSET + } im2col_spc_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] IM2COL_SPC_PERMIT[26] = '{ + 4'b1111, // index[ 0] IM2COL_SPC_SRC_PTR + 4'b1111, // index[ 1] IM2COL_SPC_DST_PTR + 4'b0011, // index[ 2] IM2COL_SPC_IW + 4'b0011, // index[ 3] IM2COL_SPC_IH + 4'b0001, // index[ 4] IM2COL_SPC_FW + 4'b0001, // index[ 5] IM2COL_SPC_FH + 4'b0001, // index[ 6] IM2COL_SPC_BATCH + 4'b0001, // index[ 7] IM2COL_SPC_NUM_CH + 4'b0011, // index[ 8] IM2COL_SPC_CH_COL + 4'b0011, // index[ 9] IM2COL_SPC_N_PATCHES_W + 4'b0011, // index[10] IM2COL_SPC_N_PATCHES_H + 4'b0001, // index[11] IM2COL_SPC_ADPT_PAD_RIGHT + 4'b0001, // index[12] IM2COL_SPC_ADPT_PAD_BOTTOM + 4'b0001, // index[13] IM2COL_SPC_LOG_STRIDES_D1 + 4'b0001, // index[14] IM2COL_SPC_LOG_STRIDES_D2 + 4'b0001, // index[15] IM2COL_SPC_STATUS + 4'b1111, // index[16] IM2COL_SPC_SLOT + 4'b0001, // index[17] IM2COL_SPC_DATA_TYPE + 4'b0001, // index[18] IM2COL_SPC_PAD_TOP + 4'b0001, // index[19] IM2COL_SPC_PAD_BOTTOM + 4'b0001, // index[20] IM2COL_SPC_PAD_RIGHT + 4'b0001, // index[21] IM2COL_SPC_PAD_LEFT + 4'b0001, // index[22] IM2COL_SPC_INTERRUPT_EN + 4'b0001, // index[23] IM2COL_SPC_SPC_IFR + 4'b1111, // index[24] IM2COL_SPC_SPC_CH_MASK + 4'b1111 // index[25] IM2COL_SPC_SPC_CH_OFFSET + }; + +endpackage + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_top.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_top.sv new file mode 100644 index 00000000..a364f98c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_reg_top.sv @@ -0,0 +1,1182 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module im2col_spc_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 7 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output im2col_spc_reg_pkg::im2col_spc_reg2hw_t reg2hw, // Write + input im2col_spc_reg_pkg::im2col_spc_hw2reg_t hw2reg, // Read + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import im2col_spc_reg_pkg::*; + + localparam int DW = 32; + localparam int DBW = DW / 8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [ AW-1:0] reg_addr; + logic [ DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [ DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic [31:0] src_ptr_qs; + logic [31:0] src_ptr_wd; + logic src_ptr_we; + logic [31:0] dst_ptr_qs; + logic [31:0] dst_ptr_wd; + logic dst_ptr_we; + logic [15:0] iw_qs; + logic [15:0] iw_wd; + logic iw_we; + logic [15:0] ih_qs; + logic [15:0] ih_wd; + logic ih_we; + logic [7:0] fw_qs; + logic [7:0] fw_wd; + logic fw_we; + logic [7:0] fh_qs; + logic [7:0] fh_wd; + logic fh_we; + logic [7:0] batch_qs; + logic [7:0] batch_wd; + logic batch_we; + logic [7:0] num_ch_qs; + logic [7:0] num_ch_wd; + logic num_ch_we; + logic [15:0] ch_col_qs; + logic [15:0] ch_col_wd; + logic ch_col_we; + logic [15:0] n_patches_w_qs; + logic [15:0] n_patches_w_wd; + logic n_patches_w_we; + logic [15:0] n_patches_h_qs; + logic [15:0] n_patches_h_wd; + logic n_patches_h_we; + logic [7:0] adpt_pad_right_qs; + logic [7:0] adpt_pad_right_wd; + logic adpt_pad_right_we; + logic [7:0] adpt_pad_bottom_qs; + logic [7:0] adpt_pad_bottom_wd; + logic adpt_pad_bottom_we; + logic [3:0] log_strides_d1_qs; + logic [3:0] log_strides_d1_wd; + logic log_strides_d1_we; + logic [3:0] log_strides_d2_qs; + logic [3:0] log_strides_d2_wd; + logic log_strides_d2_we; + logic status_qs; + logic status_re; + logic [15:0] slot_rx_trigger_slot_qs; + logic [15:0] slot_rx_trigger_slot_wd; + logic slot_rx_trigger_slot_we; + logic [15:0] slot_tx_trigger_slot_qs; + logic [15:0] slot_tx_trigger_slot_wd; + logic slot_tx_trigger_slot_we; + logic [1:0] data_type_qs; + logic [1:0] data_type_wd; + logic data_type_we; + logic [5:0] pad_top_qs; + logic [5:0] pad_top_wd; + logic pad_top_we; + logic [5:0] pad_bottom_qs; + logic [5:0] pad_bottom_wd; + logic pad_bottom_we; + logic [5:0] pad_right_qs; + logic [5:0] pad_right_wd; + logic pad_right_we; + logic [5:0] pad_left_qs; + logic [5:0] pad_left_wd; + logic pad_left_we; + logic interrupt_en_qs; + logic interrupt_en_wd; + logic interrupt_en_we; + logic spc_ifr_qs; + logic spc_ifr_re; + logic [31:0] spc_ch_mask_qs; + logic [31:0] spc_ch_mask_wd; + logic spc_ch_mask_we; + logic [31:0] spc_ch_offset_qs; + logic [31:0] spc_ch_offset_wd; + logic spc_ch_offset_we; + + // Register instances + // R[src_ptr]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_src_ptr ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(src_ptr_we), + .wd(src_ptr_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.src_ptr.q), + + // to register interface (read) + .qs(src_ptr_qs) + ); + + + // R[dst_ptr]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h0) + ) u_dst_ptr ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(dst_ptr_we), + .wd(dst_ptr_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.dst_ptr.q), + + // to register interface (read) + .qs(dst_ptr_qs) + ); + + + // R[iw]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_iw ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(iw_we), + .wd(iw_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.iw.q), + + // to register interface (read) + .qs(iw_qs) + ); + + + // R[ih]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_ih ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(ih_we), + .wd(ih_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.ih.q), + + // to register interface (read) + .qs(ih_qs) + ); + + + // R[fw]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_fw ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(fw_we), + .wd(fw_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.fw.q), + + // to register interface (read) + .qs(fw_qs) + ); + + + // R[fh]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_fh ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(fh_we), + .wd(fh_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.fh.q), + + // to register interface (read) + .qs(fh_qs) + ); + + + // R[batch]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_batch ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(batch_we), + .wd(batch_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.batch.q), + + // to register interface (read) + .qs(batch_qs) + ); + + + // R[num_ch]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_num_ch ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(num_ch_we), + .wd(num_ch_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.num_ch.qe), + .q (reg2hw.num_ch.q), + + // to register interface (read) + .qs(num_ch_qs) + ); + + + // R[ch_col]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_ch_col ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(ch_col_we), + .wd(ch_col_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.ch_col.q), + + // to register interface (read) + .qs(ch_col_qs) + ); + + + // R[n_patches_w]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_n_patches_w ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(n_patches_w_we), + .wd(n_patches_w_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.n_patches_w.q), + + // to register interface (read) + .qs(n_patches_w_qs) + ); + + + // R[n_patches_h]: V(False) + + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_n_patches_h ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(n_patches_h_we), + .wd(n_patches_h_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.n_patches_h.q), + + // to register interface (read) + .qs(n_patches_h_qs) + ); + + + // R[adpt_pad_right]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_adpt_pad_right ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(adpt_pad_right_we), + .wd(adpt_pad_right_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.adpt_pad_right.q), + + // to register interface (read) + .qs(adpt_pad_right_qs) + ); + + + // R[adpt_pad_bottom]: V(False) + + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_adpt_pad_bottom ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(adpt_pad_bottom_we), + .wd(adpt_pad_bottom_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.adpt_pad_bottom.q), + + // to register interface (read) + .qs(adpt_pad_bottom_qs) + ); + + + // R[log_strides_d1]: V(False) + + prim_subreg #( + .DW (4), + .SWACCESS("RW"), + .RESVAL (4'h0) + ) u_log_strides_d1 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(log_strides_d1_we), + .wd(log_strides_d1_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.log_strides_d1.q), + + // to register interface (read) + .qs(log_strides_d1_qs) + ); + + + // R[log_strides_d2]: V(False) + + prim_subreg #( + .DW (4), + .SWACCESS("RW"), + .RESVAL (4'h0) + ) u_log_strides_d2 ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(log_strides_d2_we), + .wd(log_strides_d2_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.log_strides_d2.q), + + // to register interface (read) + .qs(log_strides_d2_qs) + ); + + + // R[status]: V(True) + + prim_subreg_ext #( + .DW(1) + ) u_status ( + .re (status_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.status.d), + .qre(reg2hw.status.re), + .qe (), + .q (reg2hw.status.q), + .qs (status_qs) + ); + + + // R[slot]: V(False) + + // F[rx_trigger_slot]: 15:0 + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_slot_rx_trigger_slot ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(slot_rx_trigger_slot_we), + .wd(slot_rx_trigger_slot_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.slot.rx_trigger_slot.q), + + // to register interface (read) + .qs(slot_rx_trigger_slot_qs) + ); + + + // F[tx_trigger_slot]: 31:16 + prim_subreg #( + .DW (16), + .SWACCESS("RW"), + .RESVAL (16'h0) + ) u_slot_tx_trigger_slot ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(slot_tx_trigger_slot_we), + .wd(slot_tx_trigger_slot_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.slot.tx_trigger_slot.q), + + // to register interface (read) + .qs(slot_tx_trigger_slot_qs) + ); + + + // R[data_type]: V(False) + + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_data_type ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(data_type_we), + .wd(data_type_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.data_type.q), + + // to register interface (read) + .qs(data_type_qs) + ); + + + // R[pad_top]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_top ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_top_we), + .wd(pad_top_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_top.qe), + .q (reg2hw.pad_top.q), + + // to register interface (read) + .qs(pad_top_qs) + ); + + + // R[pad_bottom]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_bottom ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_bottom_we), + .wd(pad_bottom_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_bottom.qe), + .q (reg2hw.pad_bottom.q), + + // to register interface (read) + .qs(pad_bottom_qs) + ); + + + // R[pad_right]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_right ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_right_we), + .wd(pad_right_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_right.qe), + .q (reg2hw.pad_right.q), + + // to register interface (read) + .qs(pad_right_qs) + ); + + + // R[pad_left]: V(False) + + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_pad_left ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(pad_left_we), + .wd(pad_left_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(reg2hw.pad_left.qe), + .q (reg2hw.pad_left.q), + + // to register interface (read) + .qs(pad_left_qs) + ); + + + // R[interrupt_en]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_interrupt_en ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(interrupt_en_we), + .wd(interrupt_en_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.interrupt_en.q), + + // to register interface (read) + .qs(interrupt_en_qs) + ); + + + // R[spc_ifr]: V(True) + + prim_subreg_ext #( + .DW(1) + ) u_spc_ifr ( + .re (spc_ifr_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.spc_ifr.d), + .qre(reg2hw.spc_ifr.re), + .qe (), + .q (reg2hw.spc_ifr.q), + .qs (spc_ifr_qs) + ); + + + // R[spc_ch_mask]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h1) + ) u_spc_ch_mask ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(spc_ch_mask_we), + .wd(spc_ch_mask_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.spc_ch_mask.q), + + // to register interface (read) + .qs(spc_ch_mask_qs) + ); + + + // R[spc_ch_offset]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("RW"), + .RESVAL (32'h1) + ) u_spc_ch_offset ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + // from register interface + .we(spc_ch_offset_we), + .wd(spc_ch_offset_wd), + + // from internal hardware + .de(1'b0), + .d ('0), + + // to internal hardware + .qe(), + .q (reg2hw.spc_ch_offset.q), + + // to register interface (read) + .qs(spc_ch_offset_qs) + ); + + + + + logic [25:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == IM2COL_SPC_SRC_PTR_OFFSET); + addr_hit[1] = (reg_addr == IM2COL_SPC_DST_PTR_OFFSET); + addr_hit[2] = (reg_addr == IM2COL_SPC_IW_OFFSET); + addr_hit[3] = (reg_addr == IM2COL_SPC_IH_OFFSET); + addr_hit[4] = (reg_addr == IM2COL_SPC_FW_OFFSET); + addr_hit[5] = (reg_addr == IM2COL_SPC_FH_OFFSET); + addr_hit[6] = (reg_addr == IM2COL_SPC_BATCH_OFFSET); + addr_hit[7] = (reg_addr == IM2COL_SPC_NUM_CH_OFFSET); + addr_hit[8] = (reg_addr == IM2COL_SPC_CH_COL_OFFSET); + addr_hit[9] = (reg_addr == IM2COL_SPC_N_PATCHES_W_OFFSET); + addr_hit[10] = (reg_addr == IM2COL_SPC_N_PATCHES_H_OFFSET); + addr_hit[11] = (reg_addr == IM2COL_SPC_ADPT_PAD_RIGHT_OFFSET); + addr_hit[12] = (reg_addr == IM2COL_SPC_ADPT_PAD_BOTTOM_OFFSET); + addr_hit[13] = (reg_addr == IM2COL_SPC_LOG_STRIDES_D1_OFFSET); + addr_hit[14] = (reg_addr == IM2COL_SPC_LOG_STRIDES_D2_OFFSET); + addr_hit[15] = (reg_addr == IM2COL_SPC_STATUS_OFFSET); + addr_hit[16] = (reg_addr == IM2COL_SPC_SLOT_OFFSET); + addr_hit[17] = (reg_addr == IM2COL_SPC_DATA_TYPE_OFFSET); + addr_hit[18] = (reg_addr == IM2COL_SPC_PAD_TOP_OFFSET); + addr_hit[19] = (reg_addr == IM2COL_SPC_PAD_BOTTOM_OFFSET); + addr_hit[20] = (reg_addr == IM2COL_SPC_PAD_RIGHT_OFFSET); + addr_hit[21] = (reg_addr == IM2COL_SPC_PAD_LEFT_OFFSET); + addr_hit[22] = (reg_addr == IM2COL_SPC_INTERRUPT_EN_OFFSET); + addr_hit[23] = (reg_addr == IM2COL_SPC_SPC_IFR_OFFSET); + addr_hit[24] = (reg_addr == IM2COL_SPC_SPC_CH_MASK_OFFSET); + addr_hit[25] = (reg_addr == IM2COL_SPC_SPC_CH_OFFSET_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[ 0] & (|(IM2COL_SPC_PERMIT[ 0] & ~reg_be))) | + (addr_hit[ 1] & (|(IM2COL_SPC_PERMIT[ 1] & ~reg_be))) | + (addr_hit[ 2] & (|(IM2COL_SPC_PERMIT[ 2] & ~reg_be))) | + (addr_hit[ 3] & (|(IM2COL_SPC_PERMIT[ 3] & ~reg_be))) | + (addr_hit[ 4] & (|(IM2COL_SPC_PERMIT[ 4] & ~reg_be))) | + (addr_hit[ 5] & (|(IM2COL_SPC_PERMIT[ 5] & ~reg_be))) | + (addr_hit[ 6] & (|(IM2COL_SPC_PERMIT[ 6] & ~reg_be))) | + (addr_hit[ 7] & (|(IM2COL_SPC_PERMIT[ 7] & ~reg_be))) | + (addr_hit[ 8] & (|(IM2COL_SPC_PERMIT[ 8] & ~reg_be))) | + (addr_hit[ 9] & (|(IM2COL_SPC_PERMIT[ 9] & ~reg_be))) | + (addr_hit[10] & (|(IM2COL_SPC_PERMIT[10] & ~reg_be))) | + (addr_hit[11] & (|(IM2COL_SPC_PERMIT[11] & ~reg_be))) | + (addr_hit[12] & (|(IM2COL_SPC_PERMIT[12] & ~reg_be))) | + (addr_hit[13] & (|(IM2COL_SPC_PERMIT[13] & ~reg_be))) | + (addr_hit[14] & (|(IM2COL_SPC_PERMIT[14] & ~reg_be))) | + (addr_hit[15] & (|(IM2COL_SPC_PERMIT[15] & ~reg_be))) | + (addr_hit[16] & (|(IM2COL_SPC_PERMIT[16] & ~reg_be))) | + (addr_hit[17] & (|(IM2COL_SPC_PERMIT[17] & ~reg_be))) | + (addr_hit[18] & (|(IM2COL_SPC_PERMIT[18] & ~reg_be))) | + (addr_hit[19] & (|(IM2COL_SPC_PERMIT[19] & ~reg_be))) | + (addr_hit[20] & (|(IM2COL_SPC_PERMIT[20] & ~reg_be))) | + (addr_hit[21] & (|(IM2COL_SPC_PERMIT[21] & ~reg_be))) | + (addr_hit[22] & (|(IM2COL_SPC_PERMIT[22] & ~reg_be))) | + (addr_hit[23] & (|(IM2COL_SPC_PERMIT[23] & ~reg_be))) | + (addr_hit[24] & (|(IM2COL_SPC_PERMIT[24] & ~reg_be))) | + (addr_hit[25] & (|(IM2COL_SPC_PERMIT[25] & ~reg_be))))); + end + + assign src_ptr_we = addr_hit[0] & reg_we & !reg_error; + assign src_ptr_wd = reg_wdata[31:0]; + + assign dst_ptr_we = addr_hit[1] & reg_we & !reg_error; + assign dst_ptr_wd = reg_wdata[31:0]; + + assign iw_we = addr_hit[2] & reg_we & !reg_error; + assign iw_wd = reg_wdata[15:0]; + + assign ih_we = addr_hit[3] & reg_we & !reg_error; + assign ih_wd = reg_wdata[15:0]; + + assign fw_we = addr_hit[4] & reg_we & !reg_error; + assign fw_wd = reg_wdata[7:0]; + + assign fh_we = addr_hit[5] & reg_we & !reg_error; + assign fh_wd = reg_wdata[7:0]; + + assign batch_we = addr_hit[6] & reg_we & !reg_error; + assign batch_wd = reg_wdata[7:0]; + + assign num_ch_we = addr_hit[7] & reg_we & !reg_error; + assign num_ch_wd = reg_wdata[7:0]; + + assign ch_col_we = addr_hit[8] & reg_we & !reg_error; + assign ch_col_wd = reg_wdata[15:0]; + + assign n_patches_w_we = addr_hit[9] & reg_we & !reg_error; + assign n_patches_w_wd = reg_wdata[15:0]; + + assign n_patches_h_we = addr_hit[10] & reg_we & !reg_error; + assign n_patches_h_wd = reg_wdata[15:0]; + + assign adpt_pad_right_we = addr_hit[11] & reg_we & !reg_error; + assign adpt_pad_right_wd = reg_wdata[7:0]; + + assign adpt_pad_bottom_we = addr_hit[12] & reg_we & !reg_error; + assign adpt_pad_bottom_wd = reg_wdata[7:0]; + + assign log_strides_d1_we = addr_hit[13] & reg_we & !reg_error; + assign log_strides_d1_wd = reg_wdata[3:0]; + + assign log_strides_d2_we = addr_hit[14] & reg_we & !reg_error; + assign log_strides_d2_wd = reg_wdata[3:0]; + + assign status_re = addr_hit[15] & reg_re & !reg_error; + + assign slot_rx_trigger_slot_we = addr_hit[16] & reg_we & !reg_error; + assign slot_rx_trigger_slot_wd = reg_wdata[15:0]; + + assign slot_tx_trigger_slot_we = addr_hit[16] & reg_we & !reg_error; + assign slot_tx_trigger_slot_wd = reg_wdata[31:16]; + + assign data_type_we = addr_hit[17] & reg_we & !reg_error; + assign data_type_wd = reg_wdata[1:0]; + + assign pad_top_we = addr_hit[18] & reg_we & !reg_error; + assign pad_top_wd = reg_wdata[5:0]; + + assign pad_bottom_we = addr_hit[19] & reg_we & !reg_error; + assign pad_bottom_wd = reg_wdata[5:0]; + + assign pad_right_we = addr_hit[20] & reg_we & !reg_error; + assign pad_right_wd = reg_wdata[5:0]; + + assign pad_left_we = addr_hit[21] & reg_we & !reg_error; + assign pad_left_wd = reg_wdata[5:0]; + + assign interrupt_en_we = addr_hit[22] & reg_we & !reg_error; + assign interrupt_en_wd = reg_wdata[0]; + + assign spc_ifr_re = addr_hit[23] & reg_re & !reg_error; + + assign spc_ch_mask_we = addr_hit[24] & reg_we & !reg_error; + assign spc_ch_mask_wd = reg_wdata[31:0]; + + assign spc_ch_offset_we = addr_hit[25] & reg_we & !reg_error; + assign spc_ch_offset_wd = reg_wdata[31:0]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[31:0] = src_ptr_qs; + end + + addr_hit[1]: begin + reg_rdata_next[31:0] = dst_ptr_qs; + end + + addr_hit[2]: begin + reg_rdata_next[15:0] = iw_qs; + end + + addr_hit[3]: begin + reg_rdata_next[15:0] = ih_qs; + end + + addr_hit[4]: begin + reg_rdata_next[7:0] = fw_qs; + end + + addr_hit[5]: begin + reg_rdata_next[7:0] = fh_qs; + end + + addr_hit[6]: begin + reg_rdata_next[7:0] = batch_qs; + end + + addr_hit[7]: begin + reg_rdata_next[7:0] = num_ch_qs; + end + + addr_hit[8]: begin + reg_rdata_next[15:0] = ch_col_qs; + end + + addr_hit[9]: begin + reg_rdata_next[15:0] = n_patches_w_qs; + end + + addr_hit[10]: begin + reg_rdata_next[15:0] = n_patches_h_qs; + end + + addr_hit[11]: begin + reg_rdata_next[7:0] = adpt_pad_right_qs; + end + + addr_hit[12]: begin + reg_rdata_next[7:0] = adpt_pad_bottom_qs; + end + + addr_hit[13]: begin + reg_rdata_next[3:0] = log_strides_d1_qs; + end + + addr_hit[14]: begin + reg_rdata_next[3:0] = log_strides_d2_qs; + end + + addr_hit[15]: begin + reg_rdata_next[0] = status_qs; + end + + addr_hit[16]: begin + reg_rdata_next[15:0] = slot_rx_trigger_slot_qs; + reg_rdata_next[31:16] = slot_tx_trigger_slot_qs; + end + + addr_hit[17]: begin + reg_rdata_next[1:0] = data_type_qs; + end + + addr_hit[18]: begin + reg_rdata_next[5:0] = pad_top_qs; + end + + addr_hit[19]: begin + reg_rdata_next[5:0] = pad_bottom_qs; + end + + addr_hit[20]: begin + reg_rdata_next[5:0] = pad_right_qs; + end + + addr_hit[21]: begin + reg_rdata_next[5:0] = pad_left_qs; + end + + addr_hit[22]: begin + reg_rdata_next[0] = interrupt_en_qs; + end + + addr_hit[23]: begin + reg_rdata_next[0] = spc_ifr_qs; + end + + addr_hit[24]: begin + reg_rdata_next[31:0] = spc_ch_mask_qs; + end + + addr_hit[25]: begin + reg_rdata_next[31:0] = spc_ch_offset_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module im2col_spc_reg_top_intf #( + parameter int AW = 7, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output im2col_spc_reg_pkg::im2col_spc_reg2hw_t reg2hw, // Write + input im2col_spc_reg_pkg::im2col_spc_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW / 8; + + `include "register_interface/typedef.svh" + `include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + im2col_spc_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_regintfc_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_regintfc_controller.sv new file mode 100644 index 00000000..6fa9092f --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/im2col_spc_regintfc_controller.sv @@ -0,0 +1,92 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Register interface ontroller to comunicate with the AOPB. + */ + +module im2col_spc_regintfc_controller + import reg_pkg::*; +( + input logic clk_i, + input logic rst_ni, + input logic [31:0] addr_i, + input logic [31:0] wdata_i, + input logic start_i, + input reg_rsp_t aopb_resp_i, + output reg_req_t aopb_req_o, + output logic done_o +); + + /* General status signal */ + enum { + IDLE, + WAITING_READY, + SENDING, + DONE + } + im2col_status_q, im2col_status_d; + + always_comb begin + unique case (im2col_status_d) + IDLE: begin + if (start_i == 1'b1) begin + im2col_status_q = SENDING; + end else begin + im2col_status_q = IDLE; + end + end + + SENDING: begin + im2col_status_q = WAITING_READY; + end + + WAITING_READY: begin + if (aopb_resp_i.ready == 1'b1) begin + im2col_status_q = DONE; + end else begin + im2col_status_q = WAITING_READY; + end + end + + DONE: begin + im2col_status_q = IDLE; + end + endcase + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + im2col_status_d <= IDLE; + end else begin + im2col_status_d <= im2col_status_q; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + aopb_req_o.valid <= 1'b0; + aopb_req_o.write <= 1'b0; + aopb_req_o.wstrb <= 4'b1111; + aopb_req_o.addr <= '0; + aopb_req_o.wdata <= '0; + end else begin + if (im2col_status_d == SENDING) begin + aopb_req_o.valid <= 1'b1; + aopb_req_o.write <= 1'b1; + aopb_req_o.wstrb <= 4'b1111; + aopb_req_o.addr <= addr_i; + aopb_req_o.wdata <= wdata_i; + end else if (im2col_status_q == DONE) begin + aopb_req_o.valid <= 1'b0; + end + end + end + + assign done_o = (im2col_status_d == DONE); + +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/pipe_reg.sv b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/pipe_reg.sv new file mode 100644 index 00000000..b819a941 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/hw/ip_examples/im2col_spc/rtl/pipe_reg.sv @@ -0,0 +1,32 @@ +/* + * Copyright 2024 EPFL + * Solderpad Hardware License, Version 2.1, see LICENSE.md for details. + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Author: Tommaso Terzano + * + * + * Info: Generic pipe register + */ + +module pipe_reg #( + parameter WIDTH = 8 +) ( + input logic clk_i, + input logic rst_ni, + input logic [WIDTH-1:0] data_in, + output logic [WIDTH-1:0] data_out +); + + logic [WIDTH-1:0] reg_data; + + always_ff @(posedge clk_i, negedge rst_ni) begin + if (!rst_ni) begin + reg_data <= '0; + end else begin + reg_data <= data_in; + end + end + + assign data_out = reg_data; +endmodule diff --git a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl index e77bd1b4..2a01983e 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl +++ b/hw/vendor/esl_epfl_x_heep/hw/system/x_heep_system.sv.tpl @@ -11,7 +11,9 @@ module x_heep_system parameter ZFINX = 0, parameter EXT_XBAR_NMASTER = 0, parameter X_EXT = 0, // eXtension interface in cv32e40x + parameter AO_SPC_NUM = 0, //do not touch these parameters + parameter AO_SPC_NUM_RND = AO_SPC_NUM == 0 ? 1 : AO_SPC_NUM, parameter EXT_XBAR_NMASTER_RND = EXT_XBAR_NMASTER == 0 ? 1 : EXT_XBAR_NMASTER, parameter EXT_DOMAINS_RND = core_v_mini_mcu_pkg::EXTERNAL_DOMAINS == 0 ? 1 : core_v_mini_mcu_pkg::EXTERNAL_DOMAINS, parameter NEXT_INT_RND = core_v_mini_mcu_pkg::NEXT_INT == 0 ? 1 : core_v_mini_mcu_pkg::NEXT_INT @@ -29,13 +31,16 @@ module x_heep_system input obi_resp_t ext_core_data_resp_i, output obi_req_t ext_debug_master_req_o, input obi_resp_t ext_debug_master_resp_i, - output obi_req_t ext_dma_read_ch0_req_o, - input obi_resp_t ext_dma_read_ch0_resp_i, - output obi_req_t ext_dma_write_ch0_req_o, - input obi_resp_t ext_dma_write_ch0_resp_i, - output obi_req_t ext_dma_addr_ch0_req_o, - input obi_resp_t ext_dma_addr_ch0_resp_i, - + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_read_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_write_resp_i, + output obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_req_o, + input obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] ext_dma_addr_resp_i, + + input reg_req_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_req_i, + output reg_rsp_t [AO_SPC_NUM_RND-1:0] ext_ao_peripheral_resp_o, + output reg_req_t ext_peripheral_slave_req_o, input reg_rsp_t ext_peripheral_slave_resp_i, @@ -60,6 +65,9 @@ module x_heep_system if_xif.cpu_mem_result xif_mem_result_if, if_xif.cpu_result xif_result_if, + // External SPC interface + output logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_done_o, + % for pad in total_pad_list: ${pad.x_heep_system_interface} % endfor @@ -112,6 +120,7 @@ ${pad.internal_signals} .ZFINX(ZFINX), .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER), .X_EXT(X_EXT), + .AO_SPC_NUM(AO_SPC_NUM), .EXT_HARTS(EXT_HARTS) ) core_v_mini_mcu_i ( @@ -130,18 +139,20 @@ ${pad.core_v_mini_mcu_bonding} .pad_resp_i(pad_resp), .ext_xbar_master_req_i, .ext_xbar_master_resp_o, + .ext_ao_peripheral_slave_req_i(ext_ao_peripheral_req_i), + .ext_ao_peripheral_slave_resp_o(ext_ao_peripheral_resp_o), .ext_core_instr_req_o, .ext_core_instr_resp_i, .ext_core_data_req_o, .ext_core_data_resp_i, .ext_debug_master_req_o, .ext_debug_master_resp_i, - .ext_dma_read_ch0_req_o, - .ext_dma_read_ch0_resp_i, - .ext_dma_write_ch0_req_o, - .ext_dma_write_ch0_resp_i, - .ext_dma_addr_ch0_req_o, - .ext_dma_addr_ch0_resp_i, + .ext_dma_read_req_o, + .ext_dma_read_resp_i, + .ext_dma_write_req_o, + .ext_dma_write_resp_i, + .ext_dma_addr_req_o, + .ext_dma_addr_resp_i, .ext_dma_stop_i, .ext_peripheral_slave_req_o, .ext_peripheral_slave_resp_i, @@ -160,7 +171,8 @@ ${pad.core_v_mini_mcu_bonding} .external_subsystem_clkgate_en_no, .exit_value_o, .ext_dma_slot_tx_i, - .ext_dma_slot_rx_i + .ext_dma_slot_rx_i, + .dma_done_o ); pad_ring pad_ring_i ( diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson index 2871b8ed..e307c5ae 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/cv32e40px.git - rev: 15b9dd6077513342cf44e6853a5fc33098f2e73b + rev: 10b08065c50d44b5355c1535cb8f740e68e4f106 } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson index d0e289ae..4fc67fa6 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px.vendor.hjson @@ -7,7 +7,7 @@ upstream: { url: "https://github.com/esl-epfl/cv32e40px.git", - rev: "15b9dd6077513342cf44e6853a5fc33098f2e73b", + rev: "10b08065c50d44b5355c1535cb8f740e68e4f106", }, exclude_from_upstream: [ diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/README.md b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/README.md index 0b23f841..2272b680 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/README.md +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/README.md @@ -1,8 +1,8 @@ [![Build Status](https://travis-ci.com/pulp-platform/riscv.svg?branch=master)](https://travis-ci.com/pulp-platform/riscv) -# OpenHW Group CORE-V CV32E40P RISC-V IP +# OpenHW Group CORE-V CV32E40PX RISC-V IP -CV32E40P is a small and efficient, 32-bit, in-order RISC-V core with a 4-stage pipeline that implements +CV32E40PX is a small and efficient, 32-bit, in-order RISC-V core with a 4-stage pipeline that implements the RV32IM\[F|Zfinx\]C instruction set architecture, and the PULP custom extensions for achieving higher code density, performance, and energy efficiency \[[1](https://doi.org/10.1109/TVLSI.2017.2654506)\], \[[2](https://doi.org/10.1109/PATMOS.2017.8106976)\]. It started its life as a fork of the OR10N CPU core that is based on the OpenRISC ISA. @@ -14,12 +14,12 @@ when it has been contributed to [OpenHW Group](https://www.openhwgroup.org/). ## Documentation -The CV32E40P user manual can be found in the _docs_ folder and it is +The CV32E40PX user manual can be found in the _docs_ folder and it is captured in reStructuredText, rendered to html using [Sphinx](https://docs.readthedocs.io/en/stable/intro/getting-started-with-sphinx.html). These documents are viewable using readthedocs and can be viewed [here](https://docs.openhwgroup.org/projects/cv32e40p-user-manual/). ## Verification -The verification environment for the CV32E40P is _not_ in this Repository. There is a small, simple testbench here which is +The verification environment for the CV32E40PX is _not_ in this Repository. There is a small, simple testbench here which is useful for experimentation only and should not be used to validate any changes to the RTL prior to pushing to the master branch of this repo. @@ -31,7 +31,7 @@ The Makefiles supported in the **core-v-verif** project automatically clone the ## Changelog A changelog is generated automatically in the documentation from the individual pull requests. -In order to enable automatic changelog generation within the CV32E40P documentation, the committer is required to label each pull request +In order to enable automatic changelog generation within the CV32E40PX documentation, the committer is required to label each pull request that touches any file in 'rtl' (or any of its subdirectories) with *Component:RTL* and label each pull request that touches any file in 'docs' (or any of its subdirectories) with *Component:Doc*. Pull requests that are not labeled or labeled with *ignore-for-release* are ignored for the changelog generation. @@ -40,7 +40,7 @@ Only the person who actually performs the merge can add these labels (you need c 1 label is applied and therefore pull requests that touches both RTL and documentation files in the same pull request are not allowed. ## Constraints -Example synthesis constraints for the CV32E40P are provided. +Example synthesis constraints for the CV32E40PX are provided. ## Contributing @@ -71,7 +71,7 @@ Run `./util/format-verible` to format all the files. ## Issues and Troubleshooting -If you find any problems or issues with CV32E40P or the documentation, please check out the [issue +If you find any problems or issues with CV32E40PX or the documentation, please check out the [issue tracker](https://github.com/openhwgroup/cv32e40p/issues) and create a new issue if your problem is not yet tracked. diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv index e9807a38..19e21067 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_controller.sv @@ -110,6 +110,10 @@ module cv32e40px_controller import cv32e40px_pkg::*; output logic apu_stall_o, + // X-IF signals + output logic x_branch_or_async_taken_o, + output logic x_control_illegal_reset_o, + // jump/branch signals input logic branch_taken_ex_i, // branch taken signal from EX ALU input logic [1:0] ctrl_transfer_insn_in_id_i, // jump is being calculated in ALU @@ -240,7 +244,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; logic debug_req_q; logic debug_req_pending; - // qualify wfi vs nosleep locally + // qualify wfi vs nosleep locally logic wfi_active; @@ -327,6 +331,9 @@ module cv32e40px_controller import cv32e40px_pkg::*; // ensures that the target is kept constant even if pc_id is no more HWLP_END hwlp_targ_addr_o = ((hwlp_start1_leq_pc && hwlp_end1_geq_pc) && !(hwlp_start0_leq_pc && hwlp_end0_geq_pc)) ? hwlp_start_addr_i[1] : hwlp_start_addr_i[0]; + x_branch_or_async_taken_o = 1'b0; + x_control_illegal_reset_o = 1'b0; + unique case (ctrl_fsm_cs) // We were just reset, wait for fetch_enable RESET: @@ -438,6 +445,8 @@ module cv32e40px_controller import cv32e40px_pkg::*; pc_mux_o = PC_BRANCH; pc_set_o = 1'b1; + x_branch_or_async_taken_o = 1'b1; + // if we want to debug, flush the pipeline // the current_pc_if will take the value of the next instruction to // be executed (NPC) @@ -496,6 +505,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; debug_req_entry_n = 1'b1; + x_branch_or_async_taken_o = 1'b1; end else if (irq_req_ctrl_i && ~debug_mode_q) begin @@ -511,6 +521,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; exc_pc_mux_o = EXC_PC_IRQ; exc_cause_o = irq_id_ctrl_i; csr_irq_sec_o = irq_sec_ctrl_i; + x_branch_or_async_taken_o = 1'b1; // IRQ interface irq_ack_o = 1'b1; @@ -534,6 +545,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; halt_id_o = 1'b0; ctrl_fsm_ns = id_ready_i ? FLUSH_EX : DECODE; illegal_insn_n = 1'b1; + x_control_illegal_reset_o = 1'b1; end else begin @@ -679,6 +691,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; illegal_insn_i | ecall_insn_i: begin ctrl_fsm_ns = FLUSH_EX; + x_control_illegal_reset_o = illegal_insn_i; end (~ebrk_force_debug_mode & ebrk_insn_i): @@ -728,6 +741,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; halt_id_o = 1'b1; ctrl_fsm_ns = DBG_FLUSH; debug_req_entry_n = 1'b1; + x_branch_or_async_taken_o = 1'b1; end else if (irq_req_ctrl_i && ~debug_mode_q) begin @@ -743,6 +757,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; exc_pc_mux_o = EXC_PC_IRQ; exc_cause_o = irq_id_ctrl_i; csr_irq_sec_o = irq_sec_ctrl_i; + x_branch_or_async_taken_o = 1'b1; // IRQ interface irq_ack_o = 1'b1; @@ -768,6 +783,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; halt_id_o = 1'b1; ctrl_fsm_ns = FLUSH_EX; illegal_insn_n = 1'b1; + x_control_illegal_reset_o = 1'b1; end else begin @@ -865,6 +881,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; illegal_insn_i | ecall_insn_i: begin ctrl_fsm_ns = FLUSH_EX; + x_control_illegal_reset_o = illegal_insn_i; end (~ebrk_force_debug_mode & ebrk_insn_i): @@ -1207,7 +1224,7 @@ module cv32e40px_controller import cv32e40px_pkg::*; exc_pc_mux_o = EXC_PC_DBD; csr_save_cause_o = 1'b1; debug_csr_save_o = 1'b1; - if (debug_force_wakeup_q) + if (debug_force_wakeup_q) debug_cause_o = DBG_CAUSE_HALTREQ; else if (debug_single_step_i) debug_cause_o = DBG_CAUSE_STEP; // pri 0 @@ -1479,7 +1496,7 @@ endgenerate assign debug_wfi_no_sleep_o = debug_mode_q || debug_req_pending || debug_single_step_i || trigger_match_i || COREV_CLUSTER; - // Gate off wfi + // Gate off wfi assign wfi_active = wfi_i & ~debug_wfi_no_sleep_o; // sticky version of debug_req (must be on clk_ungated_i such that incoming pulse before core is enabled is not missed) @@ -1600,7 +1617,7 @@ endgenerate // Ensure DBG_TAKEN_IF can only be enterred if in single step mode or woken // up from sleep by debug_req_i - + a_single_step_dbg_taken_if : assert property (@(posedge clk) disable iff (!rst_n) (ctrl_fsm_ns==DBG_TAKEN_IF) |-> ((~debug_mode_q && debug_single_step_i) || debug_force_wakeup_n)); // Ensure DBG_FLUSH state is only one cycle. This implies that cause is either trigger, debug_req_entry, or ebreak diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv index 9f1f668b..883b5ff1 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_id_stage.sv @@ -436,6 +436,8 @@ module cv32e40px_id_stage // X-Interface logic illegal_insn; logic x_illegal_insn; + logic x_branch_or_async_taken; + logic x_control_illegal_reset; logic [4:0] waddr_id; logic [4:0] waddr_ex; logic [4:0] waddr_wb; @@ -1124,7 +1126,7 @@ module cv32e40px_id_stage .mem_instr_waddr_ex_i(regfile_waddr_ex_o[4:0]), .mem_instr_we_ex_i (regfile_we_ex_o), .regs_used_i (regs_used), - .branch_or_jump_i (pc_set_o), + .branch_or_jump_i (x_branch_or_async_taken), .instr_valid_i (instr_valid_i), .x_rs_addr_i (x_rs_addr), .x_ex_fwd_o (x_ex_fwd), @@ -1136,14 +1138,15 @@ module cv32e40px_id_stage .wb_ready_i (wb_ready_i), // additional status signals - .x_stall_o (x_stall), - .x_illegal_insn_o (x_illegal_insn), - .x_illegal_insn_dec_i(illegal_insn_dec), - .id_ready_i (id_ready_o), - .ex_valid_i (ex_valid_i), - .ex_ready_i (ex_ready_i), - .current_priv_lvl_i (current_priv_lvl_i), - .data_req_dec_i (data_req_id) + .x_stall_o (x_stall), + .x_illegal_insn_o (x_illegal_insn), + .x_illegal_insn_dec_i (illegal_insn_dec), + .x_control_illegal_reset_i(x_control_illegal_reset), + .id_ready_i (id_ready_o), + .ex_valid_i (ex_valid_i), + .ex_ready_i (ex_ready_i), + .current_priv_lvl_i (current_priv_lvl_i), + .data_req_dec_i (data_req_id) ); @@ -1445,6 +1448,8 @@ module cv32e40px_id_stage .apu_write_dep_i (apu_write_dep_i), .apu_stall_o(apu_stall), + .x_branch_or_async_taken_o(x_branch_or_async_taken), + .x_control_illegal_reset_o(x_control_illegal_reset), // jump/branch control .branch_taken_ex_i (branch_taken_ex), diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv index dc890797..f326b3f9 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/esl_epfl_cv32e40px/rtl/cv32e40px_x_disp.sv @@ -90,6 +90,7 @@ module cv32e40px_x_disp output logic x_stall_o, output logic x_illegal_insn_o, input logic x_illegal_insn_dec_i, + input logic x_control_illegal_reset_i, input logic id_ready_i, input logic ex_valid_i, input logic ex_ready_i, @@ -108,6 +109,7 @@ module cv32e40px_x_disp logic x_if_memory_instr; logic illegal_forwarding_prevention; logic x_issue_illegal; + logic x_illegal_insn_q, x_illegal_insn_n; // issue interface assign x_issue_valid_o = x_illegal_insn_dec_i & ~branch_or_jump_i & ~instr_offloaded_q & instr_valid_i & ~illegal_forwarding_prevention; @@ -182,7 +184,7 @@ module cv32e40px_x_disp assign x_wb_fwd_o[3] = (x_rs_addr_i[0] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[0]; assign x_wb_fwd_o[4] = (x_rs_addr_i[1] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[1]; assign x_wb_fwd_o[5] = (x_rs_addr_i[2] | 5'b00001) == waddr_wb_i & we_wb_i & ex_valid_i & x_issue_resp_dualread_i[2]; - assign dep = ~x_illegal_insn_o & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) + assign dep = ~x_illegal_insn_n & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) | (regs_used_i[1] & scoreboard_q[x_rs_addr_i[1]] & (x_result_rd_i != x_rs_addr_i[1])) | (regs_used_i[2] & scoreboard_q[x_rs_addr_i[2]] & (x_result_rd_i != x_rs_addr_i[2])) | (((regs_used_i[0] & x_issue_resp_dualread_i[0]) & scoreboard_q[x_rs_addr_i[0] | 5'b00001] & (x_result_rd_i != (x_rs_addr_i[0] | 5'b00001))) & x_issue_resp_dualread_i[0]) @@ -195,7 +197,7 @@ module cv32e40px_x_disp assign x_wb_fwd_o[0] = x_rs_addr_i[0] == waddr_wb_i & we_wb_i & ex_valid_i; assign x_wb_fwd_o[1] = x_rs_addr_i[1] == waddr_wb_i & we_wb_i & ex_valid_i; assign x_wb_fwd_o[2] = x_rs_addr_i[2] == waddr_wb_i & we_wb_i & ex_valid_i; - assign dep = ~x_illegal_insn_o & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) + assign dep = ~x_illegal_insn_n & ((regs_used_i[0] & scoreboard_q[x_rs_addr_i[0]] & (x_result_rd_i != x_rs_addr_i[0])) | (regs_used_i[1] & scoreboard_q[x_rs_addr_i[1]] & (x_result_rd_i != x_rs_addr_i[1])) | (regs_used_i[2] & scoreboard_q[x_rs_addr_i[2]] & (x_result_rd_i != x_rs_addr_i[2]))); end @@ -247,11 +249,12 @@ module cv32e40px_x_disp // illegal instruction assignment assign x_issue_illegal = x_illegal_insn_dec_i & ~instr_offloaded_q & instr_valid_i; always_comb begin - x_illegal_insn_o = 1'b0; + x_illegal_insn_n = 1'b0; if (x_issue_illegal & x_issue_ready_i & ~x_issue_resp_accept_i) begin - x_illegal_insn_o = 1'b1; + x_illegal_insn_n = 1'b1; end end + assign x_illegal_insn_o = x_illegal_insn_q; // scoreboard and status signal register always_ff @(posedge clk_i or negedge rst_ni) begin @@ -260,11 +263,17 @@ module cv32e40px_x_disp instr_offloaded_q <= 1'b0; id_q <= '0; mem_counter_q <= '0; + x_illegal_insn_q <= 1'b0; end else begin scoreboard_q <= scoreboard_d; instr_offloaded_q <= instr_offloaded_d; id_q <= id_d; mem_counter_q <= mem_counter_d; + if (x_control_illegal_reset_i) begin + x_illegal_insn_q <= 1'b0; + end else begin + x_illegal_insn_q <= x_illegal_insn_n; + end end end diff --git a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_register_interface.core b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_register_interface.core index b7883672..383b7eac 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_register_interface.core +++ b/hw/vendor/esl_epfl_x_heep/hw/vendor/pulp_platform_register_interface.core @@ -14,6 +14,7 @@ filesets: - pulp_platform_register_interface/src/reg_intf.sv - pulp_platform_register_interface/src/periph_to_reg.sv - pulp_platform_register_interface/src/reg_demux.sv + - pulp_platform_register_interface/src/reg_mux.sv - pulp_platform_register_interface/src/reg_to_tlul.sv file_type: systemVerilogSource diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson index df55d160..316750e1 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg.hjson @@ -42,6 +42,8 @@ length: 0x00010000, ch_length: 0x100, num_channels: 0x1, + num_master_ports: 0x1, + num_channels_per_master_port: 0x1, path: "./hw/ip/dma/data/dma.hjson" }, power_manager: { diff --git a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson index 0be257d7..d496c274 100644 --- a/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson +++ b/hw/vendor/esl_epfl_x_heep/mcu_cfg_minimal.hjson @@ -42,6 +42,8 @@ length: 0x00010000, ch_length: 0x100, num_channels: 0x1, + num_master_ports: 0x1, + num_channels_per_master_port: 0x1, path: "./hw/ip/dma/data/dma.hjson" }, power_manager: { diff --git a/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson b/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson index 1cfa8c79..b0720c2e 100644 --- a/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson +++ b/hw/vendor/esl_epfl_x_heep/pad_cfg.hjson @@ -8,7 +8,7 @@ // The pads contains the list of all the pads available in the design. // Each pad is defined by its name and can have the following attributes: // num: (mandatory) - the number of pads of this type -// type: (mandatory) - the type of the pad +// type: (mandatory) - the type of the pad // num_offset: (optional) - the offset to the first pad of this type (default 0) // mapping: (optional) - the mapping of the pad in the design. Useful for ASICs (default top) // active: (optional) - the active level of the pad (default high) @@ -16,6 +16,12 @@ // mux: (optional) - the muxing options for the pad // skip_declaration: (optional) - skip the declaration of the pad in the top level (default False) // keep_internal: (optional) - keep the pad internal to the design (default False) +// layout_attributes: (optional) - collection of attributes related to the physical (ASIC) layout of the pads +// index: (mandatory) index of the pad on its side of the I/O ring +// orient: (optional) - orientation of the pad +// cell: (mandatory for type "supply") - specific cell to use if not a default pad cell (ex. for VDD/VSS pads) +// offset: (optional) - offset from edge (in um) +// skip: (optional) - distance from neighboring pad (in um) // // Add this field at the same level of pads (not inside) if you want to define PADs attributes // attributes: { diff --git a/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/im2col_spc_verification.py b/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/im2col_spc_verification.py new file mode 100644 index 00000000..93fe9d6b --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/im2col_spc_verification.py @@ -0,0 +1,317 @@ +# +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Author: Tommaso Terzano +# +# +# Info: This is a usecase of the VerifHeep tool. It generates a dataset for the im2col function +# and the golden result, then it runs the test on the PYNQ-Z2 board and stores the results +# in a file. The data can be then read and plotted using the plotter.py script. +# +# In order to be run, these steps has to be followed: +# 0. Set the X-Heep configuration to have 4 channels, +# while there are no limits on the number of master ports +# 1. Run this command to include Verifheep: +# export PYTHONPATH="$PYTHONPATH://scripts/verification" +# 2. Perform the synthesis with Vivado and to program the FPGA with the bitstream +# 3. Connect the board using GDB by running X-Heep script "make openOCD_bscan". Close Vivado to avoid conflicts +# + +import re +import time +import verifheep +from tqdm import tqdm +import curses +import torch +import torch.nn.functional as F +import numpy as np + +# Define the USB port to which the board is connected. Useful because the port may change +USBport = 2 + +# Define the parameters for the test + +datatype = "uint8_t" +range_max = 255 + +num_masters = 4 # Number of DMA CH +num_slaves = 2 # Number of BUS master ports +max_masters_per_slave = 2 # Maximum number of DMA CH per BUS master port + +batch_max = 4 +batch_min = 1 + +channels_max = 4 +channels_min = 1 + +im_h_max = 11 +im_h_min = 10 + +im_w_max = 11 +im_w_min = 10 + +ker_h_max = 5 +ker_h_min = 3 + +ker_w_max = 5 +ker_w_min = 3 + +pad_top_max = 2 +pad_top_min = 1 +pad_bottom_max = 2 +pad_bottom_min = 1 +pad_left_max = 2 +pad_left_min = 1 +pad_right_max = 2 +pad_right_min = 1 + +stride_d1_max = 2 +stride_d1_min = 1 +stride_d2_max = 2 +stride_d2_min = 1 + +# Calculate the total number of iterations +total_iterations = ((stride_d2_max - stride_d2_min) * (stride_d1_max - stride_d1_min) * + (pad_right_max - pad_right_min) * (pad_left_max - pad_left_min) * + (pad_bottom_max - pad_bottom_min) * (pad_top_max - pad_top_min) * + (ker_w_max - ker_w_min) * (ker_h_max - ker_h_min) * + (im_w_max - im_w_min) * (im_h_max - im_h_min) * + (channels_max - channels_min) * (batch_max - batch_min)) + +# Define the patterns to be used for modifying the im2col_lib.h file +spc_mask_pattern = re.compile(r'#define SPC_CH_MASK 0b\d+') +start_id_pattern = re.compile(r'#define START_ID \d+') +test_en_pattern = re.compile(r'#define TEST_EN \d+') + +# Define the arrays to store the data +im2col_cpu_array = [] +im2col_dma_2d_C_array = [] +im2col_spc_array = [] + +# Function to generate the input dataset for the im2col test to be passed to the VerifHeep tool +def im2col_function(input_array, parameters): + + # Extract parameters + batch_size = parameters['BATCH'] + channels = parameters['CH'] + image_height = parameters['IH'] + image_width = parameters['IW'] + top_pad = parameters['TOP_PAD'] + bottom_pad = parameters['BOTTOM_PAD'] + left_pad = parameters['LEFT_PAD'] + right_pad = parameters['RIGHT_PAD'] + stride_d1 = parameters['STRIDE_D1'] + stride_d2 = parameters['STRIDE_D2'] + (filter_height, filter_width) = (parameters['FH'], parameters['FW']) + kernel_size = (filter_height, filter_width) + + # Convert the input array into a PyTorch tensor with the correct shape + input_tensor = torch.tensor(input_array).view(batch_size, channels, image_height, image_width) + + dilation = 1 + # Ensure kernel_size, stride, padding, and dilation are tuples + if isinstance(kernel_size, int): + kernel_size = (kernel_size, kernel_size) + if isinstance(dilation, int): + dilation = (dilation, dilation) + + # Adjust padding format for F.pad (expects pad_left, pad_right, pad_top, pad_bottom) + padding_format = (left_pad, right_pad, top_pad, bottom_pad) + + # Apply zero padding + padded_input = F.pad(input_tensor, padding_format, "constant", 0) + + # Unfold the padded input tensor + unfolded = padded_input.unfold(2, kernel_size[0], stride_d2).unfold(3, kernel_size[1], stride_d1) + unfolded = unfolded.permute(0, 2, 3, 1, 4, 5) + + # Reshape to get the 2D tensor where each row is a flattened receptive field + channel_dim = padded_input.size(1) + unfolded_tensor = unfolded.contiguous().view(-1, channel_dim * kernel_size[0] * kernel_size[1]).t() + + # Convert the PyTorch tensor to a NumPy array and then to a list (simple array) + unfolded_array = unfolded_tensor.numpy().flatten().tolist() + + return unfolded_array, "" + + +# Initialize the VerifHeep tool +im2colVer = verifheep.VerifHeep("pynq-z2", "../../../") + +# Connect to the pynq-z2 board +print("Connecting to the board...") +serial_status = im2colVer.serialBegin(f"/dev/ttyUSB{USBport}", 9600) +if not serial_status: + print("Error connecting to the board") + exit(1) +else: + print("Connected!\n") + time.sleep(1) + +# Set up the debug interface +im2colVer.setUpDeb() + +def main(stdscr): + + # Initialize the progress bar + progress_bar = tqdm(total=total_iterations, desc="Overall Progress", ncols=100, unit=" iter", + bar_format='{desc}: {percentage:.2f}%|{bar}| {n_fmt}/{total_fmt}') + + iteration = 1 + started = False + counter = 10 + + # Set CH0 to be the SPC channel + mask = "0001" + im2colVer.modifyFile("../../../sw/applications/example_im2col/im2col_lib.h", spc_mask_pattern, f'#define SPC_CH_MASK 0b{mask}') + + # Set the correct output format by setting the TEST_EN define + im2colVer.modifyFile("../../../sw/applications/example_im2col/im2col_lib.h", test_en_pattern, f'#define TEST_EN 1') + + curses.curs_set(0) + for j in range(batch_min, batch_max): + im2col_cpu = [] + im2col_dma_2d_C = [] + im2col_spc = [] + for k in range(channels_min, channels_max): + + for l in range(im_h_min, im_h_max): + + for m in range(im_w_min, im_w_max): + + for n in range(ker_h_min, ker_h_max): + + for o in range(ker_w_min, ker_w_max): + + for p in range(pad_top_min, pad_top_max): + + for q in range(pad_bottom_min, pad_bottom_max): + + for r in range(pad_left_min, pad_left_max): + + for s in range(pad_right_min, pad_right_max): + + for t in range(stride_d1_min, stride_d1_max): + + for u in range(stride_d2_min, stride_d2_max): + + # Start the chrono + if started and counter == 0: + im2colVer.stopDeb() + im2colVer.setUpDeb() + counter = 10 + elif not started: + im2colVer.setUpDeb() + started = True + counter -= 1 + else: + counter -= 1 + + im2colVer.chronoStart() + + # Generate the input dataset and the golden result + n_patches_h = (l + p + q - n) // u + 1 + n_patches_w = (m + s + r - o) // t + 1 + OH = o * n * k * j # Number of rows in a column -> size of a column + OW = n_patches_h * n_patches_w # Numver of columns in a row -> size of a row + input_size = k * l * m * j + golden_size = OH * OW + + parameters = { + 'IH': l, + 'IW': m, + 'CH': k, + 'BATCH': j, + 'FH': n, + 'FW': o, + 'TOP_PAD': p, + 'BOTTOM_PAD': q, + 'LEFT_PAD': r, + 'RIGHT_PAD': s, + 'STRIDE_D1': t, + 'STRIDE_D2': u + } + + im2colVer.genInputDataset(input_size, row_size=m, range_max=range_max, dataset_dir_c="../../../sw/applications/example_im2col/im2col_input.c", + dataset_dir="../../../sw/applications/example_im2col/im2col_input.h", parameters=parameters, dataset_name="input_image_nchw", + datatype=datatype) + + im2colVer.genGoldenResult(im2col_function, golden_size, parameters, row_size=OW, golden_dir="../../../sw/applications/example_im2col/im2col_golden.h", + golden_dir_c="../../../sw/applications/example_im2col/im2col_golden.c", input_dataset_dir="../../../sw/applications/example_im2col/im2col_input.c", + golden_name="golden_im2col_nchw", + output_datatype=datatype) + + im2colVer.modifyFile("../../../sw/applications/example_im2col/im2col_lib.h", start_id_pattern, f'#define START_ID 0') + + # Launch the test + im2colVer.launchTest("example_im2col", input_size=j*k*l*m) + + # Format the parameters of the current run and store them for plots + for test in im2colVer.results: + string = f'CH_SPC: 1, B: {j}, C: {k}, H: {l}, W: {m}, FH: {n}, FW: {o}, PT: {p}, PB: {q}, PL: {r}, PR: {s}, S1: {t}, S2: {u}, cycles: {test["Cycles"]}' + + if int(test["ID"]) == 0: + im2col_cpu.append(string) + elif int(test["ID"]) == 1: + im2col_dma_2d_C.append(string) + elif int(test["ID"]) == 2: + im2col_spc.append(string) + + # Stop the chrono and calculate the remaining time of the verification + im2colVer.clearResults() + im2colVer.chronoStop() + time_rem = im2colVer.chronoExecutionEst(((stride_d2_max - stride_d2_min) * (stride_d1_max - stride_d1_min) * (pad_right_max - pad_right_min) * (pad_left_max - pad_left_min) * (pad_bottom_max - pad_bottom_min) * (pad_top_max - pad_top_min) * (ker_w_max - ker_w_min) * (ker_h_max - ker_h_min) * (im_w_max - im_w_min) * (im_h_max - im_h_min) * (channels_max - channels_min) * (batch_max - batch_min))) + + # Update the progress bar + message = ( + f"Batch size: {j:>5}\n" + f"Input channels:{k:>5}\n" + f"Image height: {l:>5}\n" + f"Image width: {m:>5}\n" + f"Kernel height: {n:>5}\n" + f"Kernel width: {o:>5}\n" + f"Pad top: {p:>5}\n" + f"Pad bottom: {q:>5}\n" + f"Pad left: {r:>5}\n" + f"Pad right: {s:>5}\n" + f"Stride d1: {t:>5}\n" + f"Stride d2: {u:>5}\n" + f"Remaining time:{time_rem['hours']:>2}h:{time_rem['minutes']:>2}m:{time_rem['seconds']:.2f}s\n" + ) + + iteration += 1 + progress_bar.update(1) + + stdscr.addstr(1, 0, message) + stdscr.refresh() + + im2col_cpu_array.append(im2col_cpu) + im2col_dma_2d_C_array.append(im2col_dma_2d_C) + im2col_spc_array.append(im2col_spc) + + # Stop the debug interface and close the progress bar + im2colVer.stopDeb() + progress_bar.close() + + # Write the data to a file + with open('im2col_data.txt', 'w') as file: + file.write("im2col_cpu:\n") + for value in im2col_cpu_array: + file.write(f"{value}\n") + file.write("\n") + + file.write("im2col_dma_2d_C:\n") + for value in im2col_dma_2d_C_array: + file.write(f"{value}\n") + file.write("\n") + + file.write("im2col_spc:\n") + for value in im2col_spc_array: + file.write(f"{value}\n") + file.write("\n") + + print("Data acquired!\n") + +curses.wrapper(main) \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/plotter.py b/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/plotter.py new file mode 100644 index 00000000..3a012aa6 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/scripts/verification/examples/plotter.py @@ -0,0 +1,123 @@ +# +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Author: Tommaso Terzano +# +# +# Info: Plotter script for im2col spc verification data. +# + +import matplotlib.pyplot as plt +import pandas as pd +import ast +import numpy as np + +# Function to parse data from string to dictionary +def parse_data(data): + results = [] + for item in data: + # Split each item by ', ' to get key-value pairs + pairs = item.split(', ') + # Create a dictionary from the pairs + result_dict = {} + for pair in pairs: + key, value = pair.split(': ') + # Convert value to integer + result_dict[key] = int(value) + results.append(result_dict) + return results + +# Function to add loop_size field +def add_loop_size(data): + for entry in data: + # Calculate the number of patches, i.e. the number the filter can fit along one dimension during convolution + n_patches_h = int((entry['H'] - entry['FH'] + entry['PT'] + entry['PB']) / entry['S2']) + 1 + n_patches_w = int((entry['W'] - entry['FW'] + entry['PR'] + entry['PL']) / entry['S1']) + 1 + # Calculate the dimensions of the output matrix + OH = entry['FW'] * entry['FH'] * entry['C'] * entry['B'] # Number of rows in a column -> size of a column + OW = n_patches_h * n_patches_w # Number of columns in a row -> size of a row + entry['loop_size'] = OH*OW + return data + +# Read and parse data from file +def read_data(file_path): + with open(file_path, 'r') as file: + lines = file.readlines() + + im2col_cpu = [] + im2col_dma_2d_C = [] + im2col_spc = [] + + current_section = None + for line in lines: + line = line.strip() + if line.startswith("im2col_cpu:"): + current_section = im2col_cpu + elif line.startswith("im2col_dma_2d_C:"): + current_section = im2col_dma_2d_C + elif line.startswith("im2col_spc:"): + current_section = im2col_spc + elif line: + if current_section is not None: + current_section.append(line.strip("[]'")) + + return im2col_cpu, im2col_dma_2d_C, im2col_spc + +# Path to the file containing the data +file_path = 'im2col_data.txt' + +# Read data from the file +im2col_cpu_array, im2col_dma_2d_C_array, im2col_spc_array = read_data(file_path) + +# Elaborate the data +parsed_1ch_CPU = parse_data(ast.literal_eval("'"+im2col_cpu_array[0]+"'")) +parsed_1ch_DMA = parse_data(ast.literal_eval("'"+im2col_dma_2d_C_array[0]+"'")) +parsed_1ch_spc = parse_data(ast.literal_eval("'"+im2col_spc_array[0]+"'")) + +add_loop_size(parsed_1ch_CPU) +add_loop_size(parsed_1ch_DMA) +add_loop_size(parsed_1ch_spc) + +df_1ch_CPU = pd.DataFrame(parsed_1ch_CPU) +df_1ch_DMA = pd.DataFrame(parsed_1ch_DMA) +df_1ch_spc = pd.DataFrame(parsed_1ch_spc) + +# Plot the data +plt.figure(0, figsize=(12, 8)) + +# Scatter plots +plt.scatter(df_1ch_CPU['loop_size'], df_1ch_CPU['cycles'], color='blue', label='1ch CPU', alpha=1) +plt.scatter(df_1ch_DMA['loop_size'], df_1ch_DMA['cycles'], color='red', label='1ch DMA', alpha=1) +plt.scatter(df_1ch_spc['loop_size'], df_1ch_spc['cycles'], color='green', label='1ch SPC', alpha=1) + +# Trendline plots +p_cpu = np.polyfit(df_1ch_CPU['loop_size'],df_1ch_CPU['cycles'], 1) +trendline_cpu = np.polyval(p_cpu, df_1ch_CPU['loop_size']) + +p_dma = np.polyfit(df_1ch_DMA['loop_size'], df_1ch_DMA['cycles'], 1) +trendline_dma = np.polyval(p_dma, df_1ch_DMA['loop_size']) + +p_spc = np.polyfit(df_1ch_spc['loop_size'], df_1ch_spc['cycles'], 1) +trendline_spc = np.polyval(p_spc, df_1ch_spc['loop_size']) + +plt.plot(df_1ch_CPU['loop_size'], trendline_cpu, color='blue', linestyle='-', alpha=0.6) +plt.plot(df_1ch_DMA['loop_size'], trendline_dma, color='red', linestyle='-', alpha=0.6) +plt.plot(df_1ch_spc['loop_size'], trendline_spc, color='green', linestyle='-', alpha=0.6) + + +# Title and labels +plt.title('Loop Size vs Cycles') +plt.xlabel('Loop Size') +plt.ylabel('Cycles') +plt.grid(True) + +# Legend +plt.legend() + +# Save plot +plt.savefig('plot.png') + +# Show plot +plt.show() diff --git a/hw/vendor/esl_epfl_x_heep/scripts/verification/verifheep.py b/hw/vendor/esl_epfl_x_heep/scripts/verification/verifheep.py new file mode 100644 index 00000000..8cf07ebd --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/scripts/verification/verifheep.py @@ -0,0 +1,498 @@ +# +# Copyright EPFL contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Author: Tommaso Terzano +# +# +# Info: This library can be used to implement a software-based verification of X-Heep on a variety of targets, +# including Verilator, QuestaSim and FPGA (pynq-z2), using gdb and OpenOCD. +# Some useful information: +# +# 1) In order to enable the elaboration of the outcome of a test, the SW testbench should produce data using +# the following format: +# - 1st line to n line: "::" +# - last line: "&" +# Of course it is not mandatory to count the cycles, or to provide an outcome, or even to use different IDs. +# The crucial thing is to use the format, even if only one of its fields is relevant for your usecase. +# +# 2) The library provides methods to generate a random input dataset + a golden output dataset +# using a provided function. +# This is particularly useful for data-processing applications and accelerators, but could be used to test other +# units with some workarounds. +# If the function returns a dictionary of parameters that might be useful for the application (if not, return None), +# they will be written in the same header file as the golden output. +# The application has to be written in order to use an external output, defined in a header file, +# and to compare it against a golden output, also defined in a header. +# Both the name and directories of these datasets can be provided as arguments. +# It is also possible to generate a golden result starting from a custom input dataset, provided that it was produced +# using the same structure.# +# +# 3) The library provides methods to estimate the remaining time of the execution of a loop, based on the average duration +# of the iterations that have already been executed. +# This is useful to estimate the remaining time of the execution of a multi-iteration test. +# + +import subprocess +import re +import time +import serial +import pexpect +import threading +import queue +import random +import os + +# Set this to True to enable debugging prints +DEBUG_MODE = False + +def PRINT_DEB(*args, **kwargs): + if DEBUG_MODE: + print(*args, **kwargs) + +class VerifHeep: + def __init__(self, target, xheep_dir, opt_en=False): + self.target = target + if target not in ['verilator', 'questasim', 'pynq-z2']: + raise Exception(f'Target {target} not supported. Choose one among:\n- verilator\n- questasim (with optional optimization)\n- pynq-z2\n') + if (target != 'pynq-z2' and opt_en) or (target != 'verilator' and opt_en): + raise Exception(f'Target {target} not supported with {opt_en}. Choose one among:\n- verilator\n- questasim (with optional optimization)\n- pynq-z2\n') + + self.opt_en = opt_en + self.xheep_dir = xheep_dir + self.results = [] + self.it_times = [] + + def resetAll(self): + self.results = [] + self.it_times = [] + if self.ser.is_open: + self.ser.close() + self.ser = None + self.serial_queue = None + self.serial_thread = None + self.gdb = None + self.xheep_dir = None + + def clearResults(self): + self.results = [] + + # Synthesis & Simulation methods + + def compileModel(self, mem_banks=6, cpu="cv32e40px", bus="1toN"): + mcu_gen_cmd = f"cd {self.xheep_dir} ; make mcu-gen MEMORY_BANKS={mem_banks} CPU={cpu} BUS={bus}" + subprocess.run(mcu_gen_cmd, shell=True, capture_output=True, text=True) + if ("ERROR" in mcu_gen_cmd.stderr) or ("error" in mcu_gen_cmd.stderr): + print(mcu_gen_cmd.stderr) + exit(1) + + def buildModel(self): + if self.target == 'verilator': + cmd = f'cd {self.xheep_dir} ; make verilator-sim FUSESOC_PARAM=--JTAG_DPI=1' + elif self.target == 'questasim' and self.opt_en: + cmd = f'cd {self.xheep_dir} ; make questasim-sim-opt FUSESOC_PARAM=--JTAG_DPI=1' + elif self.target == 'questasim' and not self.opt_en: + cmd = f'cd {self.xheep_dir} ; make questasim-sim' + elif self.target == 'pynq-z2': + cmd = f"cd {self.xheep_dir} ; make vivado-fpga FPGA_BOARD={self.target} FUSESOC_FLAGS=--flag=use_bscane_xilinx" + result_synth = subprocess.run(cmd, shell=True, capture_output=True, text=True, executable="/bin/bash") + if ("ERROR" in result_synth.stderr) or ("error" in result_synth.stderr): + print(result_synth.stderr) + exit(1) + + # FPGA programming & debugging methods + + def serialBegin(self, port, baudrate): + try: + self.ser = serial.Serial(port, baudrate, timeout=1) + self.serial_queue = queue.Queue() + + if self.ser.is_open: + print("Connection successful") + return True + else: + print("Failed to open the connection") + return False + except serial.SerialException as e: + print(f"Serial exception: {e}") + return False + except Exception as e: + print(f"An error occurred: {e}") + return False + + def setUpDeb(self): + gdb_cmd = f""" + cd {self.xheep_dir} + $RISCV/bin/riscv32-unknown-elf-gdb ./sw/build/main.elf + """ + self.gdb = pexpect.spawn(f"/bin/bash -c '{gdb_cmd}'") + self.gdb.expect('(gdb)') + self.gdb.sendline('set remotetimeout 2000') + self.gdb.expect('(gdb)') + self.gdb.sendline('target remote localhost:3333') + self.gdb.expect('(gdb)') + + if self.gdb.isalive(): + PRINT_DEB("GDB process is still running.") + else: + PRINT_DEB("GDB process has terminated.") + if self.gdb.exitstatus is not None: + print(f"GDB exit status: {self.gdb.exitstatus}") + if self.gdb.signalstatus is not None: + print(f"GDB terminated by signal: {self.gdb.signalstatus}") + exit(1) + + def stopDeb(self): + self.gdb.sendcontrol('c') + self.gdb.terminate() + + def launchTest(self, example_name, input_size=0, pattern=r'(\d+):(\d+):(\d+)', en_timeout_term=False): + PRINT_DEB(f"Running test {example_name} with input size {input_size}...") + + # Check that the serial connection is still open + if not self.ser.is_open: + print("Error: Serial port is not open!") + exit(1) + + # Set up the serial communication thread and attach it the serial queue + self.serial_thread = threading.Thread(target=SerialReceiver, args=(self.ser, self.serial_queue,)) + + # Start the serial thread + self.serial_thread.start() + + # Compile the application + if self.target == 'verilator' or self.target == 'questasim': + app_compile_run_com = f"cd {self.xheep_dir} ; make app PROJECT={example_name}" + else: + app_compile_run_com = f"cd {self.xheep_dir} ; make app PROJECT={example_name} TARGET={self.target}" + + result_compilation = subprocess.run(app_compile_run_com, shell=True, capture_output=True, text=True) + + if ("Error" in result_compilation.stderr) or ("error" in result_compilation.stderr): + print(result_compilation.stderr) + return + else: + PRINT_DEB("Compilation successful!") + + # Run the testbench with gdb + self.gdb.sendline('load') + self.gdb.expect('(gdb)') + + try: + output = self.gdb.read_nonblocking(size=100, timeout=1) + PRINT_DEB("Current gdb output:", output) + except pexpect.TIMEOUT: + PRINT_DEB("No new output from GDB.") + + # Set a breakpoint at the exit and wait for it + self.gdb.sendline('b _exit') + self.gdb.expect('(gdb)') + self.gdb.sendline('continue') + try: + self.gdb.expect('Breakpoint', timeout=600) + except pexpect.TIMEOUT: + print("Timeout! Program didn't answer in time, exiting...") + self.gdb.terminate() + if en_timeout_term: + exit(1) + return + + # Wait for serial to finish + self.serial_thread.join() + + # Recover the lines + lines = [] + while not self.serial_queue.empty(): + lines.append(self.serial_queue.get()) + + # Analyse the results + pattern = re.compile(pattern) + test_id = None + for line in lines: + match = pattern.search(line) + if match: + test_id = match.group(1) + cycle_count = match.group(2) + outcome = match.group(3) + self.results.append({ "ID" : test_id, "Cycles": cycle_count, "Outcome": outcome, "Input size": input_size }) + + def dumpResults(self, filename="results.txt"): + with open(filename, 'w') as f: + for result in self.results: + f.write(result + '\n') + + # Performance estimation methods + + def chronoStart(self): + self.start_time = time.time() + + def chronoStop(self): + self.end_time = time.time() + self.it_times.append(self.end_time - self.start_time) + return self.end_time - self.start_time + + def chronoExecutionEst(self, loop_size): + avg_duration = sum(self.it_times) / len(self.it_times) + remaining_it = loop_size - len(self.it_times) + remaining_time_raw = remaining_it * avg_duration + remaining_time = {} + remaining_time["hours"], remainder = divmod(remaining_time_raw, 3600) + remaining_time["minutes"], remaining_time["seconds"] = divmod(remainder, 60) + return remaining_time + + # Data generation methods + + def genInputDataset(self, dataset_size, parameters="", row_size=0, range_min=0, range_max=1, dataset_dir="input_dataset.h", dataset_dir_c="", dataset_name="input_dataset", datatype="uint32_t"): + + if dataset_dir_c == "": + with open(dataset_dir, 'w') as f: + # Add license + f.write(f"#ifndef {dataset_name.upper()}_H\n") + f.write(f"#define {dataset_name.upper()}_H\n\n") + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f"#include \n\n") + + # Write the parameters, if there are any + if parameters: + for key, value in parameters.items(): + f.write(f"#define {key} {value}\n") + + # Vector declaration + f.write(f"const {datatype} {dataset_name}[{dataset_size}] = " + "{\n") + + # Generate the random vector + for i in range(dataset_size): + if 'float' in datatype: + value = random.uniform(range_min, range_max) # float + elif 'uint' in datatype: + if ('8' in datatype or '16' in datatype or '32' in datatype) and range_min >= 0 and range_max > 0: + value = random.randint(range_min, range_max) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + elif 'int' in datatype: + if ('8' in datatype or '16' in datatype or '32' in datatype): + value = random.randint(range_min, range_max) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + + if i < dataset_size - 1: + f.write(f" {value},") + else: + f.write(f" {value}") + + if row_size > 0 and (i + 1) % row_size == 0: + f.write("\n") + + # Close the file + f.write("};\n\n") + f.write(f"#endif // {dataset_name.upper()}_H\n") + else: + with open(dataset_dir_c, 'w') as f: + # Add license + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f'#include "{os.path.basename(dataset_dir)}"\n\n') + + # Vector declaration + f.write(f"const {datatype} {dataset_name}[{dataset_size}] = " + "{\n") + + # Generate the random vector + for i in range(dataset_size): + if 'float' in datatype: + value = random.uniform(range_min, range_max) # float + elif 'uint' in datatype: + if ('8' in datatype or '16' in datatype or '32' in datatype) and range_min >= 0 and range_max > 0: + value = random.randint(range_min, range_max) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + elif 'int' in datatype: + if ('8' in datatype or '16' in datatype or '32' in datatype): + value = random.randint(range_min, range_max) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + else: + print("Error: invalid datatype. Choose one among:\n- float\n- u/int8_t\n- u/int16_t\n- u/int32_t\n") + exit(1) + + if i < dataset_size - 1: + f.write(f" {value},") + else: + f.write(f" {value}") + + if row_size > 0 and (i + 1) % row_size == 0: + f.write("\n") + + # Close the file + f.write("};\n\n") + + with open(dataset_dir, 'w') as f: + # Add license + f.write(f"#ifndef {dataset_name.upper()}_H\n") + f.write(f"#define {dataset_name.upper()}_H\n\n") + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f"#include \n\n") + + # Write the parameters, if there are any + if parameters: + for key, value in parameters.items(): + f.write(f"#define {key} {value}\n") + + f.write("\n") + + # Vector declaration + f.write(f"extern const {datatype} {dataset_name}[{dataset_size}];\n\n") + + # Close the file + f.write(f"#endif // {dataset_name.upper()}_H\n") + + def genGoldenResult(self, function, golden_size, parameters, row_size=0, output_datatype="uint32_t", input_dataset_dir="input_dataset.h", golden_dir_c="", golden_dir="golden_output.h", golden_name = "golden_output"): + + # Recover the input dataset + with open(input_dataset_dir, 'r') as f: + content = f.read() + + # Use regular expressions to find the array data + pattern = re.compile(r"{(.*?)}", re.DOTALL) + match = pattern.search(content) + + if not match: + raise ValueError("No array data found in the file.") + + array_data = match.group(1) + # Remove extra whitespace and split the string into individual values + array_data = array_data.replace('\n', '').replace(' ', '') + values = array_data.split(',') + + # Convert values to the appropriate type + if "float" in content: + values = [float(value) for value in values] + elif "uint8_t" in content or "uint16_t" in content or "uint32_t" in content: + values = [int(value) for value in values] + elif "int8_t" in content or "int16_t" in content or "int32_t" in content: + values = [int(value) for value in values] + + # Generate the golden result + (golden_values, output_parameters) = function(values, parameters) + + if golden_dir_c == "": + with open(golden_dir, 'w') as f: + # Write the golden result to a file + f.write(f"#ifndef {golden_name.upper()}_H\n") + f.write(f"#define {golden_name.upper()}_H\n\n") + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f"#include \n\n") + + # Write the parameters that could have been returned from the function + if output_parameters: + for key, value in output_parameters.items(): + f.write(f"#define {key} {value}\n") + + f.write("\n") + + # Vector declaration + f.write(f"const {output_datatype} {golden_name}[{golden_size}] = " + "{\n") + + for i in range(golden_size): + if i < golden_size - 1: + f.write(f" {golden_values[i]},") + else: + f.write(f" {golden_values[i]}") + + if row_size > 0 and (i + 1) % row_size == 0: + f.write("\n") + + # Close the file + f.write("};\n\n") + f.write(f"#endif // {golden_name.upper()}_H\n") + else: + with open(golden_dir_c, 'w') as f: + # Write the golden result to a file + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f'#include "{os.path.basename(golden_dir)}"\n\n') + + # Vector declaration + f.write(f"const {output_datatype} {golden_name}[{golden_size}] = " + "{\n") + + for i in range(golden_size): + if i < golden_size - 1: + f.write(f" {golden_values[i]},") + else: + f.write(f" {golden_values[i]}") + + if row_size > 0 and (i + 1) % row_size == 0: + f.write("\n") + + # Close the file + f.write("};\n\n") + + with open(golden_dir, 'w') as f: + # Write the golden result to a file + f.write(f"#ifndef {golden_name.upper()}_H\n") + f.write(f"#define {golden_name.upper()}_H\n\n") + license = "/*\n\tCopyright EPFL contributors.\n\tLicensed under the Apache License, Version 2.0, see LICENSE for details.\n\tSPDX-License-Identifier: Apache-2.0\n*/\n\n" + f.write(license) + f.write(f"#include \n\n") + + # Write the parameters that could have been returned from the function + if output_parameters: + for key, value in output_parameters.items(): + f.write(f"#define {key} {value}\n") + + # Vector declaration + f.write(f"extern const {output_datatype} {golden_name}[{golden_size}];\n\n") + + # Close the file + f.write(f"#endif // {golden_name.upper()}_H\n") + + def modifyFile(self, file_dir, pattern, replacement): + + with open(file_dir, 'r') as f: + content = f.read() + + # Replace the pattern with the replacement + new_content = re.sub(pattern, replacement, content) + + with open(file_dir, 'w') as f: + f.write(new_content) + +# Serial communication thread + +def SerialReceiver(ser, serial_queue, endword="&"): + try: + if not ser.is_open: + raise serial.SerialException("Serial port not open") + + received = False + while not received: + # Read the data from the serial port + line = ser.readline().decode('utf-8').rstrip() + serial_queue.put(line) + PRINT_DEB(f">: {line}") + if line: + if endword in line: + received = True + PRINT_DEB(f"Received {endword}: end of serial transmission thread") + return + elif "ERROR" in line: + print("FAILED VERIFICATION!") + exit(1) + except serial.SerialException as e: + print(f"Serial exception: {e}") + except Exception as e: + print(f"An error occurred: {e}") + except KeyboardInterrupt: + print("Keyboard interruption") + finally: + pass \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py index 5a4a6cd2..4486daad 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/gen_stimuly.py @@ -38,9 +38,9 @@ def write_arr_flash_only(f, name, arr, ctype, size): f.write('#ifndef MATRICES_H_\n') f.write('#define MATRICES_H_\n') f.write('// This file is automatically generated\n') +f.write('#ifdef FLASH_LOAD\n') - -SIZE = 64 +SIZE = 32 RANGE = 10 m_a = [] @@ -59,6 +59,7 @@ def write_arr_flash_only(f, name, arr, ctype, size): write_arr(f, 'B', B, 'int32_t', SIZE) write_arr(f, 'C', C, 'int32_t', SIZE) +f.write('#endif\n') f.write('#define MATRIX_SIZE %d\n' % SIZE) diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c index 01f7dab7..8785dcef 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/main.c @@ -43,6 +43,10 @@ int32_t buffer_data[MATRIX_SIZE*TILING_ROWS] = {0}; int32_t output_matrix[MATRIX_SIZE*MATRIX_SIZE] = {0}; int main(int argc, char *argv[]) { +#ifndef FLASH_LOAD + PRINTF("This application is meant to run with the FLASH_LOAD linker script\n"); + return EXIT_SUCCESS; +#else soc_ctrl_t soc_ctrl; soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS); @@ -84,4 +88,6 @@ int main(int argc, char *argv[]) { } PRINTF("All tests passed!\n"); return EXIT_SUCCESS; + +#endif } diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h index 323d1a06..59dc4443 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_data_processing_from_flash/matrices.h @@ -1,206 +1,112 @@ #ifndef MATRICES_H_ #define MATRICES_H_ // This file is automatically generated +#ifdef FLASH_LOAD int32_t __attribute__((section(".xheep_data_flash_only"))) __attribute__ ((aligned (16)))A[] = { -8,0,9,3,0,0,7,3,4,4,4,0,5,1,9,3,9,1,0,4,1,1,9,4,6,9,8,1,3,3,2,6,5,6,8,7,4,3,3,1,1,9,8,9,6,3,1,6,4,3,6,1,9,0,6,7,5,0,6,5,1,5,6,2, -3,1,8,2,9,8,1,3,0,2,4,6,6,5,7,1,5,5,5,8,6,5,4,9,2,6,7,1,7,2,5,0,9,9,7,6,2,1,6,5,4,9,5,3,1,5,6,9,3,4,4,1,1,7,2,5,8,0,6,4,3,1,8,2, -3,8,8,0,7,5,1,9,1,2,2,2,0,6,4,6,2,4,7,6,0,9,9,8,5,1,9,5,9,8,2,2,7,7,7,5,9,0,3,4,5,3,9,0,2,2,0,7,2,3,1,1,5,5,3,6,4,4,3,7,5,6,0,4, -9,4,4,2,0,4,3,5,7,5,7,5,3,6,5,4,5,7,4,2,4,0,2,8,6,8,4,0,1,3,8,5,4,8,5,1,6,0,7,6,3,1,1,6,2,5,4,9,4,9,5,1,3,7,0,1,0,2,6,3,8,0,1,6, -3,7,8,9,5,1,7,5,5,8,9,7,2,1,2,1,0,3,5,5,3,0,3,0,8,3,3,5,6,3,7,2,2,6,6,1,7,1,7,6,7,1,7,2,0,6,5,1,7,6,6,4,6,3,7,2,1,0,5,9,1,1,1,1, -4,5,6,7,5,3,5,0,2,9,1,7,1,5,6,6,8,8,1,4,5,8,5,2,5,8,8,5,9,5,2,5,6,4,1,2,9,7,1,1,0,6,9,1,2,2,6,3,7,6,6,1,2,0,1,1,8,9,7,0,4,9,0,3, -5,9,0,0,6,3,8,2,4,5,2,9,1,4,4,8,9,3,5,7,1,6,8,8,7,9,3,7,7,4,8,4,9,6,3,1,5,0,6,7,9,6,9,6,4,9,0,6,0,2,1,4,9,4,7,6,0,1,8,2,8,4,2,9, -5,0,0,9,3,7,3,3,8,4,2,0,1,9,5,5,0,0,4,9,8,7,1,3,3,4,3,0,0,3,3,0,2,5,1,8,6,0,2,0,4,2,3,2,9,5,5,2,8,9,4,2,9,7,7,8,8,3,8,9,3,9,1,9, -6,8,4,2,5,3,3,5,1,0,0,8,1,3,9,9,5,5,9,0,5,9,8,2,4,1,4,3,0,6,7,9,9,2,1,8,1,5,1,9,6,3,9,5,0,1,3,6,4,7,5,0,4,6,3,1,4,9,2,1,8,2,8,5, -9,8,5,1,8,0,0,0,1,5,2,6,2,3,2,6,6,7,3,6,6,3,5,9,8,8,1,7,4,4,1,2,0,2,4,3,0,0,5,5,3,8,6,1,4,6,4,8,5,9,7,9,8,1,0,9,8,1,9,6,4,4,0,2, -1,6,0,4,7,8,1,6,8,8,9,4,7,8,1,3,5,4,1,2,8,3,6,4,2,0,1,9,3,9,6,9,2,2,3,3,2,7,1,0,2,8,9,9,9,8,7,4,2,9,4,8,2,0,9,0,3,2,5,6,4,9,3,1, -0,9,9,8,5,4,5,4,1,9,3,3,0,1,6,3,8,6,6,6,3,8,5,7,8,9,4,1,8,2,6,0,5,3,6,7,1,9,8,7,9,0,5,5,3,7,0,1,2,9,4,3,8,3,2,6,1,0,5,5,6,0,4,8, -8,6,2,6,1,4,4,2,0,3,9,8,9,3,1,8,2,9,5,9,9,4,6,0,9,9,9,4,8,7,7,4,4,1,7,9,9,7,3,2,1,6,5,6,5,4,7,9,0,1,0,5,6,9,1,5,1,1,7,5,8,6,7,6, -7,6,5,8,6,2,3,1,2,8,3,9,5,9,3,9,8,8,2,4,7,0,7,4,1,1,9,8,9,7,4,9,3,4,8,3,6,1,1,7,4,9,7,6,8,3,9,1,2,8,2,1,1,6,0,1,2,1,2,2,2,1,0,1, -3,2,7,7,9,2,1,4,0,0,4,4,4,1,4,3,2,1,1,6,4,0,4,6,2,4,9,1,1,3,6,9,0,0,0,0,4,4,6,7,5,9,0,4,1,7,7,0,5,9,4,5,4,1,9,1,3,0,8,4,9,1,8,3, -9,9,3,9,1,9,4,5,3,6,0,5,8,4,3,9,0,2,7,6,1,9,7,4,0,0,9,4,1,6,3,6,7,9,3,9,4,6,6,1,1,7,0,8,0,3,1,0,5,9,3,9,4,7,7,1,1,7,7,1,1,0,2,1, -0,8,7,7,8,0,9,0,4,3,9,1,3,8,3,8,4,2,1,2,2,9,0,2,4,6,1,3,1,8,9,0,1,7,9,0,1,7,2,3,7,7,7,0,0,1,4,4,8,4,8,7,8,9,9,8,9,3,1,6,5,4,5,2, -6,1,9,3,1,9,0,6,0,0,1,5,3,0,0,4,7,7,2,4,8,8,9,3,8,8,9,4,5,3,8,4,1,2,7,5,4,4,9,3,7,5,2,9,4,5,0,3,2,3,7,2,2,8,7,1,4,4,9,2,1,7,7,6, -6,3,0,2,7,7,2,8,8,7,1,6,8,1,5,6,7,7,7,4,9,8,4,8,7,6,0,8,0,9,8,0,8,8,1,4,7,8,7,3,3,9,8,6,5,7,8,9,0,8,6,6,7,4,8,3,6,0,2,8,3,9,3,1, -5,9,0,5,3,9,5,4,6,8,4,9,9,6,8,2,5,8,0,1,3,8,5,9,8,3,1,4,9,0,9,8,1,6,6,9,9,5,0,4,9,4,2,5,3,0,2,9,8,1,6,3,7,3,8,2,9,9,9,6,0,7,4,5, -7,0,7,7,1,7,7,3,2,5,4,5,7,5,7,2,8,7,2,0,2,8,3,9,7,5,1,0,5,8,7,2,1,9,2,3,3,7,7,1,4,3,2,2,8,3,0,7,4,6,1,5,0,3,6,5,0,9,4,2,3,1,5,0, -9,4,2,7,3,2,5,8,5,1,7,2,1,9,1,6,7,3,7,0,2,7,9,4,3,1,9,6,1,3,2,5,9,9,1,9,0,5,4,2,3,3,3,3,1,7,2,2,9,9,8,4,1,1,1,1,6,6,5,4,0,3,1,2, -1,9,3,6,6,3,4,9,3,4,2,2,4,3,5,4,0,6,5,1,1,1,2,7,9,4,0,0,3,7,1,8,9,0,7,7,1,3,7,7,5,7,9,7,0,0,8,1,9,0,3,9,3,9,0,8,4,5,4,5,6,0,9,4, -5,6,4,1,1,8,9,4,3,2,5,9,5,4,5,6,9,4,1,7,1,3,0,0,5,9,5,2,3,2,5,5,7,2,2,9,3,1,2,8,5,0,1,0,8,9,2,9,3,4,6,9,5,4,7,4,7,9,6,1,0,8,2,8, -5,3,4,4,8,1,5,5,2,4,2,1,1,5,6,3,2,4,9,1,1,5,3,1,3,3,8,0,4,8,8,4,7,0,1,1,6,2,1,0,8,2,0,4,4,4,5,4,0,7,7,8,5,5,0,0,0,1,8,8,7,4,7,9, -1,7,2,6,1,6,7,6,2,9,6,2,5,7,7,8,1,5,7,3,3,4,9,8,7,6,5,5,2,8,7,8,7,1,6,0,5,2,2,4,2,3,3,2,0,0,3,4,5,2,2,9,2,9,7,7,9,5,9,0,1,5,3,0, -7,4,1,9,4,5,0,6,7,4,1,2,7,4,0,8,8,3,7,0,5,3,2,2,4,2,7,0,0,5,0,4,6,9,6,2,2,4,5,3,4,4,2,8,7,3,9,4,5,8,5,2,9,4,1,3,2,9,2,2,4,3,9,8, -6,7,8,8,8,8,9,1,1,5,0,5,5,4,2,0,3,0,4,2,1,0,2,6,2,8,1,4,1,6,8,0,0,5,1,3,8,0,2,3,6,6,3,3,4,8,9,2,8,3,1,3,7,2,1,4,9,9,4,4,3,1,2,1, -0,9,9,6,9,3,9,7,5,3,9,3,0,2,9,6,2,2,5,6,8,2,9,6,8,3,6,7,4,4,3,8,6,1,2,6,6,0,9,0,0,9,3,9,9,8,4,8,6,8,0,6,1,3,0,8,4,3,5,3,0,6,2,2, -1,7,1,4,3,5,6,3,7,2,3,1,6,3,5,2,9,3,7,0,6,9,6,5,3,9,6,0,2,3,1,0,6,2,5,8,2,3,0,0,0,4,3,9,4,6,3,5,2,0,3,8,8,2,8,2,5,6,9,7,3,2,9,9, -5,5,4,0,2,4,0,4,5,2,7,6,6,8,5,3,5,5,2,7,3,8,7,5,5,3,6,0,8,6,3,1,7,4,7,1,0,4,3,0,7,9,5,0,6,0,7,3,3,8,2,5,1,4,4,1,6,4,2,5,5,6,8,0, -8,5,9,6,7,9,8,2,9,1,5,1,0,5,9,6,1,9,8,7,6,9,1,0,1,2,8,4,7,4,5,6,9,1,5,8,7,2,4,3,8,3,8,9,0,6,3,1,6,5,7,0,3,1,3,8,5,7,0,8,8,2,7,3, -7,2,8,3,9,8,9,1,6,5,0,4,5,7,3,9,9,0,9,9,2,6,4,3,3,3,3,9,5,5,7,4,2,4,7,2,3,5,5,9,8,6,3,1,5,7,6,8,9,4,1,8,8,5,4,9,0,7,5,4,5,3,6,9, -0,4,8,3,0,9,2,7,1,2,8,5,6,2,8,5,2,0,4,8,2,5,8,2,0,5,7,8,8,0,8,9,3,7,9,5,4,9,4,2,6,9,7,1,5,4,6,3,2,6,3,9,8,4,1,0,1,6,2,0,5,3,7,6, -6,4,6,1,0,7,3,4,6,2,7,1,3,9,0,5,5,4,7,0,0,3,4,8,2,6,6,9,9,0,2,6,5,9,9,7,7,0,6,2,2,7,8,3,8,6,0,4,7,7,0,9,2,2,1,5,1,8,2,3,7,7,1,9, -0,4,2,8,9,7,3,4,1,5,3,3,0,6,4,1,1,8,1,4,9,6,4,0,8,0,2,7,2,2,1,2,8,3,2,3,7,5,9,1,7,8,5,5,6,2,0,0,1,4,3,5,2,8,4,2,7,7,0,5,7,3,4,0, -1,7,4,5,1,3,9,1,8,2,3,7,0,2,9,3,5,3,3,9,2,6,0,5,7,4,9,7,9,6,9,6,4,1,5,3,7,3,0,2,3,9,7,7,8,2,5,8,4,0,8,3,3,0,4,3,0,5,7,3,7,3,9,7, -4,5,5,0,8,1,5,7,8,1,2,5,8,3,0,6,2,9,6,4,5,5,6,6,0,3,8,0,2,0,9,9,1,7,9,4,8,8,7,5,8,1,5,0,0,4,7,1,2,0,2,0,6,7,8,0,1,3,4,0,8,6,9,5, -6,6,9,6,5,1,2,7,1,6,5,5,5,7,2,8,3,5,6,0,8,7,6,9,3,8,8,8,5,3,4,8,5,6,9,2,7,5,7,3,1,7,2,2,9,6,1,9,2,4,4,3,9,2,5,1,6,7,7,2,9,8,6,0, -9,4,4,3,0,3,4,7,1,0,8,4,8,3,1,4,2,5,9,0,0,1,8,5,1,9,3,0,8,9,9,7,4,2,0,3,7,5,8,8,9,1,6,8,3,2,1,6,7,1,6,9,5,9,9,3,5,2,3,4,7,2,1,1, -4,8,0,1,3,6,6,2,5,2,7,2,5,5,7,0,6,4,6,4,8,0,6,4,0,3,6,7,9,7,4,6,8,9,8,7,8,5,0,5,4,5,4,2,8,6,7,8,2,2,0,8,6,4,3,9,7,1,2,3,5,2,5,2, -8,7,0,9,4,4,0,7,5,9,1,8,7,6,9,3,5,6,8,7,8,8,6,9,4,8,6,1,2,8,5,1,1,3,3,3,6,2,8,0,7,3,1,3,2,4,1,1,3,5,6,1,0,9,7,7,7,9,3,4,3,3,6,7, -3,2,8,4,1,0,4,9,4,2,9,5,7,0,9,0,7,8,1,1,8,9,9,3,4,0,7,9,1,4,7,7,9,6,1,8,1,4,1,2,1,6,8,5,8,9,5,1,2,4,3,2,4,6,9,0,6,7,0,8,5,5,2,4, -2,8,7,9,4,3,4,7,0,1,6,9,2,4,9,0,4,2,4,7,6,2,7,7,6,1,5,7,0,2,4,8,4,9,0,1,4,0,1,5,4,9,1,6,8,6,7,9,6,7,6,5,2,0,1,7,1,0,8,0,1,2,5,2, -0,6,8,8,3,3,5,7,1,1,7,5,2,6,2,0,4,2,7,0,7,9,6,9,1,8,4,3,5,7,1,9,3,3,0,5,6,2,0,5,1,6,8,0,1,2,0,6,7,7,9,6,5,6,2,6,9,4,2,7,4,9,6,8, -3,3,9,1,5,2,9,1,4,4,8,9,3,8,1,4,7,9,0,2,4,8,4,5,6,0,7,4,8,9,6,9,9,3,4,9,6,2,2,6,4,0,5,2,5,3,2,3,4,1,3,4,1,9,5,4,9,3,0,3,4,1,2,8, -4,2,0,9,7,5,7,2,9,0,8,6,0,1,5,6,8,3,4,7,5,9,2,0,8,7,6,6,7,1,3,5,3,7,6,2,1,8,2,0,4,1,6,9,3,0,5,7,1,1,6,8,3,4,1,2,7,6,5,6,6,1,1,2, -6,3,5,8,4,9,2,0,9,7,5,4,3,5,7,0,5,7,7,4,4,0,5,3,4,6,0,0,2,2,7,7,0,5,7,2,6,5,3,5,9,9,4,1,6,7,7,3,4,8,6,6,1,1,7,1,3,4,4,4,4,2,1,1, -7,1,2,0,5,9,2,1,3,9,3,7,4,9,5,1,6,5,7,2,0,5,2,4,8,0,5,2,6,6,7,9,8,7,7,8,5,2,4,6,9,3,4,8,8,1,3,4,5,2,2,7,3,9,2,8,8,8,8,8,1,4,1,4, -8,6,3,2,5,1,1,0,9,9,9,8,3,9,5,4,6,2,0,0,4,6,7,1,0,0,0,2,5,2,5,4,9,1,1,5,6,7,6,0,6,4,3,6,5,2,8,7,3,4,0,7,5,4,6,8,8,9,9,6,2,3,2,9, -0,4,9,6,2,5,0,6,0,6,2,0,5,9,7,9,9,7,9,7,3,0,9,7,9,2,5,0,7,5,7,6,7,7,9,9,1,7,1,6,1,3,9,3,6,4,4,9,8,9,6,4,8,5,8,1,5,9,2,5,4,7,2,7, -1,1,3,6,0,1,9,3,5,0,5,0,0,3,0,3,7,7,5,7,5,8,0,4,9,8,8,2,3,7,1,9,8,3,2,1,4,7,8,4,3,7,6,0,2,7,6,2,4,6,2,4,9,2,5,0,0,0,7,5,3,5,7,1, -7,5,9,1,5,8,8,6,5,1,8,4,3,2,1,9,7,8,1,2,3,5,6,0,6,1,0,3,7,9,1,3,0,2,0,5,4,7,3,9,3,4,6,6,6,8,2,0,4,8,3,1,1,2,0,6,9,9,9,8,3,4,7,7, -4,9,4,5,0,9,6,5,5,2,5,5,5,5,1,9,4,9,8,1,5,2,9,8,1,9,9,0,0,7,4,8,7,1,8,8,7,3,3,2,2,4,5,0,1,2,3,6,9,0,0,2,1,5,5,7,7,0,7,6,5,5,7,6, -9,1,9,3,8,2,2,9,7,9,4,9,5,2,6,5,5,3,7,2,8,8,7,7,9,2,1,4,0,2,2,8,8,5,9,9,0,5,2,1,5,5,3,3,7,0,7,3,5,9,8,2,6,0,3,7,8,8,4,6,6,3,3,3, -0,8,6,6,5,9,4,8,7,8,4,8,3,8,7,9,4,4,5,5,6,0,9,4,9,2,8,7,0,1,2,5,3,6,1,9,2,7,4,6,4,7,9,5,6,0,4,1,1,2,6,5,2,1,1,9,6,2,0,8,0,4,7,5, -8,5,6,2,3,3,9,4,4,1,9,2,7,0,6,8,1,5,6,7,3,9,9,4,5,6,9,6,7,9,0,2,8,5,1,3,9,2,8,3,5,3,9,2,5,6,3,7,0,2,4,8,2,8,4,2,2,1,8,9,2,1,7,4, -3,8,3,6,2,1,1,6,1,1,7,9,3,4,5,4,8,7,2,3,9,8,8,1,8,0,8,5,8,1,1,2,2,3,9,5,6,1,0,3,1,5,2,1,6,4,4,7,0,4,9,8,7,6,6,9,6,3,0,6,7,6,3,5, -2,1,9,4,2,4,3,9,1,9,0,9,9,2,2,1,5,2,2,9,2,4,6,2,3,3,4,0,0,8,8,4,6,2,2,5,6,7,5,6,1,3,9,7,0,1,2,2,5,9,2,1,3,1,8,8,1,3,6,9,6,0,9,2, -5,4,8,8,6,8,9,1,7,6,2,0,7,8,6,1,0,6,9,2,7,6,8,1,3,6,2,1,5,1,0,4,9,1,5,2,4,4,4,5,6,4,4,6,8,5,6,7,8,5,3,1,3,3,6,9,6,0,0,8,1,8,8,6, -9,0,5,0,9,6,4,8,3,9,9,8,2,8,0,0,9,5,2,1,2,0,1,5,2,1,9,6,3,8,7,0,1,0,9,1,0,1,6,0,8,7,4,5,6,4,5,6,5,9,5,8,9,4,2,0,8,2,6,5,4,5,4,5, -8,7,5,6,8,4,8,2,4,6,5,0,2,1,1,0,8,3,0,0,6,7,6,5,5,7,0,9,4,2,1,0,8,1,5,0,4,5,5,1,4,6,6,5,5,2,2,7,9,8,6,6,4,3,9,5,7,6,5,8,5,7,7,3, -2,4,8,3,7,6,5,0,3,8,0,4,8,7,6,3,6,0,3,2,8,7,4,6,2,1,6,3,5,7,5,1,5,3,8,9,9,3,0,7,2,6,7,5,5,7,3,3,9,7,6,3,6,4,3,2,5,3,5,0,1,2,7,3, -6,0,1,2,3,9,7,8,4,6,3,8,3,0,5,2,9,1,9,6,9,6,2,1,0,6,0,1,2,5,6,4,9,8,9,4,1,2,6,6,4,7,1,2,7,3,7,9,9,2,6,0,4,4,2,5,0,0,4,6,2,4,8,0, +9,2,4,0,5,0,6,4,3,9,7,8,0,8,9,0,3,2,4,0,5,8,3,4,0,4,9,8,3,6,4,7, +5,7,3,4,1,8,5,7,7,3,1,0,5,8,5,5,4,1,8,0,1,6,7,8,4,1,1,6,2,1,2,6, +0,7,7,6,4,7,2,9,9,1,2,9,7,6,1,8,1,1,6,5,0,6,3,3,7,6,6,4,2,7,2,6, +7,6,3,7,3,3,5,0,2,8,2,1,8,7,1,4,5,5,9,4,0,9,9,1,9,9,0,9,0,9,1,9, +1,1,5,0,3,4,0,2,5,4,2,3,2,8,0,4,3,8,1,2,0,2,2,7,2,7,4,6,8,1,4,7, +0,8,7,7,4,2,5,3,0,7,0,3,9,1,9,3,9,2,4,8,0,7,2,0,6,2,9,7,8,5,0,8, +3,9,3,0,1,1,7,8,2,7,9,4,2,6,9,2,4,1,8,3,9,8,3,4,5,4,8,0,2,4,9,0, +2,0,6,7,4,3,3,1,8,4,6,7,5,3,9,9,6,1,8,4,4,2,5,6,7,6,2,6,4,2,1,5, +7,3,0,8,6,6,2,8,6,9,6,8,4,0,0,5,5,5,0,4,4,0,9,8,9,9,8,2,2,0,1,0, +5,6,2,7,4,9,2,8,8,2,2,4,0,9,0,9,7,2,6,6,7,3,7,8,3,7,1,0,0,0,6,1, +5,4,8,7,5,3,3,1,2,5,6,0,3,9,6,4,7,3,1,2,0,8,6,2,4,5,1,9,5,0,8,8, +6,9,0,7,0,3,8,6,6,8,4,3,1,7,8,2,4,4,2,3,3,8,3,9,5,4,3,9,4,5,9,6, +7,0,0,7,0,8,6,7,1,1,3,9,7,7,0,7,0,9,8,3,6,4,9,1,3,9,0,3,6,0,1,0, +6,9,9,6,3,5,9,4,1,3,8,2,9,6,5,9,1,3,1,4,1,8,7,6,3,2,9,1,1,5,0,2, +5,2,8,5,3,4,7,8,6,7,0,1,0,4,7,5,6,0,8,6,9,9,5,9,7,3,2,8,5,3,6,5, +1,4,4,1,6,7,0,8,6,8,6,7,8,2,3,6,6,1,0,1,2,0,6,4,5,1,2,2,3,7,7,3, +0,3,6,7,5,4,1,2,8,1,9,3,6,5,5,3,7,5,4,1,3,2,3,0,8,5,5,2,6,9,1,7, +8,6,9,3,9,4,1,9,1,4,8,7,5,2,5,0,7,7,9,5,2,9,8,9,5,7,6,5,1,6,1,0, +2,8,6,6,7,3,0,9,3,5,5,9,2,0,2,3,9,9,3,0,0,4,5,1,2,6,5,0,6,0,6,3, +9,8,1,1,0,2,2,4,3,7,4,8,9,8,5,0,8,4,6,6,7,4,5,4,1,9,1,9,1,3,5,2, +0,8,2,2,5,3,0,2,2,4,5,3,4,1,2,3,7,7,0,2,6,8,5,7,5,1,6,5,8,2,8,4, +9,8,4,3,3,7,9,8,3,5,9,8,6,1,5,3,2,8,8,2,3,0,1,4,4,1,7,3,1,0,6,1, +6,6,1,4,4,3,1,7,9,3,6,8,2,4,4,7,6,6,0,8,6,7,6,0,0,2,9,7,4,7,2,1, +2,3,7,1,3,2,4,7,8,8,9,2,0,1,7,9,4,5,9,4,5,6,2,3,6,0,7,9,4,5,8,2, +9,2,8,2,2,5,3,6,1,2,4,3,2,3,7,6,7,9,2,4,4,3,7,1,1,0,9,2,6,3,4,9, +1,9,7,1,7,2,2,1,0,3,0,2,3,0,9,6,4,0,4,9,5,3,9,0,5,3,0,7,9,5,8,4, +1,7,6,5,4,4,6,0,7,7,4,7,8,3,8,1,6,4,2,0,6,5,6,4,7,3,6,9,8,2,5,0, +3,4,3,8,0,4,2,8,9,8,9,9,1,8,3,1,8,0,9,7,8,3,3,1,3,0,3,2,7,4,0,7, +8,6,3,2,3,9,7,5,3,2,0,2,7,2,8,8,4,3,6,9,7,7,6,6,3,1,2,7,6,5,9,0, +4,1,2,9,4,5,5,2,8,1,6,7,7,0,4,0,4,4,0,8,0,5,8,5,5,5,0,9,3,3,1,7, +9,7,0,5,1,4,6,0,2,7,5,8,5,6,5,4,8,2,4,2,9,2,2,4,6,0,2,0,3,0,6,8, +7,3,4,2,4,1,3,7,1,9,8,0,6,0,1,4,8,9,0,6,8,2,2,7,8,5,6,5,2,8,7,7, }; const int32_t B[] = { -1,1,9,1,9,6,7,6,2,8,2,8,5,6,3,0,2,4,0,1,7,5,9,1,7,4,7,3,2,2,8,0,3,1,3,7,1,9,2,5,6,5,2,3,7,1,6,3,3,2,1,4,2,4,8,9,4,0,8,3,6,4,0,9, -6,1,6,9,1,4,3,4,2,3,4,8,0,0,1,2,7,7,9,6,1,5,8,7,6,7,1,8,0,2,7,1,4,5,7,4,2,7,6,0,0,1,7,9,0,4,3,8,8,9,4,3,4,7,6,3,4,0,8,9,5,1,1,7, -3,3,4,7,0,4,1,5,2,1,2,5,6,6,1,4,4,2,8,7,5,4,0,5,8,1,7,2,3,4,7,7,6,3,1,5,6,2,8,5,7,8,7,7,9,3,5,9,9,1,1,1,6,8,5,5,9,7,9,5,8,9,0,9, -2,9,2,2,4,4,6,7,4,7,4,2,4,2,7,2,2,2,9,6,7,2,1,5,0,9,5,2,8,6,8,6,2,7,8,2,0,1,0,2,9,0,3,9,9,6,9,2,1,7,1,1,4,6,7,9,8,8,5,3,1,1,8,5, -2,2,8,2,0,6,7,3,0,1,2,0,5,2,6,9,3,5,2,0,9,7,6,7,2,5,2,3,0,6,0,4,5,1,6,4,7,8,0,1,0,7,1,6,6,5,4,7,2,3,0,3,8,0,7,4,5,0,3,8,6,3,5,0, -9,1,3,8,5,9,4,9,0,2,9,7,1,1,0,8,4,7,8,5,3,2,3,0,9,8,3,7,5,8,8,5,9,5,6,5,2,7,3,3,7,2,2,7,0,0,4,9,8,8,0,6,0,9,3,9,6,5,7,0,8,2,2,3, -4,3,2,5,2,0,4,6,7,1,5,1,6,4,1,0,4,6,1,1,3,8,8,9,1,1,9,9,7,5,0,8,5,5,9,0,4,1,7,5,2,2,7,8,5,1,1,0,0,2,0,1,7,9,2,0,3,7,7,8,6,9,4,0, -6,0,4,1,4,2,0,2,5,4,0,6,9,9,1,1,8,7,5,0,3,3,8,6,1,1,3,1,9,2,4,6,2,5,6,6,8,4,6,1,3,0,7,1,3,3,0,3,3,2,7,4,6,0,6,7,7,7,0,4,9,4,9,4, -1,9,5,5,4,5,7,7,2,4,9,4,6,0,3,5,2,6,8,0,3,0,5,5,1,6,9,2,6,9,7,3,8,0,6,1,0,0,4,4,2,3,3,7,8,1,7,4,7,0,9,2,1,4,2,7,0,3,0,7,7,7,4,0, -5,0,9,9,7,4,0,5,7,3,7,5,2,4,4,9,5,4,5,7,5,1,2,1,3,8,8,5,1,6,6,3,9,8,1,1,9,4,7,9,8,8,4,5,0,9,5,3,0,3,5,7,4,2,5,5,2,9,9,7,7,9,2,3, -4,9,9,2,5,3,1,7,6,2,5,2,5,9,3,1,1,9,0,3,1,1,2,5,0,7,6,0,4,0,0,5,5,9,8,4,1,0,9,8,9,7,1,5,8,5,7,1,1,3,7,1,3,4,7,8,7,8,8,5,2,7,5,5, -0,9,7,2,6,8,5,7,0,3,6,9,1,2,5,7,7,2,9,6,6,9,7,1,0,6,6,4,3,3,7,1,8,0,7,2,8,9,2,1,0,1,7,9,5,7,6,8,5,4,0,1,7,9,8,9,0,5,4,9,8,5,5,9, -9,9,3,4,5,3,7,5,7,3,3,2,1,5,7,5,0,8,4,5,8,9,4,3,9,8,2,6,3,9,3,1,3,6,5,3,9,0,8,4,5,5,5,9,4,0,9,6,0,4,4,6,2,5,8,2,0,9,0,0,0,0,7,9, -4,9,3,6,2,7,0,5,9,6,9,4,8,6,2,1,9,0,2,2,6,9,5,0,5,8,7,6,3,8,6,9,8,9,8,2,8,2,9,4,2,7,2,6,6,9,0,1,9,8,9,0,0,5,3,5,8,7,9,1,4,9,8,1, -3,5,1,8,4,8,7,4,0,4,9,8,0,8,6,7,0,7,9,1,6,6,4,8,2,0,8,9,7,8,9,0,1,4,2,0,9,4,9,5,3,0,4,0,6,8,2,0,3,9,7,4,8,3,4,9,4,6,9,6,2,9,9,6, -5,2,1,9,2,2,6,4,4,3,4,4,6,0,2,9,0,8,4,6,3,4,1,6,6,5,4,4,5,0,0,3,4,4,1,1,4,9,8,0,1,6,2,6,1,3,7,3,4,1,5,9,0,1,9,2,7,3,6,7,1,4,7,7, -7,7,9,0,8,0,2,4,2,3,7,5,7,4,2,0,8,8,3,7,1,4,7,2,7,9,4,3,0,8,1,6,9,8,6,0,3,4,7,8,8,6,7,1,7,9,9,9,6,0,3,9,4,8,8,3,8,9,5,0,4,4,4,7, -7,8,3,4,5,8,1,6,7,5,2,0,9,5,9,7,1,8,6,4,4,9,3,8,6,2,8,3,0,7,6,5,9,6,5,8,0,9,8,7,4,4,1,1,8,7,8,7,2,2,8,8,3,1,9,2,2,5,8,6,3,3,7,8, -1,3,6,6,2,8,8,1,2,5,2,4,8,3,8,5,0,8,4,9,9,3,4,4,3,6,6,7,3,3,8,5,0,9,6,9,0,2,5,8,9,3,1,0,8,8,4,4,3,5,9,8,6,1,2,0,9,4,2,9,4,0,0,1, -8,1,7,6,0,2,2,7,6,0,1,7,6,9,0,9,7,8,4,9,6,2,4,3,3,8,8,8,5,6,3,2,2,7,1,7,8,6,6,1,4,0,8,3,5,0,0,3,5,2,3,4,2,4,9,2,1,0,4,3,3,2,0,5, -3,8,0,3,8,6,8,3,8,8,7,2,5,4,6,5,5,8,2,8,8,1,4,0,8,9,3,2,0,9,7,2,9,4,6,2,5,0,2,5,9,1,7,7,9,9,4,5,3,7,6,3,3,9,4,8,5,4,6,4,0,8,8,2, -0,0,8,9,8,3,3,9,7,2,6,9,2,9,4,6,8,3,8,7,7,6,4,7,8,5,8,6,1,3,0,2,2,9,4,8,0,1,3,6,4,2,9,2,1,4,7,0,3,8,5,6,6,1,6,2,0,0,2,4,1,4,4,4, -6,8,7,2,1,9,3,3,8,5,8,2,7,5,9,8,5,6,5,9,8,6,3,2,7,1,1,2,7,6,7,1,1,6,8,5,0,8,4,4,3,6,8,1,7,6,0,9,2,6,0,2,2,8,6,2,6,9,7,3,3,3,5,4, -6,0,5,0,9,4,5,1,9,8,1,4,5,7,2,2,9,0,3,7,3,2,9,2,6,5,3,7,2,6,1,3,1,5,7,1,4,6,0,6,4,9,1,5,0,1,8,0,5,9,8,5,2,1,0,7,3,2,5,8,1,7,5,3, -0,5,8,3,4,8,3,3,6,1,2,9,6,8,3,6,6,9,8,1,5,2,0,9,6,7,1,7,6,3,0,9,0,3,5,6,2,4,2,8,2,7,5,7,6,5,2,2,0,2,8,9,3,6,7,6,1,5,2,9,0,1,7,5, -9,0,0,5,5,8,3,0,9,7,6,8,5,7,2,4,9,8,2,2,8,3,1,6,5,1,8,6,2,0,8,5,5,8,0,3,1,8,0,0,6,8,4,1,4,1,5,0,0,9,0,0,2,2,3,3,1,8,6,6,3,7,1,3, -6,6,0,9,4,8,7,5,0,3,1,4,0,1,1,2,8,7,4,4,8,3,1,1,6,3,7,9,2,0,8,9,6,5,8,7,0,8,8,6,3,4,9,1,5,0,9,8,8,2,0,4,2,5,7,0,7,5,1,6,5,8,6,9, -9,6,7,5,2,9,9,1,7,1,0,4,4,9,5,8,9,3,2,8,4,0,7,3,5,8,2,6,2,1,7,0,5,0,1,9,3,2,7,7,4,1,6,4,9,6,3,5,6,8,2,5,3,9,1,5,3,2,7,1,9,1,2,8, -1,0,7,9,9,1,7,7,0,5,6,8,6,8,7,4,9,6,3,7,9,3,2,5,2,4,6,7,8,9,7,5,6,9,7,4,3,7,0,1,7,1,1,7,8,4,9,8,7,1,0,2,6,8,4,9,1,9,1,3,9,7,4,5, -1,9,7,9,0,0,4,3,2,4,4,8,0,6,1,8,8,2,0,9,0,7,0,5,4,8,9,8,7,7,8,5,9,2,6,2,2,9,6,7,1,1,1,7,7,4,3,0,8,5,5,0,1,1,0,9,3,8,3,0,9,3,8,7, -4,7,5,5,2,4,5,1,3,4,6,7,7,4,3,0,7,7,8,4,0,3,4,9,0,4,6,6,4,3,9,5,5,5,2,6,2,1,8,0,8,5,0,8,2,5,7,2,6,4,3,4,7,4,3,5,0,0,1,3,0,6,7,4, -1,7,8,7,4,6,1,9,2,1,3,1,4,5,8,6,8,0,2,8,8,7,6,5,5,4,3,7,0,0,3,6,7,8,2,4,0,0,7,0,8,0,8,7,1,2,1,5,4,0,6,9,4,6,0,4,0,6,6,4,6,2,3,8, -3,2,5,5,6,6,0,8,2,5,8,5,8,9,8,6,6,2,5,0,4,4,5,9,6,3,9,5,7,6,1,6,2,6,5,8,2,2,4,1,0,6,2,1,9,7,9,5,9,7,8,3,1,2,1,0,7,5,4,4,6,4,5,8, -1,4,1,3,8,8,1,0,5,0,2,4,8,3,4,0,7,0,0,9,6,6,0,3,8,3,2,8,2,3,5,5,4,9,5,3,7,9,8,6,6,3,4,6,7,7,3,1,1,5,4,2,0,9,5,1,4,5,4,0,8,2,4,8, -5,4,4,9,9,1,0,6,9,8,4,6,0,3,8,9,4,9,5,6,2,7,0,5,7,8,0,3,7,0,1,3,1,4,7,4,7,6,3,4,7,2,4,8,9,2,4,1,7,1,9,9,5,5,4,0,5,4,5,8,6,8,1,2, -9,0,0,2,7,4,2,1,3,1,7,3,6,2,5,9,3,8,5,5,8,8,2,9,3,5,2,6,9,3,0,4,3,7,8,3,7,2,6,5,8,2,9,7,1,1,9,0,8,5,8,0,1,3,1,5,9,8,1,9,1,9,2,9, -6,7,5,6,2,5,7,6,0,9,5,7,4,3,0,6,1,8,7,9,5,7,2,8,1,5,4,3,4,7,4,7,5,0,0,4,2,8,0,2,9,9,5,1,7,3,0,7,3,3,3,0,9,7,6,8,5,6,0,2,1,5,3,5, -7,7,8,2,6,6,6,8,2,9,8,3,7,5,7,9,2,1,4,8,0,4,7,6,1,7,1,0,8,3,5,7,9,1,0,9,5,9,6,6,7,1,8,1,5,6,9,6,0,1,2,9,9,7,8,2,5,8,6,1,5,2,9,3, -1,7,5,1,6,1,4,2,8,5,1,7,0,3,0,4,1,3,2,8,0,3,6,1,8,9,4,1,7,1,2,0,3,8,7,8,1,6,9,6,5,7,6,3,3,3,9,8,2,1,0,6,6,2,4,2,5,0,8,2,6,4,6,3, -2,6,1,2,4,1,3,3,9,5,8,6,2,1,4,7,7,3,1,6,4,3,2,5,8,9,9,6,5,0,0,3,1,1,4,2,7,6,4,8,9,8,1,5,6,7,0,3,3,6,4,8,8,8,8,9,3,8,3,5,5,4,4,5, -2,3,0,1,6,0,0,1,6,3,0,9,6,8,9,5,1,4,0,7,0,5,5,2,2,8,5,1,8,2,9,9,1,9,4,5,9,6,6,5,9,2,7,6,4,4,5,2,9,5,4,6,8,4,0,7,6,1,5,3,0,9,5,1, -2,5,4,4,4,8,2,8,8,6,6,9,6,4,1,7,7,8,1,6,8,7,9,4,2,4,1,4,2,0,5,8,8,9,6,9,7,6,1,0,9,7,1,5,2,0,7,7,3,4,5,1,0,7,3,1,5,4,4,9,6,1,0,8, -2,6,8,2,6,9,8,4,3,6,5,9,8,0,0,6,7,1,8,4,0,1,8,1,2,8,2,2,2,8,1,6,1,5,9,8,9,5,6,3,2,1,4,2,9,3,2,0,9,6,8,8,3,3,7,6,7,0,0,4,8,4,0,6, -9,8,0,2,7,2,8,4,0,6,1,8,3,9,8,4,0,0,6,3,0,5,9,8,0,6,8,5,1,9,7,5,4,8,5,5,1,4,3,2,4,5,5,0,5,5,3,8,0,2,5,2,1,3,1,6,1,6,8,2,8,4,1,3, -1,0,1,5,5,2,9,9,4,1,0,0,3,6,4,0,8,5,0,6,2,9,4,5,6,2,8,8,5,5,6,0,7,4,6,3,6,9,6,1,4,3,5,4,0,3,2,6,6,5,8,1,5,7,3,0,4,5,4,8,0,0,5,4, -5,7,1,4,4,4,2,7,3,2,7,7,8,6,5,1,1,0,3,1,4,6,7,3,7,1,6,3,7,5,6,6,8,4,9,1,2,7,3,0,2,8,8,3,9,3,7,2,8,5,0,9,4,5,1,3,4,6,6,8,6,9,7,7, -1,4,8,6,7,9,7,5,6,7,4,2,0,5,4,8,2,2,4,3,4,2,3,7,2,0,4,9,6,9,1,2,6,3,2,0,4,9,9,4,9,7,7,8,4,3,4,7,8,4,9,1,9,3,1,3,4,2,5,6,2,2,8,6, -3,5,9,4,5,9,7,1,6,7,7,3,1,9,3,2,8,5,7,7,8,1,7,7,0,0,2,3,7,3,6,8,6,3,7,6,6,3,6,0,1,9,9,3,0,9,2,2,3,0,2,6,3,3,2,8,5,6,2,6,9,6,7,0, -6,5,6,4,9,5,8,1,4,2,1,7,0,7,2,9,7,7,3,8,3,2,3,7,0,0,2,7,6,7,0,6,6,8,4,9,8,5,6,3,4,4,7,0,6,6,8,2,0,4,8,2,4,2,6,0,9,7,0,9,5,2,4,1, -4,5,1,2,4,3,7,7,9,5,0,7,3,2,0,8,4,1,6,5,9,8,8,1,2,3,4,0,2,4,0,3,2,6,1,0,9,2,2,3,4,0,7,3,3,0,4,7,7,1,2,9,7,8,5,5,6,3,4,1,8,9,3,5, -1,2,9,2,1,6,5,1,5,7,5,0,2,6,5,7,6,6,8,9,1,8,3,3,6,8,2,3,0,7,8,0,9,9,8,9,7,6,1,8,8,3,7,5,5,7,6,5,5,9,0,8,6,3,1,9,5,6,2,3,4,9,2,7, -5,1,9,8,5,2,6,7,8,7,1,2,1,1,6,8,0,0,1,0,4,3,1,8,3,4,1,8,4,7,3,3,0,3,6,7,7,5,6,3,0,7,6,7,9,3,9,4,1,9,1,2,1,8,8,9,6,6,1,0,8,9,8,6, -9,4,9,5,4,3,6,1,2,9,8,6,9,1,4,4,6,0,3,6,4,6,5,0,4,2,0,1,6,8,2,6,4,6,5,5,6,8,6,8,8,2,9,9,2,9,7,4,9,3,1,3,2,1,2,2,5,8,2,2,4,2,7,0, -5,1,3,4,8,7,2,7,3,2,1,4,0,0,4,8,5,6,6,7,9,0,7,6,0,8,1,2,3,0,5,9,1,3,6,1,8,2,7,1,7,5,9,5,1,9,5,9,1,8,5,0,8,2,9,0,8,1,6,9,1,5,1,8, -4,6,2,3,5,2,7,1,6,9,9,5,2,6,1,3,6,3,3,3,7,6,5,1,4,6,2,3,0,6,0,7,4,6,0,1,9,1,5,3,3,7,3,9,0,2,8,8,8,1,1,9,0,9,7,5,3,8,8,6,7,4,0,9, -7,8,8,4,4,9,3,1,1,5,2,7,5,6,2,2,9,3,0,8,1,7,1,8,5,5,3,0,9,9,6,4,6,0,4,2,3,6,2,8,4,8,4,9,9,6,1,0,0,0,6,1,9,7,7,2,8,4,7,8,4,4,6,2, -2,4,9,4,4,3,2,9,1,4,5,2,2,4,1,9,0,0,8,0,1,5,8,5,9,0,8,3,7,8,3,3,2,1,9,5,6,0,7,6,2,1,8,4,4,4,3,2,9,3,2,8,4,1,6,3,6,2,1,4,3,0,0,5, -9,4,8,3,1,9,6,4,0,9,7,7,6,3,9,4,0,3,2,2,1,9,0,6,5,2,0,7,8,3,3,4,6,0,6,0,0,5,7,8,3,4,6,5,8,2,7,8,9,7,9,0,8,1,9,8,5,7,4,4,9,8,5,7, -3,3,3,1,4,2,9,1,7,3,7,7,9,2,7,3,1,8,6,3,6,2,0,2,0,7,6,9,6,1,9,6,2,3,7,0,1,6,7,0,0,5,8,1,0,2,2,5,8,3,3,4,1,6,8,9,3,8,0,9,2,1,6,6, -0,7,1,3,6,0,7,0,3,9,4,1,5,2,6,3,7,6,1,3,8,4,6,3,3,4,6,6,0,6,5,6,3,6,9,4,4,0,0,8,0,5,3,7,4,0,9,4,2,2,9,1,8,7,5,3,8,6,1,9,9,8,9,0, -4,8,3,0,7,6,1,6,3,7,6,5,0,1,3,4,7,3,7,0,7,8,2,8,4,0,3,3,3,2,6,3,9,1,2,6,5,6,1,7,2,8,8,5,8,0,1,4,3,8,4,4,5,6,3,4,2,9,1,7,4,0,4,5, -8,4,8,6,5,5,1,2,2,9,9,2,4,7,0,1,1,8,6,2,9,1,7,0,8,9,3,2,6,9,1,4,6,6,2,8,1,6,7,3,0,7,7,4,3,9,3,5,6,5,6,5,8,9,5,3,1,0,9,5,4,6,7,6, -7,8,3,7,7,2,5,3,4,1,7,3,8,0,0,5,2,3,6,4,5,2,0,3,3,3,1,2,6,1,1,1,4,7,6,0,4,9,1,2,8,5,0,3,3,2,5,0,1,4,5,9,0,3,6,8,2,2,4,1,2,3,7,3, -9,5,2,1,0,7,2,1,3,5,2,3,0,5,6,2,2,9,0,4,1,6,5,3,0,4,8,2,2,1,2,1,2,2,1,7,7,2,0,3,4,7,3,6,8,0,9,0,0,8,3,2,0,4,6,7,9,6,0,1,7,1,7,6, +1,2,5,3,4,3,8,1,6,3,8,5,5,9,8,5,2,6,0,2,1,4,0,0,5,8,8,6,0,8,5,9, +9,6,7,8,4,9,6,2,9,4,8,6,1,2,1,4,7,8,7,5,8,2,8,8,0,9,1,6,8,7,0,1, +3,5,5,0,0,0,6,4,1,1,9,6,6,5,2,7,4,2,0,6,8,4,2,9,1,0,5,9,5,2,8,3, +2,6,0,3,6,4,3,4,5,7,8,3,1,5,0,6,3,8,9,2,8,2,8,8,8,8,0,6,6,1,9,3, +8,9,3,8,7,7,5,2,2,7,0,4,0,1,1,4,1,2,7,1,8,9,5,7,9,6,3,1,0,8,1,4, +6,6,6,6,7,7,4,7,8,8,8,0,7,8,1,2,8,7,0,4,1,7,1,6,1,5,8,9,1,0,7,5, +3,7,2,3,7,6,5,8,7,5,6,5,3,3,3,3,8,4,7,3,0,2,0,0,0,5,9,9,3,2,4,8, +5,2,9,1,0,8,4,4,7,4,9,3,9,3,5,0,4,4,5,9,9,5,7,7,7,7,0,1,8,7,7,3, +8,0,4,2,1,7,3,0,4,8,0,2,6,1,4,9,1,0,2,4,2,8,6,1,5,0,4,0,5,6,2,3, +5,6,8,5,0,5,4,2,8,6,0,5,4,1,3,9,5,0,6,7,1,4,8,2,5,3,4,5,4,0,7,7, +1,2,9,1,9,2,2,0,8,4,3,9,2,7,3,2,7,7,5,1,1,7,3,9,8,8,9,1,5,1,7,3, +4,7,8,2,3,8,2,3,7,4,0,5,0,1,4,1,3,8,8,6,6,3,8,9,0,0,5,9,0,1,1,5, +2,9,2,2,0,1,9,4,6,1,7,5,0,1,1,3,9,6,1,4,4,9,2,8,1,3,0,4,0,6,9,6, +6,2,2,1,2,4,3,0,6,7,8,4,0,7,3,7,1,1,7,6,8,1,7,5,7,7,7,7,9,3,9,5, +8,0,9,5,9,2,4,5,6,7,8,5,9,3,2,7,4,8,0,7,1,4,4,1,4,0,4,5,7,4,0,1, +1,9,4,6,3,6,0,8,2,0,4,0,9,5,6,3,4,9,0,0,5,3,2,8,3,2,4,5,9,6,9,7, +1,9,9,4,4,6,0,1,2,6,3,0,2,0,1,4,0,0,8,4,1,3,4,6,7,5,3,6,2,0,2,9, +7,9,6,5,4,4,4,0,5,8,6,5,9,6,0,6,6,9,9,9,2,7,6,1,7,0,2,0,7,8,8,4, +3,1,9,6,2,5,0,5,4,3,8,3,3,9,2,7,8,7,1,3,6,7,1,6,5,3,0,6,9,4,1,3, +8,5,0,0,4,3,2,2,4,5,8,0,9,1,5,3,5,9,5,6,7,6,7,5,6,1,1,6,4,8,2,5, +9,6,3,7,2,6,0,1,0,9,0,2,7,2,6,1,8,0,0,3,3,5,5,1,6,4,0,8,7,9,0,2, +6,7,9,2,5,1,2,5,3,8,0,1,4,4,9,4,2,6,6,6,2,7,5,2,8,6,2,1,5,5,4,9, +5,4,9,8,7,7,8,0,0,7,9,5,4,8,6,6,1,3,7,8,2,9,0,5,2,6,0,1,8,9,4,2, +5,7,0,6,8,0,4,2,8,7,4,2,5,4,8,2,7,7,7,8,1,6,6,8,4,5,6,3,2,7,5,4, +9,4,1,7,6,0,1,3,3,7,2,3,6,7,5,4,3,2,3,5,7,2,3,1,8,1,7,2,3,6,6,8, +5,8,8,4,8,5,1,5,8,4,6,4,6,0,6,5,7,7,1,1,7,7,4,5,8,4,0,7,2,3,6,9, +2,3,9,0,0,6,2,8,1,4,0,8,5,5,6,2,1,0,2,1,7,3,1,9,7,6,8,8,0,3,1,4, +1,3,9,6,2,6,3,7,3,4,1,8,5,0,3,1,0,3,5,5,7,4,2,5,1,4,3,5,4,8,5,5, +2,9,0,3,0,8,1,0,0,7,3,9,1,7,9,8,0,2,7,0,8,2,0,9,9,3,7,9,7,9,0,8, +2,8,9,6,9,4,7,8,3,0,4,8,0,0,1,1,3,0,9,0,3,6,6,3,2,2,5,8,0,3,4,2, +8,9,0,2,3,4,7,5,0,8,1,1,3,5,5,6,8,0,7,5,7,0,8,3,4,7,4,2,2,6,6,0, +4,8,8,4,0,9,2,5,9,0,6,9,6,9,7,0,3,2,4,2,0,7,6,9,5,8,0,2,7,7,1,6, }; const int32_t C[] = { -1223,1282,1286,1163,1319,1270,1192,1100,1142,1261,1291,1367,1260,1311,985,1232,1313,1316,1148,1320,1277,1275,1145,1199,1157,1203,1225,1211,1177,1281,1164,1239,1209,1454,1377,1145,1189,1335,1306,1108,1302,1233,1421,1194,1339,1065,1322,1063,1169,979,1109,1155,976,1341,1258,1173,1250,1486,1204,1322,1273,1303,1130,1377, -1184,1267,1312,1237,1443,1455,1188,1232,1260,1222,1312,1451,1244,1331,1078,1464,1396,1375,1279,1437,1466,1272,1208,1262,1248,1352,1314,1335,1209,1309,1263,1277,1264,1509,1546,1222,1369,1428,1334,1090,1392,1323,1378,1303,1411,1190,1443,1195,1305,1244,1177,1218,1132,1317,1370,1300,1356,1338,1210,1421,1310,1349,1236,1435, -1162,1146,1395,1317,1216,1378,1119,1124,1091,1251,1202,1479,1236,1287,1005,1364,1472,1348,1223,1445,1362,1273,1148,1252,1226,1323,1226,1294,1205,1235,1192,1299,1135,1351,1441,1303,1192,1422,1313,1142,1138,1213,1390,1262,1400,1148,1242,1149,1390,1197,1230,1127,1164,1269,1347,1231,1377,1294,1109,1386,1400,1285,1202,1375, -1085,1269,1161,1032,1288,1306,1093,1075,1208,1217,1133,1354,1087,1180,994,1148,1230,1282,1151,1255,1213,1176,1122,1190,1027,1230,1284,1184,1022,1073,1237,1162,1222,1300,1273,1038,1101,1271,1263,1053,1266,1276,1277,1185,1288,1092,1256,1066,1070,1100,1139,1110,1041,1201,1214,1307,1153,1334,1146,1282,1220,1292,1202,1281, -953,1262,1262,1113,1165,1134,1165,1034,1155,1150,1092,1340,1127,1129,991,1264,1190,1241,1146,1305,1178,1086,1038,1146,925,1348,1187,1146,1084,1170,1147,1201,1109,1331,1327,1101,1191,1195,1240,1088,1269,1097,1275,1367,1394,1097,1289,1092,1121,1008,1014,1078,1185,1328,1277,1274,1192,1304,1097,1331,1288,1287,1139,1227, -1201,1282,1518,1325,1281,1510,1265,1336,1105,1327,1407,1443,1225,1295,1066,1483,1340,1349,1354,1403,1371,1315,1151,1265,1189,1335,1343,1363,1137,1399,1248,1254,1465,1378,1333,1240,1131,1468,1371,1139,1253,1175,1496,1213,1473,1246,1402,1272,1330,1226,1126,1186,1212,1376,1462,1329,1229,1447,1227,1339,1347,1301,1240,1524, -1377,1419,1524,1328,1441,1503,1332,1263,1372,1402,1486,1771,1459,1449,1219,1424,1629,1493,1295,1539,1427,1451,1453,1399,1276,1583,1497,1480,1279,1354,1389,1403,1376,1571,1552,1346,1348,1654,1440,1173,1324,1504,1554,1499,1542,1332,1499,1277,1431,1402,1203,1382,1206,1560,1479,1448,1313,1516,1372,1582,1508,1404,1374,1553, -1180,1190,1170,1150,1253,1280,1261,1120,1132,1291,1259,1295,1148,1178,936,1279,1199,1307,1136,1266,1352,1219,1137,1104,1051,1323,1299,1210,1202,1416,1149,1190,1192,1345,1331,1059,1264,1186,1238,1078,1212,1136,1433,1338,1238,1081,1314,980,1253,1209,1241,996,1074,1264,1301,1235,1360,1275,1076,1355,1130,1254,1272,1195, -1159,1328,1348,1187,1256,1466,1220,1187,1064,1249,1357,1457,1216,1173,1179,1494,1289,1263,1350,1375,1310,1373,1248,1356,1142,1296,1226,1265,1158,1135,1179,1185,1210,1338,1376,1222,1213,1348,1378,1129,1272,1097,1444,1236,1363,1248,1324,1170,1316,1302,1266,1319,1195,1216,1356,1352,1313,1320,1173,1359,1298,1234,1253,1485, -1134,1192,1510,1136,1287,1364,1271,1096,1336,1308,1148,1414,1194,1245,1032,1431,1381,1276,1130,1384,1336,1264,1240,1175,1239,1336,1183,1249,1064,1289,1208,1102,1247,1302,1428,1224,1265,1470,1235,1161,1156,1305,1444,1343,1369,1177,1340,1132,1237,1177,1092,1239,1110,1324,1379,1318,1259,1278,1188,1466,1312,1262,1205,1355, -1266,1520,1489,1292,1362,1379,1379,1383,1309,1375,1416,1341,1262,1346,1139,1468,1367,1283,1245,1376,1341,1328,1405,1194,1162,1568,1256,1316,1109,1523,1281,1251,1550,1493,1500,1225,1303,1342,1463,1098,1279,1224,1440,1471,1384,1199,1433,1338,1395,1243,1313,1311,1093,1536,1311,1466,1223,1480,1327,1313,1491,1332,1396,1461, -1324,1267,1330,1251,1403,1288,1188,1214,1312,1302,1313,1591,1341,1331,1203,1456,1421,1408,1342,1529,1301,1337,1204,1372,1206,1499,1416,1278,1280,1291,1305,1313,1258,1588,1452,1262,1314,1473,1316,1285,1467,1271,1521,1386,1488,1250,1570,1182,1258,1285,1140,1369,1305,1405,1438,1359,1400,1532,1314,1458,1338,1451,1351,1364, -1508,1591,1551,1501,1560,1630,1454,1467,1378,1516,1488,1608,1383,1444,1297,1613,1483,1759,1421,1635,1655,1449,1270,1550,1260,1637,1451,1499,1405,1380,1486,1452,1522,1566,1612,1445,1283,1683,1534,1209,1565,1462,1665,1582,1626,1309,1625,1376,1302,1344,1358,1280,1260,1595,1679,1500,1399,1654,1363,1613,1365,1399,1545,1702, -1128,1402,1315,1329,1340,1389,1269,1399,1237,1236,1196,1382,1177,1206,1166,1486,1421,1321,1176,1538,1402,1373,1244,1194,1180,1494,1352,1365,1053,1302,1324,1224,1425,1421,1437,1106,1273,1479,1411,1069,1432,1156,1353,1414,1474,1224,1352,1368,1351,1155,1216,1164,1160,1468,1376,1301,1283,1407,1340,1365,1333,1314,1222,1562, -990,1242,1037,945,1056,1066,1122,1041,1072,1106,1025,1176,971,1006,867,1205,1076,1045,1000,1134,1225,1119,1020,1013,914,1099,1048,1067,931,982,1033,1069,1108,1191,1107,972,1094,1217,1063,856,1183,1130,1222,1157,1123,796,1215,1122,1048,969,815,1089,996,1210,1176,1192,1055,1217,1003,1157,1077,1052,1133,1251, -1284,1200,1269,1326,1294,1339,1278,1318,1181,1223,1209,1465,1143,1136,1127,1486,1193,1233,1248,1465,1402,1356,1180,1231,1176,1432,1200,1408,1160,1184,1267,1200,1191,1474,1389,1208,1165,1362,1425,1053,1281,1076,1472,1331,1252,1040,1517,1310,1238,1248,1084,1152,967,1341,1425,1250,1309,1399,1241,1257,1382,1239,1175,1577, -1157,1371,1479,1324,1290,1274,1173,1187,1301,1333,1326,1392,1165,1215,985,1438,1376,1284,1211,1396,1195,1319,1162,1383,1117,1438,1185,1208,1183,1294,1112,1369,1307,1449,1440,1203,1413,1294,1443,1230,1321,1264,1402,1575,1427,1266,1471,1020,1234,1245,1201,1196,1241,1327,1444,1219,1381,1343,1251,1407,1293,1369,1284,1303, -1316,1298,1260,1190,1373,1338,1219,1183,1240,1283,1256,1493,1236,1335,1122,1382,1292,1488,1302,1486,1338,1254,1162,1173,1297,1483,1244,1220,1166,1161,1344,1272,1290,1480,1411,1317,1103,1441,1318,1080,1426,1259,1527,1254,1328,1124,1486,1371,1274,1181,1027,1319,1105,1419,1442,1367,1249,1373,1263,1297,1258,1317,1227,1527, -1421,1598,1719,1432,1649,1684,1592,1420,1513,1671,1607,1690,1512,1581,1246,1737,1578,1567,1514,1660,1608,1495,1644,1490,1460,1731,1507,1492,1354,1732,1465,1436,1612,1657,1650,1527,1527,1676,1606,1398,1527,1522,1674,1585,1600,1498,1731,1449,1478,1458,1463,1573,1379,1600,1567,1585,1439,1563,1439,1575,1620,1505,1612,1670, -1491,1497,1680,1447,1639,1595,1469,1385,1371,1551,1666,1664,1403,1545,1403,1621,1512,1657,1560,1631,1536,1573,1433,1514,1314,1649,1409,1603,1415,1605,1462,1469,1523,1675,1690,1356,1478,1533,1601,1331,1565,1380,1688,1687,1424,1429,1693,1375,1481,1428,1447,1426,1364,1620,1623,1724,1355,1714,1367,1620,1474,1547,1523,1614, -1090,1249,1258,1115,1331,1239,1173,1167,1179,1179,1203,1371,1159,1269,1009,1150,1245,1181,1104,1338,1191,1301,1036,1221,1125,1263,1207,1256,1169,1232,1197,1194,1278,1346,1321,997,1116,1309,1316,1143,1253,1186,1246,1267,1269,1089,1401,1067,1059,1099,1098,1109,1089,1309,1330,1325,1136,1422,1227,1181,1224,1284,1296,1325, -1083,1217,1287,1048,1226,1301,1124,1133,1146,1134,1156,1229,1271,1223,1073,1232,1203,1169,1079,1252,1233,1235,1179,1147,1137,1240,1198,1207,1135,1142,1101,1184,1170,1434,1480,1202,1022,1193,1354,1134,1161,1055,1393,1101,1390,1119,1408,1067,1225,1142,1141,1134,982,1215,1252,1163,1391,1336,1110,1216,1293,1274,1213,1374, -1176,1248,1367,1209,1350,1327,1126,1169,1186,1257,1147,1409,1134,1158,1140,1539,1249,1262,1208,1267,1171,1228,1130,1483,1033,1346,1135,1305,1283,1225,1075,1250,1112,1364,1485,1199,1257,1356,1297,1102,1262,1223,1307,1367,1397,1109,1360,1064,1102,1259,1421,1132,1150,1122,1323,1293,1342,1352,1120,1478,1299,1183,1290,1328, -1358,1196,1378,1279,1255,1332,1182,1268,1170,1229,1412,1412,1192,1322,1065,1309,1291,1437,1206,1262,1288,1387,1202,1326,1237,1347,1386,1400,1304,1272,1176,1260,1337,1353,1438,1130,1291,1371,1493,1071,1218,1283,1566,1423,1335,1169,1460,1183,1396,1247,1090,1229,1152,1443,1453,1404,1296,1502,1227,1393,1356,1435,1306,1545, -970,1102,1135,1132,1034,1115,1110,1029,968,1150,1057,1154,1067,1083,1050,1148,1048,1194,1057,1091,1223,1172,1002,1175,842,1109,1236,1167,1003,1080,1207,1133,1084,1245,1215,1080,1015,1208,1115,949,1090,1113,1203,1106,1225,993,1243,1012,1082,1110,1004,989,1072,1076,1100,1213,1163,1220,937,1160,1132,1206,1271,1157, -1280,1299,1484,1423,1264,1417,1198,1259,1318,1303,1342,1413,1185,1310,1112,1504,1318,1388,1303,1392,1330,1217,1124,1375,1184,1439,1286,1431,1277,1300,1269,1324,1198,1410,1436,1153,1171,1297,1529,1139,1252,1276,1397,1376,1339,1280,1301,1146,1227,1303,1277,1239,1122,1313,1444,1336,1289,1461,1322,1437,1257,1302,1310,1431, -1213,1324,1265,1154,1335,1331,1249,1177,1102,1299,1174,1296,1159,1095,1117,1293,1148,1228,1118,1345,1221,1292,1112,1155,1161,1335,1152,1185,1161,1244,1133,1151,1287,1381,1380,1096,1145,1420,1294,1142,1364,1169,1359,1304,1370,1133,1458,1201,1186,1127,1257,1200,1028,1197,1323,1221,1332,1368,1115,1191,1290,1125,1327,1335, -1100,1107,1206,1076,1070,1217,1152,1037,976,1124,1102,1303,1049,1040,882,1175,1105,1061,1042,1170,1089,1200,1062,1149,1001,1083,1126,1249,1103,1233,1170,1129,1187,1130,1274,933,1092,1276,1166,982,1200,1136,1238,1307,1227,953,1190,1037,1182,1145,936,850,1108,1180,1121,1178,1162,1225,1059,1234,1170,1117,1057,1164, -1304,1421,1468,1398,1297,1510,1405,1379,1285,1250,1266,1486,1317,1492,1127,1487,1396,1510,1326,1485,1468,1341,1380,1525,1189,1391,1401,1442,1377,1416,1318,1342,1377,1510,1619,1288,1212,1407,1511,1086,1297,1355,1607,1403,1533,1261,1387,1344,1291,1234,1317,1152,1280,1513,1394,1379,1461,1464,1440,1650,1456,1457,1417,1467, -1311,1229,1205,1189,1294,1243,1263,1098,1123,1304,1394,1277,1192,1149,1133,1228,1157,1342,1180,1163,1268,1249,1113,1244,1099,1237,1215,1302,1102,1304,1141,1175,1185,1392,1483,1056,1062,1223,1203,1080,1165,1221,1384,1235,1295,1041,1492,1081,1176,1246,1169,1099,897,1234,1279,1242,1253,1482,1052,1325,1231,1235,1262,1267, -1040,1219,1342,1241,1334,1251,1081,1293,1204,1209,1230,1364,1124,1250,975,1353,1284,1270,1159,1251,1291,1236,1125,1121,1154,1273,1190,1220,1133,1240,1114,1134,1208,1417,1376,1149,1219,1342,1313,1052,1175,1109,1288,1249,1294,1029,1356,1157,1294,1130,1236,1131,1045,1275,1329,1190,1158,1222,1145,1239,1212,1243,1217,1354, -1330,1514,1426,1478,1427,1534,1396,1449,1113,1412,1455,1612,1408,1417,1252,1604,1356,1498,1443,1472,1434,1509,1309,1542,1292,1482,1586,1417,1344,1534,1440,1396,1500,1590,1601,1427,1239,1447,1447,1338,1503,1249,1509,1459,1763,1201,1585,1278,1501,1317,1409,1322,1357,1424,1436,1494,1504,1462,1386,1541,1526,1580,1334,1504, -1483,1510,1662,1516,1472,1567,1511,1383,1427,1441,1486,1693,1423,1445,1277,1653,1566,1564,1252,1712,1527,1504,1368,1474,1343,1638,1479,1562,1473,1475,1400,1462,1536,1550,1565,1394,1529,1659,1619,1351,1574,1540,1647,1672,1703,1358,1640,1358,1459,1364,1329,1423,1398,1645,1623,1495,1576,1619,1410,1576,1638,1504,1511,1513, -1378,1291,1411,1401,1335,1462,1228,1371,1250,1265,1322,1481,1251,1293,1165,1519,1344,1376,1263,1528,1354,1316,1168,1275,1161,1352,1151,1340,1317,1165,1286,1229,1292,1526,1369,1343,1357,1465,1506,1065,1534,1125,1546,1396,1442,1091,1466,1272,1352,1308,1147,1242,1180,1487,1382,1336,1331,1464,1227,1231,1398,1345,1305,1532, -1346,1268,1352,1280,1401,1465,1207,1261,1254,1325,1211,1445,1266,1284,1084,1275,1388,1362,1081,1393,1339,1344,1202,1257,1253,1346,1235,1335,1205,1225,1189,1267,1311,1467,1462,1328,1183,1386,1372,1146,1313,1354,1377,1324,1560,1051,1474,1183,1329,1275,1320,1132,1053,1471,1323,1273,1426,1453,1205,1349,1508,1382,1197,1463, -1022,1187,1170,1044,1151,1246,1027,1219,1050,1128,1098,1206,1071,1097,1007,1357,1094,1118,1119,1173,1158,1171,1093,1157,1052,1307,1048,1041,1028,1172,1076,1129,1159,1224,1297,1159,1100,1159,1144,1040,1137,1017,1259,1165,1290,1100,1200,1175,1063,1165,1072,1022,1080,1204,1242,1138,1170,1136,1153,1163,1132,1100,1126,1205, -1228,1387,1427,1403,1300,1425,1408,1294,1135,1292,1385,1536,1215,1375,1090,1372,1493,1488,1375,1443,1291,1323,1196,1449,1011,1387,1405,1524,1237,1315,1375,1284,1439,1430,1453,1275,1203,1455,1334,1082,1336,1212,1446,1398,1447,1109,1415,1167,1347,1258,1260,1182,1166,1460,1312,1474,1164,1448,1142,1484,1380,1336,1312,1462, -1229,1355,1264,1183,1314,1315,1133,1150,1185,1272,1267,1278,1256,1081,1103,1341,1182,1357,1212,1377,1320,1300,1159,1211,1155,1350,1139,1159,1123,1117,1120,1224,1267,1341,1296,1181,1190,1433,1408,1056,1392,1231,1416,1354,1320,1066,1387,1219,1231,1083,1171,1302,1194,1261,1386,1159,1144,1254,1142,1345,1164,1230,1272,1376, -1402,1490,1593,1472,1540,1586,1420,1415,1467,1578,1512,1550,1450,1479,1264,1497,1579,1482,1403,1634,1640,1530,1355,1386,1494,1515,1378,1446,1330,1336,1452,1408,1570,1617,1621,1422,1320,1645,1575,1282,1514,1496,1689,1515,1551,1392,1592,1417,1496,1390,1331,1436,1293,1555,1537,1461,1428,1662,1461,1603,1505,1478,1485,1641, -1190,1351,1391,1151,1359,1261,1272,1151,1193,1410,1220,1442,1176,1321,1145,1331,1298,1288,1138,1432,1265,1303,1234,1344,1097,1368,1299,1257,1225,1254,1342,1328,1216,1474,1431,1321,1194,1382,1412,1126,1384,1312,1382,1311,1391,1184,1442,1234,1173,1217,1092,1163,1187,1294,1353,1395,1298,1525,1167,1290,1331,1287,1237,1428, -1304,1416,1446,1406,1444,1463,1304,1344,1205,1344,1408,1391,1263,1330,1190,1426,1445,1377,1141,1490,1381,1376,1240,1404,1244,1378,1310,1436,1337,1454,1351,1288,1410,1408,1562,1208,1295,1477,1469,1192,1434,1246,1467,1463,1576,1277,1378,1198,1375,1277,1300,1163,1179,1544,1309,1334,1374,1525,1258,1383,1395,1343,1357,1443, -1337,1425,1424,1300,1416,1506,1314,1263,1283,1442,1345,1599,1210,1381,1185,1491,1360,1514,1366,1549,1449,1436,1297,1274,1278,1592,1432,1358,1241,1418,1492,1221,1363,1523,1521,1200,1309,1466,1375,1285,1432,1284,1492,1419,1474,1272,1567,1251,1258,1427,1298,1269,1276,1309,1573,1506,1367,1432,1366,1467,1307,1432,1391,1526, -1245,1479,1359,1192,1393,1455,1247,1338,1192,1281,1363,1339,1314,1433,1229,1360,1377,1332,1284,1331,1385,1395,1346,1348,1263,1295,1340,1301,1159,1368,1222,1257,1361,1454,1507,1271,1256,1206,1537,1251,1334,1178,1573,1343,1532,1225,1547,1291,1358,1286,1343,1219,1201,1442,1395,1281,1329,1515,1276,1401,1372,1362,1373,1679, -1088,1321,1295,1136,1190,1421,1235,1158,1223,1093,1118,1345,1176,1361,1049,1237,1373,1226,1196,1435,1316,1245,1186,1244,1044,1246,1207,1342,1137,1222,1302,1160,1238,1386,1398,1125,1219,1352,1315,976,1279,1157,1435,1272,1340,1212,1151,1148,1147,1207,1109,1078,1104,1456,1245,1357,1238,1354,1232,1349,1244,1180,1291,1399, -1233,1346,1483,1244,1296,1440,1206,1207,1228,1387,1335,1338,1222,1302,1034,1380,1488,1306,1266,1492,1447,1316,1269,1265,1181,1368,1261,1244,1149,1343,1204,1310,1313,1503,1547,1292,1255,1242,1249,1197,1355,1234,1505,1377,1462,1245,1408,1104,1243,1398,1216,1132,1221,1395,1361,1429,1450,1494,1145,1375,1395,1375,1295,1414, -1150,1376,1431,1299,1328,1327,1091,1375,1134,1150,1289,1330,1179,1324,1130,1429,1436,1311,1203,1401,1274,1414,1187,1409,1205,1395,1449,1332,1164,1307,1128,1333,1378,1352,1505,1192,1250,1254,1451,1217,1289,1257,1433,1468,1507,1226,1471,1181,1337,1189,1240,1139,1172,1376,1394,1321,1324,1470,1213,1393,1332,1401,1269,1547, -1086,1274,1427,1184,1336,1347,1301,1288,1076,1234,1239,1313,1176,1249,1188,1370,1234,1309,1243,1253,1244,1162,1137,1358,1024,1365,1262,1301,1150,1258,1228,1221,1250,1336,1448,1214,1060,1271,1290,1135,1225,1045,1454,1293,1480,1147,1399,1131,1121,1131,1116,1150,1134,1318,1381,1327,1183,1343,1102,1294,1311,1241,1247,1276, -1055,1338,1289,1170,1280,1362,1196,1278,1246,1310,1316,1358,1177,1180,1127,1391,1160,1306,1197,1344,1291,1294,1137,1177,1097,1365,1251,1240,1111,1305,1330,1218,1345,1410,1325,1109,1232,1329,1290,1099,1453,1200,1285,1355,1391,1092,1356,1205,1247,1158,1168,1232,1166,1421,1269,1371,1216,1398,1251,1336,1261,1328,1173,1321, -1241,1362,1541,1375,1528,1481,1285,1364,1179,1334,1358,1569,1284,1388,1337,1545,1414,1401,1245,1493,1384,1470,1260,1417,1267,1581,1456,1544,1325,1443,1378,1432,1360,1517,1612,1293,1353,1448,1561,1323,1417,1354,1493,1485,1468,1348,1504,1294,1413,1278,1469,1253,1298,1438,1467,1442,1423,1520,1282,1510,1463,1438,1355,1512, -1191,1405,1548,1192,1355,1385,1281,1306,1116,1400,1443,1404,1205,1296,1223,1375,1174,1249,1177,1294,1233,1342,1279,1290,1032,1370,1345,1204,1249,1404,1243,1196,1357,1300,1416,1119,1227,1290,1448,1139,1231,1347,1457,1401,1401,1252,1517,1270,1319,1150,1263,1046,1187,1352,1436,1425,1350,1436,1271,1350,1371,1359,1370,1384, -1533,1515,1630,1488,1528,1655,1407,1376,1435,1595,1587,1596,1514,1517,1354,1704,1603,1606,1510,1715,1590,1563,1342,1497,1435,1593,1392,1554,1467,1607,1335,1566,1479,1775,1667,1446,1608,1589,1735,1394,1572,1454,1692,1573,1659,1501,1695,1421,1608,1406,1575,1572,1313,1565,1659,1484,1697,1825,1410,1592,1599,1564,1547,1710, -1030,1264,1235,1155,1239,1140,1107,1169,1228,1181,1199,1289,1264,1173,908,1223,1267,1189,1040,1262,1244,1091,1075,1137,1063,1274,1222,1202,1090,1111,969,1306,1205,1427,1291,1148,953,1258,1254,1058,1239,1108,1343,1147,1290,1008,1357,1026,1152,999,1101,1209,994,1239,1195,1079,1115,1298,1073,1232,1165,1155,1254,1254, -1243,1402,1384,1183,1246,1257,1266,1330,1115,1206,1321,1437,1353,1240,1078,1420,1196,1383,1183,1344,1188,1398,1211,1321,1227,1379,1400,1246,1291,1312,1190,1233,1403,1285,1511,1135,1150,1454,1366,1224,1258,1221,1410,1342,1498,1066,1384,1252,1288,1102,1202,1247,1224,1436,1536,1461,1352,1494,1232,1360,1440,1282,1332,1466, -1376,1432,1337,1363,1390,1476,1213,1241,1248,1363,1401,1387,1244,1207,1079,1454,1381,1566,1314,1472,1399,1322,1191,1356,1247,1391,1336,1360,1269,1270,1294,1360,1366,1462,1550,1256,1130,1431,1423,1110,1321,1340,1438,1383,1399,1126,1480,1170,1290,1251,1342,1232,1060,1371,1438,1266,1461,1509,1254,1567,1297,1286,1327,1459, -1238,1391,1654,1282,1535,1583,1349,1371,1349,1438,1396,1503,1400,1483,1352,1670,1451,1452,1393,1511,1507,1553,1343,1431,1373,1456,1367,1364,1333,1462,1290,1251,1432,1511,1557,1338,1462,1445,1472,1429,1484,1300,1658,1546,1579,1316,1561,1295,1411,1270,1516,1399,1360,1430,1484,1458,1469,1569,1336,1635,1471,1468,1405,1548, -1328,1454,1420,1339,1301,1584,1286,1280,1242,1267,1371,1399,1361,1255,1125,1574,1424,1452,1350,1505,1338,1342,1278,1317,1284,1571,1323,1374,1275,1421,1342,1274,1397,1487,1589,1303,1386,1468,1493,1298,1385,1243,1476,1502,1498,1285,1414,1261,1274,1307,1370,1280,1183,1533,1502,1422,1490,1479,1370,1480,1419,1377,1417,1481, -1222,1364,1443,1416,1382,1408,1431,1338,1335,1312,1306,1510,1331,1404,1159,1485,1364,1526,1255,1513,1490,1320,1246,1408,1261,1466,1481,1469,1303,1305,1353,1331,1239,1519,1619,1349,1219,1522,1492,1206,1306,1366,1531,1346,1561,1139,1528,1252,1285,1321,1207,1237,1181,1438,1533,1434,1404,1478,1258,1462,1425,1431,1400,1589, -1207,1377,1473,1278,1359,1422,1204,1284,1197,1383,1316,1329,1130,1287,1145,1371,1422,1446,1296,1427,1422,1393,1162,1300,1248,1385,1149,1205,1164,1347,1224,1188,1328,1362,1530,1244,1269,1378,1281,1228,1304,1222,1561,1470,1516,1302,1417,1272,1254,1233,1184,1200,1226,1510,1500,1344,1353,1468,1197,1424,1285,1343,1358,1503, -1191,1379,1246,1083,1210,1174,1160,1093,1102,1200,1219,1429,1167,1147,923,1368,1318,1166,1231,1362,1215,1256,1084,1156,1002,1320,1218,1141,1110,1254,1116,1175,1212,1297,1225,1082,1283,1247,1229,1081,1218,1143,1336,1235,1273,986,1269,1137,1107,975,1089,1161,1112,1296,1385,1268,1172,1429,1053,1191,1338,1190,1197,1337, -1259,1436,1359,1390,1411,1479,1330,1340,1282,1402,1434,1360,1272,1425,1205,1464,1312,1423,1284,1440,1498,1374,1303,1352,1285,1402,1470,1302,1314,1571,1313,1321,1376,1566,1517,1295,1295,1339,1354,1200,1421,1357,1432,1424,1544,1293,1445,1228,1226,1258,1330,1254,1275,1477,1365,1285,1438,1490,1414,1492,1384,1388,1358,1277, -1203,1315,1492,1177,1365,1245,1219,1234,1241,1305,1174,1385,1160,1270,1017,1348,1315,1297,1118,1263,1216,1289,1330,1083,1083,1391,1298,1197,1140,1290,1254,1276,1399,1398,1534,1247,1368,1413,1429,1207,1287,1267,1412,1361,1376,1170,1480,1240,1385,1103,1117,1211,1131,1291,1320,1385,1357,1369,1198,1306,1478,1417,1300,1326, -1277,1318,1539,1185,1440,1354,1365,1235,1312,1446,1350,1412,1227,1379,1083,1407,1381,1347,1233,1348,1337,1269,1350,1304,1212,1405,1226,1215,1164,1413,1163,1254,1348,1431,1470,1297,1250,1341,1255,1221,1268,1348,1484,1347,1474,1210,1514,1269,1228,1253,1159,1259,1213,1468,1432,1361,1359,1421,1314,1402,1464,1348,1241,1340, -1276,1309,1326,1354,1357,1323,1325,1275,1202,1251,1403,1463,1174,1212,1064,1536,1341,1326,1305,1491,1351,1375,1168,1253,1217,1436,1278,1363,1195,1441,1184,1246,1358,1420,1478,1120,1412,1381,1337,1141,1416,1238,1449,1368,1412,1217,1425,1182,1378,1282,1199,1218,1140,1381,1329,1357,1345,1478,1152,1357,1294,1417,1230,1416, -1071,1204,1308,1204,1446,1269,1175,1132,1209,1188,1315,1368,1169,1283,1042,1331,1380,1409,1113,1452,1307,1186,1166,1205,1120,1335,1265,1279,1207,1236,1194,1144,1336,1483,1401,1154,1251,1352,1293,1073,1423,1138,1343,1257,1280,1237,1323,1077,1118,1105,1228,1177,1158,1301,1205,1194,1234,1343,1162,1376,1295,1242,1234,1213, +626,710,934,522,553,696,511,517,688,718,560,731,575,571,626,583,521,524,662,600,565,671,612,693,694,657,622,732,588,660,550,698, +616,645,731,564,502,644,490,470,667,680,719,509,583,616,528,565,548,587,556,617,536,654,521,680,566,627,474,602,672,664,614,628, +701,813,830,551,536,751,510,601,719,675,721,610,631,579,569,570,606,679,645,612,779,749,676,890,664,603,515,742,656,698,698,702, +673,881,915,687,647,702,579,576,754,709,789,684,600,648,575,664,622,678,731,631,648,805,630,737,716,692,479,726,688,747,760,836, +493,654,551,399,352,537,342,336,499,559,464,494,484,465,473,479,398,425,518,466,503,526,468,623,559,434,430,509,488,560,520,562, +625,851,830,548,496,693,490,583,639,664,687,682,589,513,521,598,531,611,675,586,688,664,594,830,679,582,483,784,622,671,557,745, +746,716,855,542,589,661,488,508,667,781,628,601,617,576,599,603,697,587,635,644,637,632,648,686,710,667,571,720,680,664,567,624, +640,762,784,595,601,662,430,512,653,719,658,591,652,581,566,638,583,671,577,578,624,729,578,793,695,523,528,718,668,672,634,713, +673,794,767,596,609,711,493,433,701,789,613,562,653,555,595,576,587,654,660,624,637,731,617,769,749,629,545,652,535,687,691,736, +725,758,687,581,580,722,448,434,655,794,716,400,654,595,574,595,619,651,617,624,656,676,654,739,697,662,473,674,683,690,671,654, +623,787,751,530,549,631,508,464,616,730,669,617,566,619,556,646,501,562,667,593,626,632,586,740,705,677,522,637,662,670,687,706, +778,843,849,634,661,755,579,564,805,872,708,678,679,622,661,669,659,670,813,728,653,681,758,730,743,754,617,740,724,781,696,749, +571,742,688,522,524,667,442,434,628,696,726,505,585,625,541,546,612,723,571,568,605,671,483,670,627,552,442,688,640,666,691,696, +624,809,802,541,632,630,606,573,716,672,792,657,615,638,569,581,653,730,637,609,630,718,556,832,627,687,621,756,645,678,746,708, +795,847,844,662,612,741,523,592,679,882,736,601,790,659,722,695,658,630,689,739,705,754,678,760,788,677,578,801,778,836,680,792, +594,745,710,520,483,639,508,428,582,620,532,523,502,455,453,498,533,472,594,551,550,639,581,720,547,521,487,571,488,582,605,559, +602,751,765,526,559,641,439,453,596,658,614,648,522,559,457,576,513,523,618,477,607,692,566,760,714,541,517,650,594,603,599,633, +764,888,1043,671,739,725,630,545,781,841,819,716,705,662,639,668,693,796,778,776,759,907,690,911,826,722,595,773,667,813,734,792, +601,788,781,490,467,699,444,383,587,678,580,550,519,506,463,565,505,581,679,575,642,614,608,775,671,576,420,579,569,591,559,603, +680,776,863,573,549,696,541,441,736,739,698,607,582,499,563,602,649,657,655,676,626,709,659,704,642,641,465,747,612,721,628,718, +637,807,668,542,482,616,431,388,504,725,456,543,515,500,541,507,510,499,667,556,560,600,569,699,649,579,459,550,550,694,504,590, +645,722,796,531,548,686,546,505,745,707,698,621,624,625,495,560,716,709,601,627,602,658,568,732,605,629,610,706,580,649,643,637, +666,766,882,533,548,773,492,482,608,752,593,617,650,506,588,561,497,627,698,601,657,718,652,751,711,610,534,700,635,749,583,672, +698,754,897,585,547,703,473,574,610,766,590,644,741,610,603,652,624,597,637,642,671,707,625,745,737,581,607,685,730,741,654,670, +575,751,808,490,472,680,495,468,562,651,700,625,677,663,568,547,503,569,575,575,542,647,501,728,656,590,536,676,629,698,575,648, +662,763,664,590,513,643,476,457,452,639,616,548,557,477,511,562,506,532,572,527,648,593,514,676,552,499,392,658,616,741,443,555, +721,837,803,621,577,710,547,501,634,844,592,683,576,537,555,684,602,586,701,658,667,691,607,761,668,585,597,771,623,716,619,709, +652,692,831,503,477,770,400,407,698,752,659,621,574,604,561,613,554,570,686,599,636,679,684,801,749,628,522,755,730,626,561,674, +756,877,768,653,637,725,601,597,644,823,769,555,732,625,645,631,709,729,645,679,665,740,595,728,652,645,575,802,676,855,659,728, +591,730,693,507,594,617,491,434,649,686,622,574,556,495,510,511,502,640,653,571,524,724,555,692,606,543,451,577,510,663,588,662, +627,749,660,541,495,651,442,399,662,695,583,533,512,588,532,539,598,559,592,538,485,554,589,647,607,624,528,691,574,609,532,664, +683,909,809,598,581,661,541,501,678,728,621,660,702,562,606,543,666,567,704,625,603,735,670,734,776,657,553,664,576,775,709,741, }; -#define MATRIX_SIZE 64 +#endif +#define MATRIX_SIZE 32 #endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c index 6ed19c0c..6ee5797b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma/main.c @@ -20,9 +20,9 @@ #define TEST_ADDRESS_MODE_EXTERNAL_DEVICE #define TEST_DATA_SIZE 16 -#define TEST_DATA_LARGE 1024 +#define TEST_DATA_LARGE 256 #define TRANSACTIONS_N 3 // Only possible to perform one transaction at a time, others should be blocked -#define TEST_WINDOW_SIZE_DU 1024 // if put at <=71 the isr is too slow to react to the interrupt +#define TEST_WINDOW_SIZE_DU 256 // if put at <=71 the isr is too slow to react to the interrupt #if TEST_DATA_LARGE < 2 * TEST_DATA_SIZE #errors("TEST_DATA_LARGE must be at least 2*TEST_DATA_SIZE") @@ -112,22 +112,20 @@ dma_data_type_t C_type_2_dma_type(int C_type) } \ if (errors != 0) \ { \ - PRINTF("DMA failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); \ + PRINTF("DMA failure: %d errors out of %d elements checked\n\r", errors, trans.size_d1_du); \ return EXIT_FAILURE; \ } #define INIT_TEST(signed, data_size, dma_src_type, dma_dst_type) \ tgt_src.ptr = (uint8_t *)src; \ - tgt_src.inc_du = 1; \ + tgt_src.inc_d1_du = 1; \ tgt_src.inc_d2_du = 0; \ - tgt_src.size_du = data_size; \ tgt_src.trig = DMA_TRIG_MEMORY; \ tgt_src.type = dma_src_type; \ tgt_src.env = NULL; \ tgt_dst.ptr = (uint8_t *)dst; \ - tgt_dst.inc_du = 1; \ + tgt_dst.inc_d1_du = 1; \ tgt_dst.inc_d2_du = 0; \ - tgt_dst.size_du = data_size; \ tgt_dst.trig = DMA_TRIG_MEMORY; \ tgt_dst.type = dma_dst_type; \ tgt_dst.env = NULL; \ @@ -136,6 +134,7 @@ dma_data_type_t C_type_2_dma_type(int C_type) trans.src_addr = &tgt_addr; \ trans.src_type = dma_src_type; \ trans.dst_type = dma_dst_type; \ + trans.size_d1_du = data_size; \ trans.mode = DMA_TRANS_MODE_SINGLE; \ trans.win_du = 0; \ trans.sign_ext = signed; \ @@ -248,8 +247,7 @@ int main(int argc, char *argv[]) dma_target_t tgt_dst; dma_target_t tgt_addr = { .ptr = (uint8_t *)test_addr_4B_PTR, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, + .inc_d1_du = 1, .trig = DMA_TRIG_MEMORY, }; @@ -265,20 +263,19 @@ int main(int argc, char *argv[]) // Initialize the DMA for the next tests tgt_src.ptr = (uint8_t *)test_data_4B; - tgt_src.inc_du = 1; - tgt_src.size_du = TEST_DATA_SIZE; + tgt_src.inc_d1_du = 1; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE_WORD; tgt_dst.ptr = (uint8_t *)copied_data_4B; - tgt_dst.inc_du = 1; - tgt_dst.size_du = TEST_DATA_LARGE; + tgt_dst.inc_d1_du = 1; tgt_dst.trig = DMA_TRIG_MEMORY; tgt_dst.type = DMA_DATA_TYPE_WORD; trans.src = &tgt_src; trans.dst = &tgt_dst; trans.src_addr = &tgt_addr; + trans.size_d1_du = TEST_DATA_SIZE; trans.src_type = DMA_DATA_TYPE_WORD; trans.dst_type = DMA_DATA_TYPE_WORD; trans.mode = DMA_TRANS_MODE_SINGLE; @@ -306,7 +303,7 @@ int main(int argc, char *argv[]) PRINTF(">> Finished transaction. \n\r"); - for (uint32_t i = 0; i < trans.size_b >> 2; i++) + for (uint32_t i = 0; i < trans.size_d1_du; i++) { if (copied_data_4B[i * 2] != test_data_4B[i]) { @@ -321,11 +318,10 @@ int main(int argc, char *argv[]) } else { - PRINTF("DMA address mode failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); + PRINTF("DMA address mode failure: %d errors out of %d elements checked\n\r", errors, trans.size_d1_du); return EXIT_FAILURE; } - trans.mode = DMA_TRANS_MODE_SINGLE; #endif // TEST_ADDRESS_MODE @@ -362,7 +358,7 @@ int main(int argc, char *argv[]) PRINTF(">> Finished transaction. \n\r"); - for (uint32_t i = 0; i < trans.size_b >> 2; i++) + for (uint32_t i = 0; i < trans.size_d1_du; i++) { if (ext_copied_data_4B[i * 2] != test_data_4B[i]) { @@ -377,7 +373,7 @@ int main(int argc, char *argv[]) } else { - PRINTF("DMA address mode in external memory failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b); + PRINTF("DMA address mode in external memory failure: %d errors out of %d elements checked\n\r", errors, trans.size_d1_du); return EXIT_FAILURE; } @@ -400,12 +396,10 @@ int main(int argc, char *argv[]) } tgt_src.ptr = (uint8_t *)test_data_large; - tgt_src.size_du = TEST_DATA_LARGE; - tgt_dst.size_du = TEST_DATA_LARGE; + trans.size_d1_du = TEST_DATA_LARGE; + trans.mode = DMA_TRANS_MODE_SINGLE; - // trans.end = DMA_TRANS_END_INTR_WAIT; // This option makes no sense, because the launch is blocking the program until the trans finishes. trans.end = DMA_TRANS_END_INTR; - // trans.end = DMA_TRANS_END_POLLING; res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); PRINTF("tran: %u \t%s\n\r", res, res == DMA_CONFIG_OK ? "Ok!" : "Error!"); @@ -477,7 +471,7 @@ int main(int argc, char *argv[]) } tgt_src.ptr = (uint8_t *)test_data_large; - tgt_src.size_du = TEST_DATA_LARGE; + trans.size_d1_du = TEST_DATA_LARGE; tgt_src.type = DMA_DATA_TYPE_WORD; tgt_dst.type = DMA_DATA_TYPE_WORD; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/main.c index 0a5651c1..6805defa 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Author: Tommaso Terzano + * * * Info: Example application of matrix manipulation by exploiting the 2D DMA. * In this code, there are some optional features: @@ -43,8 +44,8 @@ /* Parameters */ /* Size of the extracted matrix (including strides on the input, excluding strides on the outputs) */ -#define SIZE_EXTR_D1 10 -#define SIZE_EXTR_D2 10 +#define SIZE_EXTR_D1 3 +#define SIZE_EXTR_D2 3 /* Set strides of the input ad output matrix */ #define STRIDE_IN_D1 1 @@ -72,6 +73,12 @@ /* Transposition example def */ #define TRANSPOSITION_EN 1 +/* Enables test format */ +#define TEST_EN 0 + +/* Define the input datatype */ +typedef uint32_t dma_input_data_type; + /* Pointer increments computation */ #define SRC_INC_D1 STRIDE_IN_D1 #define DST_INC_D1 STRIDE_OUT_D1 @@ -131,23 +138,19 @@ int main() #if EN_PERF /* Reset the counter to evaluate the performance of the DMA */ - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); + timer_cycles_init(); + #endif tgt_src.ptr = (uint8_t *) test_data; - tgt_src.inc_du = SRC_INC_D1; + tgt_src.inc_d1_du = SRC_INC_D1; tgt_src.inc_d2_du = SRC_INC_D2; - tgt_src.size_du = SIZE_EXTR_D1; - tgt_src.size_d2_du = SIZE_EXTR_D2; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE; tgt_dst.ptr = (uint8_t *) copied_data_2D_DMA; - tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d1_du = DST_INC_D1; tgt_dst.inc_d2_du = DST_INC_D2; - tgt_dst.size_du = OUT_D1_PAD_STRIDE; - tgt_dst.size_d2_du = OUT_D2_PAD_STRIDE; tgt_dst.trig = DMA_TRIG_MEMORY; tgt_dst.type = DMA_DATA_TYPE; @@ -159,11 +162,15 @@ int main() trans.pad_bottom_du = BOTTOM_PAD, trans.pad_left_du = LEFT_PAD, trans.pad_right_du = RIGHT_PAD, + trans.size_d1_du = SIZE_EXTR_D1; + trans.size_d2_du = SIZE_EXTR_D2; trans.win_du = 0, trans.end = DMA_TRANS_END_INTR; - + dma_init(NULL); + timer_start(); + #if EN_PERF res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); @@ -181,7 +188,6 @@ int main() #endif while( ! dma_is_ready(0)) { - #if !EN_PERF /* Disable_interrupts */ /* This does not prevent waking up the core as this is controlled by the MIP register */ @@ -191,18 +197,16 @@ int main() /* From here the core wakes up even if we did not jump to the ISR */ } CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - #endif } #if EN_PERF /* Read the cycles count after the DMA run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + cycles_dma = timer_stop(); /* Reset the performance counter to evaluate the CPU performance */ - CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + timer_cycles_init(); + timer_start(); #endif #if EN_VERIF @@ -266,10 +270,12 @@ int main() #if EN_PERF /* Read the cycles count after the CPU run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); - PRINTF("DMA cycles: %d\n\r", cycles_dma); - PRINTF("CPU cycles: %d \n\r", cycles_cpu); - PRINTF("\n\r"); + cycles_cpu = timer_stop(); + + #if TEST_EN == 0 + PRINTF("Total number of cycles CPU: [%d]\n\r", cycles_cpu); + PRINTF("Total number of cycles DMA: [%d]\n\r", cycles_dma); + #endif #endif @@ -285,11 +291,21 @@ int main() } if (passed) { - PRINTF("Success test 0\n\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 0 PASSED!\n\r\n\r"); + #else + PRINTF("0a:%d:0\n\r", cycles_cpu); + PRINTF("0b:%d:0\n\r", cycles_dma); + #endif } else { - PRINTF("Fail test 0\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 0 FAILED\n\r"); + #else + PRINTF("0a:%d:1\n\r", cycles_cpu); + PRINTF("0b:%d:1\n\r", cycles_dma); + #endif return EXIT_FAILURE; } #endif @@ -317,20 +333,17 @@ int main() #if EN_PERF /* Reset the counter to evaluate the performance of the DMA */ - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); + timer_cycles_init(); #endif tgt_src.ptr = (uint8_t *) test_data; - tgt_src.inc_du = SRC_INC_TRSP_D1; + tgt_src.inc_d1_du = SRC_INC_TRSP_D1; tgt_src.inc_d2_du = SRC_INC_TRSP_D2; - tgt_src.size_du = SIZE_EXTR_D1; - tgt_src.size_d2_du = SIZE_EXTR_D2; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE; tgt_dst.ptr = (uint8_t *) copied_data_2D_DMA; - tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d1_du = DST_INC_D1; tgt_dst.inc_d2_du = DST_INC_D2; tgt_dst.trig = DMA_TRIG_MEMORY; @@ -343,11 +356,15 @@ int main() trans.pad_left_du = LEFT_PAD; trans.pad_right_du = RIGHT_PAD; trans.dim_inv = TRANSPOSITION_EN; + trans.size_d1_du = SIZE_EXTR_D1; + trans.size_d2_du = SIZE_EXTR_D2; trans.win_du = 0, trans.end = DMA_TRANS_END_INTR; dma_init(NULL); + timer_start(); + #if EN_PERF res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); @@ -365,7 +382,6 @@ int main() #endif while( ! dma_is_ready(0)) { - #if !EN_PERF /* Disable_interrupts */ /* This does not prevent waking up the core as this is controlled by the MIP register */ @@ -375,18 +391,16 @@ int main() /* From here the core wakes up even if we did not jump to the ISR */ } CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - #endif } #if EN_PERF /* Read the cycles count after the DMA run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + cycles_dma = timer_stop(); /* Reset the performance counter to evaluate the CPU performance */ - CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + timer_cycles_init(); + timer_start(); #endif #if EN_VERIF @@ -450,10 +464,11 @@ int main() #if EN_PERF /* Read the cycles count after the CPU run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); - PRINTF("DMA cycles: %d\n\r", cycles_dma); - PRINTF("CPU cycles: %d \n\r", cycles_cpu); - PRINTF("\n\r"); + cycles_cpu = timer_stop(); + #if TEST_EN == 0 + PRINTF("Total number of cycles CPU: [%d]\n\r", cycles_cpu); + PRINTF("Total number of cycles DMA: [%d]\n\r", cycles_dma); + #endif #endif @@ -469,11 +484,21 @@ int main() } if (passed) { - PRINTF("Success test 1\n\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 1 PASSED!\n\r\n\r"); + #else + PRINTF("1a:%d:0\n\r", cycles_cpu); + PRINTF("1b:%d:0\n\r", cycles_dma); + #endif } else { - PRINTF("Fail test 1\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 1 FAILED\n\r"); + #else + PRINTF("1a:%d:1\n\r", cycles_cpu); + PRINTF("1b:%d:1\n\r", cycles_dma); + #endif return EXIT_FAILURE; } #endif @@ -496,20 +521,17 @@ int main() #if EN_PERF /* Reset the counter to evaluate the performance of the DMA */ - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); + timer_cycles_init(); #endif tgt_src.ptr = (uint8_t *) test_data; - tgt_src.inc_du = SRC_INC_D1; - tgt_src.size_du = SIZE_EXTR_D1; + tgt_src.inc_d1_du = SRC_INC_D1; tgt_src.inc_d2_du = 0; - tgt_src.size_d2_du = 0; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE; tgt_dst.ptr = (uint8_t *) copied_data_1D_DMA; - tgt_dst.inc_du = DST_INC_D1; + tgt_dst.inc_d1_du = DST_INC_D1; tgt_dst.inc_d2_du = 0; tgt_dst.trig = DMA_TRIG_MEMORY; @@ -523,9 +545,13 @@ int main() trans.pad_right_du = RIGHT_PAD; trans.dim_inv = 0; trans.win_du = 0; + trans.size_d1_du = SIZE_EXTR_D1; + trans.size_d2_du = 0; trans.end = DMA_TRANS_END_INTR; dma_init(NULL); + + timer_start(); #if EN_PERF @@ -544,7 +570,6 @@ int main() #endif while( ! dma_is_ready(0)) { - #if !EN_PERF /* Disable_interrupts */ CSR_CLEAR_BITS(CSR_REG_MSTATUS, 0x8); @@ -552,18 +577,16 @@ int main() wait_for_interrupt(); } CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - #endif } #if EN_PERF /* Read the cycles count after the DMA run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + cycles_dma = timer_stop(); /* Reset the performance counter to evaluate the CPU performance */ - CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + timer_cycles_init(); + timer_start(); #endif #if EN_VERIF @@ -605,11 +628,12 @@ int main() #if EN_PERF /* Read the cycles count after the CPU run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + cycles_cpu = timer_stop(); + #if TEST_EN == 0 + PRINTF("Total number of cycles CPU: [%d]\n\r", cycles_cpu); + PRINTF("Total number of cycles DMA: [%d]\n\r", cycles_dma); + #endif - PRINTF("DMA cycles: %d\n\r", cycles_dma); - PRINTF("CPU cycles: %d \n\r", cycles_cpu); - PRINTF("\n\r"); #endif #if EN_VERIF @@ -622,11 +646,21 @@ int main() } if (passed) { - PRINTF("Success test 2\n\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 2 PASSED!\n\r\n\r"); + #else + PRINTF("2a:%d:0\n\r", cycles_cpu); + PRINTF("2b:%d:0\n\r", cycles_dma); + #endif } else { - PRINTF("Fail test 2\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 2 FAILED\n\r"); + #else + PRINTF("2a:%d:1\n\r", cycles_cpu); + PRINTF("2b:%d:1\n\r", cycles_dma); + #endif return EXIT_FAILURE; } #endif @@ -655,13 +689,14 @@ int main() #if EN_PERF /* Reset the counter to evaluate the performance of the DMA */ - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); + timer_cycles_init(); #endif /* The DMA is initialized (i.e. Any current transaction is cleaned.) */ dma_init(NULL); + timer_start(); + /* Enable the DMA interrupt logic */ write_register( 0x1, DMA_INTERRUPT_EN_REG_OFFSET, @@ -731,25 +766,25 @@ int main() peri ); /* Padding configuration */ - write_register( TOP_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( TOP_PAD, DMA_PAD_TOP_REG_OFFSET, DMA_PAD_TOP_PAD_MASK, DMA_PAD_TOP_PAD_OFFSET, peri ); - write_register( RIGHT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( RIGHT_PAD, DMA_PAD_RIGHT_REG_OFFSET, DMA_PAD_RIGHT_PAD_MASK, DMA_PAD_RIGHT_PAD_OFFSET, peri ); - write_register( LEFT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( LEFT_PAD, DMA_PAD_LEFT_REG_OFFSET, DMA_PAD_LEFT_PAD_MASK, DMA_PAD_LEFT_PAD_OFFSET, peri ); - write_register( BOTTOM_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( BOTTOM_PAD, DMA_PAD_BOTTOM_REG_OFFSET, DMA_PAD_BOTTOM_PAD_MASK, DMA_PAD_BOTTOM_PAD_OFFSET, @@ -757,20 +792,19 @@ int main() /* Set the sizes */ - write_register( SIZE_EXTR_D2 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( SIZE_EXTR_D2, DMA_SIZE_D2_REG_OFFSET, DMA_SIZE_D2_SIZE_MASK, DMA_SIZE_D2_SIZE_OFFSET, peri ); - write_register( SIZE_EXTR_D1 * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( SIZE_EXTR_D1, DMA_SIZE_D1_REG_OFFSET, DMA_SIZE_D1_SIZE_MASK, DMA_SIZE_D1_SIZE_OFFSET, peri ); while( ! dma_is_ready(0)) { - #if !EN_PERF /* Disable_interrupts */ /* This does not prevent waking up the core as this is controlled by the MIP register */ @@ -780,18 +814,16 @@ int main() /* From here the core wakes up even if we did not jump to the ISR */ } CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); - #endif } #if EN_PERF /* Read the cycles count after the DMA run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + cycles_dma = timer_stop(); /* Reset the performance counter to evaluate the CPU performance */ - CSR_SET_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + timer_cycles_init(); + timer_start(); #endif #if EN_VERIF @@ -856,35 +888,42 @@ int main() #if EN_PERF /* Read the cycles count after the CPU run */ - CSR_READ(CSR_REG_MCYCLE, &cycles_cpu); + cycles_cpu = timer_stop(); + #if TEST_EN == 0 + PRINTF("Total number of cycles CPU: [%d]\n\r", cycles_cpu); + PRINTF("Total number of cycles DMA: [%d]\n\r", cycles_dma); + #endif - PRINTF("DMA cycles: %d\n\r", cycles_dma); - PRINTF("CPU cycles: %d \n\r", cycles_cpu); - PRINTF("\n\r"); #endif #if EN_VERIF /* Verify that the DMA and the CPU outputs are the same */ - for (int i = 0; i < OUT_D2_PAD_STRIDE; i++) { - for (int j = 0; j < OUT_D1_PAD_STRIDE; j++) { - if (copied_data_2D_DMA[i * OUT_D1_PAD_STRIDE + j] != copied_data_2D_CPU[i * OUT_D1_PAD_STRIDE + j]) { - passed = 0; - } - } - } - if (passed) { - PRINTF("Success test 3\n\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 3 PASSED!\n\r\n\r"); + #else + PRINTF("3a:%d:0\n\r", cycles_cpu); + PRINTF("3b:%d:0\n\r", cycles_dma); + #endif } else { - PRINTF("Fail test 3\n\r"); + #if TEST_EN == 0 + PRINTF("TEST 3 FAILED\n\r"); + #else + PRINTF("3a:%d:1\n\r", cycles_cpu); + PRINTF("3b:%d:1\n\r", cycles_dma); + #endif return EXIT_FAILURE; } #endif #endif + #if TEST_EN + PRINTF("&\n\r"); + #endif + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h index d1232223..66dcc52a 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_2d/test_data.h @@ -5,12 +5,7 @@ #define SIZE_IN_D2 25 #define DMA_DATA_TYPE DMA_DATA_TYPE_WORD -/* Change the input datatype depending on the DMA_DATA_TYPE - * The test data has been generated using byte as datatype, so it's possible to use both uint8_t, uint16_t and uint32_t - */ -typedef uint32_t dma_input_data_type; - -dma_input_data_type test_data[SIZE_IN_D1 * SIZE_IN_D2] = { +uint32_t test_data[SIZE_IN_D1 * SIZE_IN_D2] = { 93 ,178 ,28 ,23 ,5 ,231 ,211 ,236 ,45 ,196 ,55 ,124 ,113 ,188 ,36 ,43 ,147 ,111 ,254 ,126 ,145 ,83 ,77 ,7 ,126, 92 ,179 ,157 ,41 ,64 ,7 ,105 ,93 ,176 ,196 ,171 ,42 ,251 ,175 ,120 ,63 ,134 ,56 ,233 ,0 ,189 ,133 ,71 ,226 ,9, 252 ,214 ,243 ,177 ,205 ,75 ,100 ,165 ,160 ,42 ,112 ,71 ,238 ,208 ,62 ,1 ,113 ,87 ,116 ,212 ,107 ,165 ,214 ,239 ,151, diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c index e73f84af..24d8429c 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_external/main.c @@ -51,20 +51,19 @@ int main(int argc, char *argv[]) static dma_target_t tgt_src = { .ptr = test_data, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, + .inc_d1_du = 1, .trig = DMA_TRIG_MEMORY, .type = DMA_DATA_TYPE_WORD, }; static dma_target_t tgt_dst = { .ptr = copied_data, - .inc_du = 1, - .size_du = TEST_DATA_SIZE, + .inc_d1_du = 1, .trig = DMA_TRIG_MEMORY, }; static dma_trans_t trans = { .src = &tgt_src, .dst = &tgt_dst, + .size_d1_du = TEST_DATA_SIZE, .mode = DMA_TRANS_MODE_SINGLE, .win_du = 0, .end = DMA_TRANS_END_INTR, @@ -94,7 +93,7 @@ int main(int argc, char *argv[]) } PRINTF(">> Finished transaction. \n\r"); - for(uint32_t i = 0; i < trans.size_b; i++ ) { + for(uint32_t i = 0; i < trans.size_d1_du; i++ ) { if ( ((uint8_t*)copied_data)[i] != ((uint8_t*)test_data)[i] ) { PRINTF("ERROR [%d]: %04x != %04x\n\r", i, ((uint8_t*)copied_data)[i], ((uint8_t*)test_data)[i]); errors++; @@ -105,7 +104,7 @@ int main(int argc, char *argv[]) PRINTF("External DMA success\n\r"); return EXIT_SUCCESS; } else { - PRINTF("External DMA failure: %d errors out of %d bytes checked\n\r", errors, trans.size_b ); + PRINTF("External DMA failure: %d errors out of %d elements checked\n\r", errors, trans.size_d1_du ); return EXIT_FAILURE; } diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c index 2e7f2bc8..8bff88ba 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_dma_multichannel/main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Author: Tommaso Terzano + * * * Info: Example application of matrix manipulation by exploiting the multichannel feature of the DMA subsystem. * This code is capable of testing the following features: @@ -32,7 +33,7 @@ * * DISCLAIMER: * When using the default memory configuration (64kB), pay attention to the dimensions of the output matrices. - * When executing TEST_ID_4 on QuestaSim, make sure to enable the SPI FLASH. + * When executing TEST_ID_3 on QuestaSim, make sure to enable the SPI FLASH. * * Enable one or more of the following tests by defining the correct TEST_ID_* macro: * @@ -136,7 +137,7 @@ #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) -#elif TARGET_IS_FPGA && PRINTF_IN_FPGA +#elif TARGET_PYNQ_Z2 && PRINTF_IN_FPGA #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #else #define PRINTF(...) @@ -333,25 +334,25 @@ int main() dma_peri(i) ); /* Padding configuration */ - write_register( TOP_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( TOP_PAD, DMA_PAD_TOP_REG_OFFSET, DMA_PAD_TOP_PAD_MASK, DMA_PAD_TOP_PAD_OFFSET, dma_peri(i) ); - write_register( RIGHT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( RIGHT_PAD, DMA_PAD_RIGHT_REG_OFFSET, DMA_PAD_RIGHT_PAD_MASK, DMA_PAD_RIGHT_PAD_OFFSET, dma_peri(i) ); - write_register( LEFT_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( LEFT_PAD, DMA_PAD_LEFT_REG_OFFSET, DMA_PAD_LEFT_PAD_MASK, DMA_PAD_LEFT_PAD_OFFSET, dma_peri(i) ); - write_register( BOTTOM_PAD * DMA_DATA_TYPE_2_SIZE( DMA_DATA_TYPE), + write_register( BOTTOM_PAD, DMA_PAD_BOTTOM_REG_OFFSET, DMA_PAD_BOTTOM_PAD_MASK, DMA_PAD_BOTTOM_PAD_OFFSET, @@ -368,13 +369,13 @@ int main() for (int i=0; i str: + # Ensure the matrix is int16 (signed 16-bit integer) + if matrix.dtype != np.int16: + raise ValueError("Input matrix must be of dtype int16") + + num_bits = matrix.dtype.itemsize * 8 + array_ctype = "int16_t" + + # Convert each element to its 2's complement hexadecimal representation + rows = [] + for row in matrix: + row = np.atleast_1d(row) # Ensure row is array-like for iteration + # Format each element as a 16-bit signed integer in hex format + hex_values = [f"{element if element >= 0 else (1 << num_bits) + element:#06x}" for element in row] + rows.append(hex_values) + + # Format the matrix into a C-style array + matrix_contents = f"{array_ctype} {name}[{matrix.size}] = {{\n" + if len(rows) > 1: + matrix_contents += ',\n'.join([f" {', '.join(row)}" for row in rows]) + else: + matrix_contents += f" {', '.join(rows[0])}" + matrix_contents += '\n};\n\n' + + return matrix_contents + + +def generate_fft_twiddle_factors_radix2(N): + # Number of twiddle factors is N + num_twiddle_factors = N + + # Generate the angles for the twiddle factors + angles = np.linspace(0, -2 * np.pi, num_twiddle_factors, endpoint=False) + + # Compute the real and imaginary parts + real_parts = np.cos(angles) + imaginary_parts = np.sin(angles) + + # Concatenate real and imaginary parts + twiddle_factors = np.empty(2 * num_twiddle_factors) + twiddle_factors[0::2] = real_parts + twiddle_factors[1::2] = imaginary_parts + + return twiddle_factors + +import numpy as np + +def generate_fft_twiddle_factors_radix4(N): + # Ensure N is divisible by 4 for Radix-4 FFT + if N % 4 != 0: + raise ValueError("N must be a multiple of 4 for Radix-4 FFT") + + num_twiddle_groups = N // 4 + angles_k1 = np.linspace(0, -2 * np.pi / N, num_twiddle_groups, endpoint=False) + angles_k2 = 2 * angles_k1 # Corresponds to W_N^{2k} + angles_k3 = 3 * angles_k1 # Corresponds to W_N^{3k} + real_parts_k1 = np.cos(angles_k1) + imag_parts_k1 = np.sin(angles_k1) + real_parts_k2 = np.cos(angles_k2) + imag_parts_k2 = np.sin(angles_k2) + real_parts_k3 = np.cos(angles_k3) + imag_parts_k3 = np.sin(angles_k3) + twiddle_factors = np.empty(6 * num_twiddle_groups) + twiddle_factors[0::6] = real_parts_k1 + twiddle_factors[1::6] = imag_parts_k1 + twiddle_factors[2::6] = real_parts_k2 + twiddle_factors[3::6] = imag_parts_k2 + twiddle_factors[4::6] = real_parts_k3 + twiddle_factors[5::6] = imag_parts_k3 + + return twiddle_factors + + +def write_arr(f, name, arr, ctype, size): + f.write("const " + ctype + " " + name + "[2*FFT_LEN] = {\n") + + for row in arr: + for elem in row[:-1]: + f.write('%d,' % (elem)) + f.write('%d,\n' % (row[-1])) + + f.write('};\n\n') + return + +def generate_random_matrix(num_channels, length, decimal_bits): + """ + Generate a random matrix with num_channels rows and length columns. + """ + + real_part = np.random.uniform(-0.01, 0.01, (num_channels, length)) #* (2**(-decimal_bits)) + imag_part = np.random.uniform(-0.01, 0.01, (num_channels, length)) #* (2**(-decimal_bits)) + + matrix = real_part + 1j * imag_part + + return matrix + +def perform_fft(matrix): + """ + Perform FFT on each row of the matrix and return the result matrix. + """ + return np.fft.fft(matrix, axis=1) + +def convert_to_fixed_point(matrix, decimal_places=8): + """ + Convert the matrix to fixed-point format with a specified number of decimal bits. + Each element in the output matrix is of type 'int16'. + """ + # Scaling factor for conversion + scaling_factor = 1 << decimal_places # 2^decimal_bits (256 for Q1.8 format) + + # Convert to fixed-point representation + real_part = np.real(matrix) * scaling_factor + imag_part = np.imag(matrix) * scaling_factor + + # Clip values to ensure they fit within the range of int16 + real_part = np.clip(real_part, -32768, 32767) + imag_part = np.clip(imag_part, -32768, 32767) + + # Convert to int16 + real_part = real_part.astype(np.int16) + imag_part = imag_part.astype(np.int16) + + # Combine real and imaginary parts into a single matrix + fixed_point_matrix = np.empty((matrix.shape[0], matrix.shape[1] * 2), dtype=np.int16) + fixed_point_matrix[:, 0::2] = real_part + fixed_point_matrix[:, 1::2] = imag_part + + return fixed_point_matrix + +def convert_to_fixed_point_twiddles(array, decimal_bits=8): + # The input 'array' is a 1D array with interleaved real and imaginary parts + fixed_point_array = np.empty_like(array, dtype=np.int16) + + # Scale and convert to fixed-point for real and imaginary parts + scale_factor = 1 << decimal_bits + fixed_point_array = np.round(array * scale_factor).astype(np.int16) + + return fixed_point_array + +################################################################################ +f = open('data.h', 'w') +f.write('// This file is automatically generated\n// Type " python datagen.py " in the terminal to generate the data.h file. Configuration parameters can be changed in the datagen.py file.\n') +f.write('\n#ifndef DATA_H_\n') +f.write('#define DATA_H_\n\n') + +np.random.seed(seed) + +# Generate random input +input = generate_random_matrix(1, SIZE, decimal_bits) + +# Perform FFT +fft_output = perform_fft(input) + +# Comput twiddles +twiddles_radix2 = generate_fft_twiddle_factors_radix2(SIZE) +twiddles_radix4 = generate_fft_twiddle_factors_radix4(SIZE) + +# Convert FFT result to fixed-point format +R = convert_to_fixed_point(fft_output, decimal_bits) +A = convert_to_fixed_point(input, decimal_bits) +W_radix2 = convert_to_fixed_point_twiddles(twiddles_radix2, decimal_bits) +W_radix4 = convert_to_fixed_point_twiddles(twiddles_radix4, decimal_bits) + +print("Input:") +print(input) +print("A (fixed point) :") +print(A*2**-decimal_bits) +print("FFT output:") +print(fft_output) +print("R (fixed point):") +print(R*2**-decimal_bits) +print("Twiddles Radix-2 (fixed point):") +print([hex(x) for x in W_radix2.flatten()]) # Print in hexadecimal format +print("Twiddles Radix-4 (fixed point):") +print([hex(x) for x in W_radix4.flatten()]) # Print in hexadecimal format + +f.write('#define FFT_LEN %d\n' % SIZE) +f.write('#define DECIMAL_BITS %d\n\n' % decimal_bits) + +f.write(format_matrix( A, 'A')) +f.write(format_matrix( R, 'R')) +f.write(format_matrix( W_radix2, 'W_radix2')) +f.write(format_matrix( W_radix4, 'W_radix4')) + +f.write('#endif') \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/fft.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/fft.h new file mode 100644 index 00000000..6d079bda --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/fft.h @@ -0,0 +1,331 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: fft.h +// Author: Francesco Poluzzi +// Date: 04/09/2024 +// Description: FFT-related functions for X-Heep + +#ifndef FFT_H +#define FFT_H + +#include +#include +#include +#include "data.h" + +#define PI 3.14159265358979323846 + +uint8_t log_floor(uint16_t N, uint8_t base) { + if (N == 0) { + return 0; // Log of 0 is undefined, return 0 for safety + } + uint8_t log_val = 0; + + if (base == 2) { + while (N >>= 1) { // Right shift by 1 bit (equivalent to dividing by 2) + log_val++; + } + } else if (base == 4) { + while (N >= 4) { // Right shift by 2 bits (equivalent to dividing by 4) + N >>= 2; + log_val++; + } + } + return log_val; +} + +bool is_power_of(uint16_t N, uint8_t base) { + if (N == 0) { + return false; + } + if (base == 2) { + return (N & (N - 1)) == 0; + } else if (base == 4) { + return (N & (N - 1)) == 0 && (N & 0x5555) != 0; + } + return false; +} + +// Function to perform bit reversal based on radix (base) +uint16_t bit_reversal(uint16_t n, uint8_t num_bits, uint8_t base) { + uint16_t result = 0; + + // Calculate the number of bits to shift based on the base + uint8_t shiftamt = (base == 2) ? 1 : 2; // Shift by 1 for Radix-2, by 2 for Radix-4 + uint16_t mask = base - 1; // Mask is 1 for Radix-2, 3 for Radix-4 + + // Perform the bit reversal by repeatedly shifting and applying the mask + for (uint8_t i = 0; i < num_bits; i++) { + result <<= shiftamt; // Shift result to the left by `shiftamt` bits + result |= n & mask; // Add the masked bits from `n` to `result` + n >>= shiftamt; // Shift `n` to the right by `shiftamt` bits + } + + return result; +} + +// Function to generate bit-reversed sequence +void get_bit_reversed_seq(uint16_t *seq, uint16_t N, uint8_t num_bits, uint8_t base) { + for (uint16_t i = 0; i < N; i++) { + seq[i] = bit_reversal(i, num_bits, base); + } +} + +void compute_twiddle_factors_radix2(int16_t* twiddle_factors, uint32_t N, uint8_t decimal_bits) { + for (uint16_t j = 0; j < N / 2; j++) { + float angle = -2.0 * PI * j / N; + twiddle_factors[2 * j] = (int16_t)(cos(angle) * (1 << decimal_bits)); // Real part in Q1.8 format + twiddle_factors[2 * j + 1] = (int16_t)(sin(angle) * (1 << decimal_bits)); // Imaginary part in Q1.8 format + } +} + +void compute_twiddle_factors_radix4(int16_t *twiddle_factors, uint16_t N, int16_t decimal_bits) { + // Twiddle factor for radix-4 FFT + // N is the FFT size, which must be a power of 4 + // twiddle_factors is the output array where real and imaginary parts are interleaved + uint16_t twiddle_count = N / 4; // Radix-4 FFT needs twiddles for N/4 size + + for (uint16_t k = 0; k < twiddle_count; k++) { + // Compute the real and imaginary parts of W_N^k = e^(-2*pi*i*k/N) + double angle = -2.0 * PI * k / N; + double real_part = cos(angle); + double imag_part = sin(angle); + + // Convert to fixed-point with the specified number of decimal bits + int16_t real_fixed = (int16_t)(real_part * (1 << decimal_bits)); + int16_t imag_fixed = (int16_t)(imag_part * (1 << decimal_bits)); + + // Store the values in the interleaved array + twiddle_factors[2 * k] = real_fixed; // Real part + twiddle_factors[2 * k + 1] = imag_fixed; // Imaginary part + } +} + +void __attribute__((noinline, aligned(4))) iterative_FFT_radix2(int16_t *x, int16_t *X, uint16_t N, int16_t *twiddle_factors, int16_t decimal_bits, + int16_t *w_real_fixed, int16_t *w_imag_fixed, int16_t *xrev, int16_t *bit_reversed_seq) { + + // Perform bit reversal on the input array + uint8_t num_bits = log_floor(N, 2); + + for (uint16_t i = 0; i < N; i++) { + // Access real and imaginary parts independently + xrev[2 * i] = x[2 * bit_reversed_seq[i]]; // Real part + xrev[2 * i + 1] = x[2 * bit_reversed_seq[i] + 1]; // Imaginary part + } + + // Stage 0 unrolled: simple additions and subtractions + for (uint16_t i = 0; i < N; i += 2) { + // Access real and imaginary parts for two points independently + int16_t a_real = xrev[2 * i]; + int16_t a_imag = xrev[2 * i + 1]; + int16_t b_real = xrev[2 * (i + 1)]; + int16_t b_imag = xrev[2 * (i + 1) + 1]; + + // No twiddle factor for the first stage (equivalent to multiplying by 1 + 0j) + xrev[2 * i] = a_real + b_real; + xrev[2 * i + 1] = a_imag + b_imag; + xrev[2 * (i + 1)] = a_real - b_real; + xrev[2 * (i + 1) + 1] = a_imag - b_imag; + } + + // FFT processing for remaining stages + uint16_t stage_count = num_bits; + uint16_t twiddle_step = N/2; + + for (uint16_t stage = 1, step = 4; stage < stage_count; stage++, step *= 2) { + uint16_t halfstep = step / 2; + twiddle_step /= 2; + + for (uint16_t j = 0; j < halfstep; j++) { + // Access precomputed twiddle factors from the interleaved array + w_real_fixed[j] = twiddle_factors[2 * (j * twiddle_step)]; + w_imag_fixed[j] = twiddle_factors[2 * (j * twiddle_step) + 1]; + } + + // Modify the outer loop to increment from 0 to N, increasing by step + for (uint16_t i = 0; i < N; i += step) { + // Calculate the starting index for this iteration + uint16_t idx = i; + for (uint16_t j = 0; j < halfstep; j++) { + // Butterfly operations - Access real and imag parts independently + int16_t a_real = xrev[2 * (idx + j)]; + int16_t a_imag = xrev[2 * (idx + j) + 1]; + int16_t b_real = xrev[2 * (idx + j + halfstep)]; + int16_t b_imag = xrev[2 * (idx + j + halfstep) + 1]; + + // Complex multiplication (b * w) using 32-bit intermediate values + int32_t temp_real = ((int32_t)b_real * w_real_fixed[j] - (int32_t)b_imag * w_imag_fixed[j]) >> decimal_bits; + int32_t temp_imag = ((int32_t)b_real * w_imag_fixed[j] + (int32_t)b_imag * w_real_fixed[j]) >> decimal_bits; + + // Store the results directly in the array, independently for real and imag parts + xrev[2 * (idx + j)] = a_real + temp_real; + xrev[2 * (idx + j) + 1] = a_imag + temp_imag; + xrev[2 * (idx + j + halfstep)] = a_real - temp_real; + xrev[2 * (idx + j + halfstep) + 1] = a_imag - temp_imag; + } + } + } + + // Copy the result to output array X + for (uint16_t i = 0; i < 2 * N; i++) { + X[i] = xrev[i]; + } +} + +// Radix-4 FFT +void __attribute__((noinline, aligned(4))) iterative_FFT_radix4(int16_t *x, int16_t *X, uint16_t N, int16_t *twiddle_factors, int16_t *w_real_fixed, int16_t * w_imag_fixed, int16_t *xrev, int8_t decimal_bits, int16_t * bit_reversed_seq) { + + uint16_t stage_count = log_floor(N, 4); // Radix-4 halves the number of stages + uint16_t twiddle_step = N; + + for (uint16_t i = 0; i < N; i++) { + xrev[2 * i] = x[2 * bit_reversed_seq[i]]; // Real part + xrev[2 * i + 1] = x[2 * bit_reversed_seq[i] + 1]; // Imaginary part + } + + // Unroll the first stage: radix-4 butterfly (4 points per butterfly) + uint16_t quarterstep = 1; + for (uint16_t i = 0; i < N; i += 4) { + uint16_t idx = i; + // Load the real and imaginary parts for the 4 input points + int16_t a_real = xrev[2 * idx]; + int16_t a_imag = xrev[2 * idx + 1]; + int16_t b_real = xrev[2 * (idx + quarterstep)]; + int16_t b_imag = xrev[2 * (idx + quarterstep) + 1]; + int16_t c_real = xrev[2 * (idx + 2 * quarterstep)]; + int16_t c_imag = xrev[2 * (idx + 2 * quarterstep) + 1]; + int16_t d_real = xrev[2 * (idx + 3 * quarterstep)]; + int16_t d_imag = xrev[2 * (idx + 3 * quarterstep) + 1]; + + // Radix-4 butterfly calculations (without twiddle factors) + int16_t t0_real = a_real + c_real; + int16_t t0_imag = a_imag + c_imag; + int16_t t1_real = b_real + d_real; + int16_t t1_imag = b_imag + d_imag; + + int16_t t2_real = a_real - c_real; + int16_t t2_imag = a_imag - c_imag; + int16_t t3_real = b_real - d_real; + int16_t t3_imag = b_imag - d_imag; + + // Output without twiddle factors + xrev[2 * idx] = t0_real + t1_real; // Result 1 real part + xrev[2 * idx + 1] = t0_imag + t1_imag; // Result 1 imag part + + xrev[2 * (idx + quarterstep)] = t2_real - t3_imag; // Result 2 real part + xrev[2 * (idx + quarterstep) + 1] = t2_imag + t3_real; // Result 2 imag part + + xrev[2 * (idx + 2 * quarterstep)] = t0_real - t1_real; // Result 3 real part + xrev[2 * (idx + 2 * quarterstep) + 1] = t0_imag - t1_imag; // Result 3 imag part + + xrev[2 * (idx + 3 * quarterstep)] = t2_real + t3_imag; // Result 4 real part + xrev[2 * (idx + 3 * quarterstep) + 1] = t2_imag - t3_real; // Result 4 imag part + } + + // Perform the remaining stages + for (uint16_t stage = 1, step = 16; stage < stage_count; stage++, step *= 4) { + uint16_t quarterstep = step / 4; + twiddle_step /= 4; + + // Precompute the twiddle factors for this stage + for (uint16_t j = 0; j < quarterstep; j++) { + w_real_fixed[j] = twiddle_factors[2 * (j * twiddle_step)]; + w_imag_fixed[j] = twiddle_factors[2 * (j * twiddle_step) + 1]; + } + + // Loop over groups of 4 points per butterfly + for (uint16_t i = 0; i < N; i += step) { + uint16_t idx = i; + + // Perform load, butterfly, and store operations in a single loop + for (uint16_t j = 0; j < quarterstep; j++) { + // Load the data for the 4 points + int16_t a_real = xrev[2 * (idx + j)]; + int16_t a_imag = xrev[2 * (idx + j) + 1]; + int16_t b_real = xrev[2 * (idx + j + quarterstep)]; + int16_t b_imag = xrev[2 * (idx + j + quarterstep) + 1]; + int16_t c_real = xrev[2 * (idx + j + 2 * quarterstep)]; + int16_t c_imag = xrev[2 * (idx + j + 2 * quarterstep) + 1]; + int16_t d_real = xrev[2 * (idx + j + 3 * quarterstep)]; + int16_t d_imag = xrev[2 * (idx + j + 3 * quarterstep) + 1]; + + // Apply twiddle factors to b + int16_t tw_b_real = ((int32_t)b_real * w_real_fixed[j] - (int32_t)b_imag * w_imag_fixed[j]) >> decimal_bits; + int16_t tw_b_imag = ((int32_t)b_real * w_imag_fixed[j] + (int32_t)b_imag * w_real_fixed[j]) >> decimal_bits; + + int16_t res1_real = a_real + tw_b_real; // a + Tw(b) + int16_t res1_imag = a_imag + tw_b_imag; + + int16_t res2_real = a_real - tw_b_real; // a - Tw(b) + int16_t res2_imag = a_imag - tw_b_imag; + + // Apply twiddle factors to c + int16_t tw_c_real = ((int32_t)c_real * w_real_fixed[2 * j] - (int32_t)c_imag * w_imag_fixed[2 * j]) >> decimal_bits; + int16_t tw_c_imag = ((int32_t)c_real * w_imag_fixed[2 * j] + (int32_t)c_imag * w_real_fixed[2 * j]) >> decimal_bits; + + int16_t res3_real = a_real + tw_c_real; // a + Tw(c) + int16_t res3_imag = a_imag + tw_c_imag; + + int16_t res4_real = a_real - tw_c_real; // a - Tw(c) + int16_t res4_imag = a_imag - tw_c_imag; + + // Apply twiddle factors to d + int16_t tw_d_real = ((int32_t)d_real * w_real_fixed[3 * j] - (int32_t)d_imag * w_imag_fixed[3 * j]) >> decimal_bits; + int16_t tw_d_imag = ((int32_t)d_real * w_imag_fixed[3 * j] + (int32_t)d_imag * w_real_fixed[3 * j]) >> decimal_bits; + + // Store the results + xrev[2 * (idx + j)] = res1_real; + xrev[2 * (idx + j) + 1] = res1_imag; + xrev[2 * (idx + j + quarterstep)] = res2_real; + xrev[2 * (idx + j + quarterstep) + 1] = res2_imag; + xrev[2 * (idx + j + 2 * quarterstep)] = res3_real; + xrev[2 * (idx + j + 2 * quarterstep) + 1] = res3_imag; + xrev[2 * (idx + j + 3 * quarterstep)] = res4_real; + xrev[2 * (idx + j + 3 * quarterstep) + 1] = res4_imag; + } + } + } + + // Copy the result to output array X + for (uint16_t i = 0; i < 2 * N; i++) { + X[i] = xrev[i]; + } +} + +#define FIXED_POINT_SCALE (1 << DECIMAL_BITS) + +// Helper function to print the FFT result +void print_complex_array(int16_t *array, uint16_t N) { + for (uint16_t i = 0; i < N; i++) { + // Convert fixed-point to decimal by dividing by FIXED_POINT_SCALE + int16_t real_part = array[2 * i]; + int16_t imag_part = array[2 * i + 1]; + + // Calculate integer and fractional parts + int16_t real_int = real_part / FIXED_POINT_SCALE; + int16_t imag_int = imag_part / FIXED_POINT_SCALE; + + // Fractional part needs to be scaled and displayed with leading zeros if necessary + int16_t real_frac = (real_part % FIXED_POINT_SCALE) * 1000 / FIXED_POINT_SCALE; + int16_t imag_frac = (imag_part % FIXED_POINT_SCALE) * 1000 / FIXED_POINT_SCALE; + + // Adjust the fractional part for negative values, and ensure fractional part is positive + if (real_part < 0 && real_frac > 0) { + real_frac = 1000 - real_frac; + } + if (imag_part < 0 && imag_frac > 0) { + imag_frac = 1000 - imag_frac; + } + + // Print the complex number in the correct format + // Use separate handling for real and imaginary signs + printf("X[%d] = %c%d.%03d %c %d.%03dj\n", + i, + (real_part < 0) ? '-' : '+', abs(real_int), abs(real_frac), // Real part + (imag_part < 0) ? '-' : '+', abs(imag_int), abs(imag_frac)); // Imaginary part + } +} + +#endif // FFT_ITERATIVE_RADIX_2_H \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/main.c new file mode 100644 index 00000000..2f5ebb2a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_fft/main.c @@ -0,0 +1,112 @@ +// Copyright 2024 EPFL +// Solderpad Hardware License, Version 2.1, see LICENSE.md for details. +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// File: main.c +// Author: Francesco Poluzzi +// Date: 04/09/2024 +// Description: FFT example for X-Heep +// Functions for the FFT computation are in fft.h +// Parameters as FFT_LEN and DECIMAL_BITS can be changed in data.h. To also automate the input and +// golden model generation with different parameters, the script datagen.py can be used. + +#include +#include +#include + +#include "data.h" +#include "x-heep.h" +#include "timer_sdk.h" +#include "fft.h" + +/* By default, PRINTs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 1 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +// Tolerance for the comparison of the results in fixed point (needs to be adjusted based on the number of decimal bits). +// The error is due to shifts and roundings in the fixed-point computation. +#define TOLERANCE 0x000000f + +int16_t __attribute__((aligned(4))) R_radix_2[2 * FFT_LEN] ; +int16_t __attribute__((aligned(4))) R_radix_4[2 * FFT_LEN] ; +int16_t __attribute__((aligned(4))) twiddle_factors_radix2[FFT_LEN]; +int16_t __attribute__((aligned(4))) twiddle_factors_radix4[FFT_LEN]; +int16_t __attribute__((aligned(4))) w_real_fixed[FFT_LEN / 2]; +int16_t __attribute__((aligned(4))) w_imag_fixed[FFT_LEN / 2]; +int32_t __attribute__((aligned(4))) xrev_32[ FFT_LEN]; +int16_t __attribute__((aligned(4))) xrev[2* FFT_LEN]; +int16_t __attribute__((aligned(4))) bit_reversed_seq_radix2[FFT_LEN]; +int16_t __attribute__((aligned(4))) bit_reversed_seq_radix4[FFT_LEN]; + +int main(void) +{ + uint32_t radix2_cycles, radix4_cycles; + + if(!is_power_of(FFT_LEN, 2)){ + PRINTF("FFT_LEN must be a power of 2, FFT radix 2 cannot be performed.\n"); + return EXIT_FAILURE; + } + + PRINTF("Starting radix 2 FFT\n"); + + // precompute twiddle factors for radix-2 FFT + compute_twiddle_factors_radix2(twiddle_factors_radix2, FFT_LEN, DECIMAL_BITS); + + // precompute bit reversed sequence + get_bit_reversed_seq(bit_reversed_seq_radix2, FFT_LEN, log_floor(FFT_LEN, 2), 2); + + timer_cycles_init(); + timer_start(); + + iterative_FFT_radix2(A, R_radix_2, FFT_LEN, twiddle_factors_radix2, DECIMAL_BITS, w_real_fixed, w_imag_fixed, xrev, bit_reversed_seq_radix2); + + radix2_cycles = timer_stop(); + + for(int i = 0; i < 2 * FFT_LEN; i++){ + if(abs(R_radix_2[i] - R[i] > TOLERANCE)){ + PRINTF("Error: R_gold[%d] = %x, R_radix_2[%d] = %x\n", i, R[i], i, R_radix_2[i]); + return 1; + } + } + + PRINTF("Radix-2 FFT took %d cycles\n", radix2_cycles); + + if(!is_power_of(FFT_LEN, 4)){ + PRINTF("FFT_LEN must be a power of 4, FFT radix 4 cannot be performed.\n"); + return EXIT_FAILURE; + } + + PRINTF("Starting radix 4 FFT\n"); + + // precompute twiddle factors for radix-4 FFT + compute_twiddle_factors_radix4(twiddle_factors_radix4, FFT_LEN, DECIMAL_BITS); + + // precompute bit reversed sequence + get_bit_reversed_seq(bit_reversed_seq_radix4, FFT_LEN, log_floor(FFT_LEN, 4), 4); + + timer_cycles_init(); + timer_start(); + + iterative_FFT_radix4(A, R_radix_4, FFT_LEN, twiddle_factors_radix4, w_real_fixed, w_imag_fixed, xrev, DECIMAL_BITS, bit_reversed_seq_radix4); + + radix4_cycles = timer_stop(); + + for(int i = 0; i < 2 * FFT_LEN; i++){ + if(abs(R_radix_2[i] - R[i] > TOLERANCE)){ + PRINTF("Error: R_gold[%d] = %x, R_radix_4[%d] = %x\n", i, R[i], i, R_radix_4[i]); + return 1; + } + } + + PRINTF("Radix-4 FFT took %d cycles\n", radix4_cycles); + + return EXIT_SUCCESS; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c index 2c7d9a16..cef21ff5 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_i2s/main.c @@ -128,18 +128,18 @@ void setup() // -- DMA CONFIGURATION -- tgt_src.ptr = I2S_RX_DATA_ADDRESS; - tgt_src.inc_du = 0; + tgt_src.inc_d1_du = 0; tgt_src.trig = DMA_TRIG_SLOT_I2S; tgt_src.type = DMA_DATA_TYPE_WORD; - tgt_src.size_du = AUDIO_DATA_NUM; tgt_dst.ptr = audio_data_0; - tgt_dst.inc_du = 1; + tgt_dst.inc_d1_du = 1; tgt_dst.trig = DMA_TRIG_MEMORY; tgt_dst.type = DMA_DATA_TYPE_WORD; trans.src = &tgt_src; trans.dst = &tgt_dst; + trans.size_d1_du = AUDIO_DATA_NUM; trans.end = DMA_TRANS_END_INTR; dma_config_flags_t res; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c index 89cc242b..1afe2e6b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_iffifo/main.c @@ -130,16 +130,16 @@ int main(int argc, char *argv[]) { dma_init(NULL); tgt_src.ptr = to_fifo; - tgt_src.inc_du = 1; + tgt_src.inc_d1_du = 1; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE_WORD; - tgt_src.size_du = 6; tgt_dst.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_IN_REG_OFFSET; - tgt_dst.inc_du = 0; + tgt_dst.inc_d1_du = 0; tgt_dst.trig = DMA_TRIG_SLOT_EXT_TX; tgt_dst.type = DMA_DATA_TYPE_WORD; + trans.size_d1_du = 6; trans.src = &tgt_src; trans.dst = &tgt_dst; trans.end = DMA_TRANS_END_INTR; @@ -171,16 +171,16 @@ int main(int argc, char *argv[]) { dma_init(NULL); tgt_src.ptr = IFFIFO_START_ADDRESS + IFFIFO_FIFO_OUT_REG_OFFSET; - tgt_src.inc_du = 0; + tgt_src.inc_d1_du = 0; tgt_src.trig = DMA_TRIG_SLOT_EXT_RX; tgt_src.type = DMA_DATA_TYPE_WORD; - tgt_src.size_du = 4; tgt_dst.ptr = from_fifo; - tgt_dst.inc_du = 1; + tgt_dst.inc_d1_du = 1; tgt_dst.trig = DMA_TRIG_MEMORY; tgt_dst.type = DMA_DATA_TYPE_WORD; + trans.size_d1_du = 4; trans.src = &tgt_src; trans.dst = &tgt_dst; trans.end = DMA_TRANS_END_INTR; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c deleted file mode 100644 index 7ffd56bb..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - Copyright EPFL contributors. - Licensed under the Apache License, Version 2.0, see LICENSE for details. - SPDX-License-Identifier: Apache-2.0 - - Author: Tommaso Terzano - - Info: Contains randomly generated input activations and the golden result of the im2col algorithm. -*/ - -#include "im2colGolden.h" - -const uint32_t input_image_nchw[48] = { - 13932, 24003, 46802, 9895, - 46807, 33972, 44507, 1507, - 14638, 51479, 39560, 22725, - 38212, 35631, 40479, 39503, - 53705, 5796, 58640, 51585, - 45069, 32035, 41983, 18828, - 22247, 54792, 20499, 6640, - 20565, 25501, 4154, 2925, - 43660, 10618, 52141, 45092, - 46500, 63085, 57079, 16974, - 52033, 46977, 35992, 6933, - 3158, 21127, 28588, 61815 -}; - -const uint32_t golden_im2col_nchw[108] = { - 0, 0, 0, 0, 33972, 1507, 0, 35631, 39503, - 0, 0, 0, 46807, 44507, 0, 38212, 40479, 0, - 0, 24003, 9895, 0, 51479, 22725, 0, 0, 0, - 13932, 46802, 0, 14638, 39560, 0, 0, 0, 0, - 0, 0, 0, 0, 32035, 18828, 0, 25501, 2925, - 0, 0, 0, 45069, 41983, 0, 20565, 4154, 0, - 0, 5796, 51585, 0, 54792, 6640, 0, 0, 0, - 53705, 58640, 0, 22247, 20499, 0, 0, 0, 0, - 0, 0, 0, 0, 63085, 16974, 0, 21127, 61815, - 0, 0, 0, 46500, 57079, 0, 3158, 28588, 0, - 0, 10618, 45092, 0, 46977, 6933, 0, 0, 0, - 43660, 52141, 0, 52033, 35992, 0, 0, 0, 0 -}; - -const uint32_t input_image_nhwc[48] = { - 4047, 16986, 10416, - 22393, 36967, 57252, - 30217, 40720, 42651, - 3810, 4754, 56157, - 44724, 26083, 1010, - 44426, 14005, 35222, - 47712, 1887, 65, - 37412, 50137, 2236, - 7582, 53150, 12696, - 24415, 40340, 26558, - 22643, 14656, 7085, - 804, 32415, 17930, - 47706, 3314, 2947, - 19673, 37744, 24015, - 55137, 1975, 54009, - 25888, 50886, 35445 -}; - -const uint32_t golden_im2col_nhwc[108] = { - 0, 0, 0, 4047, 0, 0, 0, 16986, 0, 0, 0, 10416, - 0, 0, 22393, 30217, 0, 0, 36967, 40720, 0, 0, 57252, 42651, - 0, 0, 3810, 0, 0, 0, 4754, 0, 0, 0, 56157, 0, - 0, 44724, 0, 7582, 0, 26083, 0, 53150, 0, 1010, 0, 12696, - 44426, 47712, 24415, 22643, 14005, 1887, 40340, 14656, 35222, 65, 26558, 7085, - 37412, 0, 804, 0, 50137, 0, 32415, 0, 2236, 0, 17930, 0, - 0, 47706, 0, 0, 0, 3314, 0, 0, 0, 2947, 0, 0, - 19673, 55137, 0, 0, 37744, 1975, 0, 0, 24015, 54009, 0, 0, - 25888, 0, 0, 0, 50886, 0, 0, 0, 35445, 0, 0, 0 -}; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h deleted file mode 100644 index 27083aad..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2colGolden.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright EPFL contributors. - Licensed under the Apache License, Version 2.0, see LICENSE for details. - SPDX-License-Identifier: Apache-2.0 - - Author: Tommaso Terzano - - Info: Header file of im2colGolden, contains activations parameters and the prototypes of both input tensors and golden output. -*/ - -#ifndef IMAGE_AND_COL_H -#define IMAGE_AND_COL_H - -#include - -// Parameters -#define IW 4 -#define IH 4 -#define CH 3 -#define FW 2 -#define FH 2 -#define STRIDES 2 -#define PAD 1 -#define BATCH 1 - -extern const uint32_t input_image_nchw[48]; -extern const uint32_t golden_im2col_nchw[108]; -extern const uint32_t input_image_nhwc[48]; -extern const uint32_t golden_im2col_nhwc[108]; - -#endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.c new file mode 100644 index 00000000..c6716359 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.c @@ -0,0 +1,20 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 +*/ + +#include "im2col_golden.h" + +const uint32_t golden_im2col_nchw[225] = { + 0, 0, 0, 0, 0, 0, 45280, 44040, 39555, 48322, 0, 46986, 61580, 31407, 53015, 0, 48311, 52851, 12647, 34880, 0, 1708, 38684, 39145, 34646, + 0, 0, 0, 0, 0, 45280, 44040, 39555, 48322, 43761, 46986, 61580, 31407, 53015, 50099, 48311, 52851, 12647, 34880, 26310, 1708, 38684, 39145, 34646, 20833, + 0, 0, 0, 0, 0, 44040, 39555, 48322, 43761, 0, 61580, 31407, 53015, 50099, 0, 52851, 12647, 34880, 26310, 0, 38684, 39145, 34646, 20833, 0, + 0, 45280, 44040, 39555, 48322, 0, 46986, 61580, 31407, 53015, 0, 48311, 52851, 12647, 34880, 0, 1708, 38684, 39145, 34646, 0, 38991, 55892, 20081, 22175, + 45280, 44040, 39555, 48322, 43761, 46986, 61580, 31407, 53015, 50099, 48311, 52851, 12647, 34880, 26310, 1708, 38684, 39145, 34646, 20833, 38991, 55892, 20081, 22175, 48554, + 44040, 39555, 48322, 43761, 0, 61580, 31407, 53015, 50099, 0, 52851, 12647, 34880, 26310, 0, 38684, 39145, 34646, 20833, 0, 55892, 20081, 22175, 48554, 0, + 0, 46986, 61580, 31407, 53015, 0, 48311, 52851, 12647, 34880, 0, 1708, 38684, 39145, 34646, 0, 38991, 55892, 20081, 22175, 0, 0, 0, 0, 0, + 46986, 61580, 31407, 53015, 50099, 48311, 52851, 12647, 34880, 26310, 1708, 38684, 39145, 34646, 20833, 38991, 55892, 20081, 22175, 48554, 0, 0, 0, 0, 0, + 61580, 31407, 53015, 50099, 0, 52851, 12647, 34880, 26310, 0, 38684, 39145, 34646, 20833, 0, 55892, 20081, 22175, 48554, 0, 0, 0, 0, 0, 0 +}; + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.h new file mode 100644 index 00000000..8ef7092c --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_golden.h @@ -0,0 +1,14 @@ +#ifndef GOLDEN_IM2COL_NCHW_H +#define GOLDEN_IM2COL_NCHW_H + +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 +*/ + +#include + +extern const uint32_t golden_im2col_nchw[225]; + +#endif // GOLDEN_IM2COL_NCHW_H diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.c new file mode 100644 index 00000000..7def5007 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.c @@ -0,0 +1,16 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 +*/ + +#include "im2col_input.h" + +const uint32_t input_image_nchw[25] = { + 45280, 44040, 39555, 48322, 43761, + 46986, 61580, 31407, 53015, 50099, + 48311, 52851, 12647, 34880, 26310, + 1708, 38684, 39145, 34646, 20833, + 38991, 55892, 20081, 22175, 48554 +}; + diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.h b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.h new file mode 100644 index 00000000..b1ec30ce --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_input.h @@ -0,0 +1,27 @@ +#ifndef INPUT_IMAGE_NCHW_H +#define INPUT_IMAGE_NCHW_H + +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 +*/ + +#include + +#define IH 5 +#define IW 5 +#define CH 1 +#define BATCH 1 +#define FH 3 +#define FW 3 +#define TOP_PAD 1 +#define BOTTOM_PAD 1 +#define LEFT_PAD 1 +#define RIGHT_PAD 1 +#define STRIDE_D1 1 +#define STRIDE_D2 1 + +extern const uint32_t input_image_nchw[25]; + +#endif // INPUT_IMAGE_NCHW_H diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c index 75d38d74..6670cc0f 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/im2col_lib.c @@ -4,205 +4,483 @@ SPDX-License-Identifier: Apache-2.0 Author: Tommaso Terzano + Info: im2col_lib.c describes functions used to calculate im2col and verify it using the golden result in im2colGolden.c. - Notes: im2col_nchw_int32() and im2col_nhwc_int32() algorithms are inspired from the library SHL, developed by T-HEAD Semi. + Notes: im2col_nchw_int32() algorithm is inspired from the library SHL, developed by T-HEAD Semi. For reference, check out the following link: - https://github.com/T-head-Semi/csi-nn2/blob/main/source/reference/im2col.c + https:/*github.com/T-head-Semi/csi-nn2/blob/main/source/reference/im2col.c */ #include "im2col_lib.h" -int output_data[OH_NCHW*OW_NCHW]; +#if INPUT_DATATYPE == 2 + typedef uint8_t data_t; +#elif INPUT_DATATYPE == 1 + typedef uint16_t data_t; +#elif INPUT_DATATYPE == 0 + typedef uint32_t data_t; +#endif -int im2col_nchw_int32() +data_t output_data[OH_NCHW*OW_NCHW]; +data_t* input_image_ptr = &input_image_nchw[0]; +data_t* output_data_ptr = &output_data[0]; + +char im2col_done = 0; +int ifr_status; + +void handler_irq_im2col_spc( void ) +{ + im2col_done = 1; + + /* Read the IFR to lower the interrupt flag */ + ifr_status = * (volatile uint32_t * )(EXT_PERIPHERAL_START_ADDRESS + IM2COL_PER_OFFSET + IM2COL_SPC_SPC_IFR_REG_OFFSET); + return; +} + +/* Used to wait for the SPC interrupt handler to end */ +__attribute__ ((optimize("O0"))) void waiting_for_spc_irq( void ) { - PRINTF("OH: %d, OW: %d\n", OH_NCHW, OW_NCHW); + while (im2col_done == 0) + { + asm volatile ("wfi"); + } +} +int im2col_nchw_int32(uint8_t test_id, unsigned int *cycles) +{ int size_transfer = 0; + int size_transfer_d2 = 0; + int counter = 0; + int n_zeros_left = 0; + int n_zeros_right = 0; + int n_zeros_top = 0; + int n_zeros_bottom = 0; int im_row = 0; int im_col = 0; - int w_offset = 0; // the offset ALONG the IW - int h_offset = 0; // the offset ALONG the IH - int im_c = 0; // Gets the CH on which the im2col is being performed depending on the row of the output image (c) + int im_c = 0; + int w_offset = 0; + int h_offset = 0; int col_index = 0; - - // Iterate over each row of the output matrix. - for (int c = 0; c < CH_COL; ++c) { - // Calculate offsets within the kernel window. - // These are used to move the filter around the input image - - w_offset = c % FW; - h_offset = (c / FW) % FH; - im_c = c / (FH * FW); // Gets the CH on which the im2col is being performed depending on the row of the output image (c) - - // Iterate over each BATCH. - for (int b = 0; b < BATCH; ++b) { - // Iterate over each patch on the IW of the input matrix. - for (int h = 0; h < N_PATCHES_H; ++h) { - // Iterate over each patch on the heigth in the output matrix. - for (int w = 0; w < N_PATCHES_W; ++w) { - // Calculate the row and column indices in the original input image, applying the stride and offset. - im_row = h_offset + h * STRIDES - PAD; - im_col = w_offset + w * STRIDES - PAD; - - // Calculate the index in the flattened output array where this value should be stored. - col_index = ((c * BATCH + b) * N_PATCHES_H + h) * N_PATCHES_W + w; - - // If the calculated indices are outside the bounds of the input image, set the output to 0 (padding effect). - // Otherwise, fetch the value from the input image and store it in the output array. - if (im_row < 0 || im_col < 0 || im_row >= IH || im_col >= IW) { - output_data[col_index] = 0; - } else { - output_data[col_index] = input_image_nchw[get_index(CH, IH, IW, b, im_c, im_row, im_col)]; + int minimum = 0; + int start_max = 0; + int start_min = 0; + int stray_elements = 0; + int last_position = 0; + int tmp_pad = 0; + int w_offset_pad = 0; + int h_offset_pad = 0; + int fw_minus_w_offset = 0; + int fh_minus_h_offset = 0; + unsigned int cycles_A = 0; + unsigned int cycles_B = 0; + unsigned int avg_first_zeros; + unsigned int avg_last_zeros; + unsigned int avg_patch = 0; + int src_inc_d2 = 0; + int w_offset_counter = 0; + int h_offset_counter = 0; + int h_offset_tmp_counter = 0; + int im_c_counter = 0; + int w_offset_vs_PAD = 0; + int h_offset_vs_PAD = 0; + int fw_minus_w_offset_vs_PAD = 0; + int fh_minus_h_offset_vs_PAD = 0; + int h_offset_tmp = 0; + int n_zeros_top_counter = 0; + int n_zeros_top_cond = 0; + int pad_min_w_offset = 0; + + for (int i=0; i= IH || im_col >= IW) { + output_data[col_index] = 0; + PRINTF_DEB("Padding with 0\n\r"); + } else { + output_data[col_index] = input_image_nchw[get_index(CH, IH, IW, b, im_c, im_row, im_col)]; + PRINTF_DEB("Value: %d\n\r", input_image_nchw[get_index(CH, IH, IW, b, im_c, im_row, im_col)]); + } } } } } + + #if TIMING + *cycles = timer_stop(); + #endif } - // Finished! + /* Implementation of the nchw im2col algorithm using the DMA 2D feature */ + else if (test_id == 1) + { + + data_t* input_image_ptr = &input_image_nchw[0]; + data_t* output_data_ptr = &output_data[0]; + /* Iterate over each row of the output matrix. */ - PRINTF("Final output matrix:\n\n"); + dma_config_flags_t res; - #if DEBUG - for (int i=0; i= LEFT_PAD) + { + n_zeros_left = 0; + } + else if ( (LEFT_PAD - w_offset) % STRIDE_D1 == 0 ) + { + n_zeros_left = (LEFT_PAD - w_offset) / STRIDE_D1; + } + else + { + n_zeros_left = (LEFT_PAD - w_offset) / STRIDE_D1 + 1; + } + + /* Computing the number of zeros on the top */ + + /* In the offset of the element in the filter is bigger than P, then no zeros are needed */ + if ( h_offset >= TOP_PAD) + { + n_zeros_top = 0; + } + else if ( (TOP_PAD - h_offset) % STRIDE_D2 == 0 ) + { + n_zeros_top = (TOP_PAD - h_offset) / STRIDE_D2; + } + else + { + n_zeros_top = (TOP_PAD - h_offset) / STRIDE_D2 + 1; + } + + /* Computing the number of zeros on the right */ - // Calculate the heigth of the output matrix - - // Iterate over each row of the output matrix. - for (int b = 0; b < BATCH; ++b) { - // Iterate over each BATCH. - for (int h = 0; h < N_PATCHES_H; ++h) { - // Iterate over each patch on the IW of the input matrix. - for (int w = 0; w < N_PATCHES_W; ++w) { - // Iterate over each patch on the heigth in the output matrix. - for (int c = 0; c < CH_COL; ++c) { - // Calculate offsets within the kernel window. - // These are used to move the filter around the input image - - w_offset = c % FW; - h_offset = (c / FW) % FH; - im_c = c / (FH * FW); // Gets the CH on which the im2col is being performed depending on the row of the output image (c) - - // Calculate the row and column indices in the original input image, applying the stride and offset. - im_row = h_offset + h * STRIDES - PAD; - im_col = w_offset + w * STRIDES - PAD; - - // Calculate the index in the flattened output array where this value should be stored. - col_index = ((b * N_PATCHES_H + h) * N_PATCHES_W + w) * CH_COL + c; // ((c * BATCH + b) * N_PATCHES_H + h) * N_PATCHES_W + w; - - // If the calculated indices are outside the bounds of the input image, set the output to 0 (padding effect). - // Otherwise, fetch the value from the input image and store it in the output array. - if (im_row < 0 || im_col < 0 || im_row >= IH || im_col >= IW) { - output_data[col_index] = 0; - } else { - output_data[col_index] = input_image_nhwc[get_index(IH, IW, CH, b, im_row, im_col, im_c)]; - } + /* To adapt the final case to the formulas used to the first padded region, let's compute an "adapted" padded region, + /* by removing the elements of the row uncovered by the sliding filter */ + + if (fw_minus_w_offset >= RIGHT_PAD || ADPT_PAD_RIGHT == 0) + { + n_zeros_right = 0; + } + else if ( (ADPT_PAD_RIGHT - (fw_minus_w_offset)) % STRIDE_D1 == 0 ) + { + n_zeros_right = (ADPT_PAD_RIGHT - (fw_minus_w_offset)) / STRIDE_D1; + } + else + { + n_zeros_right = (ADPT_PAD_RIGHT - (fw_minus_w_offset)) / STRIDE_D1 + 1; + } + + /* Computing the number of zeros on the bottom */ + + /* To adapt the final case to the formulas used to the first padded region, let's compute an "adapted" padded region, + /* by removing the elements of the row uncovered by the sliding filter */ + + if (fh_minus_h_offset >= BOTTOM_PAD || ADPT_PAD_BOTTOM == 0) + { + n_zeros_bottom = 0; + } + else if ( (ADPT_PAD_BOTTOM - (fh_minus_h_offset)) % STRIDE_D2 == 0) + { + n_zeros_bottom = (ADPT_PAD_BOTTOM - (fh_minus_h_offset)) / STRIDE_D2; + } + else + { + n_zeros_bottom = (ADPT_PAD_BOTTOM - (fh_minus_h_offset)) / STRIDE_D2 + 1; + } + + /* Compute the number of elements to transfer */ + size_transfer = N_PATCHES_W - n_zeros_left - n_zeros_right; + size_transfer_d2 = N_PATCHES_H - n_zeros_top - n_zeros_bottom; + + PRINTF_DEB("\n\rn_zeros_left: %d, n_zeros_right: %d, n_zeros_top: %d, n_zeros_bottom: %d", n_zeros_left, n_zeros_right, n_zeros_top, n_zeros_bottom); + PRINTF_DEB("\n\rsize_transfer: %d, size_transfer_d2: %d\n\r", size_transfer, size_transfer_d2); + + /* DMA setup and transaction run */ + int index = get_index(CH, IH, IW, b, im_c, im_row + n_zeros_top*STRIDE_D2, im_col + n_zeros_left*STRIDE_D1); + src_inc_d2 = (STRIDE_D2 * IW - (size_transfer - 1 + (STRIDE_D1 - 1) * (size_transfer - 1))); + + PRINTF_DEB("\n\rindex: %d, src_inc_d2: %d", index, src_inc_d2); + + input_image_ptr = &input_image_nchw[0] + index; + PRINTF_DEB("\n\rsrc_ptr: %x dst_ptr: %x\n\r", input_image_ptr, output_data_ptr); + + tgt_src.ptr = input_image_ptr; + tgt_src.inc_d2_du = src_inc_d2; + + tgt_dst.ptr = output_data_ptr; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.size_d1_du = size_transfer; + trans.size_d2_du = size_transfer_d2; + trans.pad_top_du = n_zeros_top; + trans.pad_left_du = n_zeros_left; + trans.pad_right_du = n_zeros_right; + trans.pad_bottom_du = n_zeros_bottom; + + dma_run(&trans); + + output_data_ptr += OW_NCHW; + + PRINTF_DEB("\n\r"); + + #ifndef DEBUG + PRINTF_DEB("\n\rCurrent output matrix: \n\r"); + for (int i=0; i + * Info: Header file of im2col_lib.c, containing the function prototypes, parameters macros and the configuration of prints and performance analysis. */ @@ -14,25 +15,64 @@ #include #include #include -#include "im2colGolden.h" +#include "im2col_golden.h" +#include "im2col_input.h" +#include "im2col.h" #include "dma.h" +#include "im2col_spc_regs.h" #include "core_v_mini_mcu.h" #include "x-heep.h" #include "rv_plic.h" #include "csr.h" +#include -// By default, printfs are activated for FPGA and for simulation. +#include "mmio.h" +#include "handler.h" +#include "hart.h" +#include "fast_intr_ctrl.h" +#include "timer_sdk.h" + +/* + Choose between several HW configurations: + - 0: Only CPU + - 1: Exploit standard DMA + - 2: Exploit 2D DMA + - 3: Exploit Smart Peripheral Controller (SPC) +*/ +#define HW_CONFIG_CPU +#define HW_CONFIG_DMA_2D +#define HW_CONFIG_SPC + +/* Defines which DMA channels are available to the SPC, depending on HW specifications */ +#define SPC_CH_MASK 0b0001 + +/* Defines the datatype of the input */ +#define INPUT_DATATYPE 0 + +/* Defines the offset of the im2col SPC in the system (0x4000 in testharness.sv) */ +#define IM2COL_PER_OFFSET 0x4000 + +/* By default, printfs are activated for FPGA and for simulation. */ #define PRINTF_IN_FPGA 1 #define PRINTF_IN_SIM 0 -#define DEBUG 0 // Set to 1 to enable debug prints -#define TIMING 0 // Set to 1 to enable timing measurements -// Format is defined in im2colGolden.h +/* Set to 1 to enable debug prints */ +#define DEBUG 0 +/* Set to 1 to enable timing measurements */ +#define TIMING 1 #if TARGET_SIM && PRINTF_IN_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) - #define PRINTF_DEB(...) - #define PRINTF_TIM(...) + #if DEBUG + #define PRINTF_DEB(fmt, ...) printf(fmt, ## __VA_ARGS__) + #else + #define PRINTF_DEB(...) + #endif + #if TIMING + #define PRINTF_TIM(fmt, ...) printf(fmt, ## __VA_ARGS__) + #else + #define PRINTF_TIM(...) + #endif #elif PRINTF_IN_FPGA && !TARGET_SIM #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) #if DEBUG @@ -53,22 +93,30 @@ // Define the dimensions of the input tensor and the kernel -#define N_PATCHES_H ((IH + (PAD + PAD) - FH)/ STRIDES + 1) -#define N_PATCHES_W ((IW + (PAD + PAD) - FW)/ STRIDES + 1) +#define N_PATCHES_H ((IH + (TOP_PAD + BOTTOM_PAD) - FH)/ STRIDE_D2 + 1) +#define N_PATCHES_W ((IW + (RIGHT_PAD + LEFT_PAD) - FW)/ STRIDE_D1 + 1) + +#define ADPT_PAD_BOTTOM (STRIDE_D2 * (N_PATCHES_H - 1) + FH - (TOP_PAD + IH)) +#define ADPT_PAD_RIGHT (STRIDE_D1 * (N_PATCHES_W - 1) + FW - (LEFT_PAD + IW)) #define CH_COL (CH * FH * FW) #define OH_NCHW (CH * FH * FW * BATCH) #define OW_NCHW (N_PATCHES_H) * (N_PATCHES_W) -#define OW_NHWC (FW * FH * CH * BATCH) -#define OH_NHWC (N_PATCHES_W) * (N_PATCHES_H) +#define START_ID 0 -int im2col_nchw_int32(); -int im2col_nhwc_int32(); +#define TEST_EN 0 + +// Computations for 2D DMA +#define SRC_INC_D2 (STRIDE_D2 * IW - (FW - 1 + (STRIDE_D1 - 1) * (FW - 1))) + +int im2col_nchw_int32(uint8_t test_id, unsigned int *cycles); + +__attribute__((weak, optimize("O0"))) void handler_irq_im2col_spc(void); int get_index(int dim1, int dim2, int dim3, int index0, int index1, int index2, int index3); -int verify(int format); +int verify(void); -#endif \ No newline at end of file +#endif diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c index a22c8bf8..23c71e67 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_im2col/main.c @@ -4,6 +4,7 @@ SPDX-License-Identifier: Apache-2.0 Author: Tommaso Terzano + Info: Example application of im2col algorithm with configurable format, verification and performance analysis. */ @@ -14,68 +15,45 @@ #include "x-heep.h" #include "im2col_lib.h" -#define NCHW_FORMAT 0 -#define NHWC_FORMAT 1 +/* Test variables */ +int errors; +unsigned int cycles; int main() { - PRINTF("\nStarting test...\n\n"); - - int errors; - unsigned int cycles; - - #if TIMING - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - #endif - - im2col_nchw_int32(); // Execute the im2col algorithm with NCHW format - - #if TIMING - CSR_READ(CSR_REG_MCYCLE, &cycles); - #endif - - errors = verify(NCHW_FORMAT); - - PRINTF("im2col NCHW test executed\n"); - - PRINTF_TIM("Total number of cycles: [%d]\n\n", cycles); - - if (errors != 0) + for (int i=START_ID; i<3; i++) { - PRINTF("TEST FAILED: %d errors\n", errors); - return 1; - } - else - { - PRINTF("TEST PASSED!\n"); - } - - #if TIMING - CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); - CSR_WRITE(CSR_REG_MCYCLE, 0); - #endif - - im2col_nhwc_int32(); // Execute the im2col algorithm with NHWC format - - #if TIMING - CSR_READ(CSR_REG_MCYCLE, &cycles); - #endif - - errors = verify(NHWC_FORMAT); - - PRINTF("im2col NHWC test executed\n"); - PRINTF_TIM("Total number of cycles: [%d]\n\n", cycles); - - if (errors != 0) - { - PRINTF("TEST FAILED: %d errors\n", errors); - return 1; - } - else - { - PRINTF("TEST PASSED!\n"); + im2col_nchw_int32(i, &cycles); + + #if TEST_EN == 0 + PRINTF("im2col NCHW test %d executed\n\r", i); + PRINTF_TIM("Total number of cycles: [%d]\n\r", cycles); + #endif + + errors = verify(); + + if (errors != 0) + { + #if TEST_EN == 0 + PRINTF("TEST %d FAILED: %d errors\n\r", i, errors); + return EXIT_FAILURE; + #else + PRINTF_TIM("%d:%d:1\n\r", i, cycles); + #endif + + } + else + { + #if TEST_EN == 0 + PRINTF("TEST PASSED!\n\r\n\r"); + #else + PRINTF_TIM("%d:%d:0\n\r", i, cycles); + #endif + } } + + /* Print the end word for verification */ + PRINTF("&\n\r"); - return 0; + return EXIT_SUCCESS; } diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c index 4f025e1e..e1fe60e9 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_power_manager/main.c @@ -49,7 +49,7 @@ static power_manager_t power_manager; #define TEST_WORD //this data has to be big to allow the CPU to power gate -#define TEST_DATA_SIZE 500 +#define TEST_DATA_SIZE 450 // Source and destination addresses have to be aligned on a 4 bytes address uint32_t test_data_4B[TEST_DATA_SIZE] __attribute__ ((aligned (4))) = { 0 }; @@ -179,37 +179,29 @@ int main(int argc, char *argv[]) } dma_init(NULL); - dma_config_flags_t res; - dma_target_t tgt_src; - dma_target_t tgt_dst; - dma_target_t tgt_addr = { - .ptr = NULL, - .inc_du = 1, - .size_du = 0, - .trig = DMA_TRIG_MEMORY, - }; - dma_trans_t trans; + static dma_config_flags_t res; + static dma_target_t tgt_src; + static dma_target_t tgt_dst; + static dma_trans_t trans; // Initialize the DMA for the next tests tgt_src.ptr = (uint8_t *)test_data_4B; - tgt_src.inc_du = 1; - tgt_src.size_du = TEST_DATA_SIZE; + tgt_src.inc_d1_du = 1; tgt_src.trig = DMA_TRIG_MEMORY; tgt_src.type = DMA_DATA_TYPE_WORD; tgt_src.env = NULL; tgt_src.inc_d2_du = 0; tgt_dst.ptr = (uint8_t *)copied_data_4B; - tgt_dst.inc_du = 1; - tgt_dst.size_du = TEST_DATA_SIZE; + tgt_dst.inc_d1_du = 1; tgt_dst.trig = DMA_TRIG_MEMORY; tgt_dst.type = DMA_DATA_TYPE_WORD; tgt_dst.env = NULL; tgt_dst.inc_d2_du = 0; + trans.size_d1_du = TEST_DATA_SIZE; trans.src = &tgt_src; trans.dst = &tgt_dst; - trans.src_addr = &tgt_addr; trans.src_type = DMA_DATA_TYPE_WORD; trans.dst_type = DMA_DATA_TYPE_WORD; trans.mode = DMA_TRANS_MODE_SINGLE; diff --git a/hw/vendor/esl_epfl_x_heep/sw/applications/example_tensor_format_conv/main.c b/hw/vendor/esl_epfl_x_heep/sw/applications/example_tensor_format_conv/main.c new file mode 100644 index 00000000..575b8dee --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/applications/example_tensor_format_conv/main.c @@ -0,0 +1,288 @@ +/* + * Copyright EPFL contributors. + * Licensed under the Apache License, Version 2.0, see LICENSE for details. + * SPDX-License-Identifier: Apache-2.0 + * + * Author: Tommaso Terzano + * + * + * Info: This application converts a HWC tensor to a CHW tensor and viceversa, leveraging the DMA subsytem. + * + * This is a simple example of a HWC tensor with 3 channels, 2 rows and 2 columns: + * (1, 2, 3) (4, 5, 6) + * (7, 8, 9) (10, 11, 12) + * (1, 2, 3) are the values of the first "pixel" of the tensor across different channels, 1 for CH0, 2 for CH1 and 3 for CH2. + * + * On the other hand, this is the same tensor represented with the CHW format: + * + * (1) (4) + * (7) (10) + * (2) (5) + * (8) (11) + * (3) (6) + * (9) (12) + * + * (1) is the first pixel of CH0, which is composed of the values 1, 4, 7, 10, and so on. + * + * The conversion hwc -> chw is performed in this manner: + * - Copy the first element (1) + * - Skip #channels elements + * - Copy the element (4) + * And so on. + * + * To speed the conversion up, the application makes use of the DMA. + * Its transposition function is used in an unconventional way: the d1 increment is set to #channels, while the d2 increment + * is set to 1. + * In this way, the DMA will copy H*W elements with a C stride, then start the next copy from the first element + 1, + * and repeat until completion. + * This behaviour is similar to a 3D copy, because it performs a copy of a matrix (H*W) with a stride (C), even if + * using just 2 counters. + * + * The conversion chw -> hwc is performed in a similar way, but it needs H loops, making it a lot slower than the other type + * of conversion. + */ + +#include +#include +#include "dma.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "csr.h" +#include "rv_plic.h" + +/* Uncomment to disable performance analysis */ +#define EN_PERF + +#define C 3 +#define H 4 +#define W 3 + +/* By default, printfs are activated for FPGA and disabled for simulation. */ +#define PRINTF_IN_FPGA 1 +#define PRINTF_IN_SIM 0 + +#if TARGET_SIM && PRINTF_IN_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#elif PRINTF_IN_FPGA && !TARGET_SIM + #define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else + #define PRINTF(...) +#endif + +/* CHW example array */ +int chw_array[36] = { + // Channel 1 + 7, 8, 5, // Row 1 + 9, 3, 6, // Row 2 + 2, 4, 1, // Row 3 + 8, 10, 12, // Row 4 + + // Channel 2 + 15, 16, 13, // Row 1 + 19, 11, 14, // Row 2 + 10, 18, 17, // Row 3 + 20, 22, 21, // Row 4 + + // Channel 3 + 23, 25, 24, // Row 1 + 28, 26, 27, // Row 2 + 29, 31, 30, // Row 3 + 32, 34, 33 // Row 4 +}; + +/* HWC example array */ +int hwc_array[36] = { + // Row 1 + 7, 15, 23, // W1C1, W1C2, W1C3 + 8, 16, 25, // W2C1, W2C2, W2C3 + 5, 13, 24, // W3C1, W3C2, W3C3 + + // Row 2 + 9, 19, 28, // W1C1, W1C2, W1C3 + 3, 11, 26, // W2C1, W2C2, W2C3 + 6, 14, 27, // W3C1, W3C2, W3C3 + + // Row 3 + 2, 10, 29, // W1C1, W1C2, W1C3 + 4, 18, 31, // W2C1, W2C2, W2C3 + 1, 17, 30, // W3C1, W3C2, W3C3 + + // Row 4 + 8, 20, 32, // W1C1, W1C2, W1C3 + 10, 22, 34, // W2C1, W2C2, W2C3 + 12, 21, 33 // W3C1, W3C2, W3C3 +}; + +int convert_hwc_to_chw_int32(int *src, int *dst) +{ + #ifdef EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + static dma_target_t tgt_src; + static dma_target_t tgt_dst; + static dma_trans_t trans; + int res_valid, res_load, res_launch, cycles_dma; + + /* Initialize the targets */ + tgt_src.ptr = (uint8_t *) src; + tgt_src.inc_d1_du = 1; + tgt_src.inc_d2_du = C; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE_WORD; + + tgt_dst.ptr = (uint8_t *) dst; + tgt_dst.inc_d1_du = 1; + tgt_dst.inc_d2_du = 1; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.dim = DMA_DIM_CONF_2D; + trans.dim_inv = 1; // Enable transposition function + trans.size_d1_du = H * W; + trans.size_d2_du = C; + trans.win_du = 0, + trans.end = DMA_TRANS_END_INTR_WAIT; + + dma_init(NULL); + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res_load = dma_load_transaction(&trans); + res_launch = dma_launch(&trans); + if (res_launch | res_load | res_valid) { + PRINTF("Error in the DMA transaction! %d - %d - %d\n", res_valid, res_load, res_launch); + exit(1); + } + + #ifdef EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + return cycles_dma; + #endif + + return 0; +} + +int convert_chw_to_hwc_int32(int *src, int *dst) +{ + static dma_target_t tgt_src; + static dma_target_t tgt_dst; + static dma_trans_t trans; + int res_valid, res_load, res_launch, cycles_dma; + int * src_ptr = src; + int * dst_ptr = dst; + + #ifdef EN_PERF + + /* Reset the counter to evaluate the performance of the DMA */ + CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1); + CSR_WRITE(CSR_REG_MCYCLE, 0); + #endif + + dma_init(NULL); + + for (int i=0; i < H; i++) { + + /* Initialize the targets */ + tgt_src.ptr = (uint8_t *) src_ptr; + tgt_src.inc_d1_du = 1; + tgt_src.inc_d2_du = H * W; + tgt_src.trig = DMA_TRIG_MEMORY; + tgt_src.type = DMA_DATA_TYPE_WORD; + + tgt_dst.ptr = (uint8_t *) dst_ptr; + tgt_dst.inc_d1_du = 1; + tgt_dst.inc_d2_du = 1; + tgt_dst.trig = DMA_TRIG_MEMORY; + tgt_dst.type = DMA_DATA_TYPE_WORD; + + trans.src = &tgt_src; + trans.dst = &tgt_dst; + trans.mode = DMA_TRANS_MODE_SINGLE; + trans.dim = DMA_DIM_CONF_2D; + trans.dim_inv = 1; // Enable transposition function + trans.size_d1_du = C; + trans.size_d2_du = W; + trans.win_du = 0, + trans.end = DMA_TRANS_END_INTR_WAIT; + + res_valid = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY); + res_load = dma_load_transaction(&trans); + res_launch = dma_launch(&trans); + if (res_launch | res_load | res_valid) { + PRINTF("Error in the DMA transaction! %d - %d - %d\n", res_valid, res_load, res_launch); + exit(1); + } + + src_ptr += W; + dst_ptr += W * C; + } + + #ifdef EN_PERF + + /* Read the cycles count after the DMA run */ + CSR_READ(CSR_REG_MCYCLE, &cycles_dma); + return cycles_dma; + #endif + + return 0; +} + +int main() +{ + int cycles_dma; + int dst_array[36]; + int passed_chw = 1; + int passed_hwc = 1; + + /* Convert HWC to CHW */ + cycles_dma = convert_hwc_to_chw_int32(hwc_array, dst_array); + + #ifdef EN_PERF + PRINTF("DMA cycles HWC -> CHW: %d\n\n\r", cycles_dma); + #endif + + /* Verify that the computed and the expected outputs are the same */ + for (int i = 0; i < H * W * C; i++) { + if (chw_array[i] != dst_array[i]) { + passed_chw = 0; + } + } + + /* Convert CHW to HWC */ + cycles_dma = convert_chw_to_hwc_int32(chw_array, dst_array); + + #ifdef EN_PERF + PRINTF("DMA cycles CHW -> HWC: %d\n\n\r", cycles_dma); + #endif + + /* Verify that the computed and the expected outputs are the same */ + for (int i = 0; i < H * W * C; i++) { + if (hwc_array[i] != dst_array[i]) { + passed_hwc = 0; + } + } + + if (passed_hwc && passed_chw) { + PRINTF("Success\n\n\r"); + } + else + { + if (!passed_hwc) { + PRINTF("Fail HWC -> CHW\n\r"); + } + if (!passed_chw) { + PRINTF("Fail CHW -> HWC\n\r"); + } + return EXIT_FAILURE; + } + + return 0; +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c index 04908d8e..f6a3ac99 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q.c @@ -441,7 +441,7 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, } -w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_dma, uint8_t no_sanity_checks) { +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_init_dma, uint8_t no_sanity_checks) { // Sanity checks if (!no_sanity_checks) if (w25q128jw_sanity_checks(addr, data, length) != FLASH_OK) return FLASH_ERROR; @@ -453,7 +453,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 uint32_t *fifo_ptr_rx = (uint32_t *)((uintptr_t)spi + SPI_HOST_RXDATA_REG_OFFSET); // Init DMA, the integrated DMA is used (peri == NULL) - if(!no_wait_dma) dma_init(NULL); + if(!no_wait_init_dma) dma_init(NULL); // The DMA will wait for the SPI HOST/FLASH RX FIFO valid signal #ifndef USE_SPI_FLASH @@ -464,11 +464,9 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 // Set up DMA source target static dma_target_t tgt_src = { - .inc_du = 0, // Target is peripheral, no increment + .inc_d1_du = 0, // Target is peripheral, no increment .type = DMA_DATA_TYPE_WORD, // Data type is word }; - // Size is in data units (words in this case) - tgt_src.size_du = length>>2; // Target is SPI RX FIFO tgt_src.ptr = (uint8_t*)fifo_ptr_rx; // Trigger to control the data flow @@ -476,7 +474,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 // Set up DMA destination target static dma_target_t tgt_dst = { - .inc_du = 1, // Increment by 1 data unit (word) + .inc_d1_du = 1, // Increment by 1 data unit (word) .type = DMA_DATA_TYPE_WORD, // Data type is byte .trig = DMA_TRIG_MEMORY, // Read-write operation to memory }; @@ -488,6 +486,8 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 .dst = &tgt_dst, .end = DMA_TRANS_END_POLLING, }; + // Size is in data units (words in this case) + trans.size_d1_du = length>>2; // Validate, load and launch DMA transaction @@ -524,7 +524,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32 spi_wait_for_ready(spi); // Wait for DMA to finish transaction - if(!no_wait_dma) while(!dma_is_ready(0)); + if(!no_wait_init_dma) while(!dma_is_ready(0)); // Take into account the extra bytes (if any) if (length % 4 != 0) { @@ -569,11 +569,9 @@ w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, // Set up DMA source target static dma_target_t tgt_src = { - .inc_du = 0, // Target is peripheral, no increment + .inc_d1_du = 0, // Target is peripheral, no increment .type = DMA_DATA_TYPE_WORD, // Data type is word }; - // Size is in data units (words in this case) - tgt_src.size_du = length>>2; // Target is SPI RX FIFO tgt_src.ptr = (uint8_t*)fifo_ptr_rx; // Trigger to control the data flow @@ -581,7 +579,7 @@ w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, // Set up DMA destination target static dma_target_t tgt_dst = { - .inc_du = 1, // Increment by 1 data unit (word) + .inc_d1_du = 1, // Increment by 1 data unit (word) .type = DMA_DATA_TYPE_WORD, // Data type is byte .trig = DMA_TRIG_MEMORY, // Read-write operation to memory }; @@ -593,6 +591,8 @@ w25q_error_codes_t w25q128jw_read_standard_dma_async(uint32_t addr, void *data, .dst = &tgt_dst, .end = DMA_TRANS_END_INTR, //so that you can wait for interrupt }; + // Size is in data units (words in this case) + trans.size_d1_du = length>>2; // Validate, load and launch DMA transaction dma_config_flags_t res; res = dma_validate_transaction(&trans, DMA_ENABLE_REALIGN, DMA_PERFORM_CHECKS_INTEGRITY ); @@ -903,11 +903,9 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l // Set up DMA source target static dma_target_t tgt_src = { - .inc_du = 0, // Target is peripheral, no increment + .inc_d1_du = 0, // Target is peripheral, no increment .type = DMA_DATA_TYPE_WORD, // Data type is byte }; - // Size is in data units (words in this case) - tgt_src.size_du = length>>2; // Target is SPI RX FIFO tgt_src.ptr = (uint8_t*)fifo_ptr_rx; // Trigger to control the data flow @@ -915,7 +913,7 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l // Set up DMA destination target static dma_target_t tgt_dst = { - .inc_du = 1, // Increment by 1 data unit (word) + .inc_d1_du = 1, // Increment by 1 data unit (word) .type = DMA_DATA_TYPE_WORD, // Data type is byte .trig = DMA_TRIG_MEMORY, // Read-write operation to memory }; @@ -927,6 +925,8 @@ w25q_error_codes_t w25q128jw_read_quad_dma(uint32_t addr, void *data, uint32_t l .dst = &tgt_dst, .end = DMA_TRANS_END_POLLING, }; + // Size is in data units (words in this case) + trans.size_d1_du = length>>2; // Validate, load and launch DMA transaction dma_config_flags_t res; @@ -1476,11 +1476,9 @@ static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { // Set up DMA source target static dma_target_t tgt_src = { - .inc_du = 1, // Increment by 1 data unit (word) + .inc_d1_du = 1, // Increment by 1 data unit (word) .type = DMA_DATA_TYPE_WORD, // Data type is word }; - // Size is in data units (words in this case) - tgt_src.size_du = length>>2; // Target is data buffer tgt_src.ptr = data; // Reads from memory @@ -1488,7 +1486,7 @@ static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { // Set up DMA destination target static dma_target_t tgt_dst = { - .inc_du = 0, // It's a peripheral, no increment + .inc_d1_du = 0, // It's a peripheral, no increment .type = DMA_DATA_TYPE_WORD, // Data type is word }; tgt_dst.trig = slot; @@ -1502,6 +1500,8 @@ static w25q_error_codes_t dma_send_toflash(uint8_t *data, uint32_t length) { .win_du = 0, .end = DMA_TRANS_END_POLLING, }; + // Size is in data units (words in this case) + trans.size_d1_du = length>>2; // Validate, load and launch DMA transaction dma_config_flags_t res; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h index 1bc8b5e4..501f69c6 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/bsp/w25q/w25q128jw.h @@ -267,7 +267,7 @@ w25q_error_codes_t w25q128jw_erase_and_write_standard(uint32_t addr, void* data, * @param length number of bytes to read. * @return FLASH_OK if the read is successful, @ref error_codes otherwise. */ -w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_dma, uint8_t no_sanity_checks); +w25q_error_codes_t w25q128jw_read_standard_dma(uint32_t addr, void *data, uint32_t length, uint8_t no_wait_init_dma, uint8_t no_sanity_checks); /** * @brief Read from flash at standard speed using DMA but wait for DMA in the application diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/base.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/base.h index e0582e74..0d56792b 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/base.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/base.h @@ -106,7 +106,7 @@ typedef enum dif_toggle { // * @param val A potential dif_toggle_t value. // * @return Bool indicating validity of toggle value. // */ -// inline bool dif_is_valid_toggle(dif_toggle_t val) { +// static inline bool dif_is_valid_toggle(dif_toggle_t val) { // switch (val) { // case kDifToggleEnabled: // return true; @@ -123,7 +123,7 @@ typedef enum dif_toggle { // * @param val A dif_toggle_t value. // * @return Corresponding bool value. // */ -// inline bool dif_toggle_to_bool(dif_toggle_t val) { +// static inline bool dif_toggle_to_bool(dif_toggle_t val) { // switch (val) { // case kDifToggleEnabled: // return true; @@ -140,7 +140,7 @@ typedef enum dif_toggle { // * @param val A bool value. // * @return Corresponding dif_toggle_t value. // */ -// inline dif_toggle_t dif_bool_to_toggle(bool val) { +// static inline dif_toggle_t dif_bool_to_toggle(bool val) { // return val ? kDifToggleEnabled : kDifToggleDisabled; // } @@ -150,7 +150,7 @@ typedef enum dif_toggle { // * @param val A multi-bit bool value. // * @return Corresponding dif_toggle_t value. // */ -// inline dif_toggle_t dif_multi_bit_bool_to_toggle(multi_bit_bool_t val) { +// static inline dif_toggle_t dif_multi_bit_bool_to_toggle(multi_bit_bool_t val) { // switch (val) { // case kMultiBitBool4True: // case kMultiBitBool8True: @@ -169,7 +169,7 @@ typedef enum dif_toggle { // * @return Corresponding `multi_bit_bool_t` value. Invalid values resolve to // * "false". // */ -// inline multi_bit_bool_t dif_toggle_to_multi_bit_bool4(dif_toggle_t val) { +// static inline multi_bit_bool_t dif_toggle_to_multi_bit_bool4(dif_toggle_t val) { // if (val == kDifToggleEnabled) { // return kMultiBitBool4True; // } else { @@ -184,7 +184,7 @@ typedef enum dif_toggle { // * @return Corresponding `multi_bit_bool_t` value. Invalid values resolve to // * "false". // */ -// inline multi_bit_bool_t dif_toggle_to_multi_bit_bool8(dif_toggle_t val) { +// static inline multi_bit_bool_t dif_toggle_to_multi_bit_bool8(dif_toggle_t val) { // if (val == kDifToggleEnabled) { // return kMultiBitBool8True; // } else { @@ -199,7 +199,7 @@ typedef enum dif_toggle { // * @return Corresponding `multi_bit_bool_t` value. Invalid values resolve to // * "false". // */ -// inline multi_bit_bool_t dif_toggle_to_multi_bit_bool12(dif_toggle_t val) { +// static inline multi_bit_bool_t dif_toggle_to_multi_bit_bool12(dif_toggle_t val) { // if (val == kDifToggleEnabled) { // return kMultiBitBool12True; // } else { @@ -214,7 +214,7 @@ typedef enum dif_toggle { // * @return Corresponding `multi_bit_bool_t` value. Invalid values resolve to // * "false". // */ -// inline multi_bit_bool_t dif_toggle_to_multi_bit_bool16(dif_toggle_t val) { +// static inline multi_bit_bool_t dif_toggle_to_multi_bit_bool16(dif_toggle_t val) { // if (val == kDifToggleEnabled) { // return kMultiBitBool16True; // } else { diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.c deleted file mode 100644 index b2562c0d..00000000 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.c +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include "bitfield.h" - -// `extern` declarations to give the inline functions in the -// corresponding header a link location. - -extern uint32_t bitfield_field32_read(uint32_t bitfield, - bitfield_field32_t field); -extern uint32_t bitfield_field32_write(uint32_t bitfield, - bitfield_field32_t field, - uint32_t value); - -extern bitfield_field32_t bitfield_bit32_to_field32( - bitfield_bit32_index_t bit_index); - -extern bool bitfield_bit32_read(uint32_t bitfield, - bitfield_bit32_index_t bit_index); -extern uint32_t bitfield_bit32_write(uint32_t bitfield, - bitfield_bit32_index_t bit_index, - bool value); - -extern int32_t bitfield_find_first_set32(int32_t bitfield); -extern int32_t bitfield_count_leading_zeroes32(uint32_t bitfield); -extern int32_t bitfield_count_trailing_zeroes32(uint32_t bitfield); -extern int32_t bitfield_popcount32(uint32_t bitfield); -extern int32_t bitfield_parity32(uint32_t bitfield); -extern uint32_t bitfield_byteswap32(uint32_t bitfield); diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.h index e2b81b83..19377e35 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/bitfield.h @@ -74,7 +74,7 @@ typedef struct bitfield_field32 { * @return Zero-extended `field` from `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_field32_read(uint32_t bitfield, +static inline uint32_t bitfield_field32_read(uint32_t bitfield, bitfield_field32_t field) { return (bitfield >> field.index) & field.mask; } @@ -92,7 +92,7 @@ inline uint32_t bitfield_field32_read(uint32_t bitfield, * @return `bitfield` with `field` set to `value`. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_field32_write(uint32_t bitfield, +static inline uint32_t bitfield_field32_write(uint32_t bitfield, bitfield_field32_t field, uint32_t value) { bitfield &= ~(field.mask << field.index); @@ -123,7 +123,7 @@ typedef uint32_t bitfield_bit32_index_t; * @return A 1-bit field that corresponds to `bit_index`. */ BITFIELD_WARN_UNUSED_RESULT -inline bitfield_field32_t bitfield_bit32_to_field32( +static inline bitfield_field32_t bitfield_bit32_to_field32( bitfield_bit32_index_t bit_index) { return (bitfield_field32_t){ .mask = 0x1, .index = bit_index, @@ -138,7 +138,7 @@ inline bitfield_field32_t bitfield_bit32_to_field32( * @return `true` if the bit was one, `false` otherwise. */ BITFIELD_WARN_UNUSED_RESULT -inline bool bitfield_bit32_read(uint32_t bitfield, +static inline bool bitfield_bit32_read(uint32_t bitfield, bitfield_bit32_index_t bit_index) { return bitfield_field32_read(bitfield, bitfield_bit32_to_field32(bit_index)) == 0x1u; @@ -153,7 +153,7 @@ inline bool bitfield_bit32_read(uint32_t bitfield, * @return `bitfield` with the `bit_index`th bit set to `value`. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_bit32_write(uint32_t bitfield, +static inline uint32_t bitfield_bit32_write(uint32_t bitfield, bitfield_bit32_index_t bit_index, bool value) { return bitfield_field32_write(bitfield, bitfield_bit32_to_field32(bit_index), @@ -174,7 +174,7 @@ inline uint32_t bitfield_bit32_write(uint32_t bitfield, * @return Zero-extended `field` from `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_read(uint32_t bitfield, +static inline uint32_t bitfield_read(uint32_t bitfield, uint32_t mask, uint32_t index) { @@ -195,7 +195,7 @@ inline uint32_t bitfield_read(uint32_t bitfield, * @return `bitfield` with `field` set to `value`. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_write(uint32_t bitfield, +static inline uint32_t bitfield_write(uint32_t bitfield, uint32_t mask, uint32_t index, uint32_t value) @@ -223,7 +223,7 @@ inline uint32_t bitfield_write(uint32_t bitfield, * @return One plus the index of the least-significant 1-bit of `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline int32_t bitfield_find_first_set32(int32_t bitfield) { +static inline int32_t bitfield_find_first_set32(int32_t bitfield) { return __builtin_ffs(bitfield); } @@ -247,7 +247,7 @@ inline int32_t bitfield_find_first_set32(int32_t bitfield) { * @return The number of leading 0-bits in `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline int32_t bitfield_count_leading_zeroes32(uint32_t bitfield) { +static inline int32_t bitfield_count_leading_zeroes32(uint32_t bitfield) { return (bitfield != 0) ? __builtin_clz(bitfield) : 32; } @@ -271,7 +271,7 @@ inline int32_t bitfield_count_leading_zeroes32(uint32_t bitfield) { * @return The number of trailing 0-bits in `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline int32_t bitfield_count_trailing_zeroes32(uint32_t bitfield) { +static inline int32_t bitfield_count_trailing_zeroes32(uint32_t bitfield) { return (bitfield != 0) ? __builtin_ctz(bitfield) : 32; } @@ -293,7 +293,7 @@ inline int32_t bitfield_count_trailing_zeroes32(uint32_t bitfield) { * @return The number of 1-bits in `bitfield`. */ BITFIELD_WARN_UNUSED_RESULT -inline int32_t bitfield_popcount32(uint32_t bitfield) { +static inline int32_t bitfield_popcount32(uint32_t bitfield) { return __builtin_popcount(bitfield); } @@ -315,7 +315,7 @@ inline int32_t bitfield_popcount32(uint32_t bitfield) { * @return The number of 1-bits in `bitfield`, modulo 2. */ BITFIELD_WARN_UNUSED_RESULT -inline int32_t bitfield_parity32(uint32_t bitfield) { +static inline int32_t bitfield_parity32(uint32_t bitfield) { return __builtin_parity(bitfield); } @@ -338,7 +338,7 @@ inline int32_t bitfield_parity32(uint32_t bitfield) { * @return `bitfield` with the order of bytes reversed. */ BITFIELD_WARN_UNUSED_RESULT -inline uint32_t bitfield_byteswap32(uint32_t bitfield) { +static inline uint32_t bitfield_byteswap32(uint32_t bitfield) { return __builtin_bswap32(bitfield); } diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c index e0234bf1..a534074e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.c @@ -8,9 +8,6 @@ extern "C" { #include "memory.h" -extern uint32_t read_32(const void *); -extern void write_32(uint32_t, void *); - // Some symbols below are only defined for device builds. For host builds, we // their implementations will be provided by the host's libc implementation. // diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h index 3ff64ff7..7f91de70 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/memory.h @@ -55,7 +55,7 @@ extern "C" { * @param ptr a word-aligned pointer pointed to at least four bytes of memory. * @return the word `ptr` points to. */ -inline uint32_t read_32(const void *ptr) { +static inline uint32_t read_32(const void *ptr) { // Both GCC and Clang optimize the code below into a single word-load on most // platforms. It is necessary and sufficient to indicate to the compiler that // the pointer points to four bytes of four-byte-aligned memory. @@ -86,7 +86,7 @@ inline uint32_t read_32(const void *ptr) { * @param value the value to store. * @param ptr a word-aligned pointer pointed to at least four bytes of memory. */ -inline void write_32(uint32_t value, void *ptr) { +static inline void write_32(uint32_t value, void *ptr) { // Both GCC and Clang optimize the code below into a single word-store on most // platforms. See the comment in `read_32()` for more implementation-private // information. diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c index dff7f78a..be75927d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.c @@ -125,45 +125,6 @@ void mmio_region_memcpy_to_mmio32(mmio_region_t base, uint32_t offset, mmio_region_memcpy32(base, offset, (void *)src, len, false); } -// `extern` declarations to give the inline functions in the -// corresponding header a link location. -extern uint8_t mmio_region_read8(mmio_region_t base, ptrdiff_t offset); -extern uint32_t mmio_region_read32(mmio_region_t base, ptrdiff_t offset); -extern void mmio_region_write8(mmio_region_t base, ptrdiff_t offset, - uint8_t value); -extern void mmio_region_write32(mmio_region_t base, ptrdiff_t offset, - uint32_t value); -extern uint32_t mmio_region_read_mask32(mmio_region_t base, ptrdiff_t offset, - uint32_t mask, uint32_t mask_index); -extern bool mmio_region_get_bit32(mmio_region_t base, ptrdiff_t offset, - uint32_t bit_index); -extern void mmio_region_nonatomic_clear_mask32(mmio_region_t base, - ptrdiff_t offset, uint32_t mask, - uint32_t mask_index); -extern void mmio_region_nonatomic_set_mask32(mmio_region_t base, - ptrdiff_t offset, uint32_t mask, - uint32_t mask_index); -extern void mmio_region_write_only_set_mask32(mmio_region_t base, - ptrdiff_t offset, uint32_t mask, - uint32_t mask_index); -extern void mmio_region_nonatomic_set_field32(mmio_region_t base, - ptrdiff_t offset, - bitfield_field32_t field, - uint32_t value); -extern void mmio_region_write_only_set_field32(mmio_region_t base, - ptrdiff_t offset, - bitfield_field32_t field, - uint32_t value); -extern void mmio_region_nonatomic_clear_bit32(mmio_region_t base, - ptrdiff_t offset, - uint32_t bit_index); -extern void mmio_region_nonatomic_set_bit32(mmio_region_t base, - ptrdiff_t offset, - uint32_t bit_index); -extern void mmio_region_write_only_set_bit32(mmio_region_t base, - ptrdiff_t offset, - uint32_t bit_index); - #ifdef __cplusplus } diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.h index d0b94a46..51173781 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/base/mmio.h @@ -63,7 +63,7 @@ typedef struct mmio_region { volatile void *base; } mmio_region_t; * @return a `mmio_region_t` value representing that region. */ MMIO_WARN_UNUSED_RESULT -inline mmio_region_t mmio_region_from_addr(uintptr_t address) { +static inline mmio_region_t mmio_region_from_addr(uintptr_t address) { return (mmio_region_t){ .base = (volatile void *)address, }; @@ -81,7 +81,7 @@ inline mmio_region_t mmio_region_from_addr(uintptr_t address) { * @return the read value. */ MMIO_WARN_UNUSED_RESULT -inline uint8_t mmio_region_read8(mmio_region_t base, ptrdiff_t offset) { +static inline uint8_t mmio_region_read8(mmio_region_t base, ptrdiff_t offset) { return ((volatile uint8_t *)base.base)[offset / sizeof(uint8_t)]; } @@ -97,7 +97,7 @@ inline uint8_t mmio_region_read8(mmio_region_t base, ptrdiff_t offset) { * @return the read value. */ MMIO_WARN_UNUSED_RESULT -inline uint32_t mmio_region_read32(mmio_region_t base, ptrdiff_t offset) { +static inline uint32_t mmio_region_read32(mmio_region_t base, ptrdiff_t offset) { return ((volatile uint32_t *)base.base)[offset / sizeof(uint32_t)]; } @@ -112,7 +112,7 @@ inline uint32_t mmio_region_read32(mmio_region_t base, ptrdiff_t offset) { * @param offset the offset to write at, in bytes. * @param value the value to write. */ -inline void mmio_region_write8(mmio_region_t base, ptrdiff_t offset, +static inline void mmio_region_write8(mmio_region_t base, ptrdiff_t offset, uint8_t value) { ((volatile uint8_t *)base.base)[offset / sizeof(uint8_t)] = value; } @@ -128,7 +128,7 @@ inline void mmio_region_write8(mmio_region_t base, ptrdiff_t offset, * @param offset the offset to write at, in bytes. * @param value the value to write. */ -inline void mmio_region_write32(mmio_region_t base, ptrdiff_t offset, +static inline void mmio_region_write32(mmio_region_t base, ptrdiff_t offset, uint32_t value) { ((volatile uint32_t *)base.base)[offset / sizeof(uint32_t)] = value; } @@ -171,7 +171,7 @@ void mmio_region_write32(mmio_region_t base, ptrdiff_t offset, uint32_t value); */ MMIO_WARN_UNUSED_RESULT MMIO_DEPRECATED -inline uint32_t mmio_region_read_mask32(mmio_region_t base, ptrdiff_t offset, +static inline uint32_t mmio_region_read_mask32(mmio_region_t base, ptrdiff_t offset, uint32_t mask, uint32_t mask_index) { return bitfield_field32_read( mmio_region_read32(base, offset), @@ -192,7 +192,7 @@ inline uint32_t mmio_region_read_mask32(mmio_region_t base, ptrdiff_t offset, */ MMIO_WARN_UNUSED_RESULT MMIO_DEPRECATED -inline bool mmio_region_get_bit32(mmio_region_t base, ptrdiff_t offset, +static inline bool mmio_region_get_bit32(mmio_region_t base, ptrdiff_t offset, uint32_t bit_index) { return bitfield_bit32_read(mmio_region_read32(base, offset), bit_index); } @@ -209,7 +209,7 @@ inline bool mmio_region_get_bit32(mmio_region_t base, ptrdiff_t offset, * @param mask_index mask position within the selected register. */ MMIO_DEPRECATED -inline void mmio_region_nonatomic_clear_mask32(mmio_region_t base, +static inline void mmio_region_nonatomic_clear_mask32(mmio_region_t base, ptrdiff_t offset, uint32_t mask, uint32_t mask_index) { uint32_t register_value = mmio_region_read32(base, offset); @@ -231,7 +231,7 @@ inline void mmio_region_nonatomic_clear_mask32(mmio_region_t base, * @param mask_index mask position within the selected register. */ MMIO_DEPRECATED -inline void mmio_region_nonatomic_set_mask32(mmio_region_t base, +static inline void mmio_region_nonatomic_set_mask32(mmio_region_t base, ptrdiff_t offset, uint32_t mask, uint32_t mask_index) { uint32_t register_value = mmio_region_read32(base, offset); @@ -253,7 +253,7 @@ inline void mmio_region_nonatomic_set_mask32(mmio_region_t base, * @param mask_index mask position within the selected register. */ MMIO_DEPRECATED -inline void mmio_region_write_only_set_mask32(mmio_region_t base, +static inline void mmio_region_write_only_set_mask32(mmio_region_t base, ptrdiff_t offset, uint32_t mask, uint32_t mask_index) { uint32_t register_value = 0x0u; @@ -278,7 +278,7 @@ inline void mmio_region_write_only_set_mask32(mmio_region_t base, * @param value value to set the field to. */ MMIO_DEPRECATED -inline void mmio_region_nonatomic_set_field32(mmio_region_t base, +static inline void mmio_region_nonatomic_set_field32(mmio_region_t base, ptrdiff_t offset, bitfield_field32_t field, uint32_t value) { @@ -299,7 +299,7 @@ inline void mmio_region_nonatomic_set_field32(mmio_region_t base, * @param value value to set field to. */ MMIO_DEPRECATED -inline void mmio_region_write_only_set_field32(mmio_region_t base, +static inline void mmio_region_write_only_set_field32(mmio_region_t base, ptrdiff_t offset, bitfield_field32_t field, uint32_t value) { @@ -319,7 +319,7 @@ inline void mmio_region_write_only_set_field32(mmio_region_t base, * @param bit_index the bit to clear. */ MMIO_DEPRECATED -inline void mmio_region_nonatomic_clear_bit32(mmio_region_t base, +static inline void mmio_region_nonatomic_clear_bit32(mmio_region_t base, ptrdiff_t offset, uint32_t bit_index) { uint32_t register_value = mmio_region_read32(base, offset); @@ -337,7 +337,7 @@ inline void mmio_region_nonatomic_clear_bit32(mmio_region_t base, * @param bit_index the bit to set. */ MMIO_DEPRECATED -inline void mmio_region_nonatomic_set_bit32(mmio_region_t base, +static inline void mmio_region_nonatomic_set_bit32(mmio_region_t base, ptrdiff_t offset, uint32_t bit_index) { uint32_t register_value = mmio_region_read32(base, offset); @@ -358,7 +358,7 @@ inline void mmio_region_nonatomic_set_bit32(mmio_region_t base, * @param bit_index the bit to set. */ MMIO_DEPRECATED -inline void mmio_region_write_only_set_bit32(mmio_region_t base, +static inline void mmio_region_write_only_set_bit32(mmio_region_t base, ptrdiff_t offset, uint32_t bit_index) { uint32_t register_value = 0x0u; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl index 72d2b2e6..8b8ccfb7 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/crt/crt0.S.tpl @@ -1,153 +1,153 @@ -/* Copyright (c) 2017 SiFive Inc. All rights reserved. - * Copyright (c) 2019 ETH Zürich and University of Bologna - * Copyright (c) 2022 EPFL - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the FreeBSD License. This program is distributed in the hope that - * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, - * including the implied warranties of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. A copy of this license is available at - * http://www.opensource.org/licenses. - */ - -#include "x-heep.h" -#include "core_v_mini_mcu.h" -#include "soc_ctrl_regs.h" - -#define RAMSIZE_COPIEDBY_BOOTROM 2048 - -/* Entry point for bare metal programs */ -.section .text.start -.global _start -.type _start, @function - -_start: -/* initialize global pointer */ -.option push -.option norelax -1: auipc gp, %pcrel_hi(__global_pointer$) - addi gp, gp, %pcrel_lo(1b) -.option pop - -/* initialize stack pointer */ - la sp, _sp - -/* set the frequency */ - li a0, SOC_CTRL_START_ADDRESS - li a2, REFERENCE_CLOCK_Hz - sw a2, SOC_CTRL_SYSTEM_FREQUENCY_HZ_REG_OFFSET(a0) - -#ifdef EXTERNAL_CRTO - #include "external_crt0.S" -#endif - -#ifdef FLASH_LOAD - - call w25q128jw_init_crt0 - - // This assumes ram base address is 0x00000000 and the section .text stars from ram0 (in the first RAMSIZE_COPIEDBY_BOOTROM Byte) - li s1, RAMSIZE_COPIEDBY_BOOTROM - li s2, FLASH_MEM_START_ADDRESS - - // copy the remaining (if any) text and data sections // - // Setup the in/out pointers and copy size knowing 1KiB as already been copied - mv a0, s2 // src ptr (flash) - add a0, a0, s1 - - la a1, _etext - // Skip if everything has already been copied, and copy the data section - blt a1, s1, _load_data_section - - // copy size in bytes, i.e. _etext - RAMSIZE_COPIEDBY_BOOTROM - sub a2, a1, s1 - - // dst ptr (ram) - mv a1, s1 - - // copy the remaining data --> w25q128jw_read_standard(a0 is src addr, a1 is dest ptr data, a2 is length) - - // this sub is redundat as we could have simply set a0 to RAMSIZE_COPIEDBY_BOOTROM+0x0, - // but like this is more readable as we set the FLASH address as memory mapped to FLASH_MEM_START_ADDRESS, and then remove the offset - // as required bz the w25q128jw_read_standard function - sub a0,a0,s2 - call w25q128jw_read_standard - -% for i, section in enumerate(xheep.iter_linker_sections()): -% if section.name != "code": -_load_${section.name}_section: - // src ptr - la a0, _lma_${section.name}_start - // dst ptr - la a1, __${section.name}_start - // copy size in bytes - la a2, _lma_${section.name}_end - sub a2, a2, a0 - - bltz a2, _load_${section.name}_section_end // dont do anything if you do not have something in ${section.name} - - sub a0,a0,s2 - call w25q128jw_read_standard -_load_${section.name}_section_end: - -% endif -% endfor - -#endif - -/* clear the bss segment */ -_init_bss: - la a0, __bss_start - la a2, __bss_end - sub a2, a2, a0 - li a1, 0 - call memset - -#ifdef FLASH_EXEC -/* copy initialized data sections from flash to ram (to be verified, copied from picosoc)*/ - la a0, _sidata - la a1, _sdata - la a2, _edata - bge a1, a2, end_init_data - loop_init_data: - lw a3, 0(a0) - sw a3, 0(a1) - addi a0, a0, 4 - addi a1, a1, 4 - blt a1, a2, loop_init_data - end_init_data: -#endif - -/* set vector table address and vectored mode */ - la a0, __vector_start - ori a0, a0, 0x1 - csrw mtvec, a0 - -/* new-style constructors and destructors */ - la a0, __libc_fini_array - call atexit - call __libc_init_array - -/* call main */ - lw a0, 0(sp) /* a0 = argc */ - addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ - li a2, 0 /* a2 = envp = NULL */ - call main - tail exit - -.size _start, .-_start - -.global _init -.type _init, @function -.global _fini -.type _fini, @function -_init: - call init -_fini: - /* These don't have to do anything since we use init_array/fini_array. Prevent - missing symbol error */ - ret -.size _init, .-_init -.size _fini, .-_fini - - - +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + * Copyright (c) 2019 ETH Zürich and University of Bologna + * Copyright (c) 2022 EPFL + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the FreeBSD License. This program is distributed in the hope that + * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + * including the implied warranties of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. A copy of this license is available at + * http://www.opensource.org/licenses. + */ + +#include "x-heep.h" +#include "core_v_mini_mcu.h" +#include "soc_ctrl_regs.h" + +#define RAMSIZE_COPIEDBY_BOOTROM 2048 + +/* Entry point for bare metal programs */ +.section .text.start +.global _start +.type _start, @function + +_start: +/* initialize global pointer */ +.option push +.option norelax +1: auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) +.option pop + +/* initialize stack pointer */ + la sp, _sp + +/* set the frequency */ + li a0, SOC_CTRL_START_ADDRESS + li a2, REFERENCE_CLOCK_Hz + sw a2, SOC_CTRL_SYSTEM_FREQUENCY_HZ_REG_OFFSET(a0) + +#ifdef EXTERNAL_CRTO + #include "external_crt0.S" +#endif + +#ifdef FLASH_LOAD + + call w25q128jw_init_crt0 + + // This assumes ram base address is 0x00000000 and the section .text stars from ram0 (in the first RAMSIZE_COPIEDBY_BOOTROM Byte) + li s1, RAMSIZE_COPIEDBY_BOOTROM + li s2, FLASH_MEM_START_ADDRESS + + // copy the remaining (if any) text and data sections // + // Setup the in/out pointers and copy size knowing 1KiB as already been copied + mv a0, s2 // src ptr (flash) + add a0, a0, s1 + + la a1, _etext + // Skip if everything has already been copied, and copy the data section + blt a1, s1, _load_data_section + + // copy size in bytes, i.e. _etext - RAMSIZE_COPIEDBY_BOOTROM + sub a2, a1, s1 + + // dst ptr (ram) + mv a1, s1 + + // copy the remaining data --> w25q128jw_read_standard(a0 is src addr, a1 is dest ptr data, a2 is length) + + // this sub is redundat as we could have simply set a0 to RAMSIZE_COPIEDBY_BOOTROM+0x0, + // but like this is more readable as we set the FLASH address as memory mapped to FLASH_MEM_START_ADDRESS, and then remove the offset + // as required bz the w25q128jw_read_standard function + sub a0,a0,s2 + call w25q128jw_read_standard + +% for i, section in enumerate(xheep.iter_linker_sections()): +% if section.name != "code": +_load_${section.name}_section: + // src ptr + la a0, _lma_${section.name}_start + // dst ptr + la a1, __${section.name}_start + // copy size in bytes + la a2, _lma_${section.name}_end + sub a2, a2, a0 + + bltz a2, _load_${section.name}_section_end // dont do anything if you do not have something in ${section.name} + + sub a0,a0,s2 + call w25q128jw_read_standard +_load_${section.name}_section_end: + +% endif +% endfor + +#endif + +/* clear the bss segment */ +_init_bss: + la a0, __bss_start + la a2, __bss_end + sub a2, a2, a0 + li a1, 0 + call memset + +#ifdef FLASH_EXEC +/* copy initialized data sections from flash to ram (to be verified, copied from picosoc)*/ + la a0, _sidata + la a1, _sdata + la a2, _edata + bge a1, a2, end_init_data + loop_init_data: + lw a3, 0(a0) + sw a3, 0(a1) + addi a0, a0, 4 + addi a1, a1, 4 + blt a1, a2, loop_init_data + end_init_data: +#endif + +/* set vector table address and vectored mode */ + la a0, __vector_start + ori a0, a0, 0x1 + csrw mtvec, a0 + +/* new-style constructors and destructors */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +/* call main */ + lw a0, 0(sp) /* a0 = argc */ + addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ + li a2, 0 /* a2 = envp = NULL */ + call main + tail exit + +.size _start, .-_start + +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: + call init +_fini: + /* These don't have to do anything since we use init_array/fini_array. Prevent + missing symbol error */ + ret +.size _init, .-_init +.size _fini, .-_fini + + + diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c index 52097770..3d102314 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.c @@ -125,7 +125,7 @@ typedef enum * @return A configuration flags mask. Each individual flag can be accessed with * a bitwise AND ( ret & DMA_CONFIG_* ). */ -dma_config_flags_t validate_target( dma_target_t *p_tgt ); +dma_config_flags_t validate_target( dma_target_t *p_tgt, dma_trans_t *p_trans ); /** * @brief Creates an environment where targets can be added. An environment @@ -159,17 +159,17 @@ static inline uint8_t get_misalignment_b( uint8_t *p_ptr, * @param p_start Pointer to the beginning of the region. * @param p_end Pointer to the last byte of the environment. * @param p_type The data type to be transferred. - * @param p_size_du The number of data units to be transferred. Must be + * @param p_size_d1_du The number of data units to be transferred. Must be * non-zero. - * @param p_inc_du The size in data units of each increment. + * @param p_inc_d1_du The size in data units of each increment. * @retval 1 There is an outbound. * @retval 0 There is NOT an outbound. */ static inline uint8_t is_region_outbound_1D( uint8_t *p_start, uint8_t *p_end, uint32_t p_type, - uint32_t p_size_du, - uint32_t p_inc_du ); + uint32_t p_size_d1_du, + uint32_t p_inc_d1_du ); /** * @brief Determines whether a given region will fit before the end of an @@ -177,9 +177,9 @@ static inline uint8_t is_region_outbound_1D( uint8_t *p_start, * @param p_start Pointer to the beginning of the region. * @param p_end Pointer to the last byte of the environment. * @param p_type The data type to be transferred. - * @param p_size_du The number of data units to be transferred. Must be + * @param p_size_d1_du The number of data units to be transferred. Must be * non-zero. - * @param p_inc_du The size in data units of each increment. + * @param p_inc_d1_du The size in data units of each increment. * @retval 1 There is an outbound. * @retval 0 There is NOT an outbound. */ @@ -431,8 +431,8 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * A successful target validation has to be done before loading it to the * DMA. */ - uint8_t errorSrc = validate_target( p_trans->src ); - uint8_t errorDst = validate_target( p_trans->dst ); + uint8_t errorSrc = validate_target( p_trans->src, p_trans); + uint8_t errorDst = validate_target( p_trans->dst, p_trans); /* * If there are any errors or warnings in the valdiation of the targets, @@ -538,12 +538,6 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, /* The flags are cleaned in case the structure was used before.*/ p_trans->flags = DMA_CONFIG_OK; - /* The copy size of the source (in data units -of the source-) is - transformed to bytes, to be used as default size.*/ - uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE(p_trans->src->type); - p_trans->size_b = p_trans->src->size_du * dataSize_b; - p_trans->size_d2_b = p_trans->src->size_d2_du * dataSize_b; - p_trans->src_type = p_trans->src->type; p_trans->dst_type = p_trans->dst->type; @@ -645,8 +639,8 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * No further operations are done to prevent corrupting * information that could be useful for debugging purposes. */ - if( ( p_trans->src->inc_du > 1 ) - || ( p_trans->dst->inc_du > 1 ) ) + if( ( p_trans->src->inc_d1_du > 1 ) + || ( p_trans->dst->inc_d1_du > 1 ) ) { p_trans->flags |= DMA_CONFIG_DISCONTINUOUS; p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; @@ -682,7 +676,7 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * No further operations are done to prevent corrupting information * that could be useful for debugging purposes. */ - if(p_trans->src->size_du == 0 || (p_trans->dim == DMA_DIM_CONF_2D && p_trans->src->size_d2_du == 0)) + if(p_trans->size_d1_du == 0 || (p_trans->dim == DMA_DIM_CONF_2D && p_trans->size_d2_du == 0)) { p_trans->flags |= DMA_CONFIG_SRC; p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; @@ -724,8 +718,8 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, p_trans->dst->ptr, p_trans->dst->env->end, p_trans->dst_type, - p_trans->src->size_du, - p_trans->dst->inc_du ); + p_trans->size_d1_du, + p_trans->dst->inc_d1_du ); if( isOutb ) { p_trans->flags |= DMA_CONFIG_DST; @@ -749,7 +743,7 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * this would not cause any error, the transaction is rejected because * it is likely a mistake. */ - if( p_trans->win_du > p_trans->size_b ) + if( p_trans->win_du > p_trans->size_d1_du ) { p_trans->flags |= DMA_CONFIG_WINDOW_SIZE; p_trans->flags |= DMA_CONFIG_CRITICAL_ERROR; @@ -767,7 +761,7 @@ dma_config_flags_t dma_validate_transaction( dma_trans_t *p_trans, * certainty that an real error will occur. */ uint32_t threshold = dma_window_ratio_warning_threshold(); - uint32_t ratio = p_trans->size_b / p_trans->win_du; + uint32_t ratio = p_trans->size_d1_du / p_trans->win_du; if( p_trans->win_du && threshold && ( ratio > threshold) ) @@ -870,16 +864,17 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans) if (p_trans->dim == DMA_DIM_CONF_1D && (p_trans->pad_left_du != 0 || p_trans->pad_right_du != 0)) { p_trans->dim = DMA_DIM_CONF_2D; - p_trans->size_d2_b = DMA_DATA_TYPE_2_SIZE( p_trans->dst_type ); + /* Set the d2 size and increment to just the minimum */ + p_trans->size_d2_du = 1; p_trans->src->inc_d2_du = DMA_DATA_TYPE_2_SIZE( p_trans->dst_type ); - write_register( dma_subsys_per[channel].trans->pad_left_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_left_du, DMA_PAD_LEFT_REG_OFFSET, DMA_PAD_LEFT_PAD_MASK, DMA_PAD_LEFT_PAD_OFFSET, dma_subsys_per[channel].peri); - write_register( dma_subsys_per[channel].trans->pad_right_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_right_du, DMA_PAD_RIGHT_REG_OFFSET, DMA_PAD_RIGHT_PAD_MASK, DMA_PAD_RIGHT_PAD_OFFSET, @@ -887,31 +882,30 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans) } else if (p_trans->dim == DMA_DIM_CONF_2D) { - write_register( dma_subsys_per[channel].trans->pad_top_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_top_du, DMA_PAD_TOP_REG_OFFSET, DMA_PAD_TOP_PAD_MASK, DMA_PAD_TOP_PAD_OFFSET, dma_subsys_per[channel].peri); - write_register( dma_subsys_per[channel].trans->pad_bottom_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_bottom_du, DMA_PAD_BOTTOM_REG_OFFSET, DMA_PAD_BOTTOM_PAD_MASK, DMA_PAD_BOTTOM_PAD_OFFSET, dma_subsys_per[channel].peri); - write_register( dma_subsys_per[channel].trans->pad_left_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_left_du, DMA_PAD_LEFT_REG_OFFSET, DMA_PAD_LEFT_PAD_MASK, DMA_PAD_LEFT_PAD_OFFSET, dma_subsys_per[channel].peri); - write_register( dma_subsys_per[channel].trans->pad_right_du * DMA_DATA_TYPE_2_SIZE( p_trans->src_type ), + write_register( dma_subsys_per[channel].trans->pad_right_du, DMA_PAD_RIGHT_REG_OFFSET, DMA_PAD_RIGHT_PAD_MASK, DMA_PAD_RIGHT_PAD_OFFSET, dma_subsys_per[channel].peri); } - /* * SET THE POINTERS */ @@ -999,7 +993,7 @@ dma_config_flags_t dma_load_transaction( dma_trans_t *p_trans) dma_subsys_per[channel].peri->WINDOW_SIZE = dma_subsys_per[channel].trans->win_du ? dma_subsys_per[channel].trans->win_du - : dma_subsys_per[channel].trans->size_b; + : dma_subsys_per[channel].trans->size_d1_du; /* * SET THE DIMENSIONALITY @@ -1101,7 +1095,7 @@ dma_config_flags_t dma_launch( dma_trans_t *p_trans) if(dma_subsys_per[channel].trans->dim == DMA_DIM_CONF_2D) { - write_register( dma_subsys_per[channel].trans->size_d2_b, + write_register( dma_subsys_per[channel].trans->size_d2_du, DMA_SIZE_D2_REG_OFFSET, DMA_SIZE_D2_SIZE_MASK, DMA_SIZE_D2_SIZE_OFFSET, @@ -1109,7 +1103,7 @@ dma_config_flags_t dma_launch( dma_trans_t *p_trans) ); } - write_register( dma_subsys_per[channel].trans->size_b, + write_register( dma_subsys_per[channel].trans->size_d1_du, DMA_SIZE_D1_REG_OFFSET, DMA_SIZE_D1_SIZE_MASK, DMA_SIZE_D1_SIZE_OFFSET, @@ -1202,7 +1196,7 @@ __attribute__((weak, optimize("O0"))) uint8_t dma_window_ratio_warning_threshold /** **/ /****************************************************************************/ -dma_config_flags_t validate_target( dma_target_t *p_tgt ) +dma_config_flags_t validate_target( dma_target_t *p_tgt, dma_trans_t *p_trans ) { /* Flags variable to pass encountered errors. */ dma_config_flags_t flags = DMA_CONFIG_OK; @@ -1211,14 +1205,14 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) */ /* Increment can be 0 when a trigger is used. */ - DMA_STATIC_ASSERT( p_tgt->inc_du >= 0 && p_tgt->inc_du < 64 , "Increment not valid"); + DMA_STATIC_ASSERT( p_tgt->inc_d1_du >= 0 && p_tgt->inc_d1_du < 64 , "Increment not valid"); /* Increment on D2 has to be 0 for 1D operations */ DMA_STATIC_ASSERT( p_tgt->inc_d2_du >= 0 && p_tgt->inc_d2_du < 4194304 , "Increment d2 not valid"); /* The size could be 0 if the target is only going to be used as a destination. */ - DMA_STATIC_ASSERT( p_tgt->size_du >= 0 && p_tgt->size_du < 65536 , "Size not valid"); + DMA_STATIC_ASSERT( p_tgt->size_d1_du >= 0 && p_tgt->size_d1_du < 65536 , "Size not valid"); /* The size can be 0 or 1 if the target is involved in a 1D padded transaction */ - DMA_STATIC_ASSERT( p_tgt->size_d2_du >= 0 && p_tgt->size_du < 65536 , "Size d2 not valid"); + DMA_STATIC_ASSERT( p_tgt->size_d2_du >= 0 && p_tgt->size_d1_du < 65536 , "Size d2 not valid"); /* The data type must be a valid type */ DMA_STATIC_ASSERT( p_tgt->type < DMA_DATA_TYPE__size , "Source type not valid"); /* The trigger must be among the valid trigger values. */ @@ -1239,32 +1233,29 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) /* Check if the environment was properly formed.*/ flags |= validate_environment( p_tgt->env ); /* - * Check if the target selected size goes beyond the boundaries of + * Check if the transaction size goes beyond the boundaries of * the environment. - * This is only analyzed if a size was defined. */ - if( p_tgt->size_du != 0 ) + + if( p_trans->size_d2_du != 0 ) { - uint8_t isOutb = is_region_outbound_1D( p_tgt->ptr, + uint8_t isOutb = is_region_outbound_2D( p_tgt->ptr, p_tgt->env->end, p_tgt->type, - p_tgt->size_du, - p_tgt->inc_du ); + p_trans->size_d1_du, + p_trans->size_d2_du, + p_tgt->inc_d1_du, + p_tgt->inc_d2_du); if( isOutb ) { flags |= DMA_CONFIG_OUTBOUNDS; } - } - /* Do the same but for 2D case */ - if( p_tgt->size_d2_du != 0 ) - { - uint8_t isOutb = is_region_outbound_2D( p_tgt->ptr, + } else { + uint8_t isOutb = is_region_outbound_1D( p_tgt->ptr, p_tgt->env->end, p_tgt->type, - p_tgt->size_du, - p_tgt->size_d2_du, - p_tgt->inc_du, - p_tgt->inc_d2_du); + p_trans->size_d1_du, + p_tgt->inc_d1_du ); if( isOutb ) { flags |= DMA_CONFIG_OUTBOUNDS; @@ -1290,7 +1281,7 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) if( p_tgt->trig == DMA_TRIG_MEMORY ){ /* If it is a memory region. */ /* It should have an increment. */ - if( ( p_tgt->inc_du == 0 ) ){ + if( ( p_tgt->inc_d1_du == 0 ) ){ flags |= DMA_CONFIG_INCOMPATIBLE; } } @@ -1298,7 +1289,7 @@ dma_config_flags_t validate_target( dma_target_t *p_tgt ) { /* It should not have neither an environment nor an increment. */ if( ( (p_tgt->env != NULL) - || ( p_tgt->inc_du != 0 ) ) ) + || ( p_tgt->inc_d1_du != 0 ) ) ) { flags |= DMA_CONFIG_INCOMPATIBLE; } @@ -1403,8 +1394,8 @@ static inline uint8_t get_misalignment_b( uint8_t *p_ptr, static inline uint8_t is_region_outbound_1D( uint8_t *p_start, uint8_t *p_end, uint32_t p_type, - uint32_t p_size_du, - uint32_t p_inc_du ) + uint32_t p_size_d1_du, + uint32_t p_inc_d1_du ) { /* 000 = A data unit to be copied * xxx = A data unit to be skipped @@ -1420,7 +1411,7 @@ static inline uint8_t is_region_outbound_1D( uint8_t *p_start, * If the environment ends before the last affected byte, then there is * outbound writing and the function returns 1. */ - uint32_t affectedUnits = ( p_size_du - 1 ) * p_inc_du + 1; + uint32_t affectedUnits = ( p_size_d1_du - 1 ) * p_inc_d1_du + 1; uint32_t rangeSize = DMA_DATA_TYPE_2_SIZE(p_type) * affectedUnits; uint32_t lastByteInsideRange = (uint32_t)p_start + rangeSize -1; return ( p_end < lastByteInsideRange ); @@ -1467,8 +1458,8 @@ static inline uint32_t get_increment_b_1D( dma_target_t * p_tgt, */ if( inc_b == 0 ) { - uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); - inc_b = ( p_tgt->inc_du * dataSize_b ); + uint8_t dataSize_d1_du = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); + inc_b = ( p_tgt->inc_d1_du * dataSize_d1_du ); } } return inc_b; @@ -1493,8 +1484,8 @@ static inline uint32_t get_increment_b_2D( dma_target_t * p_tgt, */ if( inc_b == 0 ) { - uint8_t dataSize_b = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); - inc_b = ( p_tgt->inc_d2_du * dataSize_b ); + uint8_t dataSize_d1_du = DMA_DATA_TYPE_2_SIZE( p_tgt->type ); + inc_b = ( p_tgt->inc_d2_du * dataSize_d1_du ); } } return inc_b; diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h index ad87434a..98a4f0f4 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma.h @@ -324,15 +324,11 @@ typedef struct if the target is a peripheral. */ uint8_t* ptr; /*!< Pointer to the start address from/to where data will be copied/pasted. */ - uint8_t inc_du; /*!< How much the pointer will increase + uint8_t inc_d1_du; /*!< How much the pointer will increase every time a read/write operation is done. It is a multiple of the data units. Can be left blank if the target is a peripheral. */ uint32_t inc_d2_du; /*!< How much the D2 pointer will increase every time the DMA finishes to read a #D1 of data units. */ - uint16_t size_du; /*!< The size (in data units) of the data to - be copied. Can be left blank if the target will only be used as destination.*/ - uint16_t size_d2_du; /*!< The size (in data units) of the data - to be copied along D2.*/ dma_data_type_t type; /*!< The type of data to be transferred. Can be left blank if the target will only be used as destination. */ dma_trigger_slot_mask_t trig; /*!< If the target is a peripheral, a @@ -356,10 +352,8 @@ typedef struct copied. - only valid in address mode */ uint16_t inc_b; /*!< A common increment in case both targets need to use one same increment. */ - uint32_t size_b; /*!< The size of the transfer along D1, in bytes (in - contrast, the size stored in the targets is in data units). */ - uint32_t size_d2_b; /*!< The size of the transfer along D2, in bytes (in - contrast, the size stored in the targets is in data units). */ + uint32_t size_d1_du; /*!< The size of the transfer along D1, in data units */ + uint32_t size_d2_du; /*!< The size of the transfer along D2, in data units */ dma_dim_t dim; /*!< Sets the dimensionality of the DMA, either 1D or 2D. */ uint8_t pad_top_du; /*!< Padding at the top of the 2D transfer. */ @@ -421,7 +415,7 @@ __attribute__((optimize("O0"))) void fic_irq_dma(void); */ /* @ToDo: Consider changing the "mask" parameter for a bitfield definition (see dma_regs.h) */ -inline void write_register( uint32_t p_val, +static inline void write_register( uint32_t p_val, uint32_t p_offset, uint32_t p_mask, uint8_t p_sel, diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h index 408b23ae..c0ef3797 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/dma/dma_regs.h @@ -25,15 +25,16 @@ extern "C" { // Addess data pointer (word aligned) #define DMA_ADDR_PTR_REG_OFFSET 0x8 -// Number of bytes to copy from, defined with respect to the first dimension -// - Once a value is written, the copy starts +// Number of elements to copy from, defined with respect to the first +// dimension - Once a value is written, the copy starts #define DMA_SIZE_D1_REG_OFFSET 0xc #define DMA_SIZE_D1_SIZE_MASK 0xffff #define DMA_SIZE_D1_SIZE_OFFSET 0 #define DMA_SIZE_D1_SIZE_FIELD \ ((bitfield_field32_t) { .mask = DMA_SIZE_D1_SIZE_MASK, .index = DMA_SIZE_D1_SIZE_OFFSET }) -// Number of bytes to copy from, defined with respect to the second dimension +// Number of elements to copy from, defined with respect to the second +// dimension #define DMA_SIZE_D2_REG_OFFSET 0x10 #define DMA_SIZE_D2_SIZE_MASK 0xffff #define DMA_SIZE_D2_SIZE_OFFSET 0 diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.c new file mode 100644 index 00000000..af7e20f4 --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.c @@ -0,0 +1,234 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + + Info: This simple HAL is used to load the im2col SPC and to run it. +*/ + +#include "im2col.h" + +uint32_t im2col_spc_base_addr; + +void handler_irq_im2col_spc( void ) +{ + /* Read the IFR to lower the interrupt flag */ + * (volatile uint32_t * )(im2col_spc_base_addr + IM2COL_SPC_SPC_IFR_REG_OFFSET); + return; +} + +void im2col_spc_init(uint32_t im2col_spc_base_addr_i) +{ + if (im2col_spc_base_addr_i == NULL) + { + im2col_spc_base_addr = EXT_PERIPHERAL_START_ADDRESS + 0x4000; + } else { + im2col_spc_base_addr = im2col_spc_base_addr_i; + } +} + +/* Simple function to extract the channel from the channel mask */ +int get_channel_number(uint32_t mask) { + int channel = 0; + + // Check the position of the first set bit + while (mask > 0) { + channel++; + if (mask & 1) { // If the least significant bit is set + return channel - 1; + } + mask >>= 1; // Right shift the mask to check the next bit + } + + // If no bit is set, return -1 indicating no valid channel + return -1; +} + +int im2col_spc_run(im2col_trans_t trans){ + + /* Initializing PLIC */ + if(plic_Init()) + { + return EXIT_FAILURE; + }; + + if(plic_irq_set_priority(EXT_INTR_2, 1)) + { + return EXIT_FAILURE; + }; + + if(plic_irq_set_enabled(EXT_INTR_2, kPlicToggleEnabled)) + { + return EXIT_FAILURE; + }; + + plic_assign_external_irq_handler(EXT_INTR_2, &handler_irq_im2col_spc); + + /* Enable global interrupt for machine-level interrupts */ + CSR_SET_BITS(CSR_REG_MSTATUS, 0x8); + + /* Set mie.MEIE bit to one to enable machine-level external interrupts */ + const uint32_t mask = 1 << 11; + CSR_SET_BITS(CSR_REG_MIE, mask); + + dma_init(NULL); + + /* Write the DMA channel mask that the SPC has access to */ + write_register( trans.ch_mask, + IM2COL_SPC_SPC_CH_MASK_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Write the offset of the DMA channel the SPC has access to */ + write_register( get_channel_number(trans.ch_mask) * DMA_CH_SIZE + DMA_START_ADDRESS, + IM2COL_SPC_SPC_CH_OFFSET_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Write the source */ + write_register( trans.src, + IM2COL_SPC_SRC_PTR_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Write the destination */ + write_register( trans.dst, + IM2COL_SPC_DST_PTR_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Write the datatype */ + write_register( trans.datatype, + IM2COL_SPC_DATA_TYPE_REG_OFFSET, + IM2COL_SPC_DATA_TYPE_DATA_TYPE_MASK, + IM2COL_SPC_DATA_TYPE_DATA_TYPE_OFFSET, + im2col_spc_base_addr ); + + /* Write the filter dimensions */ + write_register( trans.filter_width, + IM2COL_SPC_FW_REG_OFFSET, + IM2COL_SPC_FW_SIZE_MASK, + IM2COL_SPC_FW_SIZE_OFFSET, + im2col_spc_base_addr ); + + write_register( trans.filter_height, + IM2COL_SPC_FH_REG_OFFSET, + IM2COL_SPC_FH_SIZE_MASK, + IM2COL_SPC_FH_SIZE_OFFSET, + im2col_spc_base_addr ); + + /* Write the image dimensions */ + write_register( trans.im_width, + IM2COL_SPC_IW_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + write_register( trans.im_height, + IM2COL_SPC_IH_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Write the CH_COL */ + write_register( trans.num_channels_col, + IM2COL_SPC_CH_COL_REG_OFFSET, + IM2COL_SPC_CH_COL_NUM_MASK, + IM2COL_SPC_CH_COL_NUM_OFFSET, + im2col_spc_base_addr ); + + /* Write n_patches */ + write_register( trans.n_patches_w, + IM2COL_SPC_N_PATCHES_W_REG_OFFSET, + IM2COL_SPC_N_PATCHES_W_NUM_MASK, + IM2COL_SPC_N_PATCHES_W_NUM_OFFSET, + im2col_spc_base_addr ); + + write_register( trans.n_patches_h, + IM2COL_SPC_N_PATCHES_H_REG_OFFSET, + IM2COL_SPC_N_PATCHES_H_NUM_MASK, + IM2COL_SPC_N_PATCHES_H_NUM_OFFSET, + im2col_spc_base_addr ); + + /* Write the padding */ + write_register( trans.left_pad, + IM2COL_SPC_PAD_LEFT_REG_OFFSET, + IM2COL_SPC_PAD_LEFT_PAD_MASK, + IM2COL_SPC_PAD_LEFT_PAD_OFFSET, + im2col_spc_base_addr ); + + write_register( trans.right_pad, + IM2COL_SPC_PAD_RIGHT_REG_OFFSET, + IM2COL_SPC_PAD_RIGHT_PAD_MASK, + IM2COL_SPC_PAD_RIGHT_PAD_OFFSET, + im2col_spc_base_addr ); + + write_register( trans.top_pad, + IM2COL_SPC_PAD_TOP_REG_OFFSET, + IM2COL_SPC_PAD_TOP_PAD_MASK, + IM2COL_SPC_PAD_TOP_PAD_OFFSET, + im2col_spc_base_addr ); + + write_register( trans.bottom_pad, + IM2COL_SPC_PAD_BOTTOM_REG_OFFSET, + IM2COL_SPC_PAD_BOTTOM_PAD_MASK, + IM2COL_SPC_PAD_BOTTOM_PAD_OFFSET, + im2col_spc_base_addr ); + + /* + * Write the strides. With respect to test_2 these are the application-point-of-view + * strides, so they are the same as STRIDE_D1 and STRIDE_D2. + */ + write_register( (int) log2(trans.stride_d1), + IM2COL_SPC_LOG_STRIDES_D1_REG_OFFSET, + IM2COL_SPC_LOG_STRIDES_D1_SIZE_MASK, + IM2COL_SPC_LOG_STRIDES_D1_SIZE_OFFSET, + im2col_spc_base_addr ); + + write_register( (int) log2(trans.stride_d2), + IM2COL_SPC_LOG_STRIDES_D2_REG_OFFSET, + IM2COL_SPC_LOG_STRIDES_D2_SIZE_MASK, + IM2COL_SPC_LOG_STRIDES_D2_SIZE_OFFSET, + im2col_spc_base_addr ); + + /* Write the batch size */ + write_register( trans.batch, + IM2COL_SPC_BATCH_REG_OFFSET, + IM2COL_SPC_BATCH_SIZE_MASK, + IM2COL_SPC_BATCH_SIZE_OFFSET, + im2col_spc_base_addr ); + + /* Write the adapted pad regions */ + write_register( trans.adpt_pad_right, + IM2COL_SPC_ADPT_PAD_RIGHT_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + write_register( trans.adpt_pad_bottom, + IM2COL_SPC_ADPT_PAD_BOTTOM_REG_OFFSET, + 0xffffffff, + 0, + im2col_spc_base_addr ); + + /* Enable the interrupt logic */ + write_register( 0x1, + IM2COL_SPC_INTERRUPT_EN_REG_OFFSET, + 0x1, + IM2COL_SPC_INTERRUPT_EN_EN_BIT, + im2col_spc_base_addr ); + + /* Write the number of channels to start the process */ + write_register( trans.num_channels, + IM2COL_SPC_NUM_CH_REG_OFFSET, + IM2COL_SPC_NUM_CH_NUM_MASK, + IM2COL_SPC_NUM_CH_NUM_OFFSET, + im2col_spc_base_addr ); +} diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.h new file mode 100644 index 00000000..eaefc0af --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col.h @@ -0,0 +1,60 @@ +/* + Copyright EPFL contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 + + Author: Tommaso Terzano + + + Info: This simple HAL is used to load the im2col SPC and to run it. Remember, only one DMA channel + at a time can be used! +*/ + +#ifndef _IM2COL_SPC_ +#define _IM2COL_SPC_ + +#include +#include +#include +#include "dma.h" +#include "im2col_spc_regs.h" +#include "core_v_mini_mcu.h" +#include "x-heep.h" +#include "rv_plic.h" +#include "csr.h" +#include +#include "mmio.h" +#include "hart.h" +#include "fast_intr_ctrl.h" + +/* Transaction structure */ +typedef struct +{ + uint32_t* src; /*!< Target from where the data will be copied. */ + uint32_t* dst; /*!< Target to where the data will be copied. */ + uint32_t ch_mask; /*!< Mask of the channels to be used. */ + uint32_t im_width; /*!< Width of the input image. */ + uint32_t im_height; /*!< Height of the input image. */ + uint32_t filter_width; /*!< Width of the filter. */ + uint32_t filter_height; /*!< Height of the filter. */ + uint32_t num_channels; /*!< Number of channels. */ + uint32_t num_channels_col; /*!< Number of channels to be processed. */ + uint32_t stride_d1; /*!< Stride in the first dimension. */ + uint32_t stride_d2; /*!< Stride in the second dimension. */ + uint32_t batch; /*!< Number of batches. */ + uint32_t n_patches_w; /*!< Number of patches in the width. */ + uint32_t n_patches_h; /*!< Number of patches in the height. */ + uint32_t left_pad; /*!< Padding on the left. */ + uint32_t right_pad; /*!< Padding on the right. */ + uint32_t top_pad; /*!< Padding on the top. */ + uint32_t bottom_pad; /*!< Padding on the bottom. */ + uint32_t adpt_pad_right; /*!< Adaptive padding on the right. */ + uint32_t adpt_pad_bottom; /*!< Adaptive padding on the bottom. */ + uint32_t datatype; /*!< Data type of the input. */ +} im2col_trans_t; + +int im2col_spc_run(im2col_trans_t trans); +void im2col_spc_init(uint32_t im2col_spc_base_addr_i); +__attribute__((weak, optimize("00"))) void handler_irq_im2col_spc(void); + +#endif \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col_spc_regs.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col_spc_regs.h new file mode 100644 index 00000000..ac34172a --- /dev/null +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/drivers/im2col_spc/im2col_spc_regs.h @@ -0,0 +1,188 @@ +// Generated register defines for im2col_spc + +// Copyright information found in source file: +// Copyright EPFL contributors. + +// Licensing information found in source file: +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _IM2COL_SPC_REG_DEFS_ +#define _IM2COL_SPC_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif +// Register width +#define IM2COL_SPC_PARAM_REG_WIDTH 32 + +// Input data pointer (word aligned) +#define IM2COL_SPC_SRC_PTR_REG_OFFSET 0x0 + +// Output data pointer (word aligned) +#define IM2COL_SPC_DST_PTR_REG_OFFSET 0x4 + +// Image width +#define IM2COL_SPC_IW_REG_OFFSET 0x8 +#define IM2COL_SPC_IW_SIZE_MASK 0xffff +#define IM2COL_SPC_IW_SIZE_OFFSET 0 +#define IM2COL_SPC_IW_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_IW_SIZE_MASK, .index = IM2COL_SPC_IW_SIZE_OFFSET }) + +// Image heigth +#define IM2COL_SPC_IH_REG_OFFSET 0xc +#define IM2COL_SPC_IH_SIZE_MASK 0xffff +#define IM2COL_SPC_IH_SIZE_OFFSET 0 +#define IM2COL_SPC_IH_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_IH_SIZE_MASK, .index = IM2COL_SPC_IH_SIZE_OFFSET }) + +// Filter width +#define IM2COL_SPC_FW_REG_OFFSET 0x10 +#define IM2COL_SPC_FW_SIZE_MASK 0xff +#define IM2COL_SPC_FW_SIZE_OFFSET 0 +#define IM2COL_SPC_FW_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_FW_SIZE_MASK, .index = IM2COL_SPC_FW_SIZE_OFFSET }) + +// Filter heigth +#define IM2COL_SPC_FH_REG_OFFSET 0x14 +#define IM2COL_SPC_FH_SIZE_MASK 0xff +#define IM2COL_SPC_FH_SIZE_OFFSET 0 +#define IM2COL_SPC_FH_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_FH_SIZE_MASK, .index = IM2COL_SPC_FH_SIZE_OFFSET }) + +// Batch number +#define IM2COL_SPC_BATCH_REG_OFFSET 0x18 +#define IM2COL_SPC_BATCH_SIZE_MASK 0xff +#define IM2COL_SPC_BATCH_SIZE_OFFSET 0 +#define IM2COL_SPC_BATCH_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_BATCH_SIZE_MASK, .index = IM2COL_SPC_BATCH_SIZE_OFFSET }) + +// Number of channels. When written, the im2col will start executing +#define IM2COL_SPC_NUM_CH_REG_OFFSET 0x1c +#define IM2COL_SPC_NUM_CH_NUM_MASK 0xff +#define IM2COL_SPC_NUM_CH_NUM_OFFSET 0 +#define IM2COL_SPC_NUM_CH_NUM_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_NUM_CH_NUM_MASK, .index = IM2COL_SPC_NUM_CH_NUM_OFFSET }) + +// Number of iterations to perform +#define IM2COL_SPC_CH_COL_REG_OFFSET 0x20 +#define IM2COL_SPC_CH_COL_NUM_MASK 0xffff +#define IM2COL_SPC_CH_COL_NUM_OFFSET 0 +#define IM2COL_SPC_CH_COL_NUM_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_CH_COL_NUM_MASK, .index = IM2COL_SPC_CH_COL_NUM_OFFSET }) + +// Number of patches along W +#define IM2COL_SPC_N_PATCHES_W_REG_OFFSET 0x24 +#define IM2COL_SPC_N_PATCHES_W_NUM_MASK 0xffff +#define IM2COL_SPC_N_PATCHES_W_NUM_OFFSET 0 +#define IM2COL_SPC_N_PATCHES_W_NUM_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_N_PATCHES_W_NUM_MASK, .index = IM2COL_SPC_N_PATCHES_W_NUM_OFFSET }) + +// Number of patches along H +#define IM2COL_SPC_N_PATCHES_H_REG_OFFSET 0x28 +#define IM2COL_SPC_N_PATCHES_H_NUM_MASK 0xffff +#define IM2COL_SPC_N_PATCHES_H_NUM_OFFSET 0 +#define IM2COL_SPC_N_PATCHES_H_NUM_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_N_PATCHES_H_NUM_MASK, .index = IM2COL_SPC_N_PATCHES_H_NUM_OFFSET }) + +// Adapted right padded region +#define IM2COL_SPC_ADPT_PAD_RIGHT_REG_OFFSET 0x2c +#define IM2COL_SPC_ADPT_PAD_RIGHT_SIZE_MASK 0xff +#define IM2COL_SPC_ADPT_PAD_RIGHT_SIZE_OFFSET 0 +#define IM2COL_SPC_ADPT_PAD_RIGHT_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_ADPT_PAD_RIGHT_SIZE_MASK, .index = IM2COL_SPC_ADPT_PAD_RIGHT_SIZE_OFFSET }) + +// Adapted bottom padded region +#define IM2COL_SPC_ADPT_PAD_BOTTOM_REG_OFFSET 0x30 +#define IM2COL_SPC_ADPT_PAD_BOTTOM_SIZE_MASK 0xff +#define IM2COL_SPC_ADPT_PAD_BOTTOM_SIZE_OFFSET 0 +#define IM2COL_SPC_ADPT_PAD_BOTTOM_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_ADPT_PAD_BOTTOM_SIZE_MASK, .index = IM2COL_SPC_ADPT_PAD_BOTTOM_SIZE_OFFSET }) + +// Logarithmic number of strides along D1, set to 1 for no stride +#define IM2COL_SPC_LOG_STRIDES_D1_REG_OFFSET 0x34 +#define IM2COL_SPC_LOG_STRIDES_D1_SIZE_MASK 0xf +#define IM2COL_SPC_LOG_STRIDES_D1_SIZE_OFFSET 0 +#define IM2COL_SPC_LOG_STRIDES_D1_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_LOG_STRIDES_D1_SIZE_MASK, .index = IM2COL_SPC_LOG_STRIDES_D1_SIZE_OFFSET }) + +// Logarithmic number of strides along D2, set to 1 for no stride +#define IM2COL_SPC_LOG_STRIDES_D2_REG_OFFSET 0x38 +#define IM2COL_SPC_LOG_STRIDES_D2_SIZE_MASK 0xf +#define IM2COL_SPC_LOG_STRIDES_D2_SIZE_OFFSET 0 +#define IM2COL_SPC_LOG_STRIDES_D2_SIZE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_LOG_STRIDES_D2_SIZE_MASK, .index = IM2COL_SPC_LOG_STRIDES_D2_SIZE_OFFSET }) + +// Status bit is set to one when the im2col SPC is ready +#define IM2COL_SPC_STATUS_REG_OFFSET 0x3c +#define IM2COL_SPC_STATUS_READY_BIT 0 + +// The DMA will wait for the signal +#define IM2COL_SPC_SLOT_REG_OFFSET 0x40 +#define IM2COL_SPC_SLOT_RX_TRIGGER_SLOT_MASK 0xffff +#define IM2COL_SPC_SLOT_RX_TRIGGER_SLOT_OFFSET 0 +#define IM2COL_SPC_SLOT_RX_TRIGGER_SLOT_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_SLOT_RX_TRIGGER_SLOT_MASK, .index = IM2COL_SPC_SLOT_RX_TRIGGER_SLOT_OFFSET }) +#define IM2COL_SPC_SLOT_TX_TRIGGER_SLOT_MASK 0xffff +#define IM2COL_SPC_SLOT_TX_TRIGGER_SLOT_OFFSET 16 +#define IM2COL_SPC_SLOT_TX_TRIGGER_SLOT_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_SLOT_TX_TRIGGER_SLOT_MASK, .index = IM2COL_SPC_SLOT_TX_TRIGGER_SLOT_OFFSET }) + +// Width/type of the data to transfer +#define IM2COL_SPC_DATA_TYPE_REG_OFFSET 0x44 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_MASK 0x3 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_OFFSET 0 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_DATA_TYPE_DATA_TYPE_MASK, .index = IM2COL_SPC_DATA_TYPE_DATA_TYPE_OFFSET }) +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_VALUE_DMA_32BIT_WORD 0x0 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_VALUE_DMA_16BIT_WORD 0x1 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD 0x2 +#define IM2COL_SPC_DATA_TYPE_DATA_TYPE_VALUE_DMA_8BIT_WORD_2 0x3 + +// Set the top padding +#define IM2COL_SPC_PAD_TOP_REG_OFFSET 0x48 +#define IM2COL_SPC_PAD_TOP_PAD_MASK 0x3f +#define IM2COL_SPC_PAD_TOP_PAD_OFFSET 0 +#define IM2COL_SPC_PAD_TOP_PAD_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_PAD_TOP_PAD_MASK, .index = IM2COL_SPC_PAD_TOP_PAD_OFFSET }) + +// Set the bottom padding +#define IM2COL_SPC_PAD_BOTTOM_REG_OFFSET 0x4c +#define IM2COL_SPC_PAD_BOTTOM_PAD_MASK 0x3f +#define IM2COL_SPC_PAD_BOTTOM_PAD_OFFSET 0 +#define IM2COL_SPC_PAD_BOTTOM_PAD_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_PAD_BOTTOM_PAD_MASK, .index = IM2COL_SPC_PAD_BOTTOM_PAD_OFFSET }) + +// Set the right padding +#define IM2COL_SPC_PAD_RIGHT_REG_OFFSET 0x50 +#define IM2COL_SPC_PAD_RIGHT_PAD_MASK 0x3f +#define IM2COL_SPC_PAD_RIGHT_PAD_OFFSET 0 +#define IM2COL_SPC_PAD_RIGHT_PAD_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_PAD_RIGHT_PAD_MASK, .index = IM2COL_SPC_PAD_RIGHT_PAD_OFFSET }) + +// Set the left padding +#define IM2COL_SPC_PAD_LEFT_REG_OFFSET 0x54 +#define IM2COL_SPC_PAD_LEFT_PAD_MASK 0x3f +#define IM2COL_SPC_PAD_LEFT_PAD_OFFSET 0 +#define IM2COL_SPC_PAD_LEFT_PAD_FIELD \ + ((bitfield_field32_t) { .mask = IM2COL_SPC_PAD_LEFT_PAD_MASK, .index = IM2COL_SPC_PAD_LEFT_PAD_OFFSET }) + +// Interrupt Enable Register +#define IM2COL_SPC_INTERRUPT_EN_REG_OFFSET 0x58 +#define IM2COL_SPC_INTERRUPT_EN_EN_BIT 0 + +// Interrupt Flag Register for the SPC operation +#define IM2COL_SPC_SPC_IFR_REG_OFFSET 0x5c +#define IM2COL_SPC_SPC_IFR_FLAG_BIT 0 + +// Mask that defines which DMA channel the SPC can access +#define IM2COL_SPC_SPC_CH_MASK_REG_OFFSET 0x60 + +// Offset of the DMA channel the SPC can access +#define IM2COL_SPC_SPC_CH_OFFSET_REG_OFFSET 0x64 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _IM2COL_SPC_REG_DEFS_ +// End generated register defines for im2col_spc \ No newline at end of file diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl index 710cf02e..aa4d3b79 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/core_v_mini_mcu.h.tpl @@ -41,6 +41,7 @@ extern "C" { #define DMA_CH_NUM ${dma_ch_count} #define DMA_CH_SIZE 0x${dma_ch_size} +#define DMA_NUM_MASTER_PORTS ${num_dma_master_ports} //switch-on/off peripherals #define PERIPHERAL_START_ADDRESS 0x${peripheral_start_address} diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h index 9759edfb..64e4d090 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/runtime/hart.h @@ -27,7 +27,7 @@ extern "C" { * * This function may behave as if it is a no-op. */ -inline void wait_for_interrupt(void) { asm volatile("wfi"); } +static inline void wait_for_interrupt(void) { asm volatile("wfi"); } #ifdef __cplusplus diff --git a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c index 67371531..8457086d 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c +++ b/hw/vendor/esl_epfl_x_heep/sw/device/lib/sdk/dma/dma_sdk.c @@ -38,7 +38,7 @@ extern "C" static __attribute__((always_inline)) void dma_start(dma *peri, uint32_t size, dma_data_type_t src_type) { - peri->SIZE_D1 = (uint32_t)((size * DMA_DATA_TYPE_2_SIZE(src_type)) & DMA_SIZE_D1_SIZE_MASK); + peri->SIZE_D1 = (uint32_t)((size) & DMA_SIZE_D1_SIZE_MASK); } // Initialize the DMA diff --git a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv index 74755de3..2e43dd14 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv @@ -34,14 +34,14 @@ module ext_bus #( input obi_pkg::obi_req_t heep_debug_master_req_i, output obi_pkg::obi_resp_t heep_debug_master_resp_o, - input obi_pkg::obi_req_t heep_dma_read_ch0_req_i, - output obi_pkg::obi_resp_t heep_dma_read_ch0_resp_o, + input obi_pkg::obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_read_req_i , + output obi_pkg::obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_read_resp_o, - input obi_pkg::obi_req_t heep_dma_write_ch0_req_i, - output obi_pkg::obi_resp_t heep_dma_write_ch0_resp_o, + input obi_pkg::obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_write_req_i, + output obi_pkg::obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_write_resp_o, - input obi_pkg::obi_req_t heep_dma_addr_ch0_req_i, - output obi_pkg::obi_resp_t heep_dma_addr_ch0_resp_o, + input obi_pkg::obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_addr_req_i , + output obi_pkg::obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_addr_resp_o, // External master ports input obi_pkg::obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_master_req_i, @@ -67,7 +67,7 @@ module ext_bus #( obi_req_t [EXT_XBAR_NMASTER-1:0][1:0] demux_xbar_req; obi_resp_t [EXT_XBAR_NMASTER-1:0][1:0] demux_xbar_resp; - // Dummy external master portp (to prevent unused warning) + // Dummy external master port (to prevent unused warning) obi_req_t [EXT_XBAR_NMASTER_RND-1:0] ext_master_req_unused; obi_resp_t [EXT_XBAR_NMASTER_RND-1:0] heep_slave_resp_unused; obi_resp_t [EXT_XBAR_NSLAVE_RND-1:0] ext_slave_resp_unused; @@ -80,9 +80,17 @@ module ext_bus #( assign master_req[CORE_INSTR_IDX] = heep_core_instr_req_i; assign master_req[CORE_DATA_IDX] = heep_core_data_req_i; assign master_req[DEBUG_MASTER_IDX] = heep_debug_master_req_i; - assign master_req[DMA_READ_CH0_IDX] = heep_dma_read_ch0_req_i; - assign master_req[DMA_WRITE_CH0_IDX] = heep_dma_write_ch0_req_i; - assign master_req[DMA_ADDR_CH0_IDX] = heep_dma_addr_ch0_req_i; + + generate + for ( + genvar i = 0; i < core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS; i++ + ) begin : gen_dma_master_req_map + assign master_req[core_v_mini_mcu_pkg::DMA_READ_P0_IDX+i*3] = heep_dma_read_req_i[i]; + assign master_req[core_v_mini_mcu_pkg::DMA_WRITE_P0_IDX+i*3] = heep_dma_write_req_i[i]; + assign master_req[core_v_mini_mcu_pkg::DMA_ADDR_P0_IDX+i*3] = heep_dma_addr_req_i[i]; + end + endgenerate + generate for (genvar i = 0; i < EXT_XBAR_NMASTER; i++) begin : gen_ext_master_req_map assign master_req[SYSTEM_XBAR_NMASTER+i] = demux_xbar_req[i][DEMUX_XBAR_EXT_SLAVE_IDX]; @@ -93,9 +101,16 @@ module ext_bus #( assign heep_core_instr_resp_o = master_resp[CORE_INSTR_IDX]; assign heep_core_data_resp_o = master_resp[CORE_DATA_IDX]; assign heep_debug_master_resp_o = master_resp[DEBUG_MASTER_IDX]; - assign heep_dma_read_ch0_resp_o = master_resp[DMA_READ_CH0_IDX]; - assign heep_dma_write_ch0_resp_o = master_resp[DMA_WRITE_CH0_IDX]; - assign heep_dma_addr_ch0_resp_o = master_resp[DMA_ADDR_CH0_IDX]; + + generate + for ( + genvar i = 0; i < core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS; i++ + ) begin : gen_dma_master_resp_map + assign heep_dma_read_resp_o[i] = master_resp[core_v_mini_mcu_pkg::DMA_READ_P0_IDX+i]; + assign heep_dma_write_resp_o[i] = master_resp[core_v_mini_mcu_pkg::DMA_WRITE_P0_IDX+i]; + assign heep_dma_addr_resp_o[i] = master_resp[core_v_mini_mcu_pkg::DMA_ADDR_P0_IDX+i]; + end + endgenerate // X-HEEP slave requests generate diff --git a/hw/vendor/esl_epfl_x_heep/tb/tb.vlt b/hw/vendor/esl_epfl_x_heep/tb/tb.vlt index 31e1d7cd..6ccdab5b 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/tb.vlt +++ b/hw/vendor/esl_epfl_x_heep/tb/tb.vlt @@ -8,6 +8,8 @@ lint_off -rule UNUSED -file "*tb/testharness.sv" -match "*" lint_off -rule UNUSED -file "*tb/ext_xbar.sv" -match "Signal is not driven, nor used: '*" lint_off -rule UNOPTFLAT -file "*tb/ext_xbar.sv" -match "Signal unoptimizable: Feedback to clock or circular logic: 'testharness.ext_bus_i.__Vcellout__ext_xbar_i__slave_req_o'" lint_off -rule UNDRIVEN -file "*tb/testharness.sv" -match "Signal is not driven: 'jtag_tdo_o'*" +lint_off -rule UNDRIVEN -file "*tb/testharness.sv" -match "Signal is not driven: 'ext_ao_peripheral_req'*" +lint_off -rule UNDRIVEN -file "*tb/testharness.sv" -match "Signal is not driven: 'ext_ao_peripheral_resp'*" lint_off -rule SYNCASYNCNET -file "*tb/testharness.sv" -match "*" lint_off -rule WIDTH -file "*tb/testharness.sv" -match "*" lint_off -rule LITENDIAN -file "*tb/testharness.sv" -match "*" diff --git a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv index 9008beb4..e9a2cd3c 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/testharness.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/testharness.sv @@ -48,7 +48,9 @@ module testharness #( import reg_pkg::*; import testharness_pkg::*; import addr_map_rule_pkg::*; + import core_v_mini_mcu_pkg::*; + localparam AO_SPC_NUM = 1; localparam SWITCH_ACK_LATENCY = 15; localparam EXT_XBAR_NMASTER_RND = USE_EXTERNAL_DEVICE_EXAMPLE ? testharness_pkg::EXT_XBAR_NMASTER : 1; localparam HEEP_EXT_XBAR_NMASTER = USE_EXTERNAL_DEVICE_EXAMPLE ? testharness_pkg::EXT_XBAR_NMASTER : 0; @@ -88,6 +90,9 @@ module testharness #( logic iffifo_in_ready, iffifo_out_valid; logic iffifo_int_o; + // Im2col SPC interrupt signal + logic im2col_spc_done_int_o; + // External DMA slots logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_tx; logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] ext_dma_slot_rx; @@ -110,12 +115,12 @@ module testharness #( obi_resp_t heep_core_data_resp; obi_req_t heep_debug_master_req; obi_resp_t heep_debug_master_resp; - obi_req_t heep_dma_read_ch0_req; - obi_resp_t heep_dma_read_ch0_resp; - obi_req_t heep_dma_write_ch0_req; - obi_resp_t heep_dma_write_ch0_resp; - obi_req_t heep_dma_addr_ch0_req; - obi_resp_t heep_dma_addr_ch0_resp; + obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_read_req; + obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_read_resp; + obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_write_req; + obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_write_resp; + obi_req_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_addr_req; + obi_resp_t [core_v_mini_mcu_pkg::DMA_NUM_MASTER_PORTS-1:0] heep_dma_addr_resp; obi_req_t [EXT_XBAR_NSLAVE-1:0] ext_slave_req; obi_resp_t [EXT_XBAR_NSLAVE-1:0] ext_slave_resp; reg_req_t periph_slave_req; @@ -146,6 +151,12 @@ module testharness #( .X_MISA(fpu_ss_pkg::X_MISA) ) ext_if (); + // External SPC interface signals + reg_req_t [AO_SPC_NUM-1:0] ext_ao_peripheral_req; + reg_rsp_t [AO_SPC_NUM-1:0] ext_ao_peripheral_resp; + + logic [core_v_mini_mcu_pkg::DMA_CH_NUM-1:0] dma_busy; + always_comb begin // All interrupt lines set to zero by default for (int i = 0; i < core_v_mini_mcu_pkg::NEXT_INT; i++) begin @@ -154,6 +165,7 @@ module testharness #( // Re-assign the interrupt lines used here intr_vector_ext[0] = memcopy_intr; intr_vector_ext[1] = iffifo_int_o; + intr_vector_ext[2] = im2col_spc_done_int_o; end //log parameters @@ -178,6 +190,7 @@ module testharness #( end `endif + // X-HEEP system x_heep_system #( .COREV_PULP(COREV_PULP), .FPU(FPU), @@ -259,12 +272,14 @@ module testharness #( .ext_core_data_resp_i(heep_core_data_resp), .ext_debug_master_req_o(heep_debug_master_req), .ext_debug_master_resp_i(heep_debug_master_resp), - .ext_dma_read_ch0_req_o(heep_dma_read_ch0_req), - .ext_dma_read_ch0_resp_i(heep_dma_read_ch0_resp), - .ext_dma_write_ch0_req_o(heep_dma_write_ch0_req), - .ext_dma_write_ch0_resp_i(heep_dma_write_ch0_resp), - .ext_dma_addr_ch0_req_o(heep_dma_addr_ch0_req), - .ext_dma_addr_ch0_resp_i(heep_dma_addr_ch0_resp), + .ext_dma_read_req_o(heep_dma_read_req), + .ext_dma_read_resp_i(heep_dma_read_resp), + .ext_dma_write_req_o(heep_dma_write_req), + .ext_dma_write_resp_i(heep_dma_write_resp), + .ext_dma_addr_req_o(heep_dma_addr_req), + .ext_dma_addr_resp_i(heep_dma_addr_resp), + .ext_ao_peripheral_req_i(ext_ao_peripheral_req), + .ext_ao_peripheral_resp_o(ext_ao_peripheral_resp), .ext_peripheral_slave_req_o(periph_slave_req), .ext_peripheral_slave_resp_i(periph_slave_rsp), .external_subsystem_powergate_switch_no(external_subsystem_powergate_switch_n), @@ -275,7 +290,8 @@ module testharness #( .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n), .ext_dma_slot_tx_i(ext_dma_slot_tx), .ext_dma_slot_rx_i(ext_dma_slot_rx), - .ext_dma_stop_i('0) + .ext_dma_stop_i('0), + .dma_done_o(dma_busy) ); // Testbench external bus @@ -286,28 +302,28 @@ module testharness #( .EXT_XBAR_NMASTER(EXT_XBAR_NMASTER), .EXT_XBAR_NSLAVE (EXT_XBAR_NSLAVE) ) ext_bus_i ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .addr_map_i (EXT_XBAR_ADDR_RULES), - .default_idx_i (SLOW_MEMORY_IDX[LOG_EXT_XBAR_NSLAVE-1:0]), - .heep_core_instr_req_i (heep_core_instr_req), - .heep_core_instr_resp_o (heep_core_instr_resp), - .heep_core_data_req_i (heep_core_data_req), - .heep_core_data_resp_o (heep_core_data_resp), - .heep_debug_master_req_i (heep_debug_master_req), - .heep_debug_master_resp_o (heep_debug_master_resp), - .heep_dma_read_ch0_req_i (heep_dma_read_ch0_req), - .heep_dma_read_ch0_resp_o (heep_dma_read_ch0_resp), - .heep_dma_write_ch0_req_i (heep_dma_write_ch0_req), - .heep_dma_write_ch0_resp_o(heep_dma_write_ch0_resp), - .heep_dma_addr_ch0_req_i (heep_dma_addr_ch0_req), - .heep_dma_addr_ch0_resp_o (heep_dma_addr_ch0_resp), - .ext_master_req_i (ext_master_req), - .ext_master_resp_o (ext_master_resp), - .heep_slave_req_o (heep_slave_req), - .heep_slave_resp_i (heep_slave_resp), - .ext_slave_req_o (ext_slave_req), - .ext_slave_resp_i (ext_slave_resp) + .clk_i (clk_i), + .rst_ni (rst_ni), + .addr_map_i (EXT_XBAR_ADDR_RULES), + .default_idx_i (SLOW_MEMORY_IDX[LOG_EXT_XBAR_NSLAVE-1:0]), + .heep_core_instr_req_i (heep_core_instr_req), + .heep_core_instr_resp_o (heep_core_instr_resp), + .heep_core_data_req_i (heep_core_data_req), + .heep_core_data_resp_o (heep_core_data_resp), + .heep_debug_master_req_i (heep_debug_master_req), + .heep_debug_master_resp_o(heep_debug_master_resp), + .heep_dma_read_req_i (heep_dma_read_req), + .heep_dma_read_resp_o (heep_dma_read_resp), + .heep_dma_write_req_i (heep_dma_write_req), + .heep_dma_write_resp_o (heep_dma_write_resp), + .heep_dma_addr_req_i (heep_dma_addr_req), + .heep_dma_addr_resp_o (heep_dma_addr_resp), + .ext_master_req_i (ext_master_req), + .ext_master_resp_o (ext_master_resp), + .heep_slave_req_o (heep_slave_req), + .heep_slave_resp_i (heep_slave_resp), + .ext_slave_req_o (ext_slave_req), + .ext_slave_resp_i (ext_slave_resp) ); logic pdm; @@ -469,18 +485,20 @@ module testharness #( ) dma_i ( .clk_i, .rst_ni, + .clk_gate_en_ni('1), .ext_dma_stop_i('0), .reg_req_i(ext_periph_slv_req[testharness_pkg::MEMCOPY_CTRL_IDX]), .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::MEMCOPY_CTRL_IDX]), - .dma_read_ch0_req_o(ext_master_req[testharness_pkg::EXT_MASTER0_IDX]), - .dma_read_ch0_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER0_IDX]), - .dma_write_ch0_req_o(ext_master_req[testharness_pkg::EXT_MASTER1_IDX]), - .dma_write_ch0_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER1_IDX]), - .dma_addr_ch0_req_o(), - .dma_addr_ch0_resp_i('0), + .dma_read_req_o(ext_master_req[testharness_pkg::EXT_MASTER0_IDX]), + .dma_read_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER0_IDX]), + .dma_write_req_o(ext_master_req[testharness_pkg::EXT_MASTER1_IDX]), + .dma_write_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER1_IDX]), + .dma_addr_req_o(), + .dma_addr_resp_i('0), .trigger_slot_i('0), .dma_done_intr_o(memcopy_intr), - .dma_window_intr_o() + .dma_window_intr_o(), + .dma_done_o() ); simple_accelerator #( @@ -499,6 +517,20 @@ module testharness #( .acc_write_ch0_resp_i(ext_master_resp[testharness_pkg::EXT_MASTER3_IDX]) ); + im2col_spc im2col_spc_i ( + .clk_i, + .rst_ni, + + .aopb2im2col_resp_i(ext_ao_peripheral_resp[0]), + .im2col2aopb_req_o (ext_ao_peripheral_req[0]), + + .reg_req_i(ext_periph_slv_req[testharness_pkg::IM2COL_SPC_IDX]), + .reg_rsp_o(ext_periph_slv_rsp[testharness_pkg::IM2COL_SPC_IDX]), + + .dma_done_i(dma_busy), + .im2col_spc_done_int_o(im2col_spc_done_int_o) + ); + // AMS external peripheral ams #( .reg_req_t(reg_pkg::reg_req_t), @@ -644,6 +676,7 @@ module testharness #( assign memcopy_intr = '0; assign iffifo_int_o = '0; assign periph_slave_rsp = '0; + assign im2col_spc_done_int_o = '0; end endgenerate diff --git a/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv b/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv index d74011f4..e26afd7a 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/testharness_pkg.sv @@ -31,7 +31,7 @@ package testharness_pkg; }; //slave encoder - localparam EXT_NPERIPHERALS = 4; + localparam EXT_NPERIPHERALS = 5; // Memcopy controller (external peripheral example) localparam logic [31:0] MEMCOPY_CTRL_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h0; @@ -57,6 +57,12 @@ package testharness_pkg; localparam logic [31:0] SIMPLE_ACC_END_ADDRESS = SIMPLE_ACC_START_ADDRESS + SIMPLE_ACC_SIZE; localparam logic [31:0] SIMPLE_ACC_IDX = 32'd3; + // External im2col SPC Peripheral + localparam logic [31:0] IM2COL_SPC_START_ADDRESS = core_v_mini_mcu_pkg::EXT_PERIPHERAL_START_ADDRESS + 32'h04000; + localparam logic [31:0] IM2COL_SPC_SIZE = 32'h100; + localparam logic [31:0] IM2COL_SPC_END_ADDRESS = IM2COL_SPC_START_ADDRESS + IM2COL_SPC_SIZE; + localparam logic [31:0] IM2COL_SPC_IDX = 32'd4; + localparam addr_map_rule_t [EXT_NPERIPHERALS-1:0] EXT_PERIPHERALS_ADDR_RULES = '{ '{ idx: MEMCOPY_CTRL_IDX, @@ -69,6 +75,11 @@ package testharness_pkg; idx: SIMPLE_ACC_IDX, start_addr: SIMPLE_ACC_START_ADDRESS, end_addr: SIMPLE_ACC_END_ADDRESS + }, + '{ + idx: IM2COL_SPC_IDX, + start_addr: IM2COL_SPC_START_ADDRESS, + end_addr: IM2COL_SPC_END_ADDRESS } }; diff --git a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py index 31826540..c187bf54 100755 --- a/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py +++ b/hw/vendor/esl_epfl_x_heep/util/mcu_gen.py @@ -20,6 +20,7 @@ from math import log2 import x_heep_gen.load_config from x_heep_gen.system import BusType +import math class Pad: @@ -209,7 +210,7 @@ def create_pad_ring_bonding(self): self.pad_ring_bonding_bonding += ' .' + self.signal_name + 'oe_i(' + oe_internal_signals + '),' self.x_heep_system_interface += ' inout wire ' + self.signal_name + 'io,' - def __init__(self, name, cell_name, pad_type, pad_mapping, index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, has_attribute, attribute_bits): + def __init__(self, name, cell_name, pad_type, pad_mapping, index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, has_attribute, attribute_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip): self.name = name self.cell_name = cell_name @@ -240,6 +241,12 @@ def __init__(self, name, cell_name, pad_type, pad_mapping, index, pad_active, pa self.is_driven_manually = pad_driven_manually self.do_skip_declaration = pad_skip_declaration + self.layout_index = pad_layout_index + self.layout_orient = pad_layout_orient + self.layout_cell = pad_layout_cell + self.layout_offset = pad_layout_offset + self.layout_skip = pad_layout_skip + if(len(pad_mux_list) == 0): self.signal_name_drive.append(self.signal_name) self.pad_type_drive.append(pad_type) @@ -505,11 +512,51 @@ def len_extracted_peripherals(peripherals): ao_peripherals = extract_peripherals(discard_path(obj['ao_peripherals'])) ao_peripherals_count = len(ao_peripherals) dma_ch_count = ao_peripherals["dma"]["num_channels"] + if int(dma_ch_count, 16) > int('256', 16) or int(dma_ch_count, 16) == 0: exit("Number of DMA channels has to be between 0 and 256, excluded") dma_ch_size = ao_peripherals["dma"]["ch_length"] + # Number of master ports for the dma subsystem + num_dma_master_ports = ao_peripherals["dma"]["num_master_ports"] + if int(num_dma_master_ports, 16) > int(dma_ch_count, 16) or int(num_dma_master_ports, 16) == 0: + exit("Number of DMA master ports has to be between 0 and " + str(dma_ch_count) + ", 0 excluded") + + # Number of masters for each slave of the DMA NtoM xbar + num_dma_xbar_channels_per_master_port = ao_peripherals["dma"]["num_channels_per_master_port"] + if (int(num_dma_xbar_channels_per_master_port, 16) > int(dma_ch_count, 16) and int(dma_ch_count, 16) != 1) or int(num_dma_xbar_channels_per_master_port, 16) == 0: + exit("Number of DMA channels per system bus master ports has to be between 0 and " + str(dma_ch_count) + ", excluded") + + if (int(num_dma_master_ports) > 1): + # Computation of full_masters_xbars + temp_full_masters_xbars = math.floor(int(dma_ch_count) / int(num_dma_xbar_channels_per_master_port)) + if temp_full_masters_xbars < int(num_dma_master_ports) and temp_full_masters_xbars * int(num_dma_xbar_channels_per_master_port) == int(dma_ch_count): + full_masters_xbars = temp_full_masters_xbars - 1 + else: + full_masters_xbars = temp_full_masters_xbars + last = int(num_dma_xbar_channels_per_master_port) * full_masters_xbars + + # Array initialization + array_xbar_gen = [0] * int(num_dma_master_ports) + + # Computation of the number of xbar channels for each master port + for i in range(int(num_dma_master_ports)): + if i < full_masters_xbars: + array_xbar_gen[i] = int(num_dma_xbar_channels_per_master_port) + else: + array_xbar_gen[i] = min(int(dma_ch_count) - last, int(dma_ch_count) - last - (int(num_dma_master_ports) - i - 1)) + last = last + array_xbar_gen[i] + + if (sum(array_xbar_gen) != int(dma_ch_count) or 0 in array_xbar_gen): + exit("Error in the DMA xbar generation: wrong parameters") + + dma_xbar_array = ", ".join(map(str, array_xbar_gen)) + else: + if (int(num_dma_xbar_channels_per_master_port) != int(dma_ch_count)): + exit("With 1 master port, the number of DMA channels per master port has to be equal to the number of DMA channels") + dma_xbar_array = "default: 1" + peripheral_start_address = string2int(obj['peripherals']['address']) if int(peripheral_start_address, 16) < int('10000', 16): exit("peripheral start address must be greater than 0x10000") @@ -625,6 +672,31 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_keep_internal = False + try: + pad_layout_orient = pads[key]['layout_attributes']['orient'] + except KeyError: + pad_layout_orient = None + + try: + pad_layout_cell = pads[key]['layout_attributes']['cell'] + except KeyError: + pad_layout_cell = None + + try: + pad_layout_offset = pads[key]['layout_attributes']['offset'] + except KeyError: + pad_layout_offset = None + + try: + pad_layout_skip = pads[key]['layout_attributes']['skip'] + except KeyError: + pad_layout_skip = None + + try: + pad_layout_index = pads[key]['layout_attributes']['index'] + except KeyError: + pad_layout_index = None + pad_mux_list = [] for pad_mux in pad_mux_list_hjson: @@ -650,13 +722,13 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_skip_declaration_mux = False - p = Pad(pad_mux, '', pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) + p = Pad(pad_mux, '', pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) pad_mux_list.append(p) if pad_num > 1: for p in range(pad_num): pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) if not pad_keep_internal: pad_obj.create_pad_ring() pad_obj.create_core_v_mini_mcu_ctrl() @@ -675,7 +747,7 @@ def len_extracted_peripherals(peripherals): else: pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, pad_index_counter, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) if not pad_keep_internal: pad_obj.create_pad_ring() pad_obj.create_core_v_mini_mcu_ctrl() @@ -736,6 +808,31 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_skip_declaration = False + try: + pad_layout_orient = external_pads[key]['layout_attributes']['orient'] + except KeyError: + pad_layout_orient = None + + try: + pad_layout_cell = external_pads[key]['layout_attributes']['cell'] + except KeyError: + pad_layout_cell = None + + try: + pad_layout_offset = external_pads[key]['layout_attributes']['offset'] + except KeyError: + pad_layout_offset = None + + try: + pad_layout_skip = external_pads[key]['layout_attributes']['skip'] + except KeyError: + pad_layout_skip = None + + try: + pad_layout_index = external_pads[key]['layout_attributes']['index'] + except KeyError: + pad_layout_index = None + pad_mux_list = [] for pad_mux in pad_mux_list_hjson: @@ -761,13 +858,13 @@ def len_extracted_peripherals(peripherals): except KeyError: pad_skip_declaration_mux = False - p = Pad(pad_mux, '', external_pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits) + p = Pad(pad_mux, '', external_pads[key]['mux'][pad_mux]['type'], pad_mapping, 0, pad_active_mux, pad_driven_manually_mux, pad_skip_declaration_mux, [], pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) pad_mux_list.append(p) if pad_num > 1: for p in range(pad_num): pad_cell_name = "pad_" + key + "_" + str(p+pad_offset) + "_i" - pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name + "_" + str(p+pad_offset), pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) pad_obj.create_pad_ring() pad_obj.create_pad_ring_bonding() pad_obj.create_internal_signals() @@ -783,7 +880,7 @@ def len_extracted_peripherals(peripherals): else: pad_cell_name = "pad_" + key + "_i" - pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits) + pad_obj = Pad(pad_name, pad_cell_name, pad_type, pad_mapping, external_pad_index, pad_active, pad_driven_manually, pad_skip_declaration, pad_mux_list, pads_attributes!=None, pads_attributes_bits, pad_layout_index, pad_layout_orient, pad_layout_cell, pad_layout_offset, pad_layout_skip) pad_obj.create_pad_ring() pad_obj.create_pad_ring_bonding() pad_obj.create_internal_signals() @@ -828,6 +925,9 @@ def len_extracted_peripherals(peripherals): "ao_peripherals_count" : ao_peripherals_count, "dma_ch_count" : dma_ch_count, "dma_ch_size" : dma_ch_size, + "num_dma_master_ports" : num_dma_master_ports, + "num_dma_xbar_channels_per_master_port" : num_dma_xbar_channels_per_master_port, + "dma_xbar_masters_array" : dma_xbar_array, "peripheral_start_address" : peripheral_start_address, "peripheral_size_address" : peripheral_size_address, "peripherals" : peripherals, diff --git a/hw/vendor/esl_epfl_x_heep/util/test_all.sh b/hw/vendor/esl_epfl_x_heep/util/test_all.sh index dd0d0374..99ad0084 100755 --- a/hw/vendor/esl_epfl_x_heep/util/test_all.sh +++ b/hw/vendor/esl_epfl_x_heep/util/test_all.sh @@ -174,7 +174,7 @@ SIMULATOR='' declare -a LINKERS=( ) # Simulation timeout to prevent apps from running infinitely -SIM_TIMEOUT_S=120 # This time, in seconds, was chosen empirically. +SIM_TIMEOUT_S=240 # This time, in seconds, was chosen empirically. # Prevent the re-generation of the mcu and the simualtion model on every # execution by changing DEBUG to 1 diff --git a/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core b/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core index 98252573..0caaea00 100644 --- a/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core +++ b/hw/vendor/esl_epfl_x_heep/x-heep-tb-utils.core @@ -17,6 +17,7 @@ filesets: - example:ip:iffifo - example:ip:i2s_microphone - example:ip:simple_accelerator + - example:ip:im2col_spc files: file_type: systemVerilogSource @@ -26,6 +27,7 @@ filesets: - hw/ip_examples/ams/ams.vlt - hw/ip_examples/iffifo/iffifo.vlt - hw/ip_examples/simple_accelerator/simple_accelerator.vlt + - hw/ip_examples/im2col_spc/im2col_spc.vlt - tb/tb.vlt file_type: vlt diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index ee180557..c62e55c8 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/Luigi2898/x-heep.git - rev: 798fd6ffc9193b613f5a85f54a496bfcc149a07d + rev: 83f1563fd4894787167b27099006c8b1b042d3d1 } } From 7fd73a7cafbea3d1324b61160ba63351d396cdd7 Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 8 Oct 2024 12:17:43 +0200 Subject: [PATCH 23/27] Updating HEEPsilon to the final version, plus fixing CGRA memory generation conflicts (generate_sram_...tcl(s)) --- Makefile | 4 +- heepsilon.core | 115 ++++++++------ hw/fpga_cgra/cgra_sram_wrapper.sv | 96 +++++++++-- hw/fpga_cgra/scripts/generate_sram_emem.tcl | 26 +++ .../scripts/generate_sram_general.tcl | 150 ++++++++++++++++++ hw/rtl/heepsilon_top.sv | 24 +-- .../esl_epfl_x_heep/configs/general.hjson | 2 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv | 36 +++++ hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv | 5 +- 9 files changed, 379 insertions(+), 79 deletions(-) create mode 100644 hw/fpga_cgra/scripts/generate_sram_emem.tcl create mode 100644 hw/fpga_cgra/scripts/generate_sram_general.tcl diff --git a/Makefile b/Makefile index 5be58865..ad59c028 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,8 @@ PORT ?= /dev/ttyUSB2 EXTERNAL_DOMAINS = 1 PROJECT ?= hello_world -MEMORY_BANKS ?= 2 # Multiple of 2 -MEMORY_BANKS_IL ?= 4 # Power of 2 +#MEMORY_BANKS ?= 2 # Multiple of 2 +#MEMORY_BANKS_IL ?= 4 # Power of 2 export HEEP_DIR = hw/vendor/esl_epfl_x_heep/ include $(HEEP_DIR)Makefile.venv diff --git a/heepsilon.core b/heepsilon.core index b19142a3..b54290ac 100644 --- a/heepsilon.core +++ b/heepsilon.core @@ -100,31 +100,23 @@ filesets: depend: - openhwgroup.org:systems:core-v-mini-mcu-fpga files: - - hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv - - hw/fpga/sram_wrapper.sv - - hw/fpga_cgra/cgra_sram_wrapper.sv - - hw/fpga_cgra/cgra_clock_gate.sv - - hw/fpga_cgra/xilinx_heepsilon_wrapper.sv - file_type: systemVerilogSource - - ip-fpga: - files: - - hw/fpga/scripts/generate_sram.tcl: { file_type: tclSource } - - hw/fpga/prim_xilinx_clk.sv: { file_type: systemVerilogSource } # Here there are the following modules - - hw/fpga/cve2_xilinx_clock_gate.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_input_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_output_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_inout_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_bypass_input_xilinx.sv: { file_type: systemVerilogSource } - - hw/fpga/pad_cell_bypass_output_xilinx.sv: { file_type: systemVerilogSource } + - hw/fpga_cgra/scripts/generate_sram_general.tcl: { file_type: tclSource } + - hw/fpga_cgra/scripts/generate_sram_emem.tcl: { file_type: tclSource } + - hw/vendor/esl_epfl_x_heep/hw/fpga/xilinx_core_v_mini_mcu_wrapper.sv: { file_type: systemVerilogSource } + - hw/fpga_cgra/cgra_sram_wrapper.sv: { file_type: systemVerilogSource } + - hw/fpga_cgra/cgra_clock_gate.sv: { file_type: systemVerilogSource } + - hw/fpga_cgra/xilinx_heepsilon_wrapper.sv: { file_type: systemVerilogSource } - ip-fpga-pynq-z2: + xdc-fpga-pynq-z2: files: - - hw/fpga/scripts/pynq-z2/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + - hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc + - hw/fpga/constraints/pynq-z2/constraints.xdc + file_type: xdc - ip-fpga-zcu104: + xdc-fpga-zcu104: files: - - hw/fpga/scripts/zcu104/xilinx_generate_clk_wizard.tcl: { file_type: tclSource } + - hw/fpga_cgra/constraints/zcu104/pin_assign.xdc + file_type: xdc fpga-arm-emulation: depend: @@ -136,39 +128,67 @@ filesets: - linux_femu/constraints/pin_assign.xdc: {file_type: xdc} - linux_femu/constraints/constraints.xdc: {file_type: xdc} - xdc-fpga-pynq-z2: - files: - - hw/fpga_cgra/constraints/pynq-z2/pin_assign.xdc - - hw/fpga/constraints/pynq-z2/constraints.xdc - file_type: xdc - - xdc-fpga-zcu104: - files: - - hw/fpga_cgra/constraints/zcu104/pin_assign.xdc - file_type: xdc - - netlist-fpga: - files: - - build/openhwgroup.org_systems_core-v-mini-mcu_0/nexys-a7-100t-vivado/core_v_mini_mcu_xiling_postsynth.v - file_type: verilogSource - parameters: COREV_PULP: datatype: int paramtype: vlogparam + description: | + Enables COREV_PULP custom RISC-V extension on the CV32E40P core. Admitted values: 1|0. + default: 0 + FPU: + datatype: int + paramtype: vlogparam + description: | + Enables RV32F RISC-V extension on the CV32E40P core. Admitted values: 1|0. default: 0 JTAG_DPI: datatype: int paramtype: vlogparam + description: | + Enables testbench JTAG DIPs. Admitted values: 1|0. + default: 0 + X_EXT: + datatype: int + paramtype: vlogparam + description: | + Enables CORE-V-XIF interface for the CV32E40X and CV32E40PX cores. Admitted values: 1|0. default: 0 + USE_EXTERNAL_DEVICE_EXAMPLE: + datatype: int + paramtype: vlogparam + description: | + Enables testbench modules compilation. Admitted values: 1|0. + default: 1 USE_UPF: datatype: bool paramtype: vlogdefine - default: false + description: | + Enables simulation with UPF with Modelsim/VCS + REMOVE_OBI_FIFO: + datatype: bool + paramtype: vlogdefine + description: | + Remove the FIFO between the BUS and the peripherals subsystems SYNTHESIS: datatype: bool paramtype: vlogdefine default: false + VERILATOR: #used by SV2V + datatype: bool + paramtype: vlogdefine + default: false + SIM_SYSTEMC: + datatype: bool + paramtype: vlogdefine + default: false + FPGA_SYNTHESIS: + datatype: bool + paramtype: vlogdefine + default: false + FPGA_NEXYS: + datatype: bool + paramtype: vlogdefine + default: false FPGA_ZCU104: datatype: bool paramtype: vlogdefine @@ -285,18 +305,21 @@ targets: description: TUL Pynq-Z2 Board filesets_append: - x_heep_system - - files_rtl_generic # Already added by default? - rtl-fpga - - ip-fpga-pynq-z2 - - ip-fpga - xdc-fpga-pynq-z2 - ext_bus parameters: - - COREV_PULP=0 + - COREV_PULP + - FPU + - X_EXT - SYNTHESIS=true + - REMOVE_OBI_FIFO + - FPGA_SYNTHESIS=true tools: vivado: part: xc7z020clg400-1 + board_part: tul.com.tw:pynq-z2:part0:1.0 + board_repo_paths: [../../../hw/fpga/board_files/vendor/esl_epfl_pynq_z2_board_files] toplevel: [xilinx_heepsilon_wrapper] zcu104: @@ -306,13 +329,15 @@ targets: filesets_append: - x_heep_system - rtl-fpga - - ip-fpga-zcu104 - - ip-fpga - xdc-fpga-zcu104 - ext_bus parameters: - - COREV_PULP=0 + - COREV_PULP + - FPU + - X_EXT - SYNTHESIS=true + - REMOVE_OBI_FIFO + - FPGA_SYNTHESIS=true - FPGA_ZCU104=true tools: vivado: diff --git a/hw/fpga_cgra/cgra_sram_wrapper.sv b/hw/fpga_cgra/cgra_sram_wrapper.sv index 1d924b29..b9b65778 100644 --- a/hw/fpga_cgra/cgra_sram_wrapper.sv +++ b/hw/fpga_cgra/cgra_sram_wrapper.sv @@ -16,25 +16,87 @@ module cgra_sram_wrapper #( input logic [AddrWidth-1:0] addr_i, // request address input logic [ 31:0] wdata_i, // write data input logic [ 3:0] be_i, // write byte enable - input logic set_retentive_i, + input logic set_retentive_ni, // output ports output logic [ 31:0] rdata_o // read data ); - sram_wrapper#( - .NumWords (NumWords), - .DataWidth(DataWidth), - .AddrWidth(AddrWidth) - ) sram_wrapper_i( - .clk_i (clk_i), - .rst_ni (rst_ni), - .req_i (req_i), - .we_i (we_i), - .addr_i (addr_i), - .wdata_i (wdata_i), - .be_i (be_i), - .set_retentive_ni(set_retentive_i), - // output ports - .rdata_o (rdata_o) - ); + + localparam int unsigned NUM_WORDS = NumWords; + + generate + if (NUM_WORDS == 128) begin + xilinx_emem_gen xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 512) begin + xilinx_mem_gen_2k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 1024) begin + xilinx_mem_gen_4k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 2048) begin + xilinx_mem_gen_8k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 4096) begin + xilinx_mem_gen_16k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 8192) begin + xilinx_mem_gen_32k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else if (NUM_WORDS == 16384) begin + xilinx_mem_gen_64k xilinx_sram_i ( + .clka (clk_i), + .ena (req_i), + .wea ({4{req_i & we_i}} & be_i), + .addra(addr_i), + .dina (wdata_i), + // output ports + .douta(rdata_o) + ); + end else begin + $error("Bank size not generated for NumWords = %0d.", NumWords); + end + endgenerate endmodule \ No newline at end of file diff --git a/hw/fpga_cgra/scripts/generate_sram_emem.tcl b/hw/fpga_cgra/scripts/generate_sram_emem.tcl new file mode 100644 index 00000000..2907ec83 --- /dev/null +++ b/hw/fpga_cgra/scripts/generate_sram_emem.tcl @@ -0,0 +1,26 @@ + +set ipName xilinx_emem_gen + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name $ipName + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Algorithm {Minimum_Area} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {128} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips $ipName] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips $ipName] +launch_run -jobs 8 ${ipName}_synth_1 +wait_on_run ${ipName}_synth_1 diff --git a/hw/fpga_cgra/scripts/generate_sram_general.tcl b/hw/fpga_cgra/scripts/generate_sram_general.tcl new file mode 100644 index 00000000..d134f9ed --- /dev/null +++ b/hw/fpga_cgra/scripts/generate_sram_general.tcl @@ -0,0 +1,150 @@ +set ipName xilinx_mem_gen_2k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_2k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {512} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_2k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_2k] +launch_run -jobs 8 xilinx_mem_gen_2k_synth_1 + +set ipName xilinx_mem_gen_4k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_4k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {1024} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_4k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_4k] +launch_run -jobs 8 xilinx_mem_gen_4k_synth_1 + +set ipName xilinx_mem_gen_8k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_8k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {2048} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_8k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_8k] +launch_run -jobs 8 xilinx_mem_gen_8k_synth_1 + +set ipName xilinx_mem_gen_16k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_16k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {4096} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_16k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_16k] +launch_run -jobs 8 xilinx_mem_gen_16k_synth_1 + +set ipName xilinx_mem_gen_32k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_32k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {8192} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_32k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_32k] +launch_run -jobs 8 xilinx_mem_gen_32k_synth_1 + +set ipName xilinx_mem_gen_64k + +create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name xilinx_mem_gen_64k + +set_property -dict [list CONFIG.Enable_32bit_Address {false} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Byte_Size {8} \ + CONFIG.Write_Width_A {32} \ + CONFIG.Write_Depth_A {16384} \ + CONFIG.Read_Width_A {32} \ + CONFIG.Enable_A {Use_ENA_Pin} \ + CONFIG.Write_Width_B {32} \ + CONFIG.Read_Width_B {32} \ + CONFIG.Register_PortA_Output_of_Memory_Primitives {false} \ + CONFIG.Use_RSTA_Pin {false} \ + CONFIG.EN_SAFETY_CKT {false}] [get_ips xilinx_mem_gen_64k] + +#generate_target {instantiation_template} [get_ips $ipName] + +#export_ip_user_files -of_objects [get_ips $ipName] -no_script -sync -force -quiet + +create_ip_run [get_ips xilinx_mem_gen_64k] +launch_run -jobs 8 xilinx_mem_gen_64k_synth_1 + +wait_on_run xilinx_mem_gen_2k_synth_1 +wait_on_run xilinx_mem_gen_4k_synth_1 +wait_on_run xilinx_mem_gen_8k_synth_1 +wait_on_run xilinx_mem_gen_16k_synth_1 +wait_on_run xilinx_mem_gen_32k_synth_1 +wait_on_run xilinx_mem_gen_64k_synth_1 diff --git a/hw/rtl/heepsilon_top.sv b/hw/rtl/heepsilon_top.sv index 6ed60463..70366e66 100644 --- a/hw/rtl/heepsilon_top.sv +++ b/hw/rtl/heepsilon_top.sv @@ -126,12 +126,12 @@ module heepsilon_top #( .heep_core_data_resp_o (heep_core_data_resp), .heep_debug_master_req_i (heep_debug_master_req), .heep_debug_master_resp_o (heep_debug_master_resp), - .heep_dma_read_ch0_req_i (heep_dma_read_ch0_req), - .heep_dma_read_ch0_resp_o (heep_dma_read_ch0_resp), - .heep_dma_write_ch0_req_i (heep_dma_write_ch0_req), - .heep_dma_write_ch0_resp_o(heep_dma_write_ch0_resp), - .heep_dma_addr_ch0_req_i (heep_dma_addr_ch0_req), - .heep_dma_addr_ch0_resp_o (heep_dma_addr_ch0_resp), + .heep_dma_read_req_i (heep_dma_read_ch0_req), + .heep_dma_read_resp_o (heep_dma_read_ch0_resp), + .heep_dma_write_req_i (heep_dma_write_ch0_req), + .heep_dma_write_resp_o(heep_dma_write_ch0_resp), + .heep_dma_addr_req_i (heep_dma_addr_ch0_req), + .heep_dma_addr_resp_o (heep_dma_addr_ch0_resp), .ext_master_req_i (ext_master_req), .ext_master_resp_o(ext_master_resp), @@ -245,12 +245,12 @@ module heepsilon_top #( .ext_core_data_resp_i(heep_core_data_resp), .ext_debug_master_req_o(heep_debug_master_req), .ext_debug_master_resp_i(heep_debug_master_resp), - .ext_dma_read_ch0_req_o(heep_dma_read_ch0_req), - .ext_dma_read_ch0_resp_i(heep_dma_read_ch0_resp), - .ext_dma_write_ch0_req_o(heep_dma_write_ch0_req), - .ext_dma_write_ch0_resp_i(heep_dma_write_ch0_resp), - .ext_dma_addr_ch0_req_o(heep_dma_addr_ch0_req), - .ext_dma_addr_ch0_resp_i(heep_dma_addr_ch0_resp), + .ext_dma_read_req_o(heep_dma_read_ch0_req), + .ext_dma_read_resp_i(heep_dma_read_ch0_resp), + .ext_dma_write_req_o(heep_dma_write_ch0_req), + .ext_dma_write_resp_i(heep_dma_write_ch0_resp), + .ext_dma_addr_req_o(heep_dma_addr_ch0_req), + .ext_dma_addr_resp_i(heep_dma_addr_ch0_resp), .external_subsystem_clkgate_en_no(external_subsystem_clkgate_en_n), .ext_peripheral_slave_req_o(ext_periph_slave_req), .ext_peripheral_slave_resp_i(ext_periph_slave_resp), diff --git a/hw/vendor/esl_epfl_x_heep/configs/general.hjson b/hw/vendor/esl_epfl_x_heep/configs/general.hjson index 0afb35ef..ec460f78 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/general.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/general.hjson @@ -3,7 +3,7 @@ bus_type: "onetoM", ram_banks: { code_and_data: { - num: 2 + num: 8 sizes: [32] } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv index 3ebc1e77..db16c9a3 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv @@ -459,6 +459,42 @@ module core_v_mini_mcu assign memory_subsystem_banks_powergate_iso_n[1] = memory_subsystem_pwr_ctrl_out[1].isogate_en_n; assign memory_subsystem_banks_set_retentive_n[1] = memory_subsystem_pwr_ctrl_out[1].retentive_en_n; assign memory_subsystem_clkgate_en_n[1] = memory_subsystem_pwr_ctrl_out[1].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[2] = memory_subsystem_pwr_ctrl_out[2].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[2].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[2]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[2] = memory_subsystem_pwr_ctrl_out[2].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[2] = memory_subsystem_pwr_ctrl_out[2].retentive_en_n; + assign memory_subsystem_clkgate_en_n[2] = memory_subsystem_pwr_ctrl_out[2].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[3] = memory_subsystem_pwr_ctrl_out[3].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[3].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[3]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[3] = memory_subsystem_pwr_ctrl_out[3].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[3] = memory_subsystem_pwr_ctrl_out[3].retentive_en_n; + assign memory_subsystem_clkgate_en_n[3] = memory_subsystem_pwr_ctrl_out[3].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[4] = memory_subsystem_pwr_ctrl_out[4].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[4].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[4]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[4] = memory_subsystem_pwr_ctrl_out[4].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[4] = memory_subsystem_pwr_ctrl_out[4].retentive_en_n; + assign memory_subsystem_clkgate_en_n[4] = memory_subsystem_pwr_ctrl_out[4].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[5] = memory_subsystem_pwr_ctrl_out[5].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[5].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[5]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[5] = memory_subsystem_pwr_ctrl_out[5].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[5] = memory_subsystem_pwr_ctrl_out[5].retentive_en_n; + assign memory_subsystem_clkgate_en_n[5] = memory_subsystem_pwr_ctrl_out[5].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[6] = memory_subsystem_pwr_ctrl_out[6].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[6].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[6]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[6] = memory_subsystem_pwr_ctrl_out[6].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[6] = memory_subsystem_pwr_ctrl_out[6].retentive_en_n; + assign memory_subsystem_clkgate_en_n[6] = memory_subsystem_pwr_ctrl_out[6].clkgate_en_n; + assign memory_subsystem_banks_powergate_switch_n[7] = memory_subsystem_pwr_ctrl_out[7].pwrgate_en_n; + assign memory_subsystem_pwr_ctrl_in[7].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[7]; + //isogate exposed outside for UPF sim flow and switch cells + assign memory_subsystem_banks_powergate_iso_n[7] = memory_subsystem_pwr_ctrl_out[7].isogate_en_n; + assign memory_subsystem_banks_set_retentive_n[7] = memory_subsystem_pwr_ctrl_out[7].retentive_en_n; + assign memory_subsystem_clkgate_en_n[7] = memory_subsystem_pwr_ctrl_out[7].clkgate_en_n; for (genvar i = 0; i < EXT_DOMAINS_RND; i = i + 1) begin assign external_subsystem_powergate_switch_no[i] = external_subsystem_pwr_ctrl_out[i].pwrgate_en_n; diff --git a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv index 2e43dd14..beed1bcf 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv @@ -137,8 +137,9 @@ module ext_bus #( // show writes if requested always_ff @(posedge clk_i, negedge rst_ni) begin : verbose_writes if ($test$plusargs("verbose") != 0 && heep_core_data_req_i.req && heep_core_data_req_i.we) - $display("write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, - heep_core_data_req_i.wdata); + $display( + "write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, heep_core_data_req_i.wdata + ); end `endif From e97c3081ca42e0db5b579be4241bca81a4c9d96b Mon Sep 17 00:00:00 2001 From: JoseCalero Date: Tue, 8 Oct 2024 12:18:25 +0200 Subject: [PATCH 24/27] deleting fpga xheep link --- hw/fpga | 1 - 1 file changed, 1 deletion(-) delete mode 120000 hw/fpga diff --git a/hw/fpga b/hw/fpga deleted file mode 120000 index b31c1596..00000000 --- a/hw/fpga +++ /dev/null @@ -1 +0,0 @@ -./vendor/esl_epfl_x_heep/hw/fpga \ No newline at end of file From 9da9e3a3a831fb3e7d7599b9bdf5a67e2628a580 Mon Sep 17 00:00:00 2001 From: jmiranda Date: Tue, 8 Oct 2024 14:39:38 +0200 Subject: [PATCH 25/27] revendorizing x-heep to fix ci issues --- .../esl_epfl_x_heep/configs/general.hjson | 2 +- .../hw/core-v-mini-mcu/core_v_mini_mcu.sv | 36 ------------------- hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv | 5 ++- hw/vendor/eslepfl_x_heep.lock.hjson | 2 +- hw/vendor/eslepfl_x_heep.vendor.hjson | 2 +- 5 files changed, 5 insertions(+), 42 deletions(-) diff --git a/hw/vendor/esl_epfl_x_heep/configs/general.hjson b/hw/vendor/esl_epfl_x_heep/configs/general.hjson index ec460f78..0afb35ef 100644 --- a/hw/vendor/esl_epfl_x_heep/configs/general.hjson +++ b/hw/vendor/esl_epfl_x_heep/configs/general.hjson @@ -3,7 +3,7 @@ bus_type: "onetoM", ram_banks: { code_and_data: { - num: 8 + num: 2 sizes: [32] } } diff --git a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv index db16c9a3..3ebc1e77 100644 --- a/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv +++ b/hw/vendor/esl_epfl_x_heep/hw/core-v-mini-mcu/core_v_mini_mcu.sv @@ -459,42 +459,6 @@ module core_v_mini_mcu assign memory_subsystem_banks_powergate_iso_n[1] = memory_subsystem_pwr_ctrl_out[1].isogate_en_n; assign memory_subsystem_banks_set_retentive_n[1] = memory_subsystem_pwr_ctrl_out[1].retentive_en_n; assign memory_subsystem_clkgate_en_n[1] = memory_subsystem_pwr_ctrl_out[1].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[2] = memory_subsystem_pwr_ctrl_out[2].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[2].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[2]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[2] = memory_subsystem_pwr_ctrl_out[2].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[2] = memory_subsystem_pwr_ctrl_out[2].retentive_en_n; - assign memory_subsystem_clkgate_en_n[2] = memory_subsystem_pwr_ctrl_out[2].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[3] = memory_subsystem_pwr_ctrl_out[3].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[3].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[3]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[3] = memory_subsystem_pwr_ctrl_out[3].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[3] = memory_subsystem_pwr_ctrl_out[3].retentive_en_n; - assign memory_subsystem_clkgate_en_n[3] = memory_subsystem_pwr_ctrl_out[3].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[4] = memory_subsystem_pwr_ctrl_out[4].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[4].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[4]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[4] = memory_subsystem_pwr_ctrl_out[4].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[4] = memory_subsystem_pwr_ctrl_out[4].retentive_en_n; - assign memory_subsystem_clkgate_en_n[4] = memory_subsystem_pwr_ctrl_out[4].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[5] = memory_subsystem_pwr_ctrl_out[5].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[5].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[5]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[5] = memory_subsystem_pwr_ctrl_out[5].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[5] = memory_subsystem_pwr_ctrl_out[5].retentive_en_n; - assign memory_subsystem_clkgate_en_n[5] = memory_subsystem_pwr_ctrl_out[5].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[6] = memory_subsystem_pwr_ctrl_out[6].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[6].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[6]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[6] = memory_subsystem_pwr_ctrl_out[6].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[6] = memory_subsystem_pwr_ctrl_out[6].retentive_en_n; - assign memory_subsystem_clkgate_en_n[6] = memory_subsystem_pwr_ctrl_out[6].clkgate_en_n; - assign memory_subsystem_banks_powergate_switch_n[7] = memory_subsystem_pwr_ctrl_out[7].pwrgate_en_n; - assign memory_subsystem_pwr_ctrl_in[7].pwrgate_ack_n = memory_subsystem_banks_powergate_switch_ack_n[7]; - //isogate exposed outside for UPF sim flow and switch cells - assign memory_subsystem_banks_powergate_iso_n[7] = memory_subsystem_pwr_ctrl_out[7].isogate_en_n; - assign memory_subsystem_banks_set_retentive_n[7] = memory_subsystem_pwr_ctrl_out[7].retentive_en_n; - assign memory_subsystem_clkgate_en_n[7] = memory_subsystem_pwr_ctrl_out[7].clkgate_en_n; for (genvar i = 0; i < EXT_DOMAINS_RND; i = i + 1) begin assign external_subsystem_powergate_switch_no[i] = external_subsystem_pwr_ctrl_out[i].pwrgate_en_n; diff --git a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv index beed1bcf..2e43dd14 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv @@ -137,9 +137,8 @@ module ext_bus #( // show writes if requested always_ff @(posedge clk_i, negedge rst_ni) begin : verbose_writes if ($test$plusargs("verbose") != 0 && heep_core_data_req_i.req && heep_core_data_req_i.we) - $display( - "write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, heep_core_data_req_i.wdata - ); + $display("write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, + heep_core_data_req_i.wdata); end `endif diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index c62e55c8..213b5fa1 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -8,7 +8,7 @@ { upstream: { - url: https://github.com/Luigi2898/x-heep.git + url: https://github.com/esl-epfl/x-heep.git rev: 83f1563fd4894787167b27099006c8b1b042d3d1 } } diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index 655e0a58..0dcb0caa 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -7,7 +7,7 @@ target_dir: "esl_epfl_x_heep", upstream: { - url: "https://github.com/Luigi2898/x-heep.git", + url: "https://github.com/esl-epfl/x-heep.git", rev: "83f1563fd4894787167b27099006c8b1b042d3d1", }, From 8a0170b7ba7deb81aa9eef4d660bcb58283184b5 Mon Sep 17 00:00:00 2001 From: jmiranda Date: Tue, 8 Oct 2024 14:58:50 +0200 Subject: [PATCH 26/27] revendorizing x-heep and cgra to fix ci issues --- .../util/INSTRUCTIONS_FFT_SPLITOPS.py | 186 ------------------ .../util/instructions_max_peak.py | 87 -------- .../util/instructions_min_max_circular.py | 83 -------- hw/vendor/esl_epfl_x_heep/Makefile | 12 +- hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt | 58 ++++-- hw/vendor/esl_epfl_x_heep/sw/Makefile | 14 +- .../esl_epfl_x_heep/sw/cmake/targets.mak | 10 +- hw/vendor/eslepfl_cgra.lock.hjson | 2 +- hw/vendor/eslepfl_cgra.vendor.hjson | 2 +- hw/vendor/eslepfl_x_heep.lock.hjson | 2 +- hw/vendor/eslepfl_x_heep.vendor.hjson | 2 +- 11 files changed, 66 insertions(+), 392 deletions(-) delete mode 100644 hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py delete mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py delete mode 100644 hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py diff --git a/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py b/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py deleted file mode 100644 index 75586fca..00000000 --- a/hw/vendor/esl_epfl_cgra/util/INSTRUCTIONS_FFT_SPLITOPS.py +++ /dev/null @@ -1,186 +0,0 @@ -# FFT OUTPUT SPLIT OPS instructions DEPREDECATED - -instructions.append(["NEXT RC"]) - -# RC1_0 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["RF2", "CONST", "SADD", "RF2", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - - -# RC1_1 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF2", "CONST", "SSUB", "RF2", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -################################################################################################# -################################################################################################# -################################################################################################# - -instructions.append(["NEXT RC"]) - -# RC2_0 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF3", "RCT", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCB", "OUT_D", "IN1", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCT", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "EXIT", "RF1", "OFF", "OUT_F", "0"]) - - -# RC2_1 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF3", "RCT", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCL", "OUT_D", "FXP_ADD", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCL", "RCB", "FXP_SUB", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF2", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -################################################################################################# -################################################################################################# -################################################################################################# - -instructions.append(["NEXT RC"]) - -# RC3_0 -# PROLOGUE -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SSUB", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF2", "CONST", "SSUB", "RF2", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCB", "RF1", "SWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - - -# RC3_1 -# PROLOGUE -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SSUB", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "IN1", "RF3", "ON", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "IN1", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF3", "OUT_D", "FXP_MUL", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCT", "RF1", "SWI", "RF1", "OFF", "OUT_F", "0"]) - -################################################################################################# -################################################################################################# -################################################################################################# - -instructions.append(["NEXT RC"]) - -# RC4_0 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCR", "OUT_D", "FXP_MUL", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["RF2", "RCB", "FXP_SUB", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCT", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RCB", "OUT_D", "FXP_ADD", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) - - -# RC4_1 -# PROLOGUE -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF1", "ON", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF2", "ON", "OUT_F", "0"]) -instructions.append(["DATA", "OUT_D", "LWD", "RF3", "ON", "OUT_F", "0"]) - -# ITERATION LOOP -instructions.append(["DATA", "RF1", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF1", "CONST", "SADD", "RF1", "ON", "OUT_F", "4"]) -instructions.append(["DATA", "RF2", "LWI", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF2", "CONST", "SADD", "RF2", "ON", "OUT_F", "4"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF4", "CONST", "SADD", "RF4", "ON", "OUT_F", "1"]) -instructions.append(["ZEROS", "OUT_D", "NOP", "RF1", "OFF", "OUT_F", "0"]) -instructions.append(["RF4", "RF3", "BLT", "RF1", "OFF", "OUT_F", "6"]) - - -################################################################################################# -################################################################################################# -################################################################################################# - -kernel_col_needed = "0011" -row_st_add = 58 -n_instructions = 14 diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py b/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py deleted file mode 100644 index 5c236c82..00000000 --- a/hw/vendor/esl_epfl_cgra/util/instructions_max_peak.py +++ /dev/null @@ -1,87 +0,0 @@ -# -# MAX_PEAK search instructions DEPREDECATED -# - -ker_col_needed = 1 -ker_num_instr = 11 - -ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ - get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ - get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) - -# Save current start address -start_add = ker_start_add -# Update start address and ID for next kernel -ker_start_add = ker_start_add + ker_num_instr*ker_col_needed -ker_next_id = ker_next_id+1 - -# Used for multi-column kernels -k = ker_num_instr - -################################################################################################# -############################################## RC0 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[0][start_add+ 0] = rcs_nop_instr -rcs_instructions[0][start_add+ 1] = rcs_nop_instr -rcs_instructions[0][start_add+ 2] = ["SRAM", "-", "LWD", "R1", "-", "-"] -rcs_instructions[0][start_add+ 3] = ["SRAM", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+ 4] = rcs_nop_instr -rcs_instructions[0][start_add+ 5] = [ "R2", "R1", "SSUB", "-", "-", "-"] -rcs_instructions[0][start_add+ 6] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] -rcs_instructions[0][start_add+ 7] = [ "R2", "PREV", "BSFA", "R2", "RCB", "-"] -rcs_instructions[0][start_add+ 8] = [ "R0", "-", "INA", "R1", "-", "-"] -rcs_instructions[0][start_add+ 9] = rcs_nop_instr -rcs_instructions[0][start_add+10] = [ "R2", "-", "SWD", "-", "-", "-"] - -################################################################################################# -############################################## RC1 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[1][start_add+ 0] = rcs_nop_instr -rcs_instructions[1][start_add+ 1] = ["SRAM", "-", "LWD", "R0", "-", "-"] -rcs_instructions[1][start_add+ 2] = [ "-", "IMM", "INB", "R1", "-", "-1"] -rcs_instructions[1][start_add+ 3] = [ "RCT", "-", "INA", "R3", "-", "-"] -rcs_instructions[1][start_add+ 4] = [ "R3", "R0", "SSUB", "-", "-", "-"] -rcs_instructions[1][start_add+ 5] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] -rcs_instructions[1][start_add+ 6] = [ "RCB", "PREV", "SADD", "-", "-", "-"] -rcs_instructions[1][start_add+ 7] = rcs_nop_instr -rcs_instructions[1][start_add+ 8] = [ "R3", "-", "INA", "R0", "-", "-"] -rcs_instructions[1][start_add+ 9] = rcs_nop_instr -rcs_instructions[1][start_add+10] = rcs_nop_instr - -################################################################################################# -############################################## RC2 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[2][start_add+ 0] = rcs_nop_instr -rcs_instructions[2][start_add+ 1] = rcs_nop_instr -rcs_instructions[2][start_add+ 2] = [ "-", "IMM", "INB", "R1", "-", "-1"] -rcs_instructions[2][start_add+ 3] = ["SRAM", "-", "INA", "-", "-", "-"] -rcs_instructions[2][start_add+ 4] = [ "RCB", "PREV", "SSUB", "-", "-", "-"] -rcs_instructions[2][start_add+ 5] = [ "R1", "R2", "BSFA", "-", "PREV", "-"] -rcs_instructions[2][start_add+ 6] = [ "RCT", "PREV", "SADD", "-", "-", "-"] -rcs_instructions[2][start_add+ 7] = rcs_nop_instr -rcs_instructions[2][start_add+ 8] = rcs_nop_instr -rcs_instructions[2][start_add+ 9] = rcs_nop_instr -rcs_instructions[2][start_add+10] = [ "-", "-", "EXIT", "-", "-", "-"] - -################################################################################################# -############################################## RC3 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[3][start_add+ 0] = ["SRAM", "-", "LWD", "R3", "-", "-"] -rcs_instructions[3][start_add+ 1] = rcs_nop_instr -rcs_instructions[3][start_add+ 2] = ["SRAM", "-", "INA", "R1", "-", "-"] -rcs_instructions[3][start_add+ 3] = [ "R1", "-", "INA", "-", "-", "-"] -rcs_instructions[3][start_add+ 4] = [ "RCB", "-", "INA", "R1", "-", "-"] -rcs_instructions[3][start_add+ 5] = [ "R0", "IMM", "SADD", "R0", "-", "1"] -rcs_instructions[3][start_add+ 6] = [ "R0", "R2", "BSFA", "-", "RCB", "-"] -rcs_instructions[3][start_add+ 7] = [ "R2", "PREV", "BSFA", "R2", "RCT", "-"] -rcs_instructions[3][start_add+ 8] = [ "R0", "R3", "BLT", "-", "-", "3"] -rcs_instructions[3][start_add+ 9] = [ "R2", "-", "SWD", "-", "-", "-"] -rcs_instructions[3][start_add+10] = rcs_nop_instr diff --git a/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py b/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py deleted file mode 100644 index 2669aa8d..00000000 --- a/hw/vendor/esl_epfl_cgra/util/instructions_min_max_circular.py +++ /dev/null @@ -1,83 +0,0 @@ -# -# MIN_MAX_CIRCULAR search instructions (manual mapping) DEPREDECATED -# - -ker_col_needed = 1 -ker_num_instr = 10 - -ker_conf_words[ker_next_id] = get_bin(int(pow(2,ker_col_needed))-1,CGRA_N_COL) +\ - get_bin(ker_start_add, CGRA_IMEM_NL_LOG2) +\ - get_bin(ker_num_instr-1, RCS_NUM_CREG_LOG2) - -# Save current start address -start_add = ker_start_add -# Update start address and ID for next kernel -ker_start_add = ker_start_add + ker_num_instr*ker_col_needed -ker_next_id = ker_next_id+1 - -# Used for multi-column kernels -k = ker_num_instr - -################################################################################################# -############################################## RC0 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[0][start_add+ 0] = rcs_nop_instr -rcs_instructions[0][start_add+ 1] = [ "RCB", "IMM", "SLT", "R3", "-", "2"] -rcs_instructions[0][start_add+ 2] = [ "RCB", "IMM", "SLT", "R1", "-", "2"] -rcs_instructions[0][start_add+ 3] = ["SRAM", "-", "LWD", "R0", "-", "-"] -rcs_instructions[0][start_add+ 4] = [ "R0", "R1", "SADD", "-", "-", "-"] -rcs_instructions[0][start_add+ 5] = [ "R1", "IMM", "SADD", "-", "-", "4"] -rcs_instructions[0][start_add+ 6] = [ "R3", "PREV", "LAND", "R1", "-", "-"] -rcs_instructions[0][start_add+ 7] = [ "R0", "R1", "SADD", "-", "-", "-"] -rcs_instructions[0][start_add+ 8] = rcs_nop_instr -rcs_instructions[0][start_add+ 9] = rcs_nop_instr - -################################################################################################# -############################################## RC1 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[1][start_add+ 0] = ["SRAM", "-", "LWD", "-", "-", "-"] -rcs_instructions[1][start_add+ 1] = ["SRAM", "-", "LWD", "-", "-", "-"] -rcs_instructions[1][start_add+ 2] = ["SRAM", "-", "LWD", "R3", "-", "-"] -rcs_instructions[1][start_add+ 3] = rcs_nop_instr -rcs_instructions[1][start_add+ 4] = rcs_nop_instr -rcs_instructions[1][start_add+ 5] = ["SRAM", "RCT", "LWI", "-", "-", "-"] -rcs_instructions[1][start_add+ 6] = [ "R0", "IMM", "SADD", "R0", "-", "1"] -rcs_instructions[1][start_add+ 7] = [ "R0", "R3", "BLT", "-", "-", "5"] -rcs_instructions[1][start_add+ 8] = rcs_nop_instr -rcs_instructions[1][start_add+ 9] = rcs_nop_instr - -################################################################################################# -############################################## RC2 ############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[2][start_add+ 0] = rcs_nop_instr -rcs_instructions[2][start_add+ 1] = rcs_nop_instr -rcs_instructions[2][start_add+ 2] = rcs_nop_instr -rcs_instructions[2][start_add+ 3] = rcs_nop_instr -rcs_instructions[2][start_add+ 4] = rcs_nop_instr -rcs_instructions[2][start_add+ 5] = ["SRAM", "-", "INA", "R1", "-", "-"] -rcs_instructions[2][start_add+ 6] = [ "R0", "R1", "SSUB", "-", "-", "-"] -rcs_instructions[2][start_add+ 7] = [ "R1", "R0", "BSFA", "R0", "PREV", "-"] -rcs_instructions[2][start_add+ 8] = [ "R0", "-", "SWD", "-", "-", "-"] -rcs_instructions[2][start_add+ 9] = [ "-", "-", "EXIT", "-", "-", "-"] - -################################################################################################# -############################################## RC03############################################## -################################################################################################# - -# COLUMN-0 -rcs_instructions[3][start_add+ 0] = rcs_nop_instr -rcs_instructions[3][start_add+ 1] = rcs_nop_instr -rcs_instructions[3][start_add+ 2] = rcs_nop_instr -rcs_instructions[3][start_add+ 3] = rcs_nop_instr -rcs_instructions[3][start_add+ 4] = rcs_nop_instr -rcs_instructions[3][start_add+ 5] = ["SRAM", "-", "INA", "R1", "-", "-"] -rcs_instructions[3][start_add+ 6] = [ "R0", "R1", "SSUB", "-", "-", "-"] -rcs_instructions[3][start_add+ 7] = [ "R0", "R1", "BSFA", "R0", "PREV", "-"] -rcs_instructions[3][start_add+ 8] = rcs_nop_instr -rcs_instructions[3][start_add+ 9] = [ "R0", "-", "SWD", "-", "-", "-"] diff --git a/hw/vendor/esl_epfl_x_heep/Makefile b/hw/vendor/esl_epfl_x_heep/Makefile index f65c4640..e1c6deac 100644 --- a/hw/vendor/esl_epfl_x_heep/Makefile +++ b/hw/vendor/esl_epfl_x_heep/Makefile @@ -150,13 +150,13 @@ verible: ## @param COMPILER_PREFIX=riscv32-unknown-(default) ## @param ARCH=rv32imc(default), app: clean-app - $(MAKE) -C sw PROJECT=$(PROJECT) TARGET=$(TARGET) LINKER=$(LINKER) LINK_FOLDER=$(LINK_FOLDER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH) SOURCE=$(SOURCE) \ + @$(MAKE) -C sw PROJECT=$(PROJECT) TARGET=$(TARGET) LINKER=$(LINKER) LINK_FOLDER=$(LINK_FOLDER) COMPILER=$(COMPILER) COMPILER_PREFIX=$(COMPILER_PREFIX) ARCH=$(ARCH) SOURCE=$(SOURCE) \ || { \ - echo "\033[0;31mHmmm... seems like the compilation failed...\033[0m"; \ - echo "\033[0;31mIf you do not understand why, it is likely that you either:\033[0m"; \ - echo "\033[0;31m a) offended the Leprechaun of Electronics\033[0m"; \ - echo "\033[0;31m b) forgot to run make mcu-gen\033[0m"; \ - echo "\033[0;31mI would start by checking b) if I were you!\033[0m"; \ + @echo "\033[0;31mHmmm... seems like the compilation failed...\033[0m"; \ + @echo "\033[0;31mIf you do not understand why, it is likely that you either:\033[0m"; \ + @echo "\033[0;31m a) offended the Leprechaun of Electronics\033[0m"; \ + @echo "\033[0;31m b) forgot to run make mcu-gen\033[0m"; \ + @echo "\033[0;31mI would start by checking b) if I were you!\033[0m"; \ exit 1; \ } diff --git a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt index cdb2a8f7..adc4546e 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt +++ b/hw/vendor/esl_epfl_x_heep/sw/CMakeLists.txt @@ -13,7 +13,7 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# Author: Juan Sapriza (juan.sapriza@epfl.ch) +# Author: Jose Miranda, Juan Sapriza (jose.mirandacalero / juan.sapriza @epfl.ch) cmake_minimum_required(VERSION 3.15) @@ -154,7 +154,9 @@ ENDFOREACH() # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # If the app was not found, look into the root project +# Before re-setting SOURCE_PATH, save it so we can look later for external defined files +SET(ORIGIN_SRCPATH ${SOURCE_PATH}) if( app_found EQUAL 0 ) SET(SOURCE_PATH ${ROOT_PROJECT}) @@ -185,9 +187,9 @@ if( app_found EQUAL 0 ) string(REPLACE ";" "" c_dir_list ${c_dir_list}) endif() - ENDFOREACH() - endif() - + ENDFOREACH() +endif() + LIST(REMOVE_DUPLICATES c_dir_list) @@ -204,6 +206,11 @@ else() message( "${Magenta}External application${ColourReset}") endif() +####################################################################### +# ADD CUSTOM DEFINITIONS +####################################################################### +add_compile_definitions($ENV{CDEFS}) + ####################################################################### # FIND CRT FILES TO BE INCLUDED ####################################################################### @@ -219,15 +226,27 @@ SET(LIB_VCTR_P "${ROOT_PROJECT}device/lib/crt/vectors.S") SET(CRTO "INTERNAL_CRTO") SET( LIB_CRT_EXT_P "" ) -if( internal_app EQUAL 0 ) - FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS "${SOURCE_PATH}/external/lib/crt/*.S") +FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS "${SOURCE_PATH}/external/lib/crt/*.S") +FOREACH(file_path IN LISTS new_list) + if(${file_path} MATCHES "external_crt0.S") + SET( CRTO "EXTERNAL_CRTO" ) + SET( LIB_CRT_EXT_P "${file_path}" ) + GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) + SET(INCLUDE_FOLDERS "${INCLUDE_FOLDERS} -I ${dir_path}") + SET(h_dir_list_ ${h_dir_list_} "${dir_path}") + endif() +ENDFOREACH() + +#In case the application is internal, but there is still an external CRT +if(NOT ${ORIGIN_SRCPATH} MATCHES ${SOURCE_PATH}) + FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS "${ORIGIN_SRCPATH}external/lib/crt/*.S") FOREACH(file_path IN LISTS new_list) if(${file_path} MATCHES "external_crt0.S") - SET( CRTO "EXTERNAL_CRTO" ) - SET( LIB_CRT_EXT_P "${file_path}" ) - GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) - SET(INCLUDE_FOLDERS "${INCLUDE_FOLDERS} -I ${dir_path}") - SET(h_dir_list_ ${h_dir_list_} "${dir_path}") + SET( CRTO "EXTERNAL_CRTO" ) + SET( LIB_CRT_EXT_P "${file_path}" ) + GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) + SET(INCLUDE_FOLDERS "${INCLUDE_FOLDERS} -I ${dir_path}") + SET(h_dir_list_ ${h_dir_list_} "${dir_path}") endif() ENDFOREACH() endif() @@ -262,6 +281,7 @@ else() message( FATAL_ERROR "Linker specification is not correct" ) endif() +if (${VERBOSE} MATCHES "true") # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Debug messages to check the paths @@ -271,10 +291,10 @@ message( "${Magenta}Root project: ${ROOT_PROJECT}${ColourReset}") message( "${Magenta}Source path: ${SOURCE_PATH}${ColourReset}") message( "${Magenta}LIB_CRT PATH for Cmake: ${LIB_CRT_P}${ColourReset}") message( "${Magenta}LINKER File for Cmake: ${LINK_FILE}${ColourReset}") -message( "${Magenta}LIB_DRIVERS PATH for Cmake: ${LIB_DRIVERS}${ColourReset}") -message( "${Magenta}Targetting folder: ${INC_FOLDERS}${ColourReset}") message( "${Magenta}Target: ${TARGET}${ColourReset}") +endif() + ####################################################################### # SET LINKER PROPERTIES @@ -289,7 +309,9 @@ SET(LINKED_FILES "${LIB_CRT_P} \ ${LIB_CRT_EXT_P} \ ${c_dir_list}") -message( "${Magenta}Linked files: ${LINKED_FILES}${ColourReset}") +if (${VERBOSE} MATCHES "true") + message( "${Magenta}Linked files: ${LINKED_FILES}${ColourReset}") +endif() # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Free-RTOS configurations @@ -413,7 +435,11 @@ SET(CMAKE_EXE_LINKER_FLAGS "-T ${LINKER_SCRIPT} \ -ffunction-sections -fdata-sections -specs=nano.specs") message( "${Magenta}Lib Folder RISCV-GCC: ${RISCV}/${COMPILER_PREFIX}elf/lib${ColourReset}") -SET(CMAKE_VERBOSE_MAKEFILE on) +if (${VERBOSE} MATCHES "true") + SET(CMAKE_VERBOSE_MAKEFILE ON) +else() + SET(CMAKE_VERBOSE_MAKEFILE OFF) +endif() # To make sure that .obj files are created and fetched from the same path. # When setting an inner path to add_executable, .obj files are stored in ${MAINFILE}.elf.dir/ @@ -434,7 +460,7 @@ if (${COMPILER} MATCHES "clang") _deps/freertos_kernel-build/libfreertos_kernel.a \ _deps/freertos_kernel-build/portable/libfreertos_kernel_port.a \ _deps/freertos_kernel-build/libfreertos_kernel.a \ _deps/freertos_kernel-build/portable/libfreertos_kernel_port.a \ ") else() - set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_LINKER} ${COMPILER_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS} \ + set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_LINKER} ${COMPILER_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS} \ ${SOURCE_PATH}build/CMakeFiles/${MAINFILE}.elf.dir/${OBJ_PATH}applications/${PROJECT}/${MAINFILE}.c.obj \ -o ${MAINFILE}.elf") endif() diff --git a/hw/vendor/esl_epfl_x_heep/sw/Makefile b/hw/vendor/esl_epfl_x_heep/sw/Makefile index e327138b..e0fa1ff1 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/Makefile +++ b/hw/vendor/esl_epfl_x_heep/sw/Makefile @@ -15,7 +15,7 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# Author: Juan Sapriza (juan.sapriza@epfl.ch) +# Author: Jose Miranda, Juan Sapriza (jose.mirandacalero / juan.sapriza @epfl.ch) MAKE = make @@ -40,6 +40,8 @@ ARCH ?= rv32imc # Path relative from the location of sw/Makefile from which to fetch source files. The directory of that file is the default value. SOURCE ?= $(".") +VERBOSE ?= false + # riscv toolchain install path RISCV ?= ~/.riscv RISCV_EXE_PREFIX = $(RISCV)/bin/${COMPILER_PREFIX}elf- @@ -48,13 +50,14 @@ RISCV_GDB_PATH = $(RISCV_EXE_PREFIX)gdb # Get the absolute path mkfile_path := $(shell dirname "$(realpath $(firstword $(MAKEFILE_LIST)))") -# Check the absolute path -$(info $$You are executing from: $(mkfile_path)) - # Get the absolute path of where to fetch sources source_path := $(realpath $(mkfile_path)/$(SOURCE)) -$(info $$You are fetching sources from $(source_path) ) +ifeq ($(ARG), value1) + $(info $$You are executing from: $(mkfile_path)) +else ifeq ($(ARG), value2) + $(info $$You are fetching sources from $(source_path) ) +endif SOURCE_PATH = $(source_path)/ ROOT_PROJECT = $(mkfile_path)/ @@ -64,6 +67,7 @@ LINK_FOLDER ?= $(mkfile_path)/linker # CMake keyword CMAKE_DIR=cmake +# to distinguish between cmake distros ifeq (, $(shell which cmake3)) # cmake3 is not defined CMAKE=cmake else diff --git a/hw/vendor/esl_epfl_x_heep/sw/cmake/targets.mak b/hw/vendor/esl_epfl_x_heep/sw/cmake/targets.mak index 33ab1777..d7679da5 100644 --- a/hw/vendor/esl_epfl_x_heep/sw/cmake/targets.mak +++ b/hw/vendor/esl_epfl_x_heep/sw/cmake/targets.mak @@ -13,17 +13,17 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# Author: Juan Sapriza (juan.sapriza@epfl.ch) +# Author: Jose Miranda, Juan Sapriza (jose.mirandacalero / juan.sapriza @epfl.ch) build : build/Makefile @echo Build - ${MAKE} -C build + ${MAKE} -s -C build setup : build/Makefile build/Makefile : CMakeLists.txt ${CMAKE_DIR}/riscv.cmake - if [ ! -d build ] ; then mkdir build ; fi - cd build; \ + @if [ ! -d build ] ; then mkdir build ; fi + @cd build; \ ${CMAKE} \ -G "Unix Makefiles" \ -DCMAKE_TOOLCHAIN_FILE=../${CMAKE_DIR}/riscv.cmake \ @@ -32,11 +32,11 @@ build/Makefile : CMakeLists.txt ${CMAKE_DIR}/riscv.cmake -DTARGET=${TARGET} \ -DPROJECT:STRING=${PROJECT} \ -DRISCV:STRING=${RISCV} \ - -DINC_FOLDERS:STRING=${INC_FOLDERS} \ -DLINK_FOLDER:STRING=${LINK_FOLDER} \ -DLINKER:STRING=${LINKER} \ -DCOMPILER:STRING=${COMPILER} \ -DCOMPILER_PREFIX:STRING=${COMPILER_PREFIX} \ + -DVERBOSE:STRING=${VERBOSE} \ ../ clean: diff --git a/hw/vendor/eslepfl_cgra.lock.hjson b/hw/vendor/eslepfl_cgra.lock.hjson index 3e767f56..b4a34e3f 100644 --- a/hw/vendor/eslepfl_cgra.lock.hjson +++ b/hw/vendor/eslepfl_cgra.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/OpenEdgeCGRA.git - rev: 92cc0b97dd9f11b17b16a2d1cc19adc902bec3d1 + rev: 618b45d2c5deb0ae3741b8dfdd472354ed073126 } } diff --git a/hw/vendor/eslepfl_cgra.vendor.hjson b/hw/vendor/eslepfl_cgra.vendor.hjson index 1e05fb8b..7848d7e9 100644 --- a/hw/vendor/eslepfl_cgra.vendor.hjson +++ b/hw/vendor/eslepfl_cgra.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/esl-epfl/OpenEdgeCGRA.git", - rev: "92cc0b97dd9f11b17b16a2d1cc19adc902bec3d1", + rev: "618b45d2c5deb0ae3741b8dfdd472354ed073126", }, patch_dir: "patches/esl_epfl_cgra", diff --git a/hw/vendor/eslepfl_x_heep.lock.hjson b/hw/vendor/eslepfl_x_heep.lock.hjson index 213b5fa1..c432c29c 100644 --- a/hw/vendor/eslepfl_x_heep.lock.hjson +++ b/hw/vendor/eslepfl_x_heep.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/esl-epfl/x-heep.git - rev: 83f1563fd4894787167b27099006c8b1b042d3d1 + rev: 2c6d7d8f581020d4961bd08dbd3956c90b676085 } } diff --git a/hw/vendor/eslepfl_x_heep.vendor.hjson b/hw/vendor/eslepfl_x_heep.vendor.hjson index 0dcb0caa..32af0bc2 100644 --- a/hw/vendor/eslepfl_x_heep.vendor.hjson +++ b/hw/vendor/eslepfl_x_heep.vendor.hjson @@ -8,7 +8,7 @@ upstream: { url: "https://github.com/esl-epfl/x-heep.git", - rev: "83f1563fd4894787167b27099006c8b1b042d3d1", + rev: "2c6d7d8f581020d4961bd08dbd3956c90b676085", }, patch_dir: "patches/esl_epfl_x_heep", From 984e55bf1c26d6cd45c01bfc29c1fd5a589a4a90 Mon Sep 17 00:00:00 2001 From: jmiranda Date: Tue, 8 Oct 2024 15:02:28 +0200 Subject: [PATCH 27/27] revendorizing x-heep and cgra to fix ci issues --- hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv index beed1bcf..2e43dd14 100644 --- a/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv +++ b/hw/vendor/esl_epfl_x_heep/tb/ext_bus.sv @@ -137,9 +137,8 @@ module ext_bus #( // show writes if requested always_ff @(posedge clk_i, negedge rst_ni) begin : verbose_writes if ($test$plusargs("verbose") != 0 && heep_core_data_req_i.req && heep_core_data_req_i.we) - $display( - "write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, heep_core_data_req_i.wdata - ); + $display("write addr=0x%08x: data=0x%08x", heep_core_data_req_i.addr, + heep_core_data_req_i.wdata); end `endif